Merge pull request #11198 from SteveCEvans/sce_rc2
[betaflight.git] / src / main / drivers / vtx_rtc6705.c
blobcd2d1aa00baed9f3241720c9c101044a30d42fd5
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)
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_soft_spi.h"
43 #include "vtx_rtc6705.h"
45 // 1 MHz max SPI frequency - datasheet says 10MHz, but this is lower for some reason
46 #define RTC6705_MAX_SPI_CLK_HZ 1000000
48 #define RTC6705_SET_HEAD 0x3210 //fosc=8mhz r=400
49 #define RTC6705_SET_R 400 //Reference clock
50 #define RTC6705_SET_FDIV 1024 //128*(fosc/1000000)
51 #define RTC6705_SET_NDIV 16 //Remainder divider to get 'A' part of equation
52 #define RTC6705_SET_WRITE 0x11 //10001b to write to register
53 #define RTC6705_SET_DIVMULT 1000000 //Division value (to fit into a uint32_t) (Hz to MHz)
55 #ifdef RTC6705_POWER_PIN
56 static IO_t vtxPowerPin = IO_NONE;
57 #endif
59 static extDevice_t *dev = NULL;
61 #define DISABLE_RTC6705() IOHi(dev->busType_u.spi.csnPin)
62 #define ENABLE_RTC6705() IOLo(dev->busType_u.spi.csnPin)
64 #define DP_5G_MASK 0x7000 // b111000000000000
65 #define PA5G_BS_MASK 0x0E00 // b000111000000000
66 #define PA5G_PW_MASK 0x0180 // b000000110000000
67 #define PD_Q5G_MASK 0x0040 // b000000001000000
68 #define QI_5G_MASK 0x0038 // b000000000111000
69 #define PA_BS_MASK 0x0007 // b000000000000111
71 #define PA_CONTROL_DEFAULT 0x4FBD
73 #define RTC6705_RW_CONTROL_BIT (1 << 4)
74 #define RTC6705_ADDRESS (0x07)
76 /**
77 * Reverse a uint32_t (LSB to MSB)
78 * This is easier for when generating the frequency to then
79 * reverse the bits afterwards
81 static uint32_t reverse32(uint32_t in)
83 uint32_t out = 0;
85 for (uint8_t i = 0 ; i < 32 ; i++) {
86 out |= ((in>>i) & 1)<<(31-i);
89 return out;
92 /**
93 * Start chip if available
95 bool rtc6705IOInit(const vtxIOConfig_t *vtxIOConfig)
97 static extDevice_t devInstance;
99 IO_t csnPin = IOGetByTag(vtxIOConfig->csTag);
100 if (!csnPin) {
101 return false;
104 vtxPowerPin = IOGetByTag(vtxIOConfig->powerTag);
105 if (vtxPowerPin) {
106 IOInit(vtxPowerPin, OWNER_VTX_POWER, 0);
108 IOHi(vtxPowerPin);
110 IOConfigGPIO(vtxPowerPin, IOCFG_OUT_PP);
113 // RTC6705 when using SOFT SPI driver doesn't use an SPI device, so don't attempt to initialise an spiInstance.
114 SPI_TypeDef *spiInstance = spiInstanceByDevice(SPI_CFG_TO_DEV(vtxIOConfig->spiDevice));
115 if (spiInstance && spiSetBusInstance(dev, vtxIOConfig->spiDevice)) {
116 devInstance.busType_u.spi.csnPin = csnPin;
117 IOInit(devInstance.busType_u.spi.csnPin, OWNER_VTX_CS, 0);
119 DISABLE_RTC6705();
120 // GPIO bit is enabled so here so the output is not pulled low when the GPIO is set in output mode.
121 // Note: It's critical to ensure that incorrect signals are not sent to the VTX.
122 IOConfigGPIO(devInstance.busType_u.spi.csnPin, IOCFG_OUT_PP);
124 return true;
125 #if defined(USE_VTX_RTC6705_SOFTSPI)
126 } else {
127 return rtc6705SoftSpiIOInit(vtxIOConfig, csnPin);
128 #endif
131 return false;;
135 * Transfer a 25bit packet to RTC6705
136 * This will just send it as a 32bit packet LSB meaning
137 * extra 0's get truncated on RTC6705 end
139 static void rtc6705Transfer(uint32_t command)
141 // Perform bitwise reverse of the command.
142 command = reverse32(command);
144 spiReadWriteBuf(dev, (uint8_t *)&command, NULL, sizeof(command));
146 delayMicroseconds(2);
150 * Set a frequency in Mhz
151 * Formula derived from datasheet
153 void rtc6705SetFrequency(uint16_t frequency)
155 #if defined(USE_VTX_RTC6705_SOFTSPI)
156 if (!dev) {
157 rtc6705SoftSpiSetFrequency(frequency);
159 return;
161 #endif
163 frequency = constrain(frequency, VTX_RTC6705_FREQ_MIN, VTX_RTC6705_FREQ_MAX);
165 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)
166 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)
168 uint32_t val_hex = RTC6705_SET_WRITE;
169 val_hex |= (val_a << 5);
170 val_hex |= (val_n << 12);
172 spiSetClkDivisor(dev, spiCalculateDivider(RTC6705_MAX_SPI_CLK_HZ));
174 rtc6705Transfer(RTC6705_SET_HEAD);
175 delayMicroseconds(10);
176 rtc6705Transfer(val_hex);
179 void rtc6705SetRFPower(uint8_t rf_power)
181 rf_power = constrain(rf_power, 1, 2);
182 #if defined(USE_VTX_RTC6705_SOFTSPI)
183 if (!dev) {
184 rtc6705SoftSpiSetRFPower(rf_power);
186 return;
188 #endif
190 uint32_t val_hex = RTC6705_RW_CONTROL_BIT; // write
191 val_hex |= RTC6705_ADDRESS; // address
192 const uint32_t data = rf_power > 1 ? PA_CONTROL_DEFAULT : (PA_CONTROL_DEFAULT | PD_Q5G_MASK) & (~(PA5G_PW_MASK | PA5G_BS_MASK));
193 val_hex |= data << 5; // 4 address bits and 1 rw bit.
195 spiSetClkDivisor(dev, spiCalculateDivider(RTC6705_MAX_SPI_CLK_HZ));
197 rtc6705Transfer(val_hex);
200 void rtc6705Disable(void)
202 if (vtxPowerPin) {
203 IOHi(vtxPowerPin);
207 void rtc6705Enable(void)
209 if (vtxPowerPin) {
210 IOLo(vtxPowerPin);
213 #endif