Created
January 25, 2017 11:26
-
-
Save lexszero/6891c12a8fa31cd0714b8d42718db4af to your computer and use it in GitHub Desktop.
stm32 adc+dma driver
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "adc.h" | |
#ifdef ADC_TABLE | |
#include "gpio.h" | |
#include "settings.h" | |
// configure all channels for 239.5 cycles per sample | |
#define SAMPLE_TIME 1 | |
#define VREF 2500L | |
#define X(name, chan) chan, | |
static const uint8_t adc_chan[ADC_TOTAL_COUNT] = { | |
ADC_TABLE | |
}; | |
#undef X | |
// here raw values will be put by DMA | |
static volatile uint16_t adc_values[ADC_TOTAL_COUNT]; | |
uint16_t adc_mv(adc_chan_t chan) { | |
return ((((uint32_t)adc_values[chan]) << 16)/4096 * VREF) >> 16; | |
} | |
void adc_init(void) { | |
uint8_t seq, chan; | |
// configure clocks | |
RCC->AHBENR |= RCC_AHBENR_DMA1EN; | |
RCC->CFGR &= ~RCC_CFGR_ADCPRE; | |
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; | |
DMA1_Channel1->CPAR = (uint32_t)&(ADC1->DR); | |
DMA1_Channel1->CMAR = (uint32_t)adc_values; | |
DMA1_Channel1->CNDTR = ADC_TOTAL_COUNT; | |
DMA1_Channel1->CCR = | |
DMA_CCR1_PL_1 | // high priority | |
DMA_CCR1_MSIZE_0 | DMA_CCR1_PSIZE_0 | // 16-bit width | |
DMA_CCR1_MINC | // memory increment | |
DMA_CCR1_CIRC; // circular mode | |
DMA1_Channel1->CCR |= DMA_CCR1_EN; | |
// turn ADC on | |
ADC1->CR2 |= ADC_CR2_ADON; | |
ADC1->CR1 |= ADC_CR1_SCAN; | |
ADC1->CR2 |= ADC_CR2_TSVREFE | ADC_CR2_DMA | ADC_CR2_CONT; | |
// reset calibration | |
ADC1->CR2 |= ADC_CR2_RSTCAL; | |
while (ADC1->CR2 & ADC_CR2_RSTCAL) {} | |
//start self-calibration | |
ADC1->CR2 |= ADC_CR2_CAL; | |
while(ADC1->CR2 & ADC_CR2_CAL) {} | |
// set sequence length | |
ADC1->SQR1 = ((ADC_TOTAL_COUNT-1) << 20) & ADC_SQR1_L; | |
// configure each channel and fill sequence | |
for (seq = 0; seq < ADC_TOTAL_COUNT; seq++) { | |
chan = adc_chan[seq]; | |
// init corresponding pin as analog input | |
if (chan <= 7) | |
gpio_hw_config_pin(GPIOA, chan, GPIO_MODE_IN_ANALOG); | |
else if (chan <= 9) | |
gpio_hw_config_pin(GPIOB, chan-8, GPIO_MODE_IN_ANALOG); | |
// add pin to sequence | |
if (seq >= 12) { | |
ADC1->SQR1 &= ~(0x1F << ((seq - 12) * 5)); | |
ADC1->SQR1 |= chan << ((seq - 12) * 5); | |
} | |
else if (seq >= 6) { | |
ADC1->SQR2 &= ~(0x1F << ((seq - 6) * 5)); | |
ADC1->SQR2 |= chan << ((seq - 6) * 5); | |
} | |
else { | |
ADC1->SQR3 &= ~(0x1F << (seq * 5)); | |
ADC1->SQR3 |= chan << (seq * 5); | |
} | |
// set sample rate | |
if (chan >= 10) { | |
ADC1->SMPR1 &= ~(0x07 << ((chan - 10) * 3)); | |
ADC1->SMPR1 |= SAMPLE_TIME << ((chan - 10) * 3); | |
} | |
else { | |
ADC1->SMPR2 &= ~(0x07 << (chan * 3)); | |
ADC1->SMPR2 |= SAMPLE_TIME << (chan * 3); | |
} | |
} | |
// start ADC | |
ADC1->CR2 |= ADC_CR2_ADON; | |
#ifdef FEATURE_ADC_CURRENT_LIMITER | |
gpio_set(BOARD_CL_EN, true); | |
#endif | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment