2019-09-22 07:49 PM
My device: STM32F051R8T6
Dev board, F0 disco.
My end goal is to make a BLDC control system with Hall Sensors and utilize the ability of general purpose timer to trigger the interrupt on hall sensor line edge change.
I am using TIM3 as an interface timer with PC6,7,8 as Ch1,2,3 respectively.
For now, just as a test I am planning to feed only PC6, or ch1 with signal generator square wave with 2ms period (1ms on, 1 ms off). I think that in order to just test the ability to receive edge signal and trigger on it is enough, since according to ref. manual all 3 inputs are XOR'ed, and if 2 inputs kept low, while one is toggling, it should still make TIM3 to trigger.
Below is a code i use for initialization:
/*************************************************************************/
// PWM configuration
/*************************************************************************/
/* Compute the prescaler value to have TIM1 counter clock equal to 12MHz */
uwPrescalerValue = (uint32_t)((SystemCoreClock / 12000000) - 1);
//--------------------------------------------------------------------------------
// configure MAIN timer: TIM1
//--------------------------------------------------------------------------------
/* Select the Timer instance */
TimHandle.Instance = TIM1;
TimHandle.Init.Prescaler = uwPrescalerValue;
TimHandle.Init.Period = PERIOD_VALUE;
TimHandle.Init.ClockDivision = 0;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.RepetitionCounter = 0;
TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
TimHandle.State = HAL_TIM_STATE_RESET;
if (HAL_TIM_OC_Init(&TimHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/*##-2- Configure the output channels ######################################*/
/* Common configuration for all channels */
sConfig.OCMode = TIM_OCMODE_TIMING;
sConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfig.OCIdleState = TIM_OCIDLESTATE_SET;
sConfig.OCNIdleState = TIM_OCNIDLESTATE_SET;
sConfig.OCFastMode = TIM_OCFAST_DISABLE;
/* Set the pulse value for channel 1 */
sConfig.Pulse = PULSE1_VALUE;
if (HAL_TIM_OC_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_1) != HAL_OK)
{
/* Configuration Error */
Error_Handler();
}
/* Set the pulse value for channel 2 */
sConfig.Pulse = PULSE2_VALUE;
if (HAL_TIM_OC_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_2) != HAL_OK)
{
/* Configuration Error */
Error_Handler();
}
/* Set the pulse value for channel 3 */
sConfig.Pulse = PULSE3_VALUE;
if (HAL_TIM_OC_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_3) != HAL_OK)
{
/* Configuration Error */
Error_Handler();
}
/*##-3- Configure the Break stage ##########################################*/
sConfigBK.OffStateRunMode = TIM_OSSR_ENABLE;
sConfigBK.OffStateIDLEMode = TIM_OSSI_ENABLE;
sConfigBK.LockLevel = TIM_LOCKLEVEL_OFF;
sConfigBK.BreakState = TIM_BREAK_ENABLE;
sConfigBK.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sConfigBK.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
sConfigBK.DeadTime = 100;
if (HAL_TIMEx_ConfigBreakDeadTime(&TimHandle, &sConfigBK) != HAL_OK)
{
/* Configuration Error */
Error_Handler();
}
// at this point all the TIM1 config is done
//--------------------------------------------------------------------------------
// configure interface timers (TIM3)
//--------------------------------------------------------------------------------
/* Set TIM3 instance */
TimHall.Instance = TIM3;
TimHall.Channel = HAL_TIM_ACTIVE_CHANNEL_1;
TimHall.Init.Period = 65535;
TimHall.Init.Prescaler = 126;
TimHall.Init.ClockDivision = 0;
TimHall.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHall.Init.RepetitionCounter = 0;
TimHall.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
TimHall.State = HAL_TIM_STATE_RESET;
TimHallConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
TimHallConfig.IC1Filter = 0;
TimHallConfig.IC1Prescaler = TIM_ICPSC_DIV1;
TimHallConfig.Commutation_Delay = 0;
// initialize the interface timer
HAL_TIMEx_HallSensor_Init(&TimHall, &TimHallConfig);
HAL_TIMEx_ConfigCommutationEvent_IT(&TimHandle, TIM_TS_ITR2, TIM_COMMUTATION_TRGI);
// HAL_TIMEx_MasterConfigSynchronization(&TimHandle, &TimMaster);
//HAL_TIM_SlaveConfigSynchronization_IT(&TimHall, &TimSlave);
// enable and configure TIM3 related interrupt
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
HAL_NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
// start the interface timer
HAL_TIMEx_HallSensor_Start_IT(&TimHall);
/*- Start signals generation ###########################################*/
/*--------------------------------------------------------------------------*/
/* Start channel 1 */
if (HAL_TIM_OC_Start(&TimHandle, TIM_CHANNEL_1) != HAL_OK)
{
/* Starting Error */
Error_Handler();
}
/* Start channel 1N */
if (HAL_TIMEx_OCN_Start(&TimHandle, TIM_CHANNEL_1) != HAL_OK)
{
/* Starting Error */
Error_Handler();
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/* Start channel 2 */
if (HAL_TIM_OC_Start(&TimHandle, TIM_CHANNEL_2) != HAL_OK)
{
/* Starting Error */
Error_Handler();
}
/* Start channel 2N */
if (HAL_TIMEx_OCN_Start(&TimHandle, TIM_CHANNEL_2) != HAL_OK)
{
/* Starting Error */
Error_Handler();
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/* Start channel 3 */
if (HAL_TIM_OC_Start(&TimHandle, TIM_CHANNEL_3) != HAL_OK)
{
/* Starting Error */
Error_Handler();
}
/* Start channel 3N */
if (HAL_TIMEx_OCN_Start(&TimHandle, TIM_CHANNEL_3) != HAL_OK)
{
/* Starting Error */
Error_Handler();
}
/*--------------------------------------------------------------------------*/
GPIO_PinState pa0;
/*
do
{
pa0 = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);
} while (pa0 == GPIO_PIN_RESET);
*/
uint32_t clock_val = HAL_RCC_GetSysClockFreq(); // what is system clock?
printf("its semi testing!\n");
for (;;)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_SET);
HAL_Delay(250);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_RESET);
HAL_Delay(250);
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET)
{
__HAL_TIM_SET_AUTORELOAD(&TimHandle, 599);
}
}
}
This is not a complete code yet, since there must be additional code for handling each of 6 "steps" and changing the OCx. however, at this point it is not necessary since I only test for now the Interface timer triggering.
So, the thing is, after i start it all up and feed PC6 with test signal, the interrupt on TIM3 not happening, any idea?
2019-09-22 10:24 PM
You first set CH1 to input capture (the "hall whatnot") and then in turn set it to output compare - output won't trigger on input pulses - contrary, the mcu output and the pulse generator are "figthing" now.
The whole Hall etc. subchapter in the timer chapter of RM is bizarre. It won't belong to the RM, rather, to an AN; and deserves a more thorought explanation with figures etc. No wonder it gets misunderstood.
JW
2019-09-22 10:29 PM
well, i am not quiet getting. As far as i udnerstood, you set ch1 to input capture, and ch2 to output compare in PWM mode.
here is a function i used by default:
HAL_StatusTypeDef HAL_TIMEx_HallSensor_Init(TIM_HandleTypeDef *htim, TIM_HallSensor_InitTypeDef* sConfig)
{
TIM_OC_InitTypeDef OC_Config;
/* Check the TIM handle allocation */
if(htim == NULL)
{
return HAL_ERROR;
}
assert_param(IS_TIM_HALL_INTERFACE_INSTANCE(htim->Instance));
assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));
assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
assert_param(IS_TIM_IC_POLARITY(sConfig->IC1Polarity));
assert_param(IS_TIM_IC_PRESCALER(sConfig->IC1Prescaler));
assert_param(IS_TIM_IC_FILTER(sConfig->IC1Filter));
assert_param(IS_TIM_AUTORELOAD_PRELOAD(htim->Init.AutoReloadPreload));
if(htim->State == HAL_TIM_STATE_RESET)
{
/* Allocate lock resource and initialize it */
htim->Lock = HAL_UNLOCKED;
/* Init the low level hardware : GPIO, CLOCK, NVIC and DMA */
HAL_TIMEx_HallSensor_MspInit(htim);
}
/* Set the TIM state */
htim->State= HAL_TIM_STATE_BUSY;
/* Configure the Time base in the Encoder Mode */
TIM_Base_SetConfig(htim->Instance, &htim->Init);
/* Configure the Channel 1 as Input Channel to interface with the three Outputs of the Hall sensor */
TIM_TI1_SetConfig(htim->Instance, sConfig->IC1Polarity, TIM_ICSELECTION_TRC, sConfig->IC1Filter);
/* Reset the IC1PSC Bits */
htim->Instance->CCMR1 &= ~TIM_CCMR1_IC1PSC;
/* Set the IC1PSC value */
htim->Instance->CCMR1 |= sConfig->IC1Prescaler;
/* Enable the Hall sensor interface (XOR function of the three inputs) */
htim->Instance->CR2 |= TIM_CR2_TI1S;
/* Select the TIM_TS_TI1F_ED signal as Input trigger for the TIM */
htim->Instance->SMCR &= ~TIM_SMCR_TS;
htim->Instance->SMCR |= TIM_TS_TI1F_ED;
/* Use the TIM_TS_TI1F_ED signal to reset the TIM counter each edge detection */
htim->Instance->SMCR &= ~TIM_SMCR_SMS;
htim->Instance->SMCR |= TIM_SLAVEMODE_RESET;
/* Program channel 2 in PWM 2 mode with the desired Commutation_Delay*/
OC_Config.OCFastMode = TIM_OCFAST_DISABLE;
OC_Config.OCIdleState = TIM_OCIDLESTATE_RESET;
OC_Config.OCMode = TIM_OCMODE_PWM2;
OC_Config.OCNIdleState = TIM_OCNIDLESTATE_RESET;
OC_Config.OCNPolarity = TIM_OCNPOLARITY_HIGH;
OC_Config.OCPolarity = TIM_OCPOLARITY_HIGH;
OC_Config.Pulse = sConfig->Commutation_Delay;
TIM_OC2_SetConfig(htim->Instance, &OC_Config);
/* Select OC2REF as trigger output on TRGO: write the MMS bits in the TIMx_CR2
register to 101 */
htim->Instance->CR2 &= ~TIM_CR2_MMS;
htim->Instance->CR2 |= TIM_TRGO_OC2REF;
/* Initialize the TIM state*/
htim->State= HAL_TIM_STATE_READY;
return HAL_OK;
}
So that function i used in a first posted code, does exactly what the RM says. why is it not triggering then? what am i missing?
2019-09-22 10:50 PM
I don't use Cube so don't understand that code, sorry. So you already use two different timers? And you have set up an ISR for TIM3, enabled in NVIC, and set the appropriate interrupt enable in TIM3_DIER?
Read out and check the relevant GPIO, TIM and NVIC registers' content. Observe the effect of changing input levels on the given pin on the respective GPIO_IDR bit. Observe on the respective TIMx_CCR register, whether capture occurs.
JW
2019-09-22 10:56 PM
well, here is the TIM3 starting code with the interrupt enabling in DIE register:
HAL_StatusTypeDef HAL_TIMEx_HallSensor_Start_IT(TIM_HandleTypeDef *htim)
{
/* Check the parameters */
assert_param(IS_TIM_HALL_INTERFACE_INSTANCE(htim->Instance));
/* Enable the capture compare Interrupts 1 event */
__HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1);
/* Enable the Input Capture channel 1
(in the Hall Sensor Interface the three possible channels that can be used are TIM_CHANNEL_1, TIM_CHANNEL_2 and TIM_CHANNEL_3) */
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);
/* Enable the Peripheral */
__HAL_TIM_ENABLE(htim);
/* Return function status */
return HAL_OK;
}
and here is how i actually enable interrupts:
// enable and configure TIM3 related interrupt
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
HAL_NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
So i do enable the TIM3_IRQn interrupt since im using TIM3 as an interface timer,
but upon feeding the PC6 with the test signal (while PC7,8 are at low and inactive), i still dont see any interrupt triggering. even though everything is setup correctly now.
2019-09-22 10:58 PM
to be more precise, i only set the CC1IE bit there, does it sound right?
2019-09-22 11:18 PM
Yes. So have you checked what's actually in the GPIO and TIM registers?
JW
2019-09-22 11:22 PM
TIM registers have proper settings, yes. and well, its not GPIO anymore it is AF function pin. So according to all settings i should be able to see TIM3 INT triggering.
what specifically you meant me to check?
2019-09-22 11:26 PM
Read out their content in debugger or in any other means, and check, whether they contain what you intend to.
Also you should observe whether respective GPIO_IDR reacts to changes of the input signal; then you can also check if TIMx_CCRy captures the counter value upon appropriate change of the input signal; and observe the interrupt flag to be set in TIMx_SR.
JW