Merge pull request #11198 from SteveCEvans/sce_rc2
[betaflight.git] / src / main / target / OMNINXT / hardware_revision.c
blob5e8d2ac1376e1644247766f37203837e5c35dbe3
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/>.
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <stdlib.h>
25 #include "platform.h"
27 #ifdef USE_HARDWARE_REVISION_DETECTION
29 #include "build/debug.h"
31 #include "drivers/adc_impl.h"
32 #include "drivers/io_types.h"
33 #include "drivers/io.h"
34 #include "drivers/io_impl.h"
35 #include "drivers/rcc.h"
36 #include "drivers/time.h"
38 #include "hardware_revision.h"
40 #undef DEBUG_HARDWARE_REVISION_ADC
41 #undef DEBUG_HARDWARE_REVISION_TABLE
43 uint8_t hardwareRevision = 0;
45 // Do ADC on IDDetectPin and determine revision
46 // If VREFINT is used, we can (probably) get a pretty good precision
47 // that we can distinguish tens of different voltages.
49 #define ADC_ID_DETECT_PIN PC2
51 typedef struct idDetect_s {
52 uint32_t ratio;
53 uint8_t revision;
54 } idDetect_t;
56 // To deploy the analog ID detection in production:
57 // - Need some theoretical evaluation and experimentation to determine
58 // IDDET_ERROR value (ADC with VREFINT compensation is quite accurate).
59 // - Do some planning on revision numbering scheme.
60 // - Divider value planning for the scheme (separation).
62 #define IDDET_RATIO(highside, lowside) ((lowside) * 1000 / ((lowside) + (highside)))
63 #define IDDET_ERROR 12
65 static idDetect_t idDetectTable[] = {
66 #ifdef OMNINXT7
67 { IDDET_RATIO(10000, 10000), 1 },
68 #endif
69 #ifdef OMNINXT4
70 { IDDET_RATIO(10000, 10000), 1 },
71 #endif
74 ioTag_t idDetectTag;
76 #if defined(OMNINXT4)
78 #define VREFINT_CAL_ADDR 0x1FFF7A2A
80 static void adcIDDetectInit(void)
82 idDetectTag = IO_TAG(ADC_ID_DETECT_PIN);
83 IOConfigGPIO(IOGetByTag(idDetectTag), IO_CONFIG(GPIO_Mode_AN, 0, GPIO_OType_OD, GPIO_PuPd_NOPULL));
85 RCC_ClockCmd(RCC_APB2(ADC1), ENABLE);
87 ADC_CommonInitTypeDef ADC_CommonInitStructure;
89 ADC_CommonStructInit(&ADC_CommonInitStructure);
90 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
91 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div8;
92 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
93 ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
94 ADC_CommonInit(&ADC_CommonInitStructure);
96 ADC_InitTypeDef ADC_InitStructure;
98 ADC_StructInit(&ADC_InitStructure);
99 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
100 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
101 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
102 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
103 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
104 ADC_InitStructure.ADC_NbrOfConversion = 2; // Not used
105 ADC_InitStructure.ADC_ScanConvMode = ENABLE;
106 ADC_Init(ADC1, &ADC_InitStructure);
108 ADC_Cmd(ADC1, ENABLE);
110 ADC_TempSensorVrefintCmd(ENABLE);
111 delayMicroseconds(10); // Maximum startup time for internal sensors (DM00037051 5.3.22 & 24)
113 uint32_t channel = adcChannelByTag(idDetectTag);
115 ADC_InjectedDiscModeCmd(ADC1, DISABLE);
116 ADC_InjectedSequencerLengthConfig(ADC1, 2);
117 ADC_InjectedChannelConfig(ADC1, channel, 1, ADC_SampleTime_480Cycles);
118 ADC_InjectedChannelConfig(ADC1, ADC_Channel_Vrefint, 2, ADC_SampleTime_480Cycles);
121 static void adcIDDetectDeinit(void)
123 ADC_Cmd(ADC1, DISABLE);
124 ADC_DeInit();
125 IOConfigGPIO(IOGetByTag(idDetectTag), IOCFG_IPU);
128 static void adcIDDetectStart(void)
130 ADC_ClearFlag(ADC1, ADC_FLAG_JEOC);
131 ADC_SoftwareStartInjectedConv(ADC1);
134 static void adcIDDetectWait(void)
136 while (ADC_GetFlagStatus(ADC1, ADC_FLAG_JEOC) == RESET) {
137 // Empty
141 static uint16_t adcIDDetectReadIDDet(void)
143 return ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1);
146 static uint16_t adcIDDetectReadVrefint(void)
148 return ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_2);
150 #endif
152 #if defined(OMNINXT7)
154 #include "drivers/adc_impl.h"
156 static adcDevice_t adcIDDetHardware =
158 .ADCx = ADC1,
159 .rccADC = RCC_APB2(ADC1),
160 #if !defined(USE_DMA_SPEC)
161 .DMAy_Streamx = ADC1_DMA_STREAM,
162 .channel = DMA_CHANNEL_0
163 #endif
166 // XXX adcIDDetectInitDevice is an exact copy of adcInitDevice() from adc_stm32f7xx.c. Export and use?
168 static void adcIDDetectInitDevice(adcDevice_t *adcdev, int channelCount)
170 adcdev->ADCHandle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8;
171 adcdev->ADCHandle.Init.ContinuousConvMode = ENABLE;
172 adcdev->ADCHandle.Init.Resolution = ADC_RESOLUTION_12B;
173 adcdev->ADCHandle.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
174 adcdev->ADCHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
175 adcdev->ADCHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
176 adcdev->ADCHandle.Init.NbrOfConversion = channelCount;
177 #ifdef USE_ADC_INTERNAL
178 // Multiple injected channel seems to require scan conversion mode to be
179 // enabled even if main (non-injected) channel count is 1.
180 adcdev->ADCHandle.Init.ScanConvMode = ENABLE;
181 #else
182 adcdev->ADCHandle.Init.ScanConvMode = channelCount > 1 ? ENABLE : DISABLE; // 1=scan more that one channel in group
183 #endif
184 adcdev->ADCHandle.Init.DiscontinuousConvMode = DISABLE;
185 adcdev->ADCHandle.Init.NbrOfDiscConversion = 0;
186 adcdev->ADCHandle.Init.DMAContinuousRequests = ENABLE;
187 adcdev->ADCHandle.Init.EOCSelection = DISABLE;
188 adcdev->ADCHandle.Instance = adcdev->ADCx;
190 if (HAL_ADC_Init(&adcdev->ADCHandle) != HAL_OK)
192 /* Initialization Error */
196 static void adcIDDetectInit(void)
198 idDetectTag = IO_TAG(ADC_ID_DETECT_PIN);
200 IOConfigGPIO(IOGetByTag(idDetectTag), IO_CONFIG(GPIO_MODE_ANALOG, 0, GPIO_NOPULL));
202 adcIDDetectInitDevice(&adcIDDetHardware, 2);
204 ADC_InjectionConfTypeDef iConfig;
206 iConfig.InjectedSamplingTime = ADC_SAMPLETIME_480CYCLES;
207 iConfig.InjectedOffset = 0;
208 iConfig.InjectedNbrOfConversion = 2;
209 iConfig.InjectedDiscontinuousConvMode = DISABLE;
210 iConfig.AutoInjectedConv = DISABLE;
211 iConfig.ExternalTrigInjecConv = 0; // Don't care
212 iConfig.ExternalTrigInjecConvEdge = 0; // Don't care
214 iConfig.InjectedChannel = ADC_CHANNEL_VREFINT;
215 iConfig.InjectedRank = 1;
217 if (HAL_ADCEx_InjectedConfigChannel(&adcIDDetHardware.ADCHandle, &iConfig) != HAL_OK) {
218 /* Channel Configuration Error */
221 iConfig.InjectedChannel = adcChannelByTag(idDetectTag);
222 iConfig.InjectedRank = 2;
224 if (HAL_ADCEx_InjectedConfigChannel(&adcIDDetHardware.ADCHandle, &iConfig) != HAL_OK) {
225 /* Channel Configuration Error */
229 static void adcIDDetectDeinit(void)
231 HAL_ADC_DeInit(&adcIDDetHardware.ADCHandle);
232 IOConfigGPIO(IOGetByTag(idDetectTag), IOCFG_IPU);
235 static void adcIDDetectStart(void)
237 HAL_ADCEx_InjectedStart(&adcIDDetHardware.ADCHandle);
240 static void adcIDDetectWait(void)
242 while (HAL_ADCEx_InjectedPollForConversion(&adcIDDetHardware.ADCHandle, 0) != HAL_OK) {
243 // Empty
247 static uint16_t adcIDDetectReadVrefint(void)
249 return HAL_ADCEx_InjectedGetValue(&adcIDDetHardware.ADCHandle, ADC_INJECTED_RANK_1);
252 static uint16_t adcIDDetectReadIDDet(void)
254 return HAL_ADCEx_InjectedGetValue(&adcIDDetHardware.ADCHandle, ADC_INJECTED_RANK_2);
256 #endif
258 void detectHardwareRevision(void)
260 adcIDDetectInit();
262 uint32_t vrefintValue = 0;
263 uint32_t iddetValue = 0;
265 for (int i = 0 ; i < 16 ; i++) {
266 adcIDDetectStart();
267 adcIDDetectWait();
268 iddetValue += adcIDDetectReadIDDet();
269 vrefintValue += adcIDDetectReadVrefint();
272 vrefintValue /= 16;
273 iddetValue /= 16;
275 uint32_t iddetRatio = (iddetValue * vrefintValue) / *(uint16_t *)VREFINT_CAL_ADDR;
276 iddetRatio = iddetRatio * 1000 / 4096;
278 #ifdef DEBUG_HARDWARE_REVISION_ADC
279 debug[0] = *(uint16_t *)VREFINT_CAL_ADDR;
280 debug[1] = vrefintValue;
281 debug[2] = iddetValue;
282 debug[3] = iddetRatio;
283 #endif
285 for (size_t entry = 0; entry < ARRAYLEN(idDetectTable); entry++) {
286 #ifdef DEBUG_HARDWARE_REVISION_TABLE
287 debug[0] = iddetRatio;
288 debug[1] = idDetectTable[entry].ratio - IDDET_ERROR;
289 debug[2] = idDetectTable[entry].ratio + IDDET_ERROR;
290 #endif
291 if (idDetectTable[entry].ratio - IDDET_ERROR < iddetRatio && iddetRatio < idDetectTable[entry].ratio + IDDET_ERROR) {
292 hardwareRevision = idDetectTable[entry].revision;
293 break;
297 adcIDDetectDeinit();
300 void updateHardwareRevision(void)
302 // Empty
305 // XXX Can be gone as sensors/gyro.c is not calling this anymore
306 ioTag_t selectMPUIntExtiConfigByHardwareRevision(void)
308 return IO_TAG_NONE;
310 #endif