cancel
Showing results for 
Search instead for 
Did you mean: 

Trigger ADC1 conversion using TIM3 using registers

UMilo.1
Associate III

Hello,

I am trying to have analog voltage converted every 2 seconds using the TRGO signal from TIM3. Without much success. For now, I managed to generate interrupt of TIM3 and in TIM3 Handler to use software trigger for ADC. Here is the code:

TIM3:

void adtim1(void){
	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // Enable the peripheral clock of GPIO Port A
 
	//TIM2->CR1 &= ~TIM_CR1_CEN;
	// Enable timer 2 clock
	RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
 
	//	Counting direction: 0 = up-counting, 1 = down-counting
	//TIM2->CR1 &= ~TIM_CR1_DIR;
 
	TIM3->CR2 &= ~TIM_CR2_MMS; 	
	TIM3->CR2 |= TIM_CR2_MMS_2;
 
	// Clock prescaler (16 bits, up to 65,535)
	TIM3->PSC = 7999;
 
	//Auto-reload:
	TIM3->ARR = 1000;
 
	TIM3->CCR2 = 50;
 
	TIM3->CCMR1 &= ~TIM_CCMR1_OC2M; 
 
	TIM3->CCMR1 |= (0b110 << TIM_CCMR1_OC2M_Pos);
 
	//TIM3->CCMR1 |= 0b01 << TIM_CCMR1_CC2S_Pos;
	//TIM3->CCMR2 &= ~TIM_CCMR2_OC4PE;
 
	// Select output polarity: 0 = active high, 1 = active Low
	TIM3->CCER &= ~TIM_CCER_CC2P;
 
	TIM3->CCER |= TIM_CCER_CC2P;
 
	TIM3->CCER |= TIM_CCER_CC2E; 
 
	//TIM3->SMCR |= 0b110 << TIM_SMCR_SMS_Pos;
 
	//TIM3->SMCR |= 0b110 << TIM_SMCR_TS_Pos;
 
 
	//	Enable timer 2
	//TIM2->CR1 |= (0b01 << TIM_CR1_CMS_Pos);
	TIM3->CR1 &= ~TIM_CR1_ARPE;
 
 
	TIM3->CR1 |= TIM_CR1_CEN;
	TIM3->DIER |=TIM_DIER_UIE; //Update Interrupt Enable
	TIM3 -> SR &= ~TIM_SR_UIF; //Update Interrupt Flag
	TIM3->DIER |=TIM_DIER_TIE; //Trigger Interrupt Enable
	TIM3 -> SR &= ~TIM_SR_TIF; //Trigger Interrupt Flag
	NVIC_EnableIRQ(TIM3_IRQn); //Interrupt Set-Enable Register
	__enable_irq();  //Enable Interrupt
 
 
 
}

ADC:

void ADC_General_Init(ADC_TypeDef *  ADCx){
 
	ADCx->CR2 |= ADC_CR2_ADON;
	delay(20);
 
	ADCx->CR2 |= ADC_CR2_CAL;
	while ((ADCx->CR2 & ADC_CR2_CAL)==ADC_CR2_CAL);
 
	ADCx->CR2 &= ~ADC_CR2_ADON;
 
	ADCx->CR2 &= ~ADC_CR2_CONT; // CONT = 0: Single conversion mode
 
	ADCx->CR2 |= ADC_CR2_TSVREFE;
 
 
	ADCx->SQR1 &= ~ADC_SQR1_L;   // L[3:0]=0000: 1 conversion, ADC_SQR1
 
	ADCx->SQR3 &= ~ADC_SQR3_SQ1;
	ADCx->SQR3 |= (1U << ADC_SQR3_SQ1_Pos); 
 
	ADCx->CR2 &= ~ADC_CR2_EXTSEL;
	ADCx->CR2 |= (0b111U << ADC_CR2_EXTSEL_Pos); // EXTSEL[2:0] = 111: SWSTART
 
	//  ADC ON
	ADCx->CR2 |= ADC_CR2_ADON;
 
}
 
void ADC_GPIO_Init(void) {
 
	GPIOA->CRL &= ~(GPIO_CRL_MODE1 | GPIO_CRL_CNF1);
}
 
void ADC_Init(void) {
	// Enable the clock of ADC 1
	RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;  // Enable ADC 1 clock
 
	ADC_GPIO_Init();
	ADC_General_Init(ADC1);
 
	ADC1->CR1 |= ADC_CR1_EOCIE; // Enable interrupt 
 
	NVIC_SetPriority(ADC1_IRQn, 1);		// Set Priority to 1
	//NVIC->ISER[0] |= NVIC_ISER_SETENA_18;
	//NVIC_EnableIRQ(ADC1_IRQn);			// Enable interrupt of ADC 1 & 2
	 NVIC_EnableIRQ(ADC1_2_IRQn); 		// Same thing
}

Sorry if comments make code hard to read.

Can somebody help me configure settings in order to trigger conversion using TIM3?

Thank you!

I am working in Eclipse and Proteus, on STM32F103R6

1 ACCEPTED SOLUTION

Accepted Solutions

Thanks for helping me out. I really appreciate it!

The current situation is like this. ADC works as expected!

