1. 程式人生 > 實用技巧 >BLDC開發筆記6.利用STM32的硬體COM事件換相

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事件流程。

  1. 三個hall訊號經過異或後,任意一相跳變,都會產生脈衝訊號IC1PS,先將計數值傳給輸入捕獲暫存器1

  2. 計數器復位,重新從零開始計數。在下一個脈衝IC1PS到來之前,輸入捕獲暫存器1的值,就表示了兩個霍爾之間的時間。

  3. 將輸出比較通道2發出的PWM作為TRGO輸入源,注意配置為PWM2模式(當CNT<CCR時輸出無效電平),設定一個較小的佔空比,將主定時器的TRGO作為另一個高階定時器(從定時器)的TRGI觸發源,每一次主定時器的TRGO有上升沿時,就會在從定時器觸發一次硬體COM事件,進行換相。

下面是中文參考手冊例項:

這裡也註明了,在COM事件到來時,要寫入的是下一個步驟的通道配置。

用OC2REF作為TRGO好處就是能夠自定義觸發COM時間。

我用的是TIM3去觸發TIM1產生COM事件。

TIM3初始化

TIM3的初始化和前面文章中用霍爾觸發中斷的初始化中,時基和輸入捕獲通道初始化是一樣的,只不過加入輸出比較通道2的初始化和COM事件的配置。

因為計數器一直在計數,而且計數器的ARR是有限的,所以這裡就需要理清楚整個思路

  1. 剛開始,電機停止時候,初始設定PWM佔空比為0,因為沒有霍爾狀態改變,計數器一直在計數,不斷產生COM事件,但是無所謂,因為沒有霍爾狀態改變,並不會捕獲CNT的值,並且因為設定佔空比為0,所以電機停轉
  2. 電機啟動,TIM3利用TIM_TS_TI1F_ED正常產生COM事件,因為開始計數器一直計數,第一次產生捕獲事件時候,並不知道會停在哪裡,可能並不是我們想要的CNT值,但是我們可以將其過濾掉。我們通過設定反饋調整時間(50ms),其實就已經把這個值過濾掉了。之後就正常捕獲。關於電機轉速慢,超出計數器ARR,則需要根據實際情況最低轉速調整時基配置,保證長於霍爾感測器上的兩次變化的時間間隔。
  3. 電機停止,同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);
}

啟動後轉動的穩態平均電流應該和用外部中斷幾乎一樣。