STM32 timer clock frequency doesn't change and stay at 1.6MHz - timer

It's been days which I'm reading the reference manual and changing the code to configure the STM32F401RE timers clock. It seems that SYSCLK is set at 84MHZ, PCLK1 is 42MHZ, and PCLK2 is 84MHZ. but every time I want to use TIM2, the clock is set at 1.6MHZ. I used my phone and lap the time from led on and led off states and with the PSC and ARR I assumed that clock frequency is something around 1.6MHZ
here is clock configuration
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR &= ~PWR_CR_VOS_Msk;
PWR->CR |= PWR_CR_VOS_1; // scale mode 2
// flash
FLASH->ACR &= ~FLASH_ACR_LATENCY;
FLASH->ACR |= FLASH_ACR_LATENCY_2WS;
// HSI CONFIGURATION
RCC->CR |= RCC_CR_HSION;
while( !(RCC->CR & RCC_CR_HSIRDY) ){}
// PLL CONFIGURATION
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLSRC; // PLL SRC= HSI
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM_Msk;
RCC->PLLCFGR |= 16 << RCC_PLLCFGR_PLLM_Pos;
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN_Msk;
RCC->PLLCFGR |= 336 << RCC_PLLCFGR_PLLN_Pos;
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLP_Msk;
RCC->PLLCFGR |= RCC_PLLCFGR_PLLP_0; // div4
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLQ_Msk;
RCC->PLLCFGR |= 4 << RCC_PLLCFGR_PLLQ_Pos;
RCC->CR |= RCC_CR_PLLON;
while( !(RCC->CR & RCC_CR_PLLRDY) ){}
// CPU, AHB, APB buses clocks
RCC->CFGR &= ~RCC_CFGR_SW_Msk;// PLL CLK SRC
RCC->CFGR |= RCC_CFGR_SW_PLL;
while( !(RCC->CFGR & RCC_CFGR_SWS_PLL) ){}
// flash
FLASH->ACR &= ~FLASH_ACR_LATENCY;
FLASH->ACR |= FLASH_ACR_LATENCY_2WS;
RCC->CFGR &= ~RCC_CFGR_HPRE; // AHB DIV 1
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
RCC->CFGR &= ~RCC_CFGR_PPRE1_Msk; // APB1 DIV 2
RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
RCC->CFGR &= ~RCC_CFGR_PPRE2_Msk; // APB2 DIV 1
RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
SystemCoreClockUpdate();
and here is the timer2 configuration
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
TIM2->CR1 |= TIM_CR1_CKD_1;
TIM2->PSC = 1093-1;
TIM2->ARR = 1024 - 1;
TIM2->CNT = 0;
TIM2->DIER |= TIM_DIER_UIE;
NVIC_EnableIRQ(TIM2_IRQn);
TIM2->CR1 |= TIM_CR1_CEN;
Is there anything I missed or misunderstood in the configuration?

Your code seems mostly correct. There are 2 problems I can detect, but I'm not sure if they are the real causes.
PLL-Q divider should be 7. But this may be irrelevant as you probably don't use USB peripheral. Still, it's best to be in clock limits.
You set peripheral divider (APB1) after you switch clock source. It means that before you set it, APB1 is clocked with 84 MHz, which is out of specs.
I'm not sure if there are other errors, but I have tested the code below on a F4 Discovery board. It has a STM32F407, but this uC is quite similar to yours.
FLASH->ACR |= FLASH_ACR_LATENCY_2WS; // 2 wait state for 84 MHz
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLQ;
RCC->PLLCFGR |= (7 << RCC_PLLCFGR_PLLQ_Pos); // PLL-Q: /7
RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC_HSI; // PLL source is HSI
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLP;
RCC->PLLCFGR |= (0b01 << RCC_PLLCFGR_PLLP_Pos); // PLL-P: /4
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN;
RCC->PLLCFGR |= (336 << RCC_PLLCFGR_PLLN_Pos); // PLL-N: x336
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM;
RCC->PLLCFGR |= (16 << RCC_PLLCFGR_PLLM_Pos); // PLL-M: /16
RCC->CR |= RCC_CR_PLLON; // Activate the PLL (Output: 84 MHz)
while ((RCC->CR & RCC_CR_PLLRDY) == 0); // Wait until PLL is ready
RCC->CFGR |= RCC_CFGR_HPRE_DIV1 // AHB divider: /1 (84 MHz)
| RCC_CFGR_PPRE1_DIV2 // APB1 divider: /2 (42 MHz)
| RCC_CFGR_PPRE2_DIV1; // APB2 divider: /1 (84 MHz)
RCC->CFGR |= RCC_CFGR_SW_PLL; // Switching to PLL clock source
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // Wait until switching is complete
And this is how I configured TIM2 to trigger interrupts with 1 Hz frequency
TIM2->PSC = 42000 - 1;
TIM2->ARR = 2000 - 1; // 1 sec. overflow time # 84 MHz
TIM2->EGR |= TIM_EGR_UG; // Event generation to update prescaler
TIM2->DIER |= TIM_DIER_UIE; // Enable update interrupt in peripheral
TIM2->CR1 |= TIM_CR1_CEN; // Start timer
NVIC_EnableIRQ(TIM2_IRQn); // Enable interrupt in NVIC

