I'm new in stm32, I recently create a project to make a quick pulse on a GPIO pin every second, just to determine the time accuracy by the logic analyzer, however, I always get the time around 0.999,935s instead of one second, I tried everything I searched on the internet, but nothing work, please give a help.
My code was mostly generated by STM32CubeMX, these are the configs of CubeMX
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
HAL_TIM_Base_Start_IT(&htim2);
while (1) { }
}
.
.
.
static void MX_TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 799;
htim2.Init.CounterMode = TIM_COUNTERMODE_DOWN;
htim2.Init.Period = 9999;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
.
.
.
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
GPIOB->BSRR = (uint32_t)GPIO_PIN_2 << 16u; // reset bit
}
The time between 2 and 3 is always around 0.999935s
how can I fix this error to exactly one second???
Related
Trying to make simple PWM transmitter i faced with a problem. I have TIM2 with Channel2 (in PWM Generation mode) on board NUCLEO F042K6 and USART1 connected to the board in Async mode (USART works in DMA).
I wanted to make a PWM transmitter that uses a circular buffer that can be filled with one character or several characters at once. The plan was that when the user enters a character (or several characters), the idle line callback is processed, in which a function is called that stores the data in a cyclic buffer. After saving, the data transferred to the buffer is passed to the function PWM_SendChar(...) to convert the data into bits and transfer them over the PWM line. But the problem is when the program goes into PWM_SendChar(...) the callback HAL_TIM_PWM_PulseFinishedCallback(...) isn't called and program stucks in infinite while loop because variable used as a flag for detecting the end of single pulse (PWM_data_sent_flag) wasn't set to value 1.
However, if I use HAL_UART_Recieve(...) func in while(1) loop (located in main(void)) to recieve a char from user program works fine without stucking in while loop in TIM callback. Ofc, for this method I don't use HAL_UARTEx_RxEventCallback(...) and cycle buffer.
Thats's why I think the problem is in USART idle line detection and please help me solve it.
Code Example
Global variable used for waiting the end of pulse:
volatile uint16_t PWM_data_sent_flag = 0;
PWM timer callback:
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_2);
PWM_data_sent_flag = 1;
}
}
Callback for USART idle line:
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
if (huart == &huart1) {
// Function_to_save_input_char_in_cycle_buffer() is called
}
}
Function used to send char as a PWM signal (emited after Function_to_save_input_char_in_cycle_buffer() completed):
void PWM_SendChar(char ch) {
for (int i = 0, mv = 7; i <= 7; ++i, --mv) {
uint8_t bit = (ch & (1 << mv)) ? 1 : 0;
// PWM_LOW_PERCENT encodes bit with zero value, PWM_HIGH_PERCENT encodes bit with value one
uint16_t duty_cycle = bit == 0 ? PWM_LOW_PERCENT : PWM_HIGH_PERCENT;
// Change TIM2 CCR2 value according to bit's value
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2,
GET_PERCENT_VALUE(TIM2->ARR, duty_cycle));
HAL_TIM_PWM_Start_IT(&htim2, TIM_CHANNEL_2);
// Program comes to this cycle and doesn't leave it
while (!PWM_data_sent_flag)
;
PWM_data_sent_flag = 0;
}
}
USART receive to idle launch (half data transmitted callback disabled):
int main(void) {
// Init code
// ...
if (HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t*) ring_buf.buff,
ARRAY_LEN(ring_buf.buff)) != HAL_OK) {
Error_Handler();
}
// Disable half word transmitted callback
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
while(1) {
}
}
TIM2 settings:
static void MX_TIM2_Init(void) {
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = { 0 };
TIM_MasterConfigTypeDef sMasterConfig = { 0 };
TIM_OC_InitTypeDef sConfigOC = { 0 };
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 48000 - 1;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 100 - 1;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) {
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) {
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig)
!= HAL_OK) {
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2)
!= HAL_OK) {
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
HAL_TIM_MspPostInit(&htim2);
}
USART1 settings:
static void MX_USART1_UART_Init(void) {
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK) {
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
DMA settings:
static void MX_DMA_Init(void) {
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel4_5_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel4_5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel4_5_IRQn);
}
I need to get interrupt at compare match of PWM.
I am using STM32CubeIDE 1.6.1, STM32Cube FW_F1 V1.8.3
even tried LL library instead of HAL inside \STM32Cube\Repository\STM32Cube_FW_F1_V1.8.3\Projects\STM32F103RB-Nucleo\Examples_LL\TIM directory but no luck!
I commented everything I tried before but didn't get the result I wanted.
I uploaded the logic analyzer result at the end.
thank you for your help.
Logic analyzer
in tim.c:
/* TIM4 init function */
void MX_TIM4_Init(void)
{
/* USER CODE BEGIN TIM4_Init 0 */
/* USER CODE END TIM4_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
/* USER CODE BEGIN TIM4_Init 1 */
/* USER CODE END TIM4_Init 1 */
htim4.Instance = TIM4;
htim4.Init.Prescaler = 6400;
htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
htim4.Init.Period = 100;
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM4_Init 2 */
/* USER CODE END TIM4_Init 2 */
HAL_TIM_MspPostInit(&htim4);
}
in main.c:
/* USER CODE BEGIN 2 */
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_4, 25);
//HAL_TIM_Base_Start_IT(&htim4);
HAL_TIM_PWM_Start_IT(&htim4, TIM_CHANNEL_4);
/* USER CODE END 2 */
.
.
.
/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
//HAL_GPIO_TogglePin(TEST_GPIO_Port, TEST_Pin);
}
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{
//HAL_GPIO_TogglePin(TEST_GPIO_Port, TEST_Pin);
}
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
HAL_GPIO_TogglePin(TEST_GPIO_Port, TEST_Pin);
}
void HAL_TIM_PWM_PulseFinishedHalfCpltCallback(TIM_HandleTypeDef *htim)
{
//HAL_GPIO_TogglePin(TEST_GPIO_Port, TEST_Pin);
}
/* USER CODE END 4 */
in stm32f1xx_it.c:
void TIM4_IRQHandler(void)
{
/* USER CODE BEGIN TIM4_IRQn 0 */
//HAL_GPIO_TogglePin(TEST_GPIO_Port, TEST_Pin);
// /* Check whether CC4 interrupt is pending */
// if (LL_TIM_IsActiveFlag_CC4(TIM4) == 1)
// {
// /* Clear the update interrupt flag*/
// LL_TIM_ClearFlag_CC4(TIM4);
//
// /* TIM4 capture/compare interrupt processing */
// if (LL_TIM_GetCounter(TIM4) == LL_TIM_OC_GetCompareCH4(TIM4))
// {
//
// //HAL_GPIO_TogglePin(TEST_GPIO_Port, TEST_Pin);
// }
// }
/* USER CODE END TIM4_IRQn 0 */
HAL_TIM_IRQHandler(&htim4);
/* USER CODE BEGIN TIM4_IRQn 1 */
/* USER CODE END TIM4_IRQn 1 */
}
TIM4 Config
TIM4 Config
Logic analyzer
I am trying to implement two independent tasks with the hardware timers.
I need task 1 to repeat after every 100us and the other to repeat 10us. I generated the code from STM32cubemx.
The timer function is as below
static void MX_TIM2_Init(void) {
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 100;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 800;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) {
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) {
Error_Handler();
}
}
I am further processing with the function as below :
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim-> Instance == TIM2)
{
ledBlueBlink();
}
}
I have a task ledGreenBlink() which is supposed to run after every 10 times task ledBlueBlink() runs.
Can anyone please let me know how can I implement this?
Not sure about the wording, if you're really looking for a task as I do not see a task "ledBlueBlink()".
If you just want to call "ledGreenBlink()" every ten calls of your callback, I would recommend just doing this by adding a counter variable and triggering for every ten times.
static unsigned counter = 0;
if (counter%10)
ledGreenBlink();
counter++;
Please be aware that the counter variable needs to be static in order to preserve its value over several calls of the callback.
Futhermore it should be an unsigned type in order to safely roll over when it reaches it's maximum value.
In case you really need tasks for something you might want to clarify your code to support the question.
I am using STM32L496RG board where I'm trying to generate a timer interrupt. But my code does not enter the TIM3_IRQHandler function at all. Initially, I thought my timer settings are wrong, so I created a test code using CUBEMX software to generate a timer interrupt, where it worked. I copied the settings from the test code to my code, but it still does not seem to work on my code. My timer initialisation -
/**
* #brief TIM3 Initialization Function
* #param None
* #retval None
*/
void MX_TIM3_Init()
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 0;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
while(1);
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
while(1);
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
while(1);
}
}
I have started the timer using HAL_TIM_BASE_START_IT(&htim3).I was also doubtful of my clock settings, so I have even copied the clock settings from my test program,but it still did not work. Clock settings -
void SystemClock_Config()
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = 0;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
RCC_OscInitStruct.PLL.PLLN = 40;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
while(1);
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
while(1);
}
/**Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
while(1);
}
/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
Need some help to figure out what's happening.
I use SW4STM32 toolchain,I want to bliking led using timer2 when overflow, in STM32103RET,
here is my functions to turn led on and of.
void TurnOnLed(){
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_10,GPIO_PIN_SET);
}
void TurnOffLed()
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_10,GPIO_PIN_RESET);
}
the timer2 initilizing has been set by stm32 cube mx, but i do not know which function called when timer2 overflows?
You need to start your timer by function
HAL_TIM_Base_Start_IT(&htimX);
And for the firs time implement you callback function named HAL_TIM_PeriodElapsedCallback:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIMx) {
}
}
If you don't know anything about HAL_Driver you may found a lot of information from:
STM32F0xx HAL_Driver description or for another family just search for HAL Driver on st.com
You can see examples of HAL Driver usage (as you use CubeMX, so you can found it in C:/Users/%USERNAME%/STM32Cube/Repository/ directory)
Just open stm32f?xx_hal_tim.c and see what functions are present, see their comments to uderstand what tey are doing. And see what functions are called from HAL_TIM_IRQHandler to know how are named callbacks.
First,You have to configure your timer:
/* TIM2 init function */
static void MX_TIM2_Init(void)
{
TIM_SlaveConfigTypeDef sSlaveConfig;
TIM_MasterConfigTypeDef sMasterConfig;
htim2.Instance = TIM2;
htim2.Init.Prescaler = 10000;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 1000;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_RESET;
sSlaveConfig.InputTrigger = TIM_TS_ITR0;
if (HAL_TIM_SlaveConfigSynchronization(&htim2, &sSlaveConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
Second use this function to handle interrupt:
void TIM2_IRQHandler(void)
{
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_10);
__HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE); //clear interrupt flag
//HAL_Delay(500);
}
Do not forget enable interrupts in main() function:
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(TIM2_IRQn);// Enable interrupt from TIM3 (NVIC level)