2025-01-13 3:58 AM - edited 2025-01-13 3:59 AM
Hi,
i created this minimum code, where the dma for the injected conversions will not work. Only after each(!) start of a regular conversion, the injected conversion does work for one time. I have set it up, in a way, that it should work in circular mode.
The pin is not set up, but it does not matter anyway.
uint32_t lastADCMeasure = 0;
volatile uint16_t adc2InjectedBits = 99;
volatile uint16_t adc1InjectedBits = 99;
void setup(){
// ######### DMA ###########
SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_DMA1EN); // Enable clock //TODO: move to better place and test if working
delayMicroseconds(50);
SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_DMA2EN); // Enable clock //TODO: move to better place and test if working
delayMicroseconds(50);
// ######## DMAMUX ######### as per 13.3.2 (13.4.3)
SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_DMAMUX1EN); // Enable DMAMUX //TODO: move to better place and test if working
delayMicroseconds(50);
DMA1_Channel3->CPAR = (uint32_t) &(ADC2->JDR1); // Address of source
DMA1_Channel3->CMAR = (uint32_t) &adc2InjectedBits; // Address of memory
DMA1_Channel3->CCR |= DMA_CCR_PL_1 | DMA_CCR_PL_0; // Priority highest
DMA1_Channel3->CCR |= DMA_CCR_MSIZE_0; // 16 bits memory destination
DMA1_Channel3->CCR |= DMA_CCR_PSIZE_0; // 16 bits peripheral destination
DMA1_Channel3->CCR |= DMA_CCR_TEIE; // Transfer error interrupt enable
DMA1_Channel3->CCR |= DMA_CCR_TCIE; // Transfer complete interrupt enable
DMA1_Channel3->CNDTR = 1; // Number of data to be transferred
// ######## DMAMUX ######### as per 13.3.2 (13.4.3)
DMAMUX1_Channel2->CCR |= 36; // ADC 2 (DMAMUX channel to DMA connection: 13.3.2)
DMA1_Channel3->CCR |= DMA_CCR_CIRC; // Circular mode
DMA1_Channel3->CCR |= DMA_CCR_EN; // Enable channel (
SET_BIT(RCC->AHB2ENR, RCC_AHB2ENR_ADC12EN);
delayMicroseconds(1); // CAUTION: Just after enabling the clock for a peripheral, software must wait for a delay before accessing the peripheral registers.
ADC12_COMMON->CCR |= (ADC_CCR_CKMODE_1 | ADC_CCR_CKMODE_0); // adc_hclk/4 -> 42.5Mhz
delayMicroseconds(1);
ADC2->CR &= ~ ADC_CR_DEEPPWD; // Disable power down (is default after reset)
ADC2->CR |= ADC_CR_ADVREGEN; // Enable voltage regulator
delayMicroseconds(100); // Wait for voltage regulator to start up (fixed value of datasheet!)
ADC2->CR |= ADC_CR_ADCAL; // Calibrate single ended (ADCALDIF is default 0)
while(ADC2->CR & ADC_CR_ADCAL); // Wait until calibration has finished
delayMicroseconds(50); // ADC can only be enabled after short wait after ADCAL
ADC2->ISR |= ADC_ISR_ADRDY; // Clear ready bit for reading the right status below
ADC2->CR |= ADC_CR_ADEN; // Enable ADC
while((ADC2->ISR & ADC_ISR_ADRDY) == false); // Wait until ready
ADC2->JSQR |= (ADC_JSQR_JSQ1_1 | ADC_JSQR_JSQ1_0); // Channel 3 injected (with dual mode)
ADC2->CFGR |= ADC_CFGR_DMACFG; // DMA circular mode
ADC2->CFGR |= ADC_CFGR_OVRMOD; // Overrun overrides data
ADC2->CFGR |= ADC_CFGR_DMAEN; // Enable DMA
while(1){
delay(100);
ADC2->CR |= ADC_CR_JADSTART;
delay(100);
if(millis() - lastADCMeasure > 350){// && lastADCMeasure == 0){
ADC2->CR |= ADC_CR_ADSTART; // Start new regular measurements TODO: keep away from times of noise (communication etc.)
lastADCMeasure = millis();
}
}
}
2025-02-21 2:43 AM
Hi @Tobe ,
Injected conversions are not managed by DMA, only regular conversions are supported.
For injected conversions, you need to use an interrupt. Additionally, you can refer to the ADC section of the reference manual RM0440 for more information. There are also examples in STM32CubeG4 that can help you
Thank you.
ELABI.1
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.