Related

STM32f401xB/C - no PWM signal on PA15

I have a STM32F401xB/C board.
I am trying to create a PWM signal for my DC motors. I have followed this tutorial and seem to understand the code.
https://ruturajn.hashnode.dev/generating-pwm-pulses-on-the-stm32f407-for-servo-motor-control-using-bare-metal-programming
But after I change the pin I want the PWM output from I get no signal. The tutorial refrences the PA5 pin, which works, but PA15 does not work even though it is connected to the same timer TIM2 and channel.
Any idea?
This is my code:
//initialises the GPIO pins
void GPIO_Init(){
//give and clock to the GPIOB and GPIOA device
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
//THESE PINS ARE THE PWM DRIVERS
//PA15
//set alternative mode
GPIOA->MODER &= ~(GPIO_MODER_MODER15_1);
GPIOA->MODER |= GPIO_MODER_MODER15_1;
//low part of the alternate function register
GPIOA->AFR[1] |= GPIO_AFRH_AFSEL15_0;
}
//initialise the TIM2 timer device
void TIM2_Init(){
//give pwr and clk to TIM2 device
RCC->AHB1ENR |= RCC_APB1ENR_TIM2EN;
//set prescaler to 1Mhz = 1 microSeconds
TIM2->PSC = 16-1;
//total period of the timer = 20ms
TIM2->ARR = 20000;
//set counter to 0
TIM2->CNT = 0;
//set capture/compare mode register 1 to PWM Mode 1
TIM2->CCMR1 = 0x0060;
//set capture/compare enable register to output on chanel 1
TIM2->CCER |= 1;
//set >50% power
TIM2->CCR1 = 10000;
}
void setup(){
//set the timer to 16 mhz
RCC->CFGR |= 0 << 10;
GPIO_Init();
TIM2_Init();
//start TIM2 timer
TIM2->CR1 |= 1;
}
This only clears a single bit
//set alternative mode
GPIOA->MODER &= ~(GPIO_MODER_MODER15_1);
...
Should be
GPIOA->MODER &= ~(GPIO_MODER_MODE15_Msk);
...
PA15 is shared with JTDI and could have external interference.
By default it has pull-up enabled, that should be cleared if this pin is used as an output.
The problem was that I was not setting the clock and power properly for the clock. The register I should have checked is RCC->APB1ENR instead of RCC->AHB1ENR. The fact that I got power through PA5 was a coincidence.

STM32 UART2 BRR Not Giving Expected Results

