cancel
Showing results for 
Search instead for 
Did you mean: 

Can't see the data using DMA and ADC

JMart.13
Senior

I'm using STM32F303RE, and I'm trying to sense analog values from different ports of the ADC using the DMA, but at the moment the application is running, I don't get any data. I tried to put an interrupt routine to see if the DMA is at least been called like the following:

extern "C" {
	void DMA1_Channel1_IRQHandler(void){
		if(DMA1->ISR & (1U << 1U)){
			counter ++; 
			DMA1->IFCR |= (1U << 1U); 
		}
	}
}

but it never gets called.

this is my initialization function for the ADC and DMA:

void Initializate_ADC1(){
	periph::GPIO::set_pin(GPIOA, 0, ANALOG); 
	periph::GPIO::set_pin(GPIOA, 1, ANALOG);
	/*configuring dma for the ADC*/
	DMA1_Channel1->CCR |= DMA_CCR_CIRC | DMA_CCR_MINC | DMA_CCR_PSIZE_0 | DMA_CCR_MSIZE_0 ; 
	//inside the adc DMA function it activates the sha channel
	//Configure length and channels
	DMA1_Channel1->CCR |= DMA_CCR_TCIE; 
	ADC1->SQR1 = 0;	
	ADC1->SQR1 |= (ADC_LENGTH_2 << 0U); 		
	periph::ADC::SetChannelSequence(ADC1_SQR1, ADC_CH_1, ADC_SQ1_1); 
	periph::ADC::SetChannelSequence(ADC1_SQR1, ADC_CH_2, ADC_SQ1_2);
	periph::ADC::DMA_Init(ADC1, DMA1_Channel1, adc_dma_buffer, DMA_BUFFER_LENGTH,ADC_LENGTH_2); 
	 
 
}

I have to say that functions like set_pin and set channel sequence work perfectly, now, this is my ADC DMA_Init:

	void DMA_Init(ADC_TypeDef * adc, DMA_Channel_TypeDef * dma_ch, std::uint16_t * buffer, std::uint32_t buffer_length,std::uint8_t length){
			adc->CFGR |= ADC_CFGR_CONT; 
			adc->CFGR |= ADC_CFGR_DMAEN;
			adc->SMPR1 |= (7U << 3U) | (7U << 6U); //max sampling rate 
	
			
			dma_ch->CPAR = (std::uint32_t)(&adc->DR); 
			dma_ch->CMAR = (std::uint32_t)(buffer); 
			dma_ch->CNDTR = buffer_length; 	
			dma_ch->CCR |= DMA_CCR_EN;				
			
			Enable_regulator(adc); 
			Calib(adc); 
			Enable(adc); 
			
		}
		

adc-> in this case, I passed ADC1 as a parameter to configure it.

dma_ch-> DMA channel as a parameter, I'm using channel one of DMA1 because the reference manual says that one of the peripherals of channel one corresponds to ADC1.

Enable_regulator, Calib, and Enable work perfectly.

If not too much bother to try to understand what's wrong or what I'm doing wrong.

Thanks

5 REPLIES 5
TDK
Guru

You need to enable the NVIC interrupt.

If you feel a post has answered your question, please click "Accept as Solution".

Yes, I have enabled the interrupt:

NVIC_EnableIRQ(DMA1_Channel1_IRQn); 
NVIC_SetPriority(DMA1_Channel1_IRQn, 0);

TDK
Guru

Do any other flags in DMA1_ISR get set? Particularly an error flag.

There's stuff here that you're not including in your OP (like NVIC), so it's a bit hard to debug with only pieces. Investigating the register values of ADC and DMA would probably expose the problem the quickest.

> DMA1->IFCR |= (1U << 1U);

Although not the cause of the issue here, IFCR is write only. To clear bit 1, this should be DMA1->IFCR = (1U << 1U);

If you feel a post has answered your question, please click "Accept as Solution".
JMart.13
Senior

Yes, I checked the error flags if any get set but no, there is no error flag set. If helps, this is the complete main function:

int main(void){
	__disable_irq(); 
	
	/*variables initializations*/
	volatile std::uint16_t sensor_value_1 = 0; 
 
	
	/*configure clock for ADC*/
	RCC->CR |= RCC_CR_PLLON; 
	RCC->CFGR2 |= (16U << 4U); 
	
	/*Peripheral activation*/
	RCC->AHBENR  |= RCC_AHBENR_GPIOBEN;
	RCC->AHBENR  |= RCC_AHBENR_GPIOAEN;
	RCC->AHBENR  |= RCC_AHBENR_DMA1EN; 
	RCC->AHBENR  |= RCC_AHBENR_ADC12EN; 
	RCC->APB1ENR |= RCC_APB1ENR_USART3EN;
	RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; 
	
 
	/*Peripheral initializattions*/	
	periph::GPIO::set_pin(GPIOA, 5, OUTPUT); 
	Initializate_UART3();
	Initializate_ADC1(); 
 
	volatile std::uint16_t val = 54230; 
	NVIC_EnableIRQ(DMA1_Channel1_IRQn); 
	NVIC_SetPriority(DMA1_Channel1_IRQn, 0);
	__enable_irq();
	while(1){
		data1 = adc_dma_buffer[0]; 
		data2 = adc_dma_buffer[1]; 
		utils::delay::ms(10); 
	}
	
}

And here are some functions I used for the ADC:

void Enable(ADC_TypeDef * adc){
		adc->CR |= ADC_CR_ADEN; 
		while(!(adc->ISR & ADC_ISR_ADRDY)){}
}
		
void Disable(ADC_TypeDef * adc){
	adc->CR |= ADC_CR_ADDIS; 
	while((adc->CR & ADC_CR_ADEN)){}
}
		
void Enable_regulator(ADC_TypeDef * adc){ 
	adc->CR &= ~(ADC_CR_ADVERGEN_CLEAR); 
	adc->CR |= ADC_CR_ADVERGEN_ENABLE; 
	utils::delay::us(25); 
}
		
void Calib(ADC_TypeDef * adc){
	Disable(adc); 
	adc->CR &= ~ADC_CR_ADCALDIF; 
	adc->CR |= ADC_CR_ADCAL; 
			
	while((adc->CR & ADC_CR_ADCAL) != 0){}
}

ok, what it seems, in the STM32F303, is necessary to start a conversion, with this: ADC1->CR |= ADC_CR_ADSTART; and then, the DMA makes the request. The thing is, I was watching a video of a guy that uses stmf1 and he didn't start any conversion when using the ADC, and I was reading the reference manual and I notice this part: "a DMA request is generated

after each conversion of a channel." I didn't understand at first but reading carefully now, it was that.

Thanks for taking the time to reply to me and forgive any inconvenience.