2023-02-11 05:47 AM
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;
}
Solved! Go to Solution.
2023-02-18 12:17 AM
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
2023-02-11 06:20 AM
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
2023-02-11 07:00 AM
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
2023-02-18 12:17 AM
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