BLDC開發筆記6.利用STM32的硬體COM事件換相
前面我是用霍爾觸發中斷進行換相,這裡將使用定時器的COM事件來換相。吐槽下看懂這個還真不容易。另外有什麼不對的請幫忙指出,互相學習。
什麼是COM事件?
在中文參考手冊中的13.3.14產生六步PWM輸出有以下描述:
COM事件,其實就是為了讓換相時相應的通道同時開啟/關斷,因為如果按前面在霍爾觸發中斷中寫配置函式的話,是順序進行的,有延時,不能做到同時配置。那麼在切換的時候上一步的MOS狀態多少會影響下一步(其實我感覺影響很小)。COM事件能讓下一步的配置暫時快取在影子暫存器中,等待COM事件觸發生效,觸發後就將相應的輸出比較通道使能位同步更新,進行換相,然後可以在COM中斷中配置下一步的通道狀態。
我理解的使用COM事件另一個好處就是,能更靈活的對定時器進行同步操作。比如在ADC進行瞬時電流取樣時候,就可以利用一個通用定時器去和高階定時器(輸出PWM)同步,去觸發ADC轉換。方式更靈活。
需要注意的是,COM事件產生時,生效的是上一次在中斷中的配置(硬體完成),在COM中斷中配置的是下一步的狀態。所以我們需要提前一相進行配置。
COM事件可由軟體產生,也可以由硬體產生,這裡主要解析硬體COM事件。
硬體COM事件產生的流程
上面是ST官方的主要流程框圖,不過我覺得還是結合下面通用定時器功能框圖解析比較清晰。
總的說就是用一個通用定時器去觸發一個高階定時器。下面是官方參考手冊中給出的產生COM事件流程。
-
三個hall訊號經過異或後,任意一相跳變,都會產生脈衝訊號IC1PS,先將計數值傳給輸入捕獲暫存器1
-
計數器復位,重新從零開始計數。在下一個脈衝IC1PS到來之前,輸入捕獲暫存器1的值,就表示了兩個霍爾之間的時間。
-
將輸出比較通道2發出的PWM作為TRGO輸入源,注意配置為PWM2模式(當CNT<CCR時輸出無效電平),設定一個較小的佔空比,將主定時器的TRGO作為另一個高階定時器(從定時器)的TRGI觸發源,每一次主定時器的TRGO有上升沿時,就會在從定時器觸發一次硬體COM事件,進行換相。
下面是中文參考手冊例項:
這裡也註明了,在COM事件到來時,要寫入的是下一個步驟的通道配置。
用OC2REF作為TRGO好處就是能夠自定義觸發COM時間。
我用的是TIM3去觸發TIM1產生COM事件。
TIM3初始化
TIM3的初始化和前面文章中用霍爾觸發中斷的初始化中,時基和輸入捕獲通道初始化是一樣的,只不過加入輸出比較通道2的初始化和COM事件的配置。
因為計數器一直在計數,而且計數器的ARR是有限的,所以這裡就需要理清楚整個思路
- 剛開始,電機停止時候,初始設定PWM佔空比為0,因為沒有霍爾狀態改變,計數器一直在計數,不斷產生COM事件,但是無所謂,因為沒有霍爾狀態改變,並不會捕獲CNT的值,並且因為設定佔空比為0,所以電機停轉
- 電機啟動,TIM3利用TIM_TS_TI1F_ED正常產生COM事件,因為開始計數器一直計數,第一次產生捕獲事件時候,並不知道會停在哪裡,可能並不是我們想要的CNT值,但是我們可以將其過濾掉。我們通過設定反饋調整時間(50ms),其實就已經把這個值過濾掉了。之後就正常捕獲。關於電機轉速慢,超出計數器ARR,則需要根據實際情況最低轉速調整時基配置,保證長於霍爾感測器上的兩次變化的時間間隔。
- 電機停止,同1,設定佔空比為0進行剎車。
//使能Timx霍爾感測器介面,CH1\CH2\CH3異或輸入
TIM_SelectHallSensor(HALL_TIMx,ENABLE);
//輸入觸發源選擇TIM_TS_TI1F_ED
TIM_SelectInputTrigger(HALL_TIMx, TIM_TS_TI1F_ED);
//從模式選擇:復位模式
TIM_SelectSlaveMode(HALL_TIMx, TIM_SlaveMode_Reset);
//主從模式選擇使能
TIM_SelectMasterSlaveMode(HALL_TIMx, TIM_MasterSlaveMode_Enable);
//輸出比較通道2配置
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM2; //選擇PWM模式2
TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; //高電平有效
TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputNState_Disable; //關閉,不用輸出
TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Disable;
TIM_OCInitStruct.TIM_Pulse= 10; //設定佔空比
TIM_OC2Init(HALL_TIMx, &TIM_OCInitStruct);
//選擇TRGO觸發源為OC2Ref
TIM_SelectOutputTrigger(HALL_TIMx,TIM_TRGOSource_OC2Ref);
COM中斷服務函式
void TIM1_TRG_COM_IRQHandler(void)
{
if(TIM_GetITStatus(BLDC_TIMx, TIM_IT_COM) !=RESET)
{
//檢測霍爾狀態,換相
HALL_Position_commutate();
//清楚標誌位
TIM_ClearITPendingBit(BLDC_TIMx, TIM_IT_COM);
}
}
TIM1初始化
TIM1的初始化和前面文章中用輸出六步PWM的初始化中,時基和輸出比較通道初始化是一樣的,加入COM事件配置
//輸入觸發源選擇,選擇定時器3,這裡可以試下,如果選擇錯誤,TIM1是不會由PWM輸出的,進而驗證
TIM_SelectInputTrigger(BLDC_TIMx,TIM_TS_ITR2);
//從模式,選擇復位模式
TIM_SelectSlaveMode(BLDC_TIMx, TIM_SlaveMode_Reset);
//COM事件配置
/*配置ccxe,ccxne,ocxm是預裝載的,只有com事件產生才更新,這個預裝載和CCRX值的預裝載不同,CCRX預裝載 由 TIM_OC1PreloadConfig 配置,配置的暫存器不同*/
TIM_CCPreloadControl(BLDC_TIMx, ENABLE);
//使能com事件
TIM_SelectCOM(BLDC_TIMx, ENABLE);
//中斷優先順序配置
NVIC_InitStruct.NVIC_IRQChannel = TIM1_TRG_COM_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStruct);
TIM_ITConfig(BLDC_TIMx, TIM_IT_COM ,ENABLE);
TIM_ClearITPendingBit( BLDC_TIMx, TIM_IT_COM);
然後在COM中斷中檢測霍爾相位,進行換相。
啟動函式
啟動的時候由於沒有霍爾狀態改變來觸發,需要軟體觸發COM事件。
void BLDC_Start(void)
{
TIM_SetCompare1(BLDC_TIMx,0);
TIM_SetCompare2(BLDC_TIMx,0);
TIM_SetCompare3(BLDC_TIMx,0);
TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Enable);
TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Enable);
TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Enable);
TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Enable);
TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Enable);
TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Enable);
TIM_GenerateEvent(BLDC_TIMx, TIM_EventSource_COM); //軟體觸發COM事件生效配置
TIM_ClearFlag(BLDC_TIMx, TIM_FLAG_COM);
Delay_nms(1); //等待boost電容充電完成
HALL_Position_commutate(); //檢測霍爾狀態,換相
TIM_GenerateEvent(BLDC_TIMx, TIM_EventSource_COM);
TIM_ClearFlag(BLDC_TIMx, TIM_FLAG_COM);
}
啟動後轉動的穩態平均電流應該和用外部中斷幾乎一樣。