Hello all, I need to get the pwm input values (freq and duty) using stm32 Hal.
The code (timer config and related stuff) was tested with stm32cubeide.
When integarted in mbedOs and the pwm is applied the application stops working (hungs).
The idea is to integrate timer special features (not supported in mbed like Input capture/compare) into mbed framework, but it looks like the problem is related to interrupts.
Any idea?
Thank you very much.
Note : the code is written for the NUCLEO-F429ZI with the latest mbedOs.
/* mbed Microcontroller Library
* Copyright (c) 2019 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*/
#include "mbed.h"
// Blinking rate in milliseconds
#define BLINKING_RATE 500ms
/* Timer handler declaration */
TIM_HandleTypeDef TimHandle;
/* Timer Input Capture Configuration Structure declaration */
TIM_IC_InitTypeDef sConfig;
/* Slave configuration structure */
TIM_SlaveConfigTypeDef sSlaveConfig;
/* Captured Value */
__IO uint32_t uwIC2Value = 0;
/* Duty Cycle Value */
__IO uint32_t uwDutyCycle = 0;
/* Frequency Value */
__IO uint32_t uwFrequency = 0;
/* Counter Prescaler value */
uint32_t uhPrescalerValue = 0;
void TIMx_IRQHandler(void)
{
HAL_TIM_IRQHandler(&TimHandle);
}
static void Error_Handler(void)
{
/* Turn LED3 on */
DigitalOut led3(LED3);
while (1)
{
led3 = !led3;
ThisThread::sleep_for(BLINKING_RATE);
}
}
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_InitStruct;
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* TIMx Peripheral clock enable */
__HAL_RCC_TIM3_CLK_ENABLE();
__HAL_RCC_TIM4_CLK_ENABLE();
/* Enable GPIO channels Clock */
__HAL_RCC_GPIOB_CLK_ENABLE();
/* Configure (TIMx_Channel) in Alternate function, push-pull and High speed */
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*##-2- Configure the NVIC for TIMx #########################################*/
HAL_NVIC_SetPriority(TIM3_IRQn, 15, 1); //lowest priority
/* Enable the TIMx global Interrupt */
HAL_NVIC_EnableIRQ(TIM3_IRQn);
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
/* Get the Input Capture value */
uwIC2Value = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
if (uwIC2Value != 0)
{
/* Duty cycle computation */
uwDutyCycle = ((HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1)) * 100) / uwIC2Value;
/* uwFrequency computation
TIM1 counter clock = (RCC_Clocks.HCLK_Frequency) */
uwFrequency = (HAL_RCC_GetHCLKFreq()/2) / uwIC2Value;
}
else
{
uwDutyCycle = 0;
uwFrequency = 0;
}
}
}
int main()
{
printf("Application started.\r\n");
// Compute the prescaler value to have TIM3 counter clock equal to 15000000 Hz
uhPrescalerValue = (uint32_t)((SystemCoreClock/2) / 15000000) - 1;
// Set TIMx instance
TimHandle.Instance = TIM3;
// Initialize TIMx peripheral as follows:
// + Period = 0xFFFF
// + Prescaler = 0
// + ClockDivision = 0
// + Counter direction = Up
TimHandle.Init.Period = 0xFFFF;
TimHandle.Init.Prescaler = 0;
TimHandle.Init.ClockDivision = 0;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.RepetitionCounter = 0;
TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_IC_Init(&TimHandle) != HAL_OK)
{
// Initialization Error
Error_Handler();
}
//##-2- Configure the Input Capture channels ###############################
// Common configuration
sConfig.ICPrescaler = TIM_ICPSC_DIV1;
sConfig.ICFilter = 0;
// Configure the Input Capture of channel 1
sConfig.ICPolarity = TIM_ICPOLARITY_FALLING;
sConfig.ICSelection = TIM_ICSELECTION_INDIRECTTI;
if (HAL_TIM_IC_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_1) != HAL_OK)
{
/* Configuration Error */
Error_Handler();
}
// Configure the Input Capture of channel 2
sConfig.ICPolarity = TIM_ICPOLARITY_RISING;
sConfig.ICSelection = TIM_ICSELECTION_DIRECTTI;
if (HAL_TIM_IC_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_2) != HAL_OK)
{
// Configuration Error
Error_Handler();
}
//##-3- Configure the slave mode ###########################################
// Select the slave Mode: Reset Mode
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_RESET;
sSlaveConfig.InputTrigger = TIM_TS_TI2FP2;
sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_NONINVERTED;
sSlaveConfig.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1;
sSlaveConfig.TriggerFilter = 0;
if (HAL_TIM_SlaveConfigSynchronization(&TimHandle, &sSlaveConfig) != HAL_OK)
{
// Configuration Error
Error_Handler();
}
//##-4- Start the Input Capture in interrupt mode ##########################
if (HAL_TIM_IC_Start_IT(&TimHandle, TIM_CHANNEL_2) != HAL_OK)
{
// Starting Error
Error_Handler();
}
//##-5- Start the Input Capture in interrupt mode ##########################
if (HAL_TIM_IC_Start_IT(&TimHandle, TIM_CHANNEL_1) != HAL_OK)
{
// Starting Error
Error_Handler();
}
// Initialise the digital pin LED1 as an output
DigitalOut led(LED1);
printf("Printing data.\r\n");
while (true) {
printf("Frequency = %u Hz\r\n", uwFrequency);
printf("Duty = %u %%\r\n", uwDutyCycle);
led = !led;
ThisThread::sleep_for(BLINKING_RATE);
}
}