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/>.
29 #include "drivers/dma.h"
30 #include "drivers/dma_reqmap.h"
31 #include "drivers/io.h"
32 #include "drivers/io_impl.h"
33 #include "drivers/rcc.h"
34 #include "drivers/sensor.h"
36 #include "drivers/adc.h"
37 #include "drivers/adc_impl.h"
41 const adcDevice_t adcHardware
[] = {
44 .rccADC
= RCC_APB2(ADC1
),
45 #if !defined(USE_DMA_SPEC)
46 .dmaResource
= (dmaResource_t
*)ADC1_DMA_STREAM
,
47 .channel
= DMA_CHANNEL_0
52 .rccADC
= RCC_APB2(ADC2
),
53 #if !defined(USE_DMA_SPEC)
54 .dmaResource
= (dmaResource_t
*)ADC2_DMA_STREAM
,
55 .channel
= DMA_CHANNEL_1
60 .rccADC
= RCC_APB2(ADC3
),
61 #if !defined(USE_DMA_SPEC)
62 .dmaResource
= (dmaResource_t
*)ADC3_DMA_STREAM
,
63 .channel
= DMA_CHANNEL_2
68 /* note these could be packed up for saving space */
69 const adcTagMap_t adcTagMap
[] = {
71 { DEFIO_TAG_E__PF3, ADC_DEVICES_3, ADC_CHANNEL_9 },
72 { DEFIO_TAG_E__PF4, ADC_DEVICES_3, ADC_CHANNEL_14 },
73 { DEFIO_TAG_E__PF5, ADC_DEVICES_3, ADC_CHANNEL_15 },
74 { DEFIO_TAG_E__PF6, ADC_DEVICES_3, ADC_CHANNEL_4 },
75 { DEFIO_TAG_E__PF7, ADC_DEVICES_3, ADC_CHANNEL_5 },
76 { DEFIO_TAG_E__PF8, ADC_DEVICES_3, ADC_CHANNEL_6 },
77 { DEFIO_TAG_E__PF9, ADC_DEVICES_3, ADC_CHANNEL_7 },
78 { DEFIO_TAG_E__PF10,ADC_DEVICES_3, ADC_CHANNEL_8 },
80 { DEFIO_TAG_E__PC0
, ADC_DEVICES_123
, ADC_CHANNEL_10
},
81 { DEFIO_TAG_E__PC1
, ADC_DEVICES_123
, ADC_CHANNEL_11
},
82 { DEFIO_TAG_E__PC2
, ADC_DEVICES_123
, ADC_CHANNEL_12
},
83 { DEFIO_TAG_E__PC3
, ADC_DEVICES_123
, ADC_CHANNEL_13
},
84 { DEFIO_TAG_E__PC4
, ADC_DEVICES_12
, ADC_CHANNEL_14
},
85 { DEFIO_TAG_E__PC5
, ADC_DEVICES_12
, ADC_CHANNEL_15
},
86 { DEFIO_TAG_E__PB0
, ADC_DEVICES_12
, ADC_CHANNEL_8
},
87 { DEFIO_TAG_E__PB1
, ADC_DEVICES_12
, ADC_CHANNEL_9
},
88 { DEFIO_TAG_E__PA0
, ADC_DEVICES_123
, ADC_CHANNEL_0
},
89 { DEFIO_TAG_E__PA1
, ADC_DEVICES_123
, ADC_CHANNEL_1
},
90 { DEFIO_TAG_E__PA2
, ADC_DEVICES_123
, ADC_CHANNEL_2
},
91 { DEFIO_TAG_E__PA3
, ADC_DEVICES_123
, ADC_CHANNEL_3
},
92 { DEFIO_TAG_E__PA4
, ADC_DEVICES_12
, ADC_CHANNEL_4
},
93 { DEFIO_TAG_E__PA5
, ADC_DEVICES_12
, ADC_CHANNEL_5
},
94 { DEFIO_TAG_E__PA6
, ADC_DEVICES_12
, ADC_CHANNEL_6
},
95 { DEFIO_TAG_E__PA7
, ADC_DEVICES_12
, ADC_CHANNEL_7
},
98 void adcInitDevice(adcDevice_t
*adcdev
, int channelCount
)
100 adcdev
->ADCHandle
.Init
.ClockPrescaler
= ADC_CLOCK_SYNC_PCLK_DIV8
;
101 adcdev
->ADCHandle
.Init
.ContinuousConvMode
= ENABLE
;
102 adcdev
->ADCHandle
.Init
.Resolution
= ADC_RESOLUTION_12B
;
103 adcdev
->ADCHandle
.Init
.ExternalTrigConv
= ADC_EXTERNALTRIGCONV_T1_CC1
;
104 adcdev
->ADCHandle
.Init
.ExternalTrigConvEdge
= ADC_EXTERNALTRIGCONVEDGE_NONE
;
105 adcdev
->ADCHandle
.Init
.DataAlign
= ADC_DATAALIGN_RIGHT
;
106 adcdev
->ADCHandle
.Init
.NbrOfConversion
= channelCount
;
107 #ifdef USE_ADC_INTERNAL
108 // Multiple injected channel seems to require scan conversion mode to be
109 // enabled even if main (non-injected) channel count is 1.
110 adcdev
->ADCHandle
.Init
.ScanConvMode
= ENABLE
;
112 adcdev
->ADCHandle
.Init
.ScanConvMode
= channelCount
> 1 ? ENABLE
: DISABLE
; // 1=scan more that one channel in group
114 adcdev
->ADCHandle
.Init
.DiscontinuousConvMode
= DISABLE
;
115 adcdev
->ADCHandle
.Init
.NbrOfDiscConversion
= 0;
116 adcdev
->ADCHandle
.Init
.DMAContinuousRequests
= ENABLE
;
117 adcdev
->ADCHandle
.Init
.EOCSelection
= DISABLE
;
118 adcdev
->ADCHandle
.Instance
= adcdev
->ADCx
;
120 if (HAL_ADC_Init(&adcdev
->ADCHandle
) != HAL_OK
)
122 /* Initialization Error */
126 static adcDevice_t adc
;
128 #ifdef USE_ADC_INTERNAL
130 static adcDevice_t adcInternal
;
131 static ADC_HandleTypeDef
*adcInternalHandle
;
133 void adcInitInternalInjected(adcDevice_t
*adcdev
)
135 adcInternalHandle
= &adcdev
->ADCHandle
;
137 ADC_InjectionConfTypeDef iConfig
;
139 iConfig
.InjectedChannel
= ADC_CHANNEL_VREFINT
;
140 iConfig
.InjectedRank
= 1;
141 iConfig
.InjectedSamplingTime
= ADC_SAMPLETIME_480CYCLES
;
142 iConfig
.InjectedOffset
= 0;
143 iConfig
.InjectedNbrOfConversion
= 2;
144 iConfig
.InjectedDiscontinuousConvMode
= DISABLE
;
145 iConfig
.AutoInjectedConv
= DISABLE
;
146 iConfig
.ExternalTrigInjecConv
= 0; // Don't care
147 iConfig
.ExternalTrigInjecConvEdge
= 0; // Don't care
149 if (HAL_ADCEx_InjectedConfigChannel(adcInternalHandle
, &iConfig
) != HAL_OK
) {
150 /* Channel Configuration Error */
153 iConfig
.InjectedChannel
= ADC_CHANNEL_TEMPSENSOR
;
154 iConfig
.InjectedRank
= 2;
156 if (HAL_ADCEx_InjectedConfigChannel(adcInternalHandle
, &iConfig
) != HAL_OK
) {
157 /* Channel Configuration Error */
160 adcVREFINTCAL
= *(uint16_t *)VREFINT_CAL_ADDR
;
161 adcTSCAL1
= *TEMPSENSOR_CAL1_ADDR
;
162 adcTSCAL2
= *TEMPSENSOR_CAL2_ADDR
;
163 adcTSSlopeK
= (TEMPSENSOR_CAL2_TEMP
- TEMPSENSOR_CAL1_TEMP
) * 1000 / (adcTSCAL2
- adcTSCAL1
);
166 // Note on sampling time for temperature sensor and vrefint:
167 // Both sources have minimum sample time of 10us.
168 // With prescaler = 8:
169 // 168MHz : fAPB2 = 84MHz, fADC = 10.5MHz, tcycle = 0.090us, 10us = 105cycle < 144cycle
170 // 240MHz : fAPB2 = 120MHz, fADC = 15.0MHz, tcycle = 0.067usk 10us = 150cycle < 480cycle
172 // 480cycles@15.0MHz = 32us
174 static bool adcInternalConversionInProgress
= false;
176 bool adcInternalIsBusy(void)
178 if (adcInternalConversionInProgress
) {
179 if (HAL_ADCEx_InjectedPollForConversion(adcInternalHandle
, 0) == HAL_OK
) {
180 adcInternalConversionInProgress
= false;
184 return adcInternalConversionInProgress
;
187 void adcInternalStartConversion(void)
189 HAL_ADCEx_InjectedStart(adcInternalHandle
);
191 adcInternalConversionInProgress
= true;
194 uint16_t adcInternalReadVrefint(void)
196 return HAL_ADCEx_InjectedGetValue(adcInternalHandle
, ADC_INJECTED_RANK_1
);
199 uint16_t adcInternalReadTempsensor(void)
201 return HAL_ADCEx_InjectedGetValue(adcInternalHandle
, ADC_INJECTED_RANK_2
);
205 void adcInit(const adcConfig_t
*config
)
208 uint8_t configuredAdcChannels
= 0;
210 memset(&adcOperatingConfig
, 0, sizeof(adcOperatingConfig
));
212 if (config
->vbat
.enabled
) {
213 adcOperatingConfig
[ADC_BATTERY
].tag
= config
->vbat
.ioTag
;
216 if (config
->rssi
.enabled
) {
217 adcOperatingConfig
[ADC_RSSI
].tag
= config
->rssi
.ioTag
; //RSSI_ADC_CHANNEL;
220 if (config
->external1
.enabled
) {
221 adcOperatingConfig
[ADC_EXTERNAL1
].tag
= config
->external1
.ioTag
; //EXTERNAL1_ADC_CHANNEL;
224 if (config
->current
.enabled
) {
225 adcOperatingConfig
[ADC_CURRENT
].tag
= config
->current
.ioTag
; //CURRENT_METER_ADC_CHANNEL;
228 ADCDevice device
= ADC_CFG_TO_DEV(config
->device
);
230 if (device
== ADCINVALID
) {
234 adc
= adcHardware
[device
];
236 bool adcActive
= false;
237 for (int i
= 0; i
< ADC_CHANNEL_COUNT
; i
++) {
238 if (adcVerifyPin(adcOperatingConfig
[i
].tag
, device
)) {
240 IOInit(IOGetByTag(adcOperatingConfig
[i
].tag
), OWNER_ADC_BATT
+ i
, 0);
241 IOConfigGPIO(IOGetByTag(adcOperatingConfig
[i
].tag
), IO_CONFIG(GPIO_MODE_ANALOG
, 0, GPIO_NOPULL
));
242 adcOperatingConfig
[i
].adcChannel
= adcChannelByTag(adcOperatingConfig
[i
].tag
);
243 adcOperatingConfig
[i
].dmaIndex
= configuredAdcChannels
++;
244 adcOperatingConfig
[i
].sampleTime
= ADC_SAMPLETIME_480CYCLES
;
245 adcOperatingConfig
[i
].enabled
= true;
249 #ifndef USE_ADC_INTERNAL
255 RCC_ClockCmd(adc
.rccADC
, ENABLE
);
257 adcInitDevice(&adc
, configuredAdcChannels
);
259 #ifdef USE_ADC_INTERNAL
260 // If device is not ADC1 or there's no active channel, then initialize ADC1 here.
261 if (device
!= ADCDEV_1
|| !adcActive
) {
262 adcInternal
= adcHardware
[ADCDEV_1
];
263 RCC_ClockCmd(adcInternal
.rccADC
, ENABLE
);
264 adcInitDevice(&adcInternal
, 0);
265 adcInitInternalInjected(&adcInternal
);
267 adcInitInternalInjected(&adc
);
272 for (i
= 0; i
< ADC_CHANNEL_COUNT
; i
++) {
273 if (adcOperatingConfig
[i
].enabled
) {
274 ADC_ChannelConfTypeDef sConfig
;
276 sConfig
.Channel
= adcOperatingConfig
[i
].adcChannel
;
277 sConfig
.Rank
= rank
++;
278 sConfig
.SamplingTime
= adcOperatingConfig
[i
].sampleTime
;
281 if (HAL_ADC_ConfigChannel(&adc
.ADCHandle
, &sConfig
) != HAL_OK
)
283 /* Channel Configuration Error */
289 const dmaChannelSpec_t
*dmaspec
= dmaGetChannelSpecByPeripheral(DMA_PERIPH_ADC
, device
, config
->dmaopt
[device
]);
291 if (!dmaspec
|| !dmaAllocate(dmaGetIdentifier(dmaspec
->ref
), OWNER_ADC
, 0)) {
295 dmaEnable(dmaGetIdentifier(dmaspec
->ref
));
296 adc
.DmaHandle
.Init
.Channel
= dmaspec
->channel
;
297 adc
.DmaHandle
.Instance
= (DMA_ARCH_TYPE
*)dmaspec
->ref
;
299 if (!dmaAllocate(dmaGetIdentifier(adc
.dmaResource
), OWNER_ADC
, 0)) {
302 dmaEnable(dmaGetIdentifier(adc
.dmaResource
));
303 adc
.DmaHandle
.Init
.Channel
= adc
.channel
;
304 adc
.DmaHandle
.Instance
= (DMA_ARCH_TYPE
*)adc
.dmaResource
;
307 adc
.DmaHandle
.Init
.Direction
= DMA_PERIPH_TO_MEMORY
;
308 adc
.DmaHandle
.Init
.PeriphInc
= DMA_PINC_DISABLE
;
309 adc
.DmaHandle
.Init
.MemInc
= configuredAdcChannels
> 1 ? DMA_MINC_ENABLE
: DMA_MINC_DISABLE
;
310 adc
.DmaHandle
.Init
.PeriphDataAlignment
= DMA_PDATAALIGN_HALFWORD
;
311 adc
.DmaHandle
.Init
.MemDataAlignment
= DMA_MDATAALIGN_HALFWORD
;
312 adc
.DmaHandle
.Init
.Mode
= DMA_CIRCULAR
;
313 adc
.DmaHandle
.Init
.Priority
= DMA_PRIORITY_HIGH
;
314 adc
.DmaHandle
.Init
.FIFOMode
= DMA_FIFOMODE_DISABLE
;
315 adc
.DmaHandle
.Init
.FIFOThreshold
= DMA_FIFO_THRESHOLD_FULL
;
316 adc
.DmaHandle
.Init
.MemBurst
= DMA_MBURST_SINGLE
;
317 adc
.DmaHandle
.Init
.PeriphBurst
= DMA_PBURST_SINGLE
;
320 if (HAL_DMA_Init(&adc
.DmaHandle
) != HAL_OK
)
322 /* Initialization Error */
325 __HAL_LINKDMA(&adc
.ADCHandle
, DMA_Handle
, adc
.DmaHandle
);
327 //HAL_CLEANINVALIDATECACHE((uint32_t*)&adcValues, configuredAdcChannels);
329 if (HAL_ADC_Start_DMA(&adc
.ADCHandle
, (uint32_t*)&adcValues
, configuredAdcChannels
) != HAL_OK
)
331 /* Start Conversion Error */
335 void adcGetChannelValues(void)