mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-14 00:13:42 +08:00
22a8575199
Keep official openpilot ancestry and dependency licenses. Store resources directly in Git, remove LFS setup requirements, and leave the downloadable big model outside the source tree.
83 lines
2.5 KiB
C
83 lines
2.5 KiB
C
#pragma once
|
|
|
|
#include "lladc_declarations.h"
|
|
|
|
static uint32_t adc_avdd_mV = 0U;
|
|
|
|
void adc_init(ADC_TypeDef *adc) {
|
|
adc->CR &= ~(ADC_CR_ADEN); // Disable ADC
|
|
adc->CR &= ~(ADC_CR_DEEPPWD); // Reset deep-power-down mode
|
|
adc->CR |= ADC_CR_ADVREGEN; // Enable ADC regulator
|
|
while(!(adc->ISR & ADC_ISR_LDORDY) && (adc != ADC3));
|
|
|
|
if (adc != ADC3) {
|
|
adc->CR &= ~(ADC_CR_ADCALDIF); // Choose single-ended calibration
|
|
adc->CR |= ADC_CR_ADCALLIN; // Lineriality calibration
|
|
}
|
|
adc->CR |= ADC_CR_ADCAL; // Start calibration
|
|
while((adc->CR & ADC_CR_ADCAL) != 0U);
|
|
|
|
adc->ISR |= ADC_ISR_ADRDY;
|
|
adc->CR |= ADC_CR_ADEN;
|
|
while(!(adc->ISR & ADC_ISR_ADRDY));
|
|
}
|
|
|
|
uint16_t adc_get_raw(const adc_signal_t *signal) {
|
|
signal->adc->SQR1 &= ~(ADC_SQR1_L);
|
|
signal->adc->SQR1 = ((uint32_t) signal->channel << 6U);
|
|
|
|
// sample time
|
|
if (signal->channel < 10U) {
|
|
signal->adc->SMPR1 = ((uint32_t) signal->sample_time << (signal->channel * 3U));
|
|
} else {
|
|
signal->adc->SMPR2 = ((uint32_t) signal->sample_time << ((signal->channel - 10U) * 3U));
|
|
}
|
|
|
|
// select channel
|
|
signal->adc->PCSEL_RES0 = (0x1UL << signal->channel);
|
|
|
|
// oversampling
|
|
signal->adc->CFGR2 = (((1U << (uint32_t) signal->oversampling) - 1U) << ADC_CFGR2_OVSR_Pos) | ((uint32_t) signal->oversampling << ADC_CFGR2_OVSS_Pos);
|
|
signal->adc->CFGR2 |= (signal->oversampling != OVERSAMPLING_1) ? ADC_CFGR2_ROVSE : 0U;
|
|
|
|
// start conversion
|
|
signal->adc->CR |= ADC_CR_ADSTART;
|
|
while (!(signal->adc->ISR & ADC_ISR_EOC));
|
|
|
|
uint16_t res = signal->adc->DR;
|
|
|
|
while (!(signal->adc->ISR & ADC_ISR_EOS));
|
|
signal->adc->ISR |= ADC_ISR_EOS;
|
|
|
|
return res;
|
|
}
|
|
|
|
static void adc_calibrate_vdda(void) {
|
|
// ADC2 used for calibration
|
|
adc_init(ADC2);
|
|
|
|
// enable VREFINT channel
|
|
ADC3_COMMON->CCR |= ADC_CCR_VREFEN;
|
|
SYSCFG->ADC2ALT |= SYSCFG_ADC2ALT_ADC2_ROUT1;
|
|
|
|
// measure VREFINT and derive AVDD
|
|
uint16_t raw_vrefint = adc_get_raw(&(adc_signal_t){.adc = ADC2, .channel = 17U, .sample_time = SAMPLETIME_810_CYCLES, .oversampling = OVERSAMPLING_256});
|
|
adc_avdd_mV = (uint32_t) *VREFINT_CAL_ADDR * 16U * 3300U / raw_vrefint;
|
|
print(" AVDD: 0x"); puth(adc_avdd_mV); print(" mV\n");
|
|
}
|
|
|
|
uint16_t adc_get_mV(const adc_signal_t *signal) {
|
|
uint16_t ret = 0;
|
|
|
|
if (adc_avdd_mV == 0U) {
|
|
adc_calibrate_vdda();
|
|
}
|
|
|
|
if ((signal->adc == ADC1) || (signal->adc == ADC2)) {
|
|
ret = (adc_get_raw(signal) * adc_avdd_mV) / 65535U;
|
|
} else if (signal->adc == ADC3) {
|
|
ret = (adc_get_raw(signal) * adc_avdd_mV) / 4095U;
|
|
} else {}
|
|
return ret;
|
|
}
|