cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F303 DMA fails to collect data when ADC is running at maximum speed

Utyf
Associate II

My code works fine when STM32F303 ADC run at 8 bit, 3.6 MSPS

When I trying to run ADC at maximum speed - 8bit 7.2 MSPS, DMA fails to get data. The bit OVR in ADC1_ISR is set and conversation stopped.

If I read the ADC1_2_CDR register through the debugger - ADC make one conversation and DMA make one transaction then stopped again.

I stop the CPU and there are no interrupts.

In addition to DMA and ADC, nothing works.

Why is DMA not collecting data?

#include <stm32f3xx.h>
 
#define SYSTEM_CORE_CLOCK 72000000
#define DWT_IN_MICROSEC (SYSTEM_CORE_CLOCK/1000000)
 
void DWT_Init() {
    if (!(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)) {
        CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
        DWT->CYCCNT = 0;
        DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
    }
}
 
void DWT_Delay_us(uint32_t us) {
    uint32_t t0 = DWT->CYCCNT;
    uint32_t delta = us * DWT_IN_MICROSEC;
 
    while ((DWT->CYCCNT - t0) < delta) {}
}
 
void SystemClock_Config(void) {
    // External oscillator (HSE) = 24MHz
    // SYS_CLK = 72MHz
    // APB1 = 36MHz
    RCC->CR |= RCC_CR_HSEON;           // Enable HSE
    while ((RCC->CR & RCC_CR_HSERDY) == 0);
 
    RCC->CFGR |= RCC_CFGR_PLLMUL3;     // PLL MUL = x3, SYS_CLK=72MHz (x9 for 8MHz)
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;  // APB1 Prescaler = 2
    RCC->CFGR |= RCC_CFGR_PLLSRC;      // PLL source = HSE
 
    FLASH->ACR |= FLASH_ACR_LATENCY_1; // Two wait states
 
    RCC->CR |= RCC_CR_PLLON;           // Enable and wait PLL
    while ((RCC->CR & RCC_CR_PLLRDY) == 0);
    RCC->CFGR |= RCC_CFGR_SW_PLL;      // Select PLL as system clock
}
 
int main(void) {
    SystemClock_Config();
 
    DWT_Init();
    ADC_Init();
 
    while (1) {
    }
}
 
#include <stm32f3xx.h>
 
 
/**
 * ADC1 channel 1 - PA0
 * ADC2 channel 1 - PA4
 */
 
 
#define ADC_6BITS  0b11u
#define ADC_8BITS  0b10u
#define ADC_10BITS 0b01u
#define ADC_12BITS 0b00u
uint8_t adcResolution = ADC_8BITS;
 
// 0b10000: PLL clock divided by 1  // RCC_CFGR2_ADCPRE12_DIV1
// 0b10001: PLL clock divided by 2
// 0b10010: PLL clock divided by 4
// 0b10011: PLL clock divided by 6
// 0b10100: PLL clock divided by 8
// 0b10101: PLL clock divided by 10
// 0b10110: PLL clock divided by 12
// 0b10111: PLL clock divided by 16
// 0b11000: PLL clock divided by 32
// 0b11001: PLL clock divided by 64
// 0b11010: PLL clock divided by 128
// 0b11011: PLL clock divided by 256
uint8_t rccAdcDivider = 0b10001;
 
// Delay for interleaved mode. Set only when ADEN=0
// circle time = SAMPLE_TIME + CONV. TIME = 1.5 + 8.5 = 10 tics
// Delay = circle time /2 - SAMPLE_TIME = 10 / 2 - 1.5 = 3.5 tics
// 0b0000 - 1
// 0b0001 - 2
// 0b0010 - 3
// 0b0011 - 4   MAX: 1011 - 12
uint8_t adcDelay = 0b0010;
 
//000: 1.5 ADC clock cycles
//001: 2.5 ADC clock cycles
//010: 4.5 ADC clock cycles
//011: 7.5 ADC clock cycles
//100: 19.5 ADC clock cycles
//101: 61.5 ADC clock cycles
//110: 181.5 ADC clock cycles
//111: 601.5 ADC clock cycles
uint8_t sampleTime = 0b000;
 
