Fix USE_RTC6705_CLK_HACK resource checking.
[betaflight.git] / src / main / drivers / vtx_rtc6705.c
blob4b16aff44c4e2a797dd6dfe8414e916ccebc39ed
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
22 * Author: Giles Burgess (giles@multiflite.co.uk)
24 * This source code is provided as is and can be used/modified so long
25 * as this header is maintained with the file at all times.
28 #include <stdbool.h>
29 #include <stdint.h>
31 #include "platform.h"
33 #if defined(USE_VTX_RTC6705) && !defined(USE_VTX_RTC6705_SOFTSPI)
35 #include "common/maths.h"
37 #include "drivers/bus_spi.h"
38 #include "drivers/bus_spi_impl.h"
39 #include "drivers/io.h"
40 #include "drivers/time.h"
41 #include "drivers/vtx_rtc6705.h"
43 #define RTC6705_SET_HEAD 0x3210 //fosc=8mhz r=400
44 #define RTC6705_SET_R 400 //Reference clock
45 #define RTC6705_SET_FDIV 1024 //128*(fosc/1000000)
46 #define RTC6705_SET_NDIV 16 //Remainder divider to get 'A' part of equation
47 #define RTC6705_SET_WRITE 0x11 //10001b to write to register
48 #define RTC6705_SET_DIVMULT 1000000 //Division value (to fit into a uint32_t) (Hz to MHz)
50 #ifdef RTC6705_POWER_PIN
51 static IO_t vtxPowerPin = IO_NONE;
52 #endif
54 static busDevice_t busInstance;
55 static busDevice_t *busdev;
57 #define DISABLE_RTC6705() IOHi(busdev->busdev_u.spi.csnPin)
59 #ifdef USE_RTC6705_CLK_HACK
60 static IO_t vtxCLKPin = IO_NONE;
61 // HACK for missing pull up on CLK line - drive the CLK high *before* enabling the CS pin.
62 #define ENABLE_RTC6705() {IOHi(vtxCLKPin); delayMicroseconds(5); IOLo(busdev->busdev_u.spi.csnPin); }
63 #else
64 #define ENABLE_RTC6705() IOLo(busdev->busdev_u.spi.csnPin)
65 #endif
67 #define DP_5G_MASK 0x7000 // b111000000000000
68 #define PA5G_BS_MASK 0x0E00 // b000111000000000
69 #define PA5G_PW_MASK 0x0180 // b000000110000000
70 #define PD_Q5G_MASK 0x0040 // b000000001000000
71 #define QI_5G_MASK 0x0038 // b000000000111000
72 #define PA_BS_MASK 0x0007 // b000000000000111
74 #define PA_CONTROL_DEFAULT 0x4FBD
76 #define RTC6705_RW_CONTROL_BIT (1 << 4)
77 #define RTC6705_ADDRESS (0x07)
79 #define ENABLE_VTX_POWER() IOLo(vtxPowerPin)
80 #define DISABLE_VTX_POWER() IOHi(vtxPowerPin)
82 /**
83 * Reverse a uint32_t (LSB to MSB)
84 * This is easier for when generating the frequency to then
85 * reverse the bits afterwards
87 static uint32_t reverse32(uint32_t in)
89 uint32_t out = 0;
91 for (uint8_t i = 0 ; i < 32 ; i++) {
92 out |= ((in>>i) & 1)<<(31-i);
95 return out;
98 /**
99 * Start chip if available
101 bool rtc6705IOInit(const vtxIOConfig_t *vtxIOConfig)
103 busdev = &busInstance;
105 busdev->busdev_u.spi.csnPin = IOGetByTag(vtxIOConfig->csTag);
107 bool rtc6705HaveRequiredResources =
108 (busdev->busdev_u.spi.csnPin != IO_NONE);
110 #ifdef RTC6705_POWER_PIN
111 vtxPowerPin = IOGetByTag(vtxIOConfig->powerTag);
113 rtc6705HaveRequiredResources = rtc6705HaveRequiredResources && vtxPowerPin;
114 #endif
116 #ifdef USE_RTC6705_CLK_HACK
117 SPIDevice device = SPI_CFG_TO_DEV(vtxIOConfig->spiDevice);
118 spiDevice_t *spi = &(spiDevice[device]);
120 vtxCLKPin = IOGetByTag(spi->sck);
121 // we assume the CLK pin will have been initialised by the SPI code.
123 rtc6705HaveRequiredResources = rtc6705HaveRequiredResources && vtxCLKPin;
124 #endif
126 if (!rtc6705HaveRequiredResources) {
127 return false;
130 #ifdef RTC6705_POWER_PIN
131 IOInit(vtxPowerPin, OWNER_VTX_POWER, 0);
133 DISABLE_VTX_POWER();
134 IOConfigGPIO(vtxPowerPin, IOCFG_OUT_PP);
135 #endif
138 IOInit(busdev->busdev_u.spi.csnPin, OWNER_VTX_CS, 0);
140 DISABLE_RTC6705();
141 // GPIO bit is enabled so here so the output is not pulled low when the GPIO is set in output mode.
142 // Note: It's critical to ensure that incorrect signals are not sent to the VTX.
143 IOConfigGPIO(busdev->busdev_u.spi.csnPin, IOCFG_OUT_PP);
145 busdev->bustype = BUSTYPE_SPI;
146 spiBusSetInstance(busdev, spiInstanceByDevice(SPI_CFG_TO_DEV(vtxIOConfig->spiDevice)));
148 return true;
152 * Transfer a 25bit packet to RTC6705
153 * This will just send it as a 32bit packet LSB meaning
154 * extra 0's get truncated on RTC6705 end
156 static void rtc6705Transfer(uint32_t command)
158 command = reverse32(command);
160 ENABLE_RTC6705();
162 spiTransferByte(busdev->busdev_u.spi.instance, (command >> 24) & 0xFF);
163 spiTransferByte(busdev->busdev_u.spi.instance, (command >> 16) & 0xFF);
164 spiTransferByte(busdev->busdev_u.spi.instance, (command >> 8) & 0xFF);
165 spiTransferByte(busdev->busdev_u.spi.instance, (command >> 0) & 0xFF);
167 delayMicroseconds(2);
169 DISABLE_RTC6705();
171 delayMicroseconds(2);
175 * Set a frequency in Mhz
176 * Formula derived from datasheet
178 void rtc6705SetFrequency(uint16_t frequency)
180 frequency = constrain(frequency, VTX_RTC6705_FREQ_MIN, VTX_RTC6705_FREQ_MAX);
182 const uint32_t val_a = ((((uint64_t)frequency*(uint64_t)RTC6705_SET_DIVMULT*(uint64_t)RTC6705_SET_R)/(uint64_t)RTC6705_SET_DIVMULT) % RTC6705_SET_FDIV) / RTC6705_SET_NDIV; //Casts required to make sure correct math (large numbers)
183 const uint32_t val_n = (((uint64_t)frequency*(uint64_t)RTC6705_SET_DIVMULT*(uint64_t)RTC6705_SET_R)/(uint64_t)RTC6705_SET_DIVMULT) / RTC6705_SET_FDIV; //Casts required to make sure correct math (large numbers)
185 uint32_t val_hex = RTC6705_SET_WRITE;
186 val_hex |= (val_a << 5);
187 val_hex |= (val_n << 12);
189 spiSetDivisor(busdev->busdev_u.spi.instance, SPI_CLOCK_SLOW);
191 rtc6705Transfer(RTC6705_SET_HEAD);
192 delayMicroseconds(10);
193 rtc6705Transfer(val_hex);
196 void rtc6705SetRFPower(uint8_t rf_power)
198 rf_power = constrain(rf_power, VTX_RTC6705_MIN_POWER, VTX_RTC6705_POWER_COUNT - 1);
200 spiSetDivisor(busdev->busdev_u.spi.instance, SPI_CLOCK_SLOW);
202 uint32_t val_hex = RTC6705_RW_CONTROL_BIT; // write
203 val_hex |= RTC6705_ADDRESS; // address
204 const uint32_t data = rf_power > 1 ? PA_CONTROL_DEFAULT : (PA_CONTROL_DEFAULT | PD_Q5G_MASK) & (~(PA5G_PW_MASK | PA5G_BS_MASK));
205 val_hex |= data << 5; // 4 address bits and 1 rw bit.
207 rtc6705Transfer(val_hex);
210 void rtc6705Disable(void)
212 #ifdef RTC6705_POWER_PIN
213 DISABLE_VTX_POWER();
214 #endif
217 void rtc6705Enable(void)
219 #ifdef RTC6705_POWER_PIN
220 ENABLE_VTX_POWER();
221 #endif
224 #endif