【WCH蓝牙系列芯片】-基于CH592开发板—BLE_USB程序中低功耗模式下,USB设备的拔插唤醒操作

-------------------------------------------------------------------------------------------------------------------------------------

  在CH592EVT例程中,有一个BLE_USB程序,是蓝牙与USB合用例程,通过USB模拟340设备转发蓝牙数据。在正常使用中,蓝牙和USB设备都可以一起运行,蓝牙做为蓝牙从机,USB设备模拟出340设备,通过串口与蓝牙进行数据透传功能。

  但是如果开启蓝牙低功耗睡眠模式(HAL_SLEEP=1)时,此时插入USB接口,电脑就不会模拟出340设备,还会弹出无法识别的USB设备的提示。这是因为BLE是通过不断地休眠唤醒来实现低功耗的,而USB需要常供电。如果接入芯片模拟的USB设备时,芯片正处于休眠状态,没有及时响应主机,则会被主机判断为设备有问题而被挂起。这也是为什么默认的BLE_USB例程中是不开启HAL_SLEEP的,开了就会由协议栈进管理休眠,休眠时接入USB设备会出问题。

  针对这一问题,需要做USB口的拔插唤醒操作,TMOS系统从休眠实现唤醒有两个方法,一个是RTC定时唤醒,由TMOS内部处理,到时间后唤醒;另一个是GPIO中断唤醒,在中断中置位一个标志,根据标志位来开TMOS任务。CH592的BLE是基于TMOS系统跑的,TMOS不是抢占机制而是轮询机制,不具备中断能力,所以需要借用芯片本身的中断系统。

  最简单的方式就通过硬件检测,将USB的5V输入脚引出来,然后通过电阻分压的方式,把CH592拉出来一个GPIO脚接上,通过GPIO的外部中断来进行唤醒和睡眠操作,当USB设备接入到主机时该引脚上产生了从低电平变到高电平的状态,从而判断为USB设备接入,芯片唤醒,USB设备工作。当高电平转换到低电平的时候,此时判断USB设备拔出,芯片又重新进入低功耗模式。

  这样做了一个分压电阻的电路,通过PB4连接,通过USB上产生的5V脚。连接到分压电阻上,这样PB4端的电压就是差不多在3V左右,这样当USB设备插入时,PB4这个脚就会产生一个高电平,反之,当拔掉USB设备,PB4的状态就是低电平。

 

   在软件方面,BLE_USB程序中,在初始化USB函数中app_usb_init(),先将PFIC_EnableIRQ( USB_IRQn ); 启用USB中断改成PFIC_DisableIRQ( USB_IRQn ); 禁用USB中断。

   然后再把低功耗模式打开,将HAL_SLEEP=1,DCDC_ENABLE=1.DC-DC也使能,进一步降低功耗。

   在工程文件中,添加GPIO外部中断的函数,在外部中断初始化中,先将PB4配置为下拉输入,方式IO口漏电到芯片中。并将GPIOB引脚中断模式配置为上升沿触发。然后先清除一下标注位,然后再重新开启GPIOB的中断,然后启用GPIO唤醒功能。

  在中断服务函数中,先检测是否有PB4的中断标志状态,然后先判断是否为0,如果为0表示是上升沿触发的中断,如果不为0,则是下降沿触发中断,因为flag_wakeup这个标志默认初始化为0,只有当上升沿触发中断之后,flag_wakeup置为1。

  当上升沿触发中断后,设置flag_wakeup标志位为1,并将GPIO中断触发模式改为下降沿触发。然后要重新初始化USB,app_usb_init();然后要将USB中断使能。这样做的目的:当USB设备插入时,就会触发上升沿中断,这样代表USB设备已经插入,需要唤醒蓝牙,初始化USB设备,让USB设备工作。切换为下降沿中断是为检测什么时候USB拔出,从高电平变为低电平状态的时候从而进入睡眠模式。

   在下降沿中断里,先将flag_wakeup标志位清除,退出唤醒状态。然后关闭GPIOB的中断功能,也关闭GPIO中断唤醒功能,并且重新初始一下app_usb_init();,为了将USB中断失能,不能让USB干扰蓝牙的低功耗睡眠状态。

 

//中断函数
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void GPIOB_IRQHandler( void )
{
    i++;
    printf("i = %d\r\n",i);
    if(GPIOB_ReadITFlagBit(GPIO_Pin_4)) // 检查GPIO4的中断标志
    {
       if(flag_wakeup == 0) // 如果flag_wakeup为0,表示是上升沿触发的中断
       {
           flag_wakeup = 1; // 设置flag_wakeup标志位
           GPIOB_ITModeCfg( GPIO_Pin_4, GPIO_ITMode_FallEdge );   //上升沿触发
           GPIOB_ClearITFlagBit( GPIO_Pin_4);//清中断
           PFIC_EnableIRQ( GPIO_B_IRQn );//开启GPIOB中断

           app_usb_init();  //重新初始化USB
           USB_DeviceInit();
           PFIC_EnableIRQ( USB_IRQn );  //使能USB中断
       }
       else //表示是下降沿触发的中断
       {
           flag_wakeup = 0; // 清除flag_wakeup标志位
           printf("/flag_wakeup/ = %x \n",flag_wakeup);
           PFIC_DisableIRQ(GPIO_B_IRQn);                               //关闭GPIO中断唤醒功能
           PWR_PeriphWakeUpCfg(DISABLE, RB_SLP_GPIO_WAKE, Long_Delay);
           app_usb_init();   //将USB中断关闭
       }
        GPIOB_ClearITFlagBit(GPIO_Pin_4); // 清除中断标志
    }
}

  在低功耗睡眠函数中,通过判断flag_wakeup这个标志位,当这个上升沿触发后,flag_wakeup标志位为1,说明USB设备已经插入,这个时候就直接退出低功耗状态,不进行休眠。并将GPIO外部中断函数初始化,配置GPIO中断唤醒源为PB4.

 

 

  通过功耗仪,来观察一下整个USB拔插的过程,观察一下芯片功耗的实际情况。

  当蓝牙的广播间隔设置为1s,并且发射功率设置为0dbm时。睡眠模式和DC-DC都使能的情况下,功耗在30多个uA左右。

   当USB插入后,可以明显看到功耗上升,蓝牙唤醒。通过串口调试工具可以看到COM15口,COM15模拟出一个CH340设备,这样就可以与蓝牙进行透传数据。

   当拔掉USB之后,观察功耗仪从唤醒状态,又重新进入低功耗休眠状态。这样也就完成USB插入唤醒和拔出睡眠的操作。

 

posted on 2025-01-07 20:51  凡仕  阅读(620)  评论(0)    收藏  举报