Various fixes around Companion trainer mode (#7116)
[opentx.git] / radio / src / targets / horus / x12s_adc_driver.cpp
blob2833c4620155a990c4c64bd98be56155373d1d4c
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "opentx.h"
23 uint16_t adcValues[NUM_ANALOGS] __DMA;
24 uint16_t rtcBatteryVoltage;
26 #define ADC_CS_HIGH() (ADC_SPI_GPIO->BSRRL = ADC_SPI_PIN_CS)
27 #define ADC_CS_LOW() (ADC_SPI_GPIO->BSRRH = ADC_SPI_PIN_CS)
29 #define SPI_STICK1 0
30 #define SPI_STICK2 1
31 #define SPI_STICK3 2
32 #define SPI_STICK4 3
33 #define SPI_S1 4
34 #define SPI_6POS 5
35 #define SPI_S2 6
36 #define SPI_LS 7
37 #define SPI_RS 8
38 #define SPI_TX_VOLTAGE 9
39 #define SPI_L2 10
40 #define SPI_L1 11
41 #define RESETCMD 0x4000
42 #define MANUAL_MODE 0x1000 // manual mode channel 0
44 uint16_t SPIx_ReadWriteByte(uint16_t value)
46 while (SPI_I2S_GetFlagStatus(ADC_SPI, SPI_I2S_FLAG_TXE) == RESET);
47 SPI_I2S_SendData(ADC_SPI, value);
49 while (SPI_I2S_GetFlagStatus(ADC_SPI, SPI_I2S_FLAG_RXNE) == RESET);
50 return SPI_I2S_ReceiveData(ADC_SPI);
53 static void ADS7952_Init()
55 GPIO_InitTypeDef GPIO_InitStructure;
56 SPI_InitTypeDef SPI_InitStructure;
58 GPIO_InitStructure.GPIO_Pin = ADC_SPI_PIN_MISO | ADC_SPI_PIN_SCK | ADC_SPI_PIN_MOSI;
59 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
60 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
61 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
62 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
63 GPIO_Init(ADC_SPI_GPIO, &GPIO_InitStructure);
65 GPIO_InitStructure.GPIO_Pin = ADC_SPI_PIN_CS;
66 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
67 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
68 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
69 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
70 GPIO_Init(ADC_SPI_GPIO, &GPIO_InitStructure);
72 GPIO_PinAFConfig(ADC_SPI_GPIO, ADC_SPI_PinSource_SCK, ADC_GPIO_AF);
73 GPIO_PinAFConfig(ADC_SPI_GPIO, ADC_SPI_PinSource_MISO, ADC_GPIO_AF);
74 GPIO_PinAFConfig(ADC_SPI_GPIO, ADC_SPI_PinSource_MOSI, ADC_GPIO_AF);
76 SPI_I2S_DeInit(ADC_SPI);
78 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
79 SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
80 SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
81 SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
82 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
83 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
84 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
85 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
86 SPI_InitStructure.SPI_CRCPolynomial = 7;
87 SPI_Init(ADC_SPI, &SPI_InitStructure);
88 SPI_Cmd(ADC_SPI, ENABLE);
89 SPI_I2S_ITConfig(ADC_SPI, SPI_I2S_IT_TXE, DISABLE);
90 SPI_I2S_ITConfig(ADC_SPI, SPI_I2S_IT_RXNE, DISABLE);
92 ADC_CS_HIGH();
93 delay_01us(1);
94 ADC_CS_LOW();
95 SPIx_ReadWriteByte(RESETCMD);
96 ADC_CS_HIGH();
97 delay_01us(1);
98 ADC_CS_LOW();
99 SPIx_ReadWriteByte(MANUAL_MODE);
100 ADC_CS_HIGH();
103 void adcInit()
105 ADS7952_Init();
107 GPIO_InitTypeDef GPIO_InitStructure;
108 GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN_MOUSE1 | ADC_GPIO_PIN_MOUSE2;
109 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
110 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
111 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
112 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
113 GPIO_Init(ADC_GPIO_MOUSE, &GPIO_InitStructure);
115 ADC3->CR1 = ADC_CR1_SCAN;
116 ADC3->CR2 = ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS;
117 ADC3->SQR1 = (2 - 1) << 20;
118 ADC3->SQR2 = 0;
119 ADC3->SQR3 = (ADC_CHANNEL_MOUSE1 << 0) + (ADC_CHANNEL_MOUSE2 << 5);
120 ADC3->SMPR1 = (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24);
121 ADC3->SMPR2 = (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24) + (ADC_SAMPTIME << 27);
122 ADC->CCR = 0;
124 // Enable the DMA channel here, DMA2 stream 1, channel 2
125 ADC_DMA_Stream->CR = DMA_SxCR_PL | DMA_SxCR_CHSEL_1 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC;
126 ADC_DMA_Stream->PAR = CONVERT_PTR_UINT(&ADC3->DR);
127 ADC_DMA_Stream->M0AR = CONVERT_PTR_UINT(&adcValues[MOUSE1]);
128 ADC_DMA_Stream->NDTR = 2;
129 ADC_DMA_Stream->FCR = DMA_SxFCR_DMDIS | DMA_SxFCR_FTH_0;
131 ADC1->CR1 = ADC_CR1_SCAN;
132 ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS;
133 ADC1->SQR1 = (1 - 1) << 20;
134 ADC1->SQR2 = 0;
135 ADC1->SQR3 = (ADC_Channel_Vbat << 0);
136 ADC1->SMPR1 = (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24);
137 ADC1->SMPR2 = (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24) + (ADC_SAMPTIME << 27);
140 uint16_t getRTCBatteryVoltage()
142 return (rtcBatteryVoltage * 2 * ADC_VREF_PREC2) / 2048;
145 const uint16_t adcCommands[MOUSE1+2] =
147 MANUAL_MODE | (SPI_STICK1 << 7),
148 MANUAL_MODE | (SPI_STICK2 << 7),
149 MANUAL_MODE | (SPI_STICK3 << 7),
150 MANUAL_MODE | (SPI_STICK4 << 7),
151 MANUAL_MODE | (SPI_S1 << 7),
152 MANUAL_MODE | (SPI_6POS << 7),
153 MANUAL_MODE | (SPI_S2 << 7),
154 MANUAL_MODE | (SPI_L1 << 7),
155 MANUAL_MODE | (SPI_L2 << 7),
156 MANUAL_MODE | (SPI_LS << 7),
157 MANUAL_MODE | (SPI_RS << 7),
158 MANUAL_MODE | (SPI_TX_VOLTAGE << 7),
159 MANUAL_MODE | (0 << 7), // small joystick left/right
160 MANUAL_MODE | (0 << 7) // small joystick up/down
163 void adcReadSPIDummy()
165 // A dummy command to get things started
166 // (because the sampled data is lagging behind for two command cycles)
167 ADC_CS_LOW();
168 delay_01us(1);
169 SPIx_ReadWriteByte(adcCommands[0]);
170 ADC_CS_HIGH();
171 delay_01us(1);
174 uint32_t adcReadNextSPIChannel(uint8_t index)
176 uint32_t result = 0;
178 // This delay is to allow charging of ADC input capacitor
179 // after the MUX changes from one channel to the other.
180 // It was determined experimentally. Biggest problem seems to be
181 // the cross-talk between A4:S1 and A5:MULTIPOS. Changing S1 for one extreme
182 // to the other resulted in A5 change of:
184 // delay value A5 change Time needed for adcRead()
185 // 1 16 0.154ms - 0.156ms
186 // 38 5 0.197ms - 0.199ms
187 // 62 0 0.225ms - 0.243ms
188 delay_01us(40);
190 for (uint8_t i = 0; i < 4; i++) {
191 ADC_CS_LOW();
192 delay_01us(1);
193 // command is changed to the next index for the last two readings
194 // (because the sampled data is lagging behind for two command cycles)
195 uint16_t val = (0x0fff & SPIx_ReadWriteByte(adcCommands[(i>1) ? index+1 : index]));
196 #if defined(JITTER_MEASURE)
197 if (JITTER_MEASURE_ACTIVE()) {
198 rawJitter[index].measure(val);
200 #endif
201 ADC_CS_HIGH();
202 delay_01us(1);
203 result += val;
206 return result >> 2;
209 void adcOnChipReadStart()
211 ADC_DMA_Stream->CR &= ~DMA_SxCR_EN; // Disable DMA
212 ADC3->SR &= ~(uint32_t)(ADC_SR_EOC | ADC_SR_STRT | ADC_SR_OVR);
213 ADC_DMA->LIFCR = DMA_LIFCR_CTCIF0 | DMA_LIFCR_CHTIF0 | DMA_LIFCR_CTEIF0 | DMA_LIFCR_CDMEIF0 | DMA_LIFCR_CFEIF0; // Write ones to clear bits
214 ADC_DMA_Stream->M0AR = CONVERT_PTR_UINT(&adcValues[MOUSE1]);
215 ADC_DMA_Stream->NDTR = 2;
216 ADC_DMA_Stream->CR |= DMA_SxCR_EN; // Enable DMA
217 ADC3->CR2 |= (uint32_t)ADC_CR2_SWSTART;
219 ADC1->SR &= ~(uint32_t)(ADC_SR_EOC | ADC_SR_STRT | ADC_SR_OVR);
220 ADC1->CR2 |= (uint32_t)ADC_CR2_SWSTART;
223 bool adcOnChipReadFinished()
225 return (ADC_DMA->LISR & DMA_LISR_TCIF0);
228 void adcRead()
230 uint16_t temp[NUM_ANALOGS-MOUSE1] = { 0 };
231 uint8_t noInternalReads = 0;
233 adcOnChipReadStart();
234 adcReadSPIDummy();
235 adcReadSPIDummy();
236 for (uint32_t index=0; index<MOUSE1; index++) {
237 adcValues[index] = adcReadNextSPIChannel(index);
238 if (noInternalReads < 4 && adcOnChipReadFinished()) {
239 for (uint8_t x=0; x<NUM_ANALOGS-MOUSE1; x++) {
240 uint16_t val = adcValues[MOUSE1+x];
241 #if defined(JITTER_MEASURE)
242 if (JITTER_MEASURE_ACTIVE()) {
243 rawJitter[MOUSE1+x].measure(val);
245 #endif
246 temp[x] += val;
248 if (++noInternalReads < 4) {
249 adcOnChipReadStart();
254 #if defined(DEBUG)
255 if (noInternalReads != 4) {
256 TRACE("Internal ADC problem: reads: %d", noInternalReads);
258 #endif
260 for (uint8_t x=0; x<NUM_ANALOGS-MOUSE1; x++) {
261 adcValues[MOUSE1+x] = temp[x] >> 2;
264 if (isVBatBridgeEnabled()) {
265 rtcBatteryVoltage = ADC1->DR;
269 #if !defined(SIMU)
270 const int8_t ana_direction[NUM_ANALOGS] = {1,-1,1,-1, -1,1,-1, -1,-1, -1,1, 0,0,0};
272 uint16_t getAnalogValue(uint8_t index)
274 if (ana_direction[index] < 0)
275 return 4095 - adcValues[index];
276 else
277 return adcValues[index];
279 #endif // #if !defined(SIMU)