为了让CSR867x的开发更容易,现与思度科技联合推出CSR867x学习板【淘宝链接:思度科技CSR开发板】。
技术交流QQ群号:743434463
开发板会员QQ群号:725398389(凭订单号入群,赠PPT、项目源码、视频教程)
——————————正文分割线———————————–
#1. UART通信异常
##1.1. 现象
周五在调试CSR8670时遇到一个严重的问题:在xIDE环境下调试时,CSR8670收到MCU发来的数据后都会正常应答。一旦脱机运行,CSR8670与MCU的通信发生异常,具体现象如下:
- MCU发送一条x字节的命令给CSR8670,UART task收到的命令的长度不足x字节,最先发送的若干字节丢失
- MCU以较短间隔发送多条x字节的命令给CSR8670,UART task收到的第一条命令的长度不足x字节,之后每条命令的长度都是x字节
##1.2. 检查硬件
我们开始检查硬件是否有问题:
- 用示波器测量TXD的波形,波形正常。
- 解析TXD、RXD传输的协议,符合协议。
- 降低波特率,现象仍存在。
- 将CSR8670和MCU之间的TXD和RXD直接用飞线连接,并把电路板上的连接断开,现象仍存在。
- 将软件烧录到CSR的官方Demo板运行,现象消失。
对比了Demo板和我们自己电路板的原理图,没发现用来配置UART功能的引脚。主要区别是Demo板用USB供电,我们自己的板子是稳压电源模块供电。
##1.3. 检查软件
负责MCU端代码的程序猿J回忆起上一版软件在测试时没遇到这个问题。于是程序猿J快速测试了上一版软件,发现了新的现象:
- 新旧版本软件的通信异常的现象相同
- 一旦CSR8670与手机连接成功,UART通信恢复正常
- 在CSR8670没有与其他设备建立蓝牙连接的情况下,UART通信异常
##1.4. 检查编程器
看来旧的软件也存在相同的问题,于是关注点又回到了弄清楚为何在xIDE环境下调试时都能正常应答。在线调试必须连接USB-SPI编程器,脱机运行不需要连接编程器。
USB-SPI Convert:
Custom firmware, stored in flash memory, takes USB packets containing SPI commands and forwards the commands over SPI. The DSP:
- serialises the SPI commands
- uses the PIO pins to create the SPI_MOSI, SPI_CSB and SPI_CLK signals
- reads the SPI_MISO line
USBSPI automatically reduces the SPI bit rate when it sees SPI data corruption.
Voltage level is set by default to 3.3V.
于是我们在离线运行时不移除编程器,发现如下现象:
- 连接上USB-SPI编程器,UART通信恢复正常
- 移除USB-SPI编程器,UART通信发生异常
我们用示波器测量了编程器各个引脚的波形,发现编程器会以固定的时间间隔发送SPI数据给CSR8670。
##1.5. 谁是真凶
我和程序猿J整理了不会发生通信异常的条件:
- USB供电
- 连接了USB-SPI编程器
- 手机或其他设备与CSR8670建立了蓝牙链接
目前市面上很多无线蓝牙耳机类的产品用的都是CSR8670这颗芯片。这些耳机的共同特点是电池供电。
由于电池供电的产品需要在充满一次电后尽量工作较长时间,因此在器件选型和软件设计时都会要求系统尽可能降低电能的消耗。
综上所述,芯片很可能有一个低功耗模式。在低功耗模式下,UART的功能很可能受到了影响。
#2. 省电模式
登录CSR开发者账户,搜索关键词low power,查询结果中有一篇文章BlueCore Power Saving Mode。
The BlueCore chips have hardware support for two methods of reducing power consumption when the chip is idle:
Shallow Sleep: The chip processor’s clock speed is reduced. At best this can reduce current consumption to approximately 2 mA on BlueCore01b, less on BlueCore2 chips. The processor’s speed
can be restored within a few machine instructions, with a latency that depends on the slowed clock rate.Deep Sleep: Much of the chip’s circuitry is shut down. At best, this can reduce the chip’s current consumption to approximately 100µA on BlueCore01b, less on BlueCore2 chips. However, it takes at least 10 milliseconds to enter Deep Sleep and at least another 10 milliseconds to exit Deep Sleep.
The document describes features specific to BlueCore chips; Bluetooth’s own standard power saving support (Hold, Sniff and Park modes) are mentioned only where they interact with the chip’s power saving modes.
这两种模式的功耗是不一样的。在deep sleep的描述中提到了芯片的多个电路是关闭的,其中可能也包括UART相关的电路。
In Deep Sleep, the processor, the fast (16MHz) clock and much of the digital and analogue hardware are shut down. This has a major effect on power consumption
When the device enters Deep Sleep, it sets an alarm clock (a timed event from a counter that is clocked by the slow clock). The timed event normally wakes the chip, but it can be woken prematurely by activity on the UART or USB.
在deep sleep模式下,芯片每1ms被唤醒一次,也可以被UART或USB激活。
Deep Sleep cannot be used when the chip has a USB host connection and the connection is in its USB “active” state.
这就是Demo板的UART通信不会发生异常的原因。
Once the system is in Deep Sleep, only a limited set of stimuli can rouse it:
- Expiry of a timer (clocked from the chip’s slow clock)
- When configured to provide a UART, any activity on the data-receive pin. (Including asserting a break condition, e.g., to force a reboot.)
- When configured to provide a UART, activity on the CTS line (This is configured with the PS Key PSKEY_DEEP_SLEEP_WAKE_CTS.)
- BlueCore2-External can be configured to wake on PIO activity
- When configured to provide a USB host connection, any activity on the data lines
- Any activity on the chip’s SPI port (pstool.exe relies on this to read and write PS Keys if the chip is in Deep Sleep.)
- System reboot
SPI口的数据能够激活芯片,这就是USB-SPI编程器连接时通信不会异常的原因。
#3. 异常分析
回顾章1.1的现象,为什么会丢失的数据总在前几个字节?
在非Deep Sleep状态下,CSR8670收到MCU的指令后会向UART task提交2次MESSAGE_MORE_DATA。
在Deep Sleep状态下,CSR8670可能只把第2个MESSAGE_MORE_DATA发给UART task,第1个MESSAGE_MORE_DATA被丢掉了。
#3. 修复异常
为了正常接收MCU发来的指令,CSR8670可以选择如下策略中的一种:
- 不使用Deep Sleep
- 在MCU发来指令前从Deep Sleep唤醒
##3.1. 不使用Deep Sleep
用PSTool工具将PSKEY_DEEP_SLEEP_STATE设为0。
##3.2. 使用Deep Sleep
用PSTool工具将PSKEY_DEEP_SLEEP_STATE设为1。
###3.2.1. 用CTS line上的信号唤醒
The PS Key PSKEY_DEEP_SLEEP_WAKE_CTS (0x23c) can be set to allow a transition on the UART CTS line to wake the host from Deep Sleep; this can provide an alternative to sending a short “wake up” packet.
###3.2.2. 用PIO唤醒
The PIO port continues to drive output signals when the chip drops into Deep Sleep.
for a button on a headset, a common technique is to route the button’s signal to an input PIO pin and also to the UART CTS line. Activity on the CTS line can then wake the chip.
###3.2.3. 用唤醒包唤醒
The chip is eligible to enter Deep Sleep if there has been no UART traffic from the host for at least one second and if there is no data waiting to be passed to the host.
The “one second” is actually the value of the PS Key PSKEY_UART_SLEEP_TIMEOUT (0x0222).
MCU可以先发送一个唤醒包,发送完毕后等待10ms以上再发送命令包。