問題:
? ? 在使用CH58X開發(fā)BLE功能時,遇到一個問題,就是如果使用了稍微長一點的延時或者處理耗時的操作時。BLE會斷開連接。
原因:
? ? CH58X的藍牙功能是基于TMOS輪詢的方式去處理各個事件的。因為是單線程,所以如果在代碼里使用了延時就會導致藍牙的事件沒能得到及時處理,就會導致斷開連接。
解決思路:
? ? 在一個低優(yōu)先級中斷中去執(zhí)行TMOS的輪詢。這樣主函數(shù)就能無限延時或者處理各種耗時操作。相當于雙線程運行。為了保證其它中斷不受影響,這個執(zhí)行TMOS輪詢的中斷必須是最低優(yōu)先級的,并且能被所有中斷搶斷。
接下來我們使用RTC中斷來驗證我們的思路:
? ? 使用官方BLE_USB的Demo來實現(xiàn),具體步驟如下:
? ? 首先,把HAL_SLEEP宏打開
? ? 然后main函數(shù)需要改成:
int?main(void) { ????... ????PFIC_DisableIRQ(RTC_IRQn);?????????????//先關(guān)閉RTC中斷 ????CH58X_BLEInit(); ????HAL_Init(); ????GAPRole_PeripheralInit(); ????Peripheral_Init(); ????app_usb_init(); ????PFIC_EnableIRQ(RTC_IRQn);?????????????//所有初始化工作完成后,打開RTC中斷 ????RTC_SetTignTime(RTC_GetCycle32k()?+?10);????//設(shè)置RTC在10個時鐘周期后觸發(fā)中斷 ????Main_Circulation(); }
? ?
主循環(huán)需要把TMOS_SystemProcess();注釋掉,然后改成一個周期打印的功能來測試
void?Main_Circulation() { ????while(1) ????{ ????????//TMOS_SystemProcess(); ????????PRINT("123\n"); ????????DelayMs(1000); ????} }
?
在SLEEP.c文件的HAL_SleepInit函數(shù)中需要增加設(shè)置RTC中斷優(yōu)先級成最低優(yōu)先級
void?HAL_SleepInit(void) { #if(defined(HAL_SLEEP))?&&?(HAL_SLEEP?==?TRUE) ????sys_safe_access_enable(); ????R8_SLP_WAKE_CTRL?|=?RB_SLP_RTC_WAKE;? ????sys_safe_access_enable(); ????R8_RTC_MODE_CTRL?|=?RB_RTC_TRIG_EN;? ????sys_safe_access_disable();?????????????? ????PFIC_SetPriority(RTC_IRQn,?0xFF);????//將RTC中斷優(yōu)先級設(shè)置到最低,用于跑TMOS事務(wù)輪詢 #endif }
然后把CH58X_LowPower函數(shù)中的休眠相關(guān)的函數(shù)注釋掉,并且在設(shè)置RTC觸發(fā)時間后把RTC中斷標志位清除
uint32_t?CH58X_LowPower(uint32_t?time) { #if(defined(HAL_SLEEP))?&&?(HAL_SLEEP?==?TRUE) ????uint32_t?time_sleep,?time_curr,?irq_status; ????SYS_DisableAllIrq(&irq_status); ????time_curr?=?RTC_GetCycle32k(); ????//?檢測睡眠時間 ????if?(time?<?time_curr)?{ ????????time_sleep?=?time?+?(RTC_TIMER_MAX_VALUE?-?time_curr); ????}?else?{ ????????time_sleep?=?time?-?time_curr; ????} ????if?((time_sleep??(RTC_TIMER_MAX_VALUE?-?TMOS_TIME_VALID)))?{ ????????SYS_RecoverIrq(irq_status); ????????return?2; ????} ????RTC_SetTignTime(time); ????SYS_RecoverIrq(irq_status); ????R8_RTC_FLAG_CTRL?=?(RB_RTC_TMR_CLR?|?RB_RTC_TRIG_CLR);??//清除中斷標志位,等待下一次RTC觸發(fā) #endif ????return?0; }
在RTC.c文件中需要修改RTC_IRQHandler函數(shù)為:
void?RTC_IRQHandler(void)?{ ????RTCTigFlag?=?1; ????TMOS_SystemProcess();????//RTC中斷中進行TMOS事務(wù)輪詢,并且不清除中斷標志位。 ?????????????????????????????//等TMOS調(diào)用CH58X_LowPower時才清除標志,不然一直進中斷。 }
到此代碼修改完畢,編譯、燒錄、測試。在主循環(huán)中延時1秒鐘也不會影響藍牙的連接、數(shù)據(jù)收發(fā)。并且USB功能正常。
附上工程代碼
注意事項:
1、PRINT在主循環(huán)和RTC中斷中都會調(diào)用到,因為PRINT不是可重入函數(shù),有可能會導致錯誤。