Skip to main content
Visitor II
March 28, 2024
Question

STM32F756VGH6 problem running 2 timers at the same time

  • March 28, 2024
  • 2 replies
  • 1752 views

Hi,

I am a newbie learning to program STM32 via registers only. I have been doing step after step progress and managed to test and run the led blink program, timer delay, external interrupt etc. So hardware, core clock and other configurations are already tested. Now I ran into a problem of running 2 timers at the same time. I am using Timer1 as my blocking delay source (timer 1 is tested and works well), but when I entered interrupts, the need for second timer was imminent to implement timer interrupts etc.

The problem arises in the first line of Timer8 setup. I have done countless test, skipping the timer 8 setup and usage results in perfectly working code (except the timer 8 of course), but as soon as I try to even enable the clock for timer 8 (or do an further timer8 and its interrupt setup) whole code jams without any response. I have been reading the datasheet for a good few days now, but after so many tests I can not resolve it on my own. Any ideas or obvious mistakes? Thank you in advance.

 

#include "main.h"

void Core_Clock_Setup (void){

	RCC->CR |= RCC_CR_HSEON; //Set the clock source to external crystal/resonator (HSE)
	while (!(RCC->CR & RCC_CR_HSEON));	 //Wait until clock gets stable
	RCC->APB1ENR |= RCC_APB1ENR_PWREN; //Enable power interface clock
	PWR->CR1 &= ~(1U << 14);
	PWR->CR1 &= ~(1U << 15); //Set internal voltage regulator to is reset value (scale 1)
	FLASH->ACR &= ~FLASH_ACR_ARTEN; //Disable ART accelerator
	FLASH->ACR &= ~FLASH_ACR_ARTRST; //Reset ART accelerator
	FLASH->ACR |= FLASH_ACR_PRFTEN; //Enable prefetch
	FLASH->ACR |= FLASH_ACR_LATENCY_6WS; //Set 7 CPU clock cycle flash memory access time (in order to get 200 MHz core clock)

	//@ 25 MHz crystal, 200 MHz core clock configuration down below
	RCC->CFGR &= 0x0F; //--------------------------------------------------------
	RCC->CFGR &= ~(1 << 4); //Core clock division by 1 (core clock is not devided)
	RCC->CFGR &= ~(1 << 5);
	RCC->CFGR &= ~(1 << 6);
	RCC->CFGR &= ~(1 << 7);
	RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC_HSE;//HSE is set to be PLL entry
	RCC->PLLCFGR &= ~(1 << 16); //PLLP Setting corresponding PLL prescalers (division by 2)
	RCC->PLLCFGR &= ~(1 << 17);
	RCC->PLLCFGR |= (16 << 0);
	RCC->PLLCFGR &= 0x7F;//-----------------------------------------------------------------
	RCC->PLLCFGR |= (256 << 6); //PLLN Setting corresponding PLL prescalers ( multiplication by 256)
	RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //APB1 Low speed prescaler of 4 (50 MHz, max is 54 Mhz)
	RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; //APB2 High speed prescaler of 2 (100 MHz, max is 108 Mhz)
	RCC->CR |= RCC_CR_PLLON; //Enable PLL
	while (!(RCC->CR & RCC_CR_PLLRDY));	 //Wait until PLL gets stable
	RCC->CFGR |= RCC_CFGR_SW_PLL; //PLL is set to be core clock
	while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // Wait until PLL indeed becomes core clock source
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Timer1_Setup(void){ //16 bit advanced timer

	RCC->DCKCFGR1 &= ~ (1 << 24); //TIMxCLK = 2xPCLKx
	//TIM1 CLK is HCLK in this case
	RCC->APB2ENR = (1 << 0); //Enable Timer 1 clock
	TIM1->PSC = 99; //APB1 is 50 Mhz and 100 MHZ for timer (The number is set: Clock in MHz - 1) 1 full period equals 1 MHZ
	TIM1->ARR = 0xFFFF; //Auto reload at 100 ticks -> (around 100 micro seconds at 100 MHz timer clock)/2
	TIM1->CR1 = (1 << 0); //Enable Timer 1 counter
	while(!(TIM1->SR & (1<<0))); //Wait until timer update bit is set
	//TIM1->CR1 &= ~(1 << 0); //Disable Timer 1 counter
	//TIM1->CNT = 0;

}

void Timer8_Setup(void){ //16 bit advanced timer

	//THIS LINE ALREADY JAMS THE CODE ---------------------------------------------------------------
	//RCC->APB2ENR |= (1 << 1); //Enable Timer 8 clock
	//---------------------------------------------------------------

	//TIM8->PSC = 99; //APB1 is 50 Mhz and 100 MHZ for timer (The number is set: Clock in MHz - 1) 1 full period equals 1 MHZ
	//TIM8->ARR = 0xFFFF;

	//TIM8->CR1 = (1 << 2); //Only counter overflow/underflow generates an update interrupt or DMA request if enabled
	//TIM8->DIER = (1 << 0); //Update interrupt enabled
	//TIM8->EGR = (1 << 0);

	//NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 1);
	//NVIC_EnableIRQ (TIM1_UP_TIM10_IRQn);

	//TIM8->CR1 = (1 << 0); //Enable Timer 1 counter
	//while(!(TIM8->SR & (1<<0))); //Wait until timer update bit is set

	//TIM8->CR1 &= ~(1 << 0); //Disable Timer 1 counter
	//TIM8->CNT = 0;
}

void delay_ms (uint16_t ms){
	TIM1->CR1 = (1 << 0); //Enable Timer 1 counter
	for(uint16_t i = 0; i<ms; i++)
	{
		TIM1->CNT = 0; //Reset counter
		while (TIM1->CNT < 2000); //Wait until counter reaches desired value
	}
	TIM1->CR1 &= ~(1 << 0); //Disable Timer 1 counter
	TIM1->CNT = 0;
}

void TIM1_UP_TIM10_IRQnHandler(void){

	//If multiple timer interrupts are enabled, have to check the status bits, to determine, which of the 1-10 timer interrupts have occurred
	if(TIM8->SR & (1<<0)){

	TIM8->CR1 &= ~(1 << 0); //Disable Timer 1 counter
	TIM8->CNT = 0;
	GPIOC->BSRR = (1 << 15);
	delay_ms(1000);
	GPIOC->BSRR = (1 << 31);

	TIM8->SR &= ~(1<<0);
	}
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void GPIO_Setup(void){

	//PC14 OUTPUT //LEDS
	RCC->AHB1ENR |= (1 << 2);				 //Enable clock for GPIO bank C
	RCC->AHB1ENR |= (1 << 4); //Enable clock for GPIO bank E
	delay_ms(1);
	GPIOC->MODER |= (0b01 << 28); //PC14 General purpose output mode
	GPIOC->OTYPER &= ~ (1 << 14); //PC14 Output push-pull (reset state)
	GPIOC->OSPEEDR |= (0b11 << 28); //PC14 very high GPIO speed
	GPIOC->PUPDR |= (0b10 << 28); //PC14 pull down resistors
	//PC15 OUTPUT
	GPIOC->MODER |= (0b01 << 30); //PC15 General purpose output mode
	GPIOC->OTYPER &= ~ (1 << 15); //PC15 Output push-pull (reset state)
	GPIOC->OSPEEDR |= (0b11 << 30); //PC15 very high GPIO speed
	GPIOC->PUPDR |= (0b10 << 30); //PC15 pull down resistors
	//PE4 OUTPUT
	GPIOE->MODER |= (0b01 << 8); //PE4 General purpose output mode
	GPIOE->OTYPER &= ~ (1 << 4); //PE4 Output push-pull (reset state)
	GPIOE->OSPEEDR |= (0b11 << 8); //PE4 very high GPIO speed
	GPIOE->PUPDR |= (0b10 << 8); //PE4 pull down resistors
	//PE0 OUTPUT
	GPIOE->MODER |= (0b01 << 0); //PE0 General purpose output mode
	GPIOE->OTYPER &= ~ (1 << 0); //PE0 Output push-pull (reset state)
	GPIOE->OSPEEDR |= (0b11 << 0); //PE0 very high GPIO speed
	GPIOE->PUPDR |= (0b10 << 0); //PE0 pull down resistors
	//-----------------------------------------------------------------------------------
	//PE5 INPUT ALL BUTTONS EXTERNALLY PULLED UP
	GPIOE->MODER |= (0b00 << 10); //PE5 General purpose input mode
	//PE6 INPUT
	GPIOE->MODER |= (0b00 << 12); //PE6 General purpose input mode
	/*
	//PH0 INPUT
	RCC->AHB1ENR |= (1 << 7);
	GPIOH->MODER |= (0b00 << 0); //PH0 General purpose input mode
	//PH1 INPUT
	GPIOH->MODER |= (0b00 << 2); //PH1 General purpose input mode
	*/

}


int main (void){

	Core_Clock_Setup();
	Timer1_Setup();
	GPIO_Setup();
	Timer8_Setup();

	GPIOC->BSRR = 0x4000;

	while(1){

		GPIOC->BSRR = (1 << 15);
		delay_ms(200);
		GPIOC->BSRR = (1 << 31);
		delay_ms(200);
	}

}

 



    This topic has been closed for replies.

    2 replies

    Graduate II
    March 29, 2024
    TIM1_UP_TIM10_IRQnHandler

    This is not TIM8 IRQ handler ! If you enable TIM8 and its interrupt, program stops in "non handled" interrupt handler. (Moreover this is not any handler (if you didnt rename it in startup file) - because of letter "n" inside.) Look into  file for startup_stm32f7xx.s your TIM8 handler.

    ViliusAuthor
    Visitor II
    April 1, 2024

    Right, that was my mistake. Thank you for pointing it out.

    However, there are still some problems left. Timer 1 is used for blocking delay and timer 8 is used for interrupt. Both timers have exact same clock setup, same prescalers, same source etc. Full period of 16 bit count is around 500 us in my setup, timer 1 justifies that. However, in my external interrupt ISR, I turn on led, start the timer8, and in the timer 8 ISR I turn the led off. That effectively should depict the period of timer 8 with a minor discrepancy. My logic analyzer shows that period is 32 ms which is is way off the expected 500 us. External interrupt setup and ISR is tested previously, it worked well. What could possibly cause such unexplainable GPIO on state period (it has to be related with timer 8, but since its 64 times off the target, I dont have an ideas...)?

    #include "main.h"
    
    void Core_Clock_Setup (void){
    
    	RCC->CR |= RCC_CR_HSEON; //Set the clock source to external crystal/resonator (HSE)
    	while (!(RCC->CR & RCC_CR_HSEON));	 //Wait until clock gets stable
    
    	RCC->APB1ENR |= RCC_APB1ENR_PWREN; //Enable power interface clock
    	PWR->CR1 &= ~(1U << 14);
    	PWR->CR1 &= ~(1U << 15); //Set internal voltage regulator to is reset value (scale 1)
    
    	FLASH->ACR &= ~FLASH_ACR_ARTEN; //Disable ART accelerator
    	FLASH->ACR &= ~FLASH_ACR_ARTRST; //Reset ART accelerator
    	FLASH->ACR |= FLASH_ACR_PRFTEN; //Enable prefetch
    	FLASH->ACR |= FLASH_ACR_LATENCY_6WS; //Set 7 CPU clock cycle flash memory access time (in order to get 200 MHz core clock)
    
    	//@ 25 MHz crystal, 200 MHz core clock configuration down below
    
    	RCC->CFGR &= ~(((1 << (7 - 4 + 1)) - 1) << 4);
    	RCC->CFGR &= ~(1 << 4); //Core clock division by 1 (core clock is not devided)
    	RCC->CFGR &= ~(1 << 5);
    	RCC->CFGR &= ~(1 << 6);
    	RCC->CFGR &= ~(1 << 7);
    
    	RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC_HSE;//HSE is set to be PLL entry
    
    	RCC->PLLCFGR &= ~(1 << 16); //PLLP Setting corresponding PLL prescalers (division by 2)
    	RCC->PLLCFGR &= ~(1 << 17);
    
    	RCC->PLLCFGR &= ~((1 << 6) - 1);
    	RCC->PLLCFGR |= (16 & ((1 << 6) - 1)); //PLLM Setting corresponding PLL prescalers (division by 16)
    	//RCC->PLLCFGR |= (16 << 0);
    
    	RCC->PLLCFGR &= ~(((1 << (14 - 6 + 1)) - 1) << 6);
    	RCC->PLLCFGR |= (256 << 6); //PLLN Setting corresponding PLL prescalers ( multiplication by 256)
    
    	RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //APB1 Low speed prescaler of 4 (50 MHz, max is 54 Mhz)
    	RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; //APB2 High speed prescaler of 2 (100 MHz, max is 108 Mhz)
    
    	RCC->CR |= RCC_CR_PLLON; //Enable PLL
    	while (!(RCC->CR & RCC_CR_PLLRDY));	 //Wait until PLL gets stable
    
    	RCC->CFGR |= RCC_CFGR_SW_PLL; //PLL is set to be core clock
    
    
    	//RCC->CFGR |= RCC_CFGR_SW_HSE; //HSE is set to be core clock
    
    	while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // Wait until PLL indeed becomes core clock source
    }
    
    //----------------------------------------------------------------------------------------------------------------------------------------------------------------------
    void Timer1_Setup(void){ //16 bit advanced timer
    
    	RCC->DCKCFGR1 &= ~ (1 << 24); //TIMxCLK = 2xPCLKx
    
    	//When TIMPRE bit of the RCC_DCKCFGR1 register is reset, if APBx prescaler is 1, then TIMxCLK = PCLKx, otherwise
    	//TIMxCLK = 2x PCLKx.
    	// When TIMPRE bit in the RCC_DCKCFGR1 register is set, if APBx prescaler is 1,2 or 4, then TIMxCLK = HCLK, otherwise
    	//TIMxCLK = 4x PCLKx.
    	//TIM1 CLK is HCLK in this case
    
    	RCC->APB2ENR |= (1 << 0); //Enable Timer 1 clock
    	TIM1->PSC = 99; //APB1 is 50 Mhz and 100 MHZ for timer (The number is set: Clock in MHz - 1) 1 full period equals 1 MHZ
    	TIM1->ARR = 0xFFFF; //Auto reload at 100 ticks -> around 100 micro seconds at 100 MHz timer clock
    	TIM1->CR1 |= (1 << 0); //Enable Timer 1 counter
    	while(!(TIM1->SR & (1<<0))); //Wait until timer update bit is set
    }
    
    void Timer8_Setup(void){ //16 bit advanced timer
    
    	RCC->APB2ENR |= (1 << 1); //Enable Timer 8 clock
    
    	TIM8->PSC = 99; //APB1 is 50 Mhz and 100 MHZ for timer (The number is set: Clock in MHz - 1) 1 full period equals 1 MHZ
    	TIM8->ARR = 0xFFFF;
    
    	TIM8->CR1 = (1 << 2); //Only counter overflow/underflow generates an update interrupt or DMA request if enabled
    	TIM8->DIER = (1 << 0); //Update interrupt enabled
    
    	//TIM8->EGR = (1 << 0); //Reinitialize timer
    	//TIM8->CR1 = (1 << 0); //Enable Timer 8 counter
    	//while(!(TIM8->SR & (1<<0))); //Wait until timer update bit is set
    	//TIM8->CR1 &= ~(1 << 0); //Disable Timer 8 counter not to generate any unwanted interrupts
    	//TIM8->CNT = 0;
    
    	NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 1);
    	NVIC_EnableIRQ (TIM8_UP_TIM13_IRQn);
    }
    
    
    void delay_ms (uint16_t ms){
    	TIM1->CR1 = (1 << 0);
    	for(uint16_t i = 0; i<ms; i++)
    	{
    		TIM1->CNT = 0; //Reset counter
    		while (TIM1->CNT < 2000); //Wait until counter reaches desired value
    	}
    	TIM1->CR1 &= ~(1 << 0);
    }
    //-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    void GPIO_Setup(void){
    
    	//PC14 OUTPUT //LEDS
    
    	RCC->AHB1ENR |= (1 << 2);				 //Enable clock for GPIO bank C
    	RCC->AHB1ENR |= (1 << 4); //Enable clock for GPIO bank E
    
    	delay_ms(1);
    
    	GPIOC->MODER |= (0b01 << 28); //PC14 General purpose output mode
    	GPIOC->OTYPER &= ~ (1 << 14); //PC14 Output push-pull (reset state)
    	GPIOC->OSPEEDR |= (0b11 << 28); //PC14 very high GPIO speed
    	GPIOC->PUPDR |= (0b10 << 28); //PC14 pull down resistors
    	//PC15 OUTPUT
    	GPIOC->MODER |= (0b01 << 30); //PC15 General purpose output mode
    	GPIOC->OTYPER &= ~ (1 << 15); //PC15 Output push-pull (reset state)
    	GPIOC->OSPEEDR |= (0b11 << 30); //PC15 very high GPIO speed
    	GPIOC->PUPDR |= (0b10 << 30); //PC15 pull down resistors
    	//PE4 OUTPUT
    	GPIOE->MODER |= (0b01 << 8); //PE4 General purpose output mode
    	GPIOE->OTYPER &= ~ (1 << 4); //PE4 Output push-pull (reset state)
    	GPIOE->OSPEEDR |= (0b11 << 8); //PE4 very high GPIO speed
    	GPIOE->PUPDR |= (0b10 << 8); //PE4 pull down resistors
    	//PE0 OUTPUT
    	GPIOE->MODER |= (0b01 << 0); //PE0 General purpose output mode
    	GPIOE->OTYPER &= ~ (1 << 0); //PE0 Output push-pull (reset state)
    	GPIOE->OSPEEDR |= (0b11 << 0); //PE0 very high GPIO speed
    	GPIOE->PUPDR |= (0b10 << 0); //PE0 pull down resistors
    	//-----------------------------------------------------------------------------------
    	//PE5 INPUT ALL BUTTONS EXTERNALLY PULLED UP
    	GPIOE->MODER |= (0b00 << 10); //PE5 General purpose input mode
    	//PE6 INPUT
    	GPIOE->MODER |= (0b00 << 12); //PE6 General purpose input mode
    
    }
    
    void Interrupt_setup(void){
    	//PE5
    	RCC->APB2ENR |= (1 << 14); //System configuration controller clock enabled
    
    	SYSCFG->EXTICR[1] |= (0b0100 << 4); //0100: PE[x] pin
    
    	EXTI->IMR |= (1<< 5); //Interrupt request from line x is not masked
    
    	EXTI->FTSR |= (1<< 5); //Falling trigger enabled (for Event and Interrupt) for input line
    	EXTI->RTSR &= ~ (1<< 5); //Rising trigger disabled (for Event and Interrupt) for input line
    
    	NVIC_SetPriority(EXTI9_5_IRQn, 0);
    	NVIC_EnableIRQ (EXTI9_5_IRQn);
    }
    
    void EXTI9_5_IRQHandler(void){
    
    	if(EXTI->PR &(1<<5)){
    	EXTI->PR = (1 << 5); //Clear the interrupt flag
    
    	GPIOC->BSRR = (1 << 14); //Set GPIO on
    	TIM8->CR1 = (1 << 0); //Enable Timer 8 counter
    
    	}
    }
    
    void TIM8_UP_TIM13_IRQHandler(void){
    
    	if(TIM8->SR & (1<<0)){
    		GPIOC->BSRR = (1 << 30); //Set GPIO off
    		TIM8->CR1 &= ~(1 << 0); //Disable Timer 8 counter
    
    		TIM8->CNT = 0; //Reset Timer 8 counter
    		TIM8->SR &= ~(1<<0); //Clear the interrupt flag
    	}
    }
    
    int main (void){
    	__disable_irq();
    	Core_Clock_Setup();
    
    	Timer1_Setup();
    	TIM1->CR1 &= ~(1 << 0);
    
    	GPIO_Setup();
    	Timer8_Setup();
    	Interrupt_setup();
    	__enable_irq();
    
    	GPIOC->BSRR = 0x4000;
    
    	GPIOC->BSRR = (1 << 30);
    
    	while(1){
    
    		GPIOC->BSRR = (1 << 15);
    		delay_ms(100);
    		GPIOC->BSRR = (1 << 31);
    		delay_ms(100);
    	}
    
    }
    

     

     

    Super User
    April 1, 2024

    According to your delay_ms() function, 1ms is equivalent to 2000 counts of TIM1.

    With identical clock source and prescaler, the 65536 counts of TIM8 from 0 to ARR  should take 65536/2000 = 32.768ms.

    Isn't it exactly what you observe?

    JW

    PS. Don't use RMW to clear TIMx_SR bits. Here it's not a problem, as you have only one interrupt source, but it's a bad habit.

    ViliusAuthor
    Visitor II
    April 1, 2024

    Oh right,

    I wrote my delay function quite some time ago. I somehow perceived it as 2000 times full 16 bit count without ever catching the eye to it... Thank you once again... This made and end to my prolong headache on this timer interrupt problem...