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)
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.
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
;
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); }
64 #define ENABLE_RTC6705() IOLo(busdev->busdev_u.spi.csnPin)
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)
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
)
91 for (uint8_t i
= 0 ; i
< 32 ; i
++) {
92 out
|= ((in
>>i
) & 1)<<(31-i
);
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
;
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
;
126 if (!rtc6705HaveRequiredResources
) {
130 #ifdef RTC6705_POWER_PIN
131 IOInit(vtxPowerPin
, OWNER_VTX_POWER
, 0);
134 IOConfigGPIO(vtxPowerPin
, IOCFG_OUT_PP
);
138 IOInit(busdev
->busdev_u
.spi
.csnPin
, OWNER_VTX_CS
, 0);
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
)));
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
);
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);
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
217 void rtc6705Enable(void)
219 #ifdef RTC6705_POWER_PIN