I am currently working with an STM32F407VG on the Discovery board. I am going through the peripherals and trying to get each one working by manipulating the registers only (no HAL).
When I go to initialize UART2 it is transmitting the character I write to the DR but it is doing so ~12x faster than expected, I'm shooting for 9600 baud. I measured this using an oscilloscope (~8-9 us per bit) and playing with the baud rate in Putty (111,111 baud to show the actual character).
I am maxing out the clock speed of the chip 168 MHz SYSCLK, APB1 Prescaler "/4", APB2 Prescaler "/2". I am pretty sure my clocks are at what they are supposed to be, to verify I set up TIMER12, which shares the APB1 clock and set the prescaler to 8400 and had an interrupt generated every time there was a compare match (CCR = 5000) and overflow. I measured this with the oscilloscope and I am getting a 1 Hz square wave as expected which means that the APB1 for Timer 12 is at 84 MHz.
Here is my clock init code:
void SysClockConfig ( void ){
//setting up the MCO output to see the clock signal
//RCC->CFGR |= ( 6 << 24 ) | (3 << 21 ) | ( 4 << 27 );
//1. ENABLE HSE and wait for the HSE to become Ready
RCC->CR |= RCC_CR_HSEON;
while (!(RCC->CR & RCC_CR_HSERDY));
// 2. Set the POWER ENABLE CLOCK and VOLTAGE REGULATOR
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS;
// 3. Configure the FLASH PREFETCH and the LATENCY Related Settings
FLASH->ACR = FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_PRFTEN | FLASH_ACR_LATENCY_5WS;
//4. Configure the PRESCALARS HCLK, PCLK1, PCLK2
// AHB PR
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
// APB1 PR
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
// APB2 PR
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
//5. Configure the MAIN PLL
RCC->PLLCFGR = (PLL_M << RCC_PLLCFGR_PLLM_Pos) | (PLL_N << RCC_PLLCFGR_PLLN_Pos) | (PLL_Q << RCC_PLLCFGR_PLLQ_Pos) | (RCC_PLLCFGR_PLLSRC_HSE);
//6. Enable the PLL and wait for it to become ready
RCC->CR |= RCC_CR_PLLON;
while (!(RCC->CR & RCC_CR_PLLRDY));
//7. Set source
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
}
This is my UART2 config code:
void UART2_Config ( void )
{
RCC->APB1ENR |= RCC_APB1ENR_USART2EN; //clock UART
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; //clock GPIOA
GPIOA->MODER |= ( 2 << GPIO_MODER_MODER2_Pos ) | ( 2 << GPIO_MODER_MODER3_Pos ); //set PA2 and PA3 alternate function
GPIOA->OSPEEDR |= ( 3 << GPIO_OSPEEDR_OSPEED2_Pos ) | ( 3 << GPIO_OSPEEDR_OSPEED3_Pos ); //clock GPIO pin at fastest speed
GPIOA->AFR[0] |= ( 7 << GPIO_AFRL_AFSEL2_Pos ) | ( 7 << GPIO_AFRL_AFSEL3_Pos ); //set PA2 and PA3 to alt func UART2
USART2->CR1 = 0;
USART2->CR1 |= USART_CR1_UE; //UART Enable
//USART2->BRR = (0x16 << USART_BRR_DIV_Mantissa_Pos) | (0xc << USART_BRR_DIV_Fraction_Pos); //Set Baud rate
USART2->BRR = 4300;
//USART2->CR1 |= USART_CR1_RE; //Receiver enable
USART2->CR1 |= USART_CR1_TE; //Transmitter enable
//Baud rate is off by a factor of 12ish
}
Finally, my main and while loop with the function for sending a character:
void UART2_SendChar ( uint8_t c )
{
USART2->DR = c;
while ( !(USART_SR_TC));
}
int main ( void )
{
SysClockConfig();
GPIO_Config();
TIM10_Config();
TIM12_Config();
UART2_Config();
//NVIC_SetPriority (TIM1_UP_TIM10_IRQn, 1);
//NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
NVIC_SetPriority (TIM8_BRK_TIM12_IRQn, 1);
NVIC_EnableIRQ(TIM8_BRK_TIM12_IRQn);
while ( 1 )
{
//GPIOD->BSRR |= (1<<12);
//delay(2000000);
//GPIOD->BSRR |= (1<<28);
delay(4000000);
UART2_SendChar('a');
}
}
I can't find anything in the reference manual to explain this behavior. That tells me I am doing something wrong but I can't seem to track it down. On a final note, I had Putty set up to receive 9600 baud and played around with the BRR and setting it to a value of 4300 output the desired character. Plugging that value into the equation for baud in the reference manual gave me an insane system clock 660 MHz, again telling me I am missing something probably pretty obvious.
I've answered a similar question here recently, so let me copy that one:
BRR is a Q12.4 format fixed point number, which needs one additional operation when OVER8 mode is selected.
OP's question is about STM32F4, but if one inspects STM32F030 reference manual, he/she can find the same logic but represented by a different formula. IMO, that one (F030) is more clear and easier to understand.
To convert uint16_t (Q16.0) to Q12.4, you need to multiply it by 16.
Basically, for OVER16 case, BRR is simply becomes PeripheralClock / BaudRate.
For OVER8 case, you first need to calculate a temporary variable as temp = 2 * PeripheralClock / BaudRate. When writing it into BRR, you need to right-shift its lower 4 bits once.
See the example code:
void setBaudRate(uint32_t baud, bool over8)
{
const uint32_t pClock = 42000000ull; // Hard-code or call a function to obtain it
uint32_t usartDiv = (over8) ? (2 * pClock / baud) : (pClock / baud);
uint32_t reg = USART1->BRR;
reg &= ~0xffff; // Clear the lower 16 bits
if (over8) {
reg |= (usartDiv & 0xfff0) | ((usartDiv & 0xf) >> 1);
}
else { // over16
reg |= usartDiv;
}
USART1->BRR = reg;
}
So, for your case, the correct value of BRR is 4375.

