cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G0 series TIM+ADC+DMA. Why does an external event not come from the timer?

red15530
Associate II

I have had an experience of working with TIM+ADC+DMA on microcontrollers F series. Now I need to use TIM+ADC+DMA on microcontroller STM32G030F6P6. A part of ADC and DMA registers was changed in G0 series. I want to digitize sequencely two channels after external event and get result with DMA. I wrote a code for working with TIM+ADC+DMA on STM32G030F6P6:

RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
	__NOP();
	GPIOA->MODER |= GPIO_MODER_MODE4_0 | GPIO_MODER_MODE4_1; //11: Analog mode
	GPIOA->MODER |= GPIO_MODER_MODE5_0 | GPIO_MODER_MODE5_1; //11: Analog mode
 
	RCC->APBENR2 |= RCC_APBENR2_ADCEN;
	__NOP();
	ADC1->CFGR1 |= ADC_CFGR1_DMAEN; //1: DMA enabled
	ADC1->CFGR1 |= (1 << ADC_CFGR1_EXTEN_Pos); //01: Hardware trigger detection on the rising edge
	ADC1->CFGR1 |= (3 << ADC_CFGR1_EXTSEL_Pos); //TIM3_TRGO
	ADC1->SMPR |= (7 << ADC_SMPR_SMP1_Pos); //160.5 ADC clock cycles
	ADC1->SMPR |= (7 << ADC_SMPR_SMP2_Pos); //160.5 ADC clock cycles
	ADC1->SMPR |= (1 << ADC_SMPR_SMPSEL4_Pos);
	ADC1->SMPR |= (1 << ADC_SMPR_SMPSEL5_Pos);
	ADC1->ISR |= ADC_ISR_CCRDY;
	ADC1->CHSELR |= ADC_CHSELR_CHSEL4; //1: Input Channel-x is selected for conversion
	while (ADC1->ISR & ~ADC_ISR_CCRDY);
	ADC1->ISR |= ADC_ISR_CCRDY;
	ADC1->CHSELR |= ADC_CHSELR_CHSEL5; //1: Input Channel-x is selected for conversion
	while (ADC1->ISR & ~ADC_ISR_CCRDY);
	ADC1->ISR |= ADC_ISR_CCRDY;
	ADC1->CR |= ADC_CR_ADEN; // ON ADC
 
	RCC->AHBENR |= RCC_AHBENR_DMA1EN;
	__NOP();
	DMAMUX1_Channel0->CCR |= (5 << DMAMUX_CxCR_DMAREQ_ID_Pos); //ADC
	DMA1_Channel1->CCR &= ~DMA_CCR_TEIE;
	DMA1_Channel1->CCR &= ~DMA_CCR_HTIE;
	DMA1_Channel1->CCR |= DMA_CCR_TCIE;
	DMA1_Channel1->CCR |= (3 << DMA_CCR_PL_Pos); //11: Very high
	DMA1_Channel1->CCR |= (1 << DMA_CCR_MSIZE_Pos) | (1 << DMA_CCR_PSIZE_Pos); //01: half-word (16-bit)
	DMA1_Channel1->CCR |= DMA_CCR_MINC; //1: Memory address pointer is incremented after each data transfer (increment is done according to MSIZE)
	DMA1_Channel1->CCR |= DMA_CCR_CIRC; //1: Circular mode enabled
	DMA1_Channel1->CCR |= 0 << DMA_CCR_DIR_Pos; //00: Peripheral-to-memory ! 01: Memory-to-peripheral
	DMA1_Channel1->CNDTR = 2; //Number of data items to transfer
	DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR; //Peripheral address
	DMA1_Channel1->CMAR = (uint32_t)&res_adc_other[0]; //Memory 0 address
	NVIC_SetPriority(DMA1_Channel1_IRQn,0);
	NVIC_EnableIRQ(DMA1_Channel1_IRQn);
	DMA1_Channel1->CCR |= DMA_CCR_EN;
 
	RCC->APBENR1 |= RCC_APBENR1_TIM3EN;
	__NOP();
	TIM3->CR2 = (2 << TIM_CR2_MMS_Pos); //010: Update - The update event is selected as trigger output (TRGO)
	TIM3->PSC = 1600-1;
	TIM3->ARR = 1000-1;
	TIM3->EGR |= TIM_EGR_UG;
	TIM3->SR &= ~ TIM_SR_UIF;
	TIM3->CR1 |= TIM_CR1_CEN;

It doesn't work. I noticed that external event which should start ADC doesn't come from timer. If I manually start ADC (ADC1->CR |= ADC_CR_ADSTART) then I get result. Why does an external event not start ADC?

I went over the documentation several times, tried various options, but could not start TIM + ADC + DMA on STM32G030F6P6. I was already desperate and decided maybe someone could help me here ...

4 REPLIES 4
Javier1
Principal

being 100% honest , i let cubeMX initialize these kind of things, or at least as a template to guide my own baremetal initialization code.

  • Did you tried using TIM1 or TIM4?

  • are you sure of
TIM3->CR2 = (2 << TIM_CR2_MMS_Pos); //010: Update - The update event is selected as trigger output (TRGO)

does what you want ?

  • are you sure of
ADC1->CFGR1 |= (3 << ADC_CFGR1_EXTSEL_Pos); //TIM3_TRGO

doing what you want?

I prefer CMSIS to understand how things work at the register level.

I was trying to use only TIM3. TIM1 is busy for PWM output. TIM4 is not present in this microcontroller.

are you sure of
TIM3->CR2 = (2 << TIM_CR2_MMS_Pos); //010: Update - The update event is selected as trigger output (TRGO)
does what you want ?

0693W00000WJWiuQAH.png 

are you sure of
ADC1->CFGR1 |= (3 << ADC_CFGR1_EXTSEL_Pos); //TIM3_TRGO
doing what you want?

0693W00000WJWj4QAH.png

S.Ma
Principal

Debug Dig and split, make the timer output signal to a pin, then wire it to the adc trigger input pin. Check functionality stage by stage.

What if

TIM3->CR2 = (2 << TIM_CR2_MMS_Pos);

is overwriting some other important stuff in CR2?

Im seeing now you dont use any

|=

to set those bits

Or maybe youre trying to set the MMS in the wrong register, i dont really know, just trying to get some clues