2023-10-17 10:48 PM - last edited on 2023-10-18 04:41 AM by Sarra.S
Hello
I am designing a controller that will drive a 3 phase BLDC 0.5kW motor. I choose STM32G474VET3 to generate the signaling with external gate driver and some beefy MOSFETs for that.
The MCU has advanced timer controller, and for my application i went with TIM20, ch1, ch2 and ch4. I see they can generate "PWM Generation CH CHN". How ever i dont see how to generate those with proper phase shift for a 3phase motor.
Can you please provide me some guide lines how to generate 3 phase pwm that is properly phase shifted. Which settings in the Cube i should look in to. If you have any app note i take a look it would be appreciated.
Thank you
Mirza
2023-10-26 04:07 AM
I have made a small test bench setup to test this. I have a NUCLEO-STM32G432RBT. I also have a BLDC with hall sensors attached to it. Currently BLDC is not driven by anything ... the phase connections are unconnected. I attached a drill machine to the shaft of the bldc and made it spin. On the scope i measure the 3 hall sensors and they are as they should be as the shaft is turning.
I am trying to implement what is described in RM0440, on p1159 sec 28.3.29. I have connected the 3 hall sensors to the NUCLEO on Timer2 pins (A0,A1, B10). As the drill machine is turning the hall sensors generate the pulses and drive the NUCLEO. I have configured TIMER8 to be in slave mode, with trigger ITR1 and source.
After CubeIDE generates the code i add following
// ENABLE Hall
__HAL_TIM_ENABLE_IT(&htim2,TIM_IT_TRIGGER);
__HAL_TIM_ENABLE_IT(&htim2,TIM_IT_UPDATE);
HAL_TIMEx_HallSensor_Start(&htim2);
HAL_TIM_TriggerCallback(&htim2);
// START Commutation events
HAL_TIMEx_ConfigCommutationEvent(&htim8, TIM_TS_ITR1, TIM_COMMUTATION_SOFTWARE);
HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_3);
I am then just connecting my oscilloscope to the NUCLEO to see if PWM are generated and they are NOT. I know i should also enable the Inverted pins, but for now i would be happy just with 3 pins. Any suggestions on what to do?
Mirza
2023-10-27 01:45 AM
Please check below link it may be helpful.
https://community.st.com/t5/power-management/6-step-drive-with-hall-sensor-interface/td-p/221043
2023-10-31 11:44 AM
Hello @Mirza-AEC,
The timer is a quite complex IPs with a lot of possibilities. An overview of the internal of the timer is given Figure 269. Advanced-control timer block diagram page 1078. In this picture you can see the presence of the bus tim_itr[15..0] which goes (after muxing) into the "slave controller mode". Those triggers are used to start the timer from an other Timer. The table 252 tells you which trigger will be connected to your timer if you configure the TS field from the SCMR register. From what I understand from your configuration, you configure in Timer 8 ITR8. So from the table 252, you selected tim17_oc1 to start your timer.
If you look at the TIMx slave mode control register (TIMx_SMCR)(x = 1, 8, 20) :
Bits 6:4 TS[2:0]: Trigger selection
This bitfield is combined with TS[4:3] bits.
This bit-field selects the trigger input to be used to synchronize the counter.
00000: Internal Trigger 0 (tim_itr0)
00001: Internal Trigger 1 (tim_itr1)
00010: Internal Trigger 2 (tim_itr2)
00011: Internal Trigger 3 (tim_itr3)
00100: tim_ti1 Edge Detector (tim_ti1f_ed)
00101: Filtered Timer Input 1 (tim_ti1fp1)
00110: Filtered Timer Input 2 (tim_ti2fp2)
00111: External Trigger input (tim_etrf)
01000: Internal Trigger 4 (tim_itr4)
01001: Internal Trigger 5 (tim_itr5)
01010: Internal Trigger 6 (tim_itr6)
01011: Internal Trigger 7 (tim_itr7)
01100: Internal Trigger 8 (tim_itr8)
01101: Internal Trigger 9 (tim_itr9)
01110: Internal Trigger 10 (tim_itr10)
01111: Internal trigger 11 (tim_itr11)
10000: Internal trigger 12 (tim_itr12)
10001: Internal trigger 13 (tim_itr13)
10010: Internal trigger 14 (tim_itr14)
10011: Internal trigger 15 (tim_itr15)
As this register description is common to TIM 1|8|20, and this content is timer dependent, the information of what is behind the trigger number is available from the table 252.
Now the real question I have is: do you really need an external trigger to start your counter ?
In the MCSDK we use the TIM2 to start the TIM1 because in case of dual drive we want to start the both PWM timers (TIM1 and TIM8) in the exact same clock cycle. Then we configure TIM1 as follow (from HAL code gen) :
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;
sSlaveConfig.InputTrigger = TIM_TS_ITR1; ( which means from table 252 : tim2_trgo)
Then to start the TIM1, we play with TIM2 in StartTimers function :
LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_UPDATE);
LL_TIM_GenerateEvent_UPDATE(TIM2); // On this event, TIM2 TRGO will start TIM1 (thanks to ITR1)
Hope it helps
Regards
Cedric
2023-10-31 12:49 PM
Could you check that the bit 15 (Master Output Enable) of register TIM8_BDTR (TIMx break and dead-time register) is correctly set.
Do not hesitate to dump all the registers of your timer, I will try to give you some clues.
Cedric
2023-11-01 09:03 PM
Hello
so i have taken your advice. But i wanted to start a bit more simple. On my P-NUCLEO-IMH03 I implemented my hall sensors on TIM2. The STM32G431 is running on 90Mhz so i first scale down with pre-scaler 900-1, then counter period 10000-1. In the main.c i add lines
__HAL_TIM_ENABLE_IT(&htim2,TIM_IT_TRIGGER);
__HAL_TIM_ENABLE_IT(&htim2,TIM_IT_UPDATE);
HAL_TIMEx_HallSensor_Start_IT(&htim2);
I also implemented Callback function to read hall sensor state
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{
state = get_hall_state();
}
uint8_t get_hall_state(void)
{
uint8_t _state = 0;
if(HAL_GPIO_ReadPin(HALLA_GPIO_Port, HALLA_Pin) != GPIO_PIN_RESET)
{
_state |= 0x01U << 0;
}
if(HAL_GPIO_ReadPin(HALLB_GPIO_Port, HALLB_Pin) != GPIO_PIN_RESET)
{
_state |= 0x01U << 1;
}
if(HAL_GPIO_ReadPin(HALLC_GPIO_Port, HALLC_Pin) != GPIO_PIN_RESET)
{
_state |= 0x01U << 2;
}
return _state;
}
i can compile this with no problem and download to mt STM32G4. I then set a break point once get_hall_sensor is called just to see if the "HAL_TIM_TriggerCallback" is executed. It never is. Just to se my TIM2 settings i have put a brak point before while(1). These are the settings
In the ioc, i have enabeled TIM2 global interrupt (NVIC settings).
What am i doing wrong so that TriggerCallback is never called?
Thank you