#define BUF_SIZE 4096
uint8_t samplesBuffer[BUF_SIZE];
 
void DWT_Delay_us(uint32_t us);
void DMA_init();
void ADC_start();
 
 
void ADC_Init() {
    DMA_init();
 
    // init GPIO, VR and calibration run only once
    // Enable clocks GPIOA and GPIOB
    RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN;
 
    // Set mode b11 (analog input) for ADC pins
    GPIOA->MODER |= (0b11u << 0u);      // PA0 for ADC1 ch1
    GPIOA->MODER |= (0b11u << (4 * 2)); // PA4 for ADC2 ch1
 
    RCC->AHBENR |= RCC_AHBENR_ADC12EN; // turn on ADC12 clock
 
    // Set Prescaler ADC for Asynchronous clock mode
    MODIFY_REG(RCC->CFGR2, RCC_CFGR2_ADCPRE12_Msk, rccAdcDivider << RCC_CFGR2_ADCPRE12_Pos);
 
    // Set ADC clock
    // 00: (Asynchronous clock mode) PLL as clock source
    ADC12_COMMON->CCR &= ~ADC_CCR_CKMODE_Msk;
 
    // enable the ADC voltage regulator
    ADC1->CR &= ~ADC_CR_ADVREGEN_1;
    ADC2->CR &= ~ADC_CR_ADVREGEN_1;
 
    ADC1->CR |= ADC_CR_ADVREGEN_0;
    ADC2->CR |= ADC_CR_ADVREGEN_0;
    DWT_Delay_us(10); // voltage regulator startup time
 
    // start ADC calibration cycle
    ADC1->CR |= ADC_CR_ADCAL;
    // wait for calibration to complete
    while (ADC1->CR & ADC_CR_ADCAL);
 
    // start ADC calibration cycle
    ADC2->CR |= ADC_CR_ADCAL;
    // wait for calibration to complete
    while (ADC2->CR & ADC_CR_ADCAL);
 
    ADC_start();
}
 
void ADC_start() {
    // Delay for interleaved mode. Set only when ADEN=0
    ADC12_COMMON->CCR |= (adcDelay << ADC_CCR_DELAY_Pos);
 
    // enable the ADC
    ADC1->CR |= ADC_CR_ADEN;
    ADC2->CR |= ADC_CR_ADEN;
 
    // wait till ADC start
    while (!(ADC1->ISR & ADC_ISR_ADRDY));
    while (!(ADC2->ISR & ADC_ISR_ADRDY));
 
    // Select ADC Channels
    ADC1->SQR1 = (1u << ADC_SQR1_SQ1_Pos); // 1-st channel for ADC1
    ADC2->SQR1 = (1u << ADC_SQR1_SQ1_Pos); // 1-st channel for ADC2
 
    // Regular channel sequence length - 1
    ADC1->SQR1 &= ~ADC_SQR1_L_Msk;
    ADC2->SQR1 &= ~ADC_SQR1_L_Msk;
 
    // Set Prescaler ADC for Asynchronous clock mode
    MODIFY_REG(RCC->CFGR2, RCC_CFGR2_ADCPRE12_Msk, rccAdcDivider << RCC_CFGR2_ADCPRE12_Pos);
 
    // Set sampling time for channels
    MODIFY_REG(ADC1->SMPR1, ADC_SMPR1_SMP1_Msk, sampleTime << ADC_SMPR1_SMP1_Pos); // ADC1 channel 1
    MODIFY_REG(ADC2->SMPR1, ADC_SMPR1_SMP1_Msk, sampleTime << ADC_SMPR1_SMP1_Pos); // ADC2 channel 1
 
    // set data resolution
    MODIFY_REG(ADC1->CFGR, ADC_CFGR_RES_Msk, adcResolution << ADC_CFGR_RES_Pos);
    MODIFY_REG(ADC2->CFGR, ADC_CFGR_RES_Msk, adcResolution << ADC_CFGR_RES_Pos);
 
    // Enable continuous conversion mode. Only on the master
    ADC1->CFGR |= ADC_CFGR_CONT; // Master ADC1 + ADC2
 
    // dual mode
    // 00111: Interleaved mode only
    ADC12_COMMON->CCR |= (0b00111u << ADC_CCR_DUAL_Pos);
 
    // DMA mode.  0 -> One Shot; 1 -> Circular
    // 0 - stop when DMA_CCR_TCIE
    ADC12_COMMON->CCR |= ADC_CCR_DMACFG;
 
    // COMMON DMA mode b11 - for 8-bit resolution
    ADC12_COMMON->CCR |= (0b11u << ADC_CCR_MDMA_Pos);
 
    // ADC start conversion
    ADC1->CR |= ADC_CR_ADSTART;
 
    __WFI(); // stop CPU
}
 
