cancel
Showing results for 
Search instead for 
Did you mean: 

Slave Timer Not Starting After Master Timer Enable. CMSIS-only. STM32F746

ilyus
Senior II

STM32F746 Disco. CubeIDE 1.8.0. Win 10. CMSIS-only (no HAL, no LL, full registers)

Learning stuff. The purpose is to make a simple demo-program to make sure I understand how things work. Timers have been the most confusing piece so far due to amount of information and functionality. (tbh DMA feels like a child's toy next to them). I have no problem using basic timer function such as setting regular interrupts.

Resources: datasheet, reference manual, programming manual, some application notes on timers.

Given: System at 216MHz. 2 Timers: TIM1 adv. as master. TIM3 gp. as slave. When I do Counter Enable for TIM1, I want TIM3 to start immediately as well. TIM3 doesn't start. I don't understand what I missed.

TIM1 and TIM3 both work correctly individually (tested), when I start each of them manually.

TIM1 advanced timer master:

void advanced_timer_setup_master(TIM_TypeDef *TMR) {
	/*
	 * CR1 reset value = 0x00000000
	 * ARR is not buffered
	 * only overflow/underflow generates update event
	 * dead-time/sampling period =  1 * tck_int
	 * upcounter (default)
	 * update request source: only overflow/underflow
	 *
	 * */
	TMR->CR1 = 0x00; //reset
	TMR->CR1 |= TIM_CR1_URS | (0x00 << TIM_CR1_CKD_Pos) | TIM_CR1_OPM;
	//TMR->CR1 |= TIM_CR1_URS | (0x00 << TIM_CR1_CKD_Pos);
 
 
	/*
	 * CR2 reset value = 0x00000000
	 * Master Mode Selection 1: Enable. CNT_EN Triggers TRGO to start another timer
	 * Master Mode Selection 2: OC1REF is used as trigger output TRGO2 (not implemented yet)
	 *
	 * */
	TMR->CR2 = 0x00; //reset
	TMR->CR2 |= (0x01 << TIM_CR2_MMS_Pos) | (0x04 << TIM_CR2_MMS2_Pos);
 
	TMR->PSC = (216000U / 4U) - 1U; //APB2 is 108MHz, timer is 2x APB1 Freq, so now the timer is at 4kHz; 16-bit value!!! 65535 max!
	TMR->ARR = 12000U - 1U; //12000 ticks at 4kHz is 3s
	TMR->CNT = 0x00; //start value
	TMR->EGR |= TIM_EGR_UG; //force update event to make sure all values are loaded
	TMR->SR &= ~TIM_SR_UIF; //make sure the update flag is cleared
	//TMR->DIER |= TIM_DIER_UIE; //update event interrupt enable
 
	/*
	//enable interrupt
	TMR->SR &= ~TIM_SR_UIF; //make sure the update flag is cleared
	NVIC_ClearPendingIRQ(TIM1_UP_TIM10_IRQn); //clear NVIC pending interrupt
	NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 4U);
	NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
	*/
}

Commented out code was used for testing if it works as intended. It does.

TIM3 slave code:

void general_purpose_setup_slave1(TIM_TypeDef *TMR) {
	//TIMER 3 channel 1 PB4 ARD D3
	//TIM3,4 16-bit ARR, TIM2,5 32-bit
 
	/*
	 * CR1 reset value = 0x00000000
	 * ARR is not buffered
	 * only overflow/underflow generates update event
	 * dead-time/sampling period =  1 * tck_int
	 * upcounter (default)
	 * update request source: only overflow/underflow
	 *
	 * */
	TMR->CR1 = 0x00; //reset
	TMR->CR1 |= TIM_CR1_URS | (0x00 << TIM_CR1_CKD_Pos);
 
	/*
	 * CR2 reset value = 0x00000000
	 * Master Mode Selection 1: Enable. CNT_EN Triggers TRGO to start another timer
	 * Master Mode Selection 2: reset
	 *
	 * */
	TMR->CR2 = 0x00; //reset
	TMR->CR2 |= (0x01 << TIM_CR2_MMS_Pos);
 
	/*
	 * SMCR Slave Mode Control Register reset value = 0x00000000
	 * Master/Slave Mode - Effect of TRGI is delayed to allow sync btw this tmr and its slaves MSM
	 * Trigger Selection - ITR0 (TIM1 as Master)
	 * Slave Mode Selection - Reset Mode - Rising edge of the selected trigger input (TRGI) reinitializes the counter 0100
	 * and generates an update of the registers
	 */
	TMR->SMCR = 0x00; //reset
	//TMR->SMCR |= TIM_SMCR_MSM
	TMR->SMCR |= (0x00 << TIM_SMCR_TS_Pos) | (0x00 << 16U) | (0x04 << TIM_SMCR_SMS_Pos);
 
	TMR->PSC = (108000U / 2U) - 1U; //APB1 is 54MHz, timer is 2x APB1 Freq, so now the timer is at 2kHz; 16-bit value!!! 65535 max!
	TMR->ARR = 2000U - 1U; //2000 ticks at 2kHz is 1s
	TMR->CNT = 0x00; //start value
	TMR->EGR |= TIM_EGR_UG; //force update event and load all values into registers
	TMR->DIER |= TIM_DIER_UIE; //update event interrupt enable
 
	//enable interrupt
	TMR->SR &= ~TIM_SR_UIF; //make sure the update flag is cleared
	NVIC_ClearPendingIRQ(TIM3_IRQn); //clear NVIC pending interrupt
	NVIC_SetPriority(TIM3_IRQn, 4U);
	NVIC_EnableIRQ(TIM3_IRQn);
}

Yeah, I was planning to chain 3 timers originally (or more), thus this timer has some master config. I figured, I take it one step at a time.

As you can see, on Counter Enable, Timer 1 is supposed to output TRGO, which via ITR0 must Counter Enable TIM3. But it doesn't happen, and I don't know why.

I would appreciate any assistance to make it work and make it slightly more intuitive.

EDIT: I have a feeling I haven't connected TRGO of TIM1 to ITR0 to TRGI of TIM3, but I don't know how to do it. Doing some reading for now.

EDIT2: My first edit was wrong. Dug up an old stackoverflow post. The only difference with my algo was that the slave (in the stackoverflow answer) was not in Reset mode but in Combined Reset + Trigger Mode. Tried both Combined + Trigger Mode or just Trigger Mode. Both worked correctly.

My mistake was that I thought Slave Reset Mode would start the timer. I have just realized that reset mode doesn't start the slave timer, only reloads its registers. Problem solved.

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

> TMR->SR &= ~TIM_SR_UIF;

To avoid potentially clearing other flags, do this instead:

TMR->SR = ~TIM_SR_UIF;

> TMR->SMCR |= (0x00 << TIM_SMCR_TS_Pos) | (0x00 << 16U) | (0x04 << TIM_SMCR_SMS_Pos);

So its in reset slave mode. It resets when TRGO happens. Don't you want Gated mode? Or Trigger mode?

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

View solution in original post

7 REPLIES 7
TDK
Guru

> TMR->SR &= ~TIM_SR_UIF;

To avoid potentially clearing other flags, do this instead:

TMR->SR = ~TIM_SR_UIF;

> TMR->SMCR |= (0x00 << TIM_SMCR_TS_Pos) | (0x00 << 16U) | (0x04 << TIM_SMCR_SMS_Pos);

So its in reset slave mode. It resets when TRGO happens. Don't you want Gated mode? Or Trigger mode?

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

I don't think I clear any unnecessary flags anywhere. I AND all flags with 1 except UIF AND 0. Why do you think I clear flags wrong?

And yes, I already solved the problem as per my EDIT 2. I picked the wrong slave mode. First timer problems (I'm first timer with timers)

read-modify-write is not atomic. If a flag is set mid-way through that process, you will clear it without knowing.
It isn't an issue in this example, but RMW is unnecessary here and can bite you.
If you feel a post has answered your question, please click "Accept as Solution".

I don't clear any other flags than UIF. I don't affect them in any way. Whatever was 1, will stay 1. Whatever was 0, will stay 0. I don't see any problem. Can you provide a detailed example of something going wrong and how do you suggest I should do it instead.

Edit: I think I know what you mean after a little consideration. Indeed. I see it. Still, how do I fix it then? Your proposed solution looks plain wrong as it sets all 0 flags to 1

Checked the reference manual. The bits in status register are rc_w0. What exactly does it mean? (I take it it's OK to write smth there, but I want to know the definition of that thing to understand it)

"rc_w0, meaning software can write a 1 with no effect, or write a

0 to clear a particular status." Ok. I understand your answer! I got why you're right about everything. Thanks!

Glad you understand. It is a minor point but it can get you when you're doing more complex stuff.

Flag clearing on the various peripherals can vary so it's good to check the reference manual for the exact method to clear them, especially if you are doing register-access and care about speed.

Definitions for the various registers are in the beginning of the RM:

0693W00000KcHkgQAF.png 

Edit:

I did not see your edits at the time I looked at this, otherwise I wouldn't have replied.

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