Reputation: 51
I am trying to create a metronome by using the led on my microcontroller board to blink at a specific number of beats per minute in order to figure out how to do hardware interrupts at specific intervals. I am using the HSI as the system clock.
The HSI runs at a default 16mhz. The expected behavior is that since 16mhz equals 16 million cycles per second, I want to get this to 1000 cycles per second to get a timer that runs on milliseconds (which is 1000 per second). So I divided HAL_RCC_GetHCLKFreq()/16000 and set the if statement (if(ms_counter >= 1000){}) to activate when ms_counter reaches 1000, the led blinks way to fast to see it. To actually get 60bpm with this setup I have to set the if statement to ms_counter if(ms_counter >= 200000){}, why?
The values I have input into the code below actually blink the led at 60bpm, but I am confused why these numbers work the way they do? It seems to behave this way ->
Divide 16mhz by 160,000 -> 100cps (cycles per second) -> Every 1ms = 100 interrupts? (ms_counter >= 100,000) is 60bpm
Divide 16mhz by 16,000 -> 1000cps (cycles per second) -> Every 1ms = 200 interrupts? (ms_counter >= 200,000) is 60bpm
If anyone can see what I'm doing wrong then it would be greatly appreciated! Or if this is working the way it's intended then I would appreciate some explanation... maybe I am missing something.
#include "stm32f4xx_hal.h"
#include "stm32f4xx.h"
#include <stdint.h>
#include <stdio.h>
void SystemClock_Config(void);
volatile uint32_t ms_counter = 0; // A counter to track the number of milliseconds elapsed
int main(void)
{
GPIO_InitTypeDef GPIOD_Params;
__HAL_RCC_GPIOD_CLK_ENABLE();
GPIOD_Params.Pin = GPIO_PIN_12; // Select pins 12 to 15
GPIOD_Params.Mode = GPIO_MODE_OUTPUT_PP; // Set pins to push pull output mode
GPIOD_Params.Speed = GPIO_SPEED_LOW; // Set low output speed
HAL_GPIO_Init(GPIOD, &GPIOD_Params); // Initialise GPIOD according to parameters on GPIOD_Params
HAL_Init(); // Initialize the HAL library
SystemClock_Config(); // Set up the system clock (HSI as the source)
// Configure SysTick to generate interrupts at 1ms intervals
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 16000); // 1ms interval (HAL_RCC_GetHCLKFreq() == 16,000,000)
// Main Loop
while (1)
{
// Example: Toggle an LED every 500ms
if (ms_counter >= 200000)
{
ms_counter = 0; // Reset the counter
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12); // Toggle an LED
}
HAL_SYSTICK_Callback();
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
// Configure HSI as the system clock source
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // Disable PLL
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK |
RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; // Set HSI as SYSCLK
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
}
void HAL_SYSTICK_Callback(void)
{
ms_counter++; // Increment a custom counter
}
Upvotes: 0
Views: 77
Reputation: 67835
You passed the wrong value. You set the interrupts frequency to 16k/sec
. You need to pass the number of ticks per required period. You can easily figure it out yourself.
/**
* @brief Initialize the System Timer with interrupt enabled and start the System Tick Timer (SysTick):
* Counter is in free running mode to generate periodic interrupts.
* @param TicksNumb: Specifies the ticks Number of ticks between two interrupts.
* @retval status: - 0 Function succeeded.
* - 1 Function failed.
*/
uint32_t HAL_SYSTICK_Config(uint32_t TicksNumb)
{
return SysTick_Config(TicksNumb);
}
So you want
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000);
Upvotes: 4