void DMA_init() {
    // Enable clocks DMA1
    RCC->AHBENR |= RCC_AHBENR_DMA1EN;
 
    // interrupt disabled
    // Circular mode
    DMA1_Channel1->CCR |= DMA_CCR_CIRC;
 
    // Memory increment mode
    DMA1_Channel1->CCR |= DMA_CCR_MINC;
 
    // Peripheral size
    // 00: 8-bits
    // 01: 16-bits
    // 10: 32-bits
    DMA1_Channel1->CCR |= (0b01u << DMA_CCR_PSIZE_Pos);
    // Memory size
    DMA1_Channel1->CCR |= (0b01u << DMA_CCR_MSIZE_Pos);
 
    // Channel Priority level 11 - Very high
    DMA1_Channel1->CCR |= DMA_CCR_PL_Msk;
 
    // Number of data to transfer. 2 samples in 1 transfer.
    DMA1_Channel1->CNDTR = BUF_SIZE / 2;
 
    // Peripheral address register
    DMA1_Channel1->CPAR = (uint32_t) &ADC12_COMMON->CDR;
 
    // Memory address register
    DMA1_Channel1->CMAR = (uint32_t) (&samplesBuffer);
 
    // Reset interrupt flags
    DMA1->IFCR |= DMA_IFCR_CGIF1 | DMA_IFCR_CTCIF1 | DMA_IFCR_CHTIF1 | DMA_IFCR_CTEIF1;
 
    // Enable DMA
    DMA1_Channel1->CCR |= DMA_CCR_EN;
}
 

1 ACCEPTED SOLUTION

Accepted Solutions
Utyf
Associate II

The result of my research.

When the DAC is running at 7.2 MSPS, DMA operation is independent of the debugger session and the value of the CKMODE bits in the ADCx_CCR register.

If I use one ADC - DMA sends data without problems.

If I use 2 ADCs in interleaved mode, then DMA only works if the delay between ADCs is 2 clk cycles or less

(value DELAY bits in register ADCx_CCR <=1).

It turns out that DMA requires 6.5 clk cycles for the operation:

 ADC full cycle - sampling time - delay time = 10 - 1.5 - 2 = 6.5

View solution in original post

3 REPLIES 3

DMA transfer is not instantaneous, see AN2548. Trigger must propagate to DMA, DMA's arbiter takes some time, then there's the peripheral-side transfer (through the AHB/APB bridge) and then the memory-side transfer. And there's only 10 cycles to do all this. You can have conflicts with processor/debugger on the memory bus, on the APB. Using asynchronous ADC clock may make things worse.

JW

Utyf
Associate II

I checked. HCLK/2 works well.

HCLK/1 works 2 times better than asynchronous mode :)

The ADC makes 2 conversations and 2 transactions, then stops again.

I will try to check without debugger and read AN2548

Thank you for idea

Utyf
Associate II

The result of my research.

When the DAC is running at 7.2 MSPS, DMA operation is independent of the debugger session and the value of the CKMODE bits in the ADCx_CCR register.

If I use one ADC - DMA sends data without problems.

If I use 2 ADCs in interleaved mode, then DMA only works if the delay between ADCs is 2 clk cycles or less

(value DELAY bits in register ADCx_CCR <=1).

It turns out that DMA requires 6.5 clk cycles for the operation:

 ADC full cycle - sampling time - delay time = 10 - 1.5 - 2 = 6.5