问题:
在使用CH58X开发BLE功能时,遇到一个问题,就是如果使用了稍微长一点的延时或者处理耗时的操作时。BLE会断开连接。
原因:
CH58X的蓝牙功能是基于TMOS轮询的方式去处理各个事件的。因为是单线程,所以如果在代码里使用了延时就会导致蓝牙的事件没能得到及时处理,就会导致断开连接。
解决思路:
在一个低优先级中断中去执行TMOS的轮询。这样主函数就能无限延时或者处理各种耗时操作。相当于双线程运行。为了保证其它中断不受影响,这个执行TMOS轮询的中断必须是最低优先级的,并且能被所有中断抢断。
接下来我们使用RTC中断来验证我们的思路:
使用官方BLE_USB的Demo来实现,具体步骤如下:
首先,把HAL_SLEEP宏打开
然后main函数需要改成:
int main(void) { ... PFIC_DisableIRQ(RTC_IRQn); //先关闭RTC中断 CH58X_BLEInit(); HAL_Init(); GAPRole_PeripheralInit(); Peripheral_Init(); app_usb_init(); PFIC_EnableIRQ(RTC_IRQn); //所有初始化工作完成后,打开RTC中断 RTC_SetTignTime(RTC_GetCycle32k() + 10); //设置RTC在10个时钟周期后触发中断 Main_Circulation(); }
主循环需要把TMOS_SystemProcess();注释掉,然后改成一个周期打印的功能来测试
void Main_Circulation() { while(1) { //TMOS_SystemProcess(); PRINT("123\n"); DelayMs(1000); } }
在SLEEP.c文件的HAL_SleepInit函数中需要增加设置RTC中断优先级成最低优先级
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中断优先级设置到最低,用于跑TMOS事务轮询 #endif }
然后把CH58X_LowPower函数中的休眠相关的函数注释掉,并且在设置RTC触发时间后把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触发 #endif return 0; }
在RTC.c文件中需要修改RTC_IRQHandler函数为:
void RTC_IRQHandler(void) { RTCTigFlag = 1; TMOS_SystemProcess(); //RTC中断中进行TMOS事务轮询,并且不清除中断标志位。 //等TMOS调用CH58X_LowPower时才清除标志,不然一直进中断。 }
到此代码修改完毕,编译、烧录、测试。在主循环中延时1秒钟也不会影响蓝牙的连接、数据收发。并且USB功能正常。
附上工程代码
注意事项:
1、PRINT在主循环和RTC中断中都会调用到,因为PRINT不是可重入函数,有可能会导致错误。