cancel
Showing results for 
Search instead for 
Did you mean: 

ADC: DMA of injected conversions does not work, when there are no regular conversions

Tobe
Senior III

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();
		}
	}
}

 

 

 

1 REPLY 1
ELABI.1
ST Employee

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.