STM32F407 Register Level Clock Configuration Issue

I am working on an STM32F407 Discovery Board. But I didn't solve my clock configuration problem. I want to 168 MHz working frequency and I get help from CubeMX Clock Configuration Manager. And this is my PLLCFGR Register value from CubeMX: 0x4405408. (I have problem with this register). Then I was copy paste all RCC registers to my CMSIS code. This is my clock configuration code:
RCC->CFGR = 0x4008940A; //MCO2 Source is PLLI2S (4), HSE Divided by 8 for RTC (8), APB2 Divided by 2 for 84Mhz, APB1 Divided by 4 for 42 Mhz
RCC->CR = 0x0F0B6783; //PLL, PLLI2S, HSE, CSS ON
RCC->PLLCFGR = 0x04405408; //PLLQ 4 (4), PLLSRC = HSE (4), PLLP 2 (0), PLLN 336 (54), PLLM 8 (8)
RCC->PLLI2SCFGR = 0x50003C00; //PLLI2SR 5 (5), PLLI2SN 240 (3C)
But I can't read the same values from SFRs menu in Atollic. All registers are correct but the PLLCFGR register value is 0x04405419. This issue effects my clock speed, peripheral speed etc. I want to set PLLM bits to 8 but I read 19. So I get less speed then I want, because PLLM bits decide PLL input clock division. How can I solve this register problem?
When doing the clock configuration, you can't just load the registers with their final values. You need to follow some logical order and satisfy the limits mentioned in the reference manual. You must also consider the flash memory wait states.
Here is an example code to run STM32F407 at 48 MHz, using 8 MHz HSE. I feel lazy to modify & test it for 168 MHz, but this should give you the idea and a starting point.
FLASH->ACR |= FLASH_ACR_LATENCY_1WS; // 1 wait state for 48 MHz
RCC->CR |= RCC_CR_HSEON; // Activate external clock (HSE: 8 MHz)
while ((RCC->CR & RCC_CR_HSERDY) == 0); // Wait until HSE is ready
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLQ;
RCC->PLLCFGR |= 4 << RCC_PLLCFGR_PLLQ_Pos; // PLL-Q: /4
RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC_HSE; // PLL source is HSE
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLP; // PLL-P: /2
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN;
RCC->PLLCFGR |= 96 << RCC_PLLCFGR_PLLN_Pos; // PLL-N: x96
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM;
RCC->PLLCFGR |= 4 << RCC_PLLCFGR_PLLM_Pos; // PLL-M: /4
RCC->CR |= RCC_CR_PLLON; // Activate the PLL (Output: 96 MHz)
while ((RCC->CR & RCC_CR_PLLRDY) == 0); // Wait until PLL is ready
RCC->CFGR |= RCC_CFGR_HPRE_DIV2 // AHB divider: /2 (48 MHz)
| RCC_CFGR_PPRE1_DIV2 // APB1 divider: /2 (24 MHz)
| RCC_CFGR_PPRE2_DIV2; // APB2 divider: /2 (24 MHz)
RCC->CFGR |= RCC_CFGR_SW_PLL; // Switching to PLL clock source
I found my Issue where did came from. system_stm32f4xx.c and stm32f4xx.h files need changes for Stm32f4 Discovery board. This codes writing for 25Mhz HSE crystal but Discovery Board has 8Mhz HSE crystal. Then PLL bits. These bits defined in system_stm32f4xx.c file. You must be change PLL bits as you want. Thanks all of us;)

