Skip to content

Instantly share code, notes, and snippets.

@lexszero
Created January 25, 2017 11:26
Show Gist options
  • Save lexszero/6891c12a8fa31cd0714b8d42718db4af to your computer and use it in GitHub Desktop.
Save lexszero/6891c12a8fa31cd0714b8d42718db4af to your computer and use it in GitHub Desktop.
stm32 adc+dma driver
#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