The only thing that concerns me is why ADC works when Update interrupt is enabled in TIM3, I figured it out that Trigger interrupt should do that.

So, ADC is configured like this:

    ADCx->CR2 &= ~ADC_CR2_EXTSEL;
    ADCx->CR2 |= (0b100U << ADC_CR2_EXTSEL_Pos); // EXTSEL[2:0] = 100: //TIM3 TRGO
     
    ADC1 -> CR2 |= ADC_CR2_EXTTRIG; // 1: Conversion on external event enabled (page 241 ref manual)

So it should only be triggered with TIM3 TRGO.

When I enable TIE in SR of TIM3, ADC does not work. But when I enable UIE it works. I could not find online a clear difference between these two. Maybe TIE should be used by other timers to activate TIM3? Not sure.

If somebody can confirm that my TIM3 setup generates TRGO then this case is closed!

View solution in original post

9 REPLIES 9
Javier1
Principal

I tried but i cant help you, i dont do register level coding :(

Why dont you do a pwm to check that TIM3 is doing what you want

>>if comments make code hard to read.

Its the other way around, thanks for the //

>>I am working in Eclipse and Proteus

Why dont you use STM32cubeMX to generate your boilerplate code?

we dont need to firmware by ourselves, lets talk

Thanks for trying! I really appreciate that.

I am working on college project and we are not allowed to use Cube :(

I tried a lot of things, and I think I am able to set up ADC to be triggered on TRGO signal but I do not really understand how Master/Slave configuration works for Timers... I mean I use only one timer so I don't really understand what should I set up.

It's not that comments are in serbian/croatian (sorry I can't distinguish them), but that they are incorrect/misleading...

> TIM3->CR2 |= TIM_CR2_MMS_2; // setovanje OC1REF as trigger output TRGO (OC1REF=100)

Okay, code does what the comment says; but then:

> // Polje OC3M[2:0], 011: Toggle - OC4REF toggles when TIMx_CNT=TIMx_CCR4.

> TIM3->CCMR1 &= ~TIM_CCMR1_OC2M;

so, CH3 as in OC3M; CH4 as in CCR4, or CH2 as in the actual code?

It appears that the TIM3_CR2.MMS setting is incorrect and you want to set it to OC2REF.

You also posted the version with software trigger in ADC_CR2.EXTSEL; don't forget to change it TIM3_TRGO.

As a general debugging method, I recommend to read out the content of relevant registers and check.

Also, note, that the simulation may be incomplete/incorrect, so you might want to go for the real chip.

JW

Thanks for the reply and help.

Yes, the comments are a mess because I combined many codes and did not modify the comments. I will delete them all.

I am using CH2 of TIM3.

I will check OC2REF and try to set them up according to the Ref manual. Thank you

UMilo.1
Associate III

I made changes to the following:

TIM3->CR2 |= (0b101 << TIM_CR2_MMS_Pos); // OC2REF as trigger output TRGO (OC2REF=101)

And I disabled Update Interrupt Enable, just TIE left:

//TIM3->DIER |=TIM_DIER_UIE; //Update Interrupt Enable
	//TIM3 -> SR &= ~TIM_SR_UIF; //Update Interrupt Flag
	TIM3->DIER |=TIM_DIER_TIE; //Update Interrupt Enable
	TIM3 -> SR &= ~TIM_SR_TIF; //Update Interrupt Flag

In ADC I change the following:

ADCx->CR2 &= ~ADC_CR2_EXTSEL;
ADCx->CR2 |= (0b100U << ADC_CR2_EXTSEL_Pos); // EXTSEL[2:0] = 100: //TIM3 TRGO
 
ADC1 -> CR2 |= ADC_CR2_EXTTRIG; // 1: Conversion on external event enabled (page 241 ref manual)

But it does not trigger yet. Does somebody know what else should I configure in order to get this to work?

Thank you!

UMilo.1
Associate III

UPDATE:

ADC Conversion seems to be working when I use Update Interrupt instead of Trigger interrupt. Not sure why and what is the key difference.

Read out and check/post content of TIM3 and ADC registers, and describe exactly the symptoms, for the current variant.

> Also, note, that the simulation may be incomplete/incorrect, so you might want to go for the real chip.

JW

Thanks for helping me out. I really appreciate it!

The current situation is like this. ADC works as expected!

The only thing that concerns me is why ADC works when Update interrupt is enabled in TIM3, I figured it out that Trigger interrupt should do that.

So, ADC is configured like this:

    ADCx->CR2 &= ~ADC_CR2_EXTSEL;
    ADCx->CR2 |= (0b100U << ADC_CR2_EXTSEL_Pos); // EXTSEL[2:0] = 100: //TIM3 TRGO
     
    ADC1 -> CR2 |= ADC_CR2_EXTTRIG; // 1: Conversion on external event enabled (page 241 ref manual)

So it should only be triggered with TIM3 TRGO.

When I enable TIE in SR of TIM3, ADC does not work. But when I enable UIE it works. I could not find online a clear difference between these two. Maybe TIE should be used by other timers to activate TIM3? Not sure.

If somebody can confirm that my TIM3 setup generates TRGO then this case is closed!