SPI read failing on STM32F4 device

I'm using the STM32F4 trying to read over SPI. Debug environments is Visual Studio with the VisualGDB plugin.
The spi config is as follows. 8-bit frames, MSB first, using GPIOA/B for the SPI signals
void spiInit() {
RCC->AHB1ENR |= 3; //enable gpioA/B clock
RCC->APB2ENR |= 0x1000; //enable SPI1 clock (bit 12)
// configure A5 for SCLK
GPIOA->MODER &= ~0x00000C00; //clear pin mode for pin 5
GPIOA->MODER |= 0x00000800; //alternate function mode for pin 5
GPIOA->AFR[0] &= ~0x00F00000; //clear alternate mode
GPIOA->AFR[0] |= 0x00500000; //setup pins 5 for AF5
// configure B4 for MISO
GPIOB->MODER &= ~0x00000300; //clear pin mode for pin 4
GPIOB->MODER |= 0x00000200; //alternate function mode for pin 5
GPIOB->AFR[0] &= ~0x000F0000; //clear alternate mode
GPIOB->AFR[0] |= 0x00050000; //setup pins 4 for AF5
// configure B5 for MOSI
GPIOB->MODER &= ~0x00000C00; //clear pin mode for pin 5
GPIOB->MODER |= 0x00000800; //alternate function mode for pin 5
GPIOB->AFR[0] &= ~0x00F00000; //clear alternate mode
GPIOB->AFR[0] |= 0x00500000; //setup pins 5 for AF5
// configure A15 for output SS
GPIOA->MODER &= ~0xC0000000; //clear PA15 function bits
GPIOA->MODER |= 0x40000000; //set PA15 (SS) as output
SPI1->CR1 = 0x31E; //8-bit frames
SPI1->CR2 = 0; //mostly read/status/interrupt config
SPI1->CR1 |= 0x40; //enable SPI1
GPIOA->BSRR = 0x00008000; //deassert SS
}
Writes are fine, data is loaded correctly to slave and it responds as expected, reads from the slave however are not working. I can see that MISO looks good on the bus when i look at the waveforms, but it's not picked up by the Master.
After a few attempts at watching the SPI status-register flags, (getting the results described above) I'm using a utility function that i saw on another SO question (here). The data always reads 0 and i am confused, the code waits for the receive buffer to fill, but there seems to nothing there when it is read.
uint8_t SPI_ReadWrite8(SPI_TypeDef *spi, uint8_t data)
{
while(!(spi -> SR & SPI_SR_TXE)); //Wait for tx buffer to empty
*(volatile uint8_t *)&spi->DR = data; //Send data
while (!(spi -> SR & SPI_SR_RXNE)); //Wait for rx buffer to fill
return *(volatile uint8_t *)&spi->DR;
}
Any ideas what i'm missing?

ATMEGA 328P varying frequency

I am trying to generate a 16kHz pwm... this is the code i am working with right now. `
int main(void){
DDRD |= (1 << DDD6);
// PD6 is now an output
OCR0A = 128;
// set PWM for 50% duty cycle
TCCR0A |= (1 << COM0A1);
// set none-inverting mode
TCCR0A |= (1 << WGM01) | (1 << WGM00);
// set fast PWM Mode
TCCR0B |= (1 << CS01);
// set prescaler to 8 and starts PWM
while (1);
{
// we have a working Fast PWM
}}`
The default frequency is set to 64kHz... is there any way i can change the default frequency ? Because changing the prescalars does not help me get a frequency of 16kHz...
If you can use CTC mode instead of fast PWM (which means, you don't need to vary the pulse-pause-width ratio), you can use CTC mode to accomplish that:
DDRD |= (1 << DDD6);
// PD6 is now an output
OCR0A = 32;
// set PWM for 12.5% duty cycle
TCCR0A |= (1 << COM0A0);
// set toggle mode
TCCR0A |= (1 << WGM01);
// set CTC Mode
TCCR0B |= (1 << CS01);
// set prescaler to 8 and start PWM

Resources