为了让CSR867x的开发更容易,现与思度科技联合推出CSR867x学习板
【淘宝链接:思度科技CSR开发板】。
技术交流QQ群号:743434463
开发板会员QQ群号:725398389(凭订单号入群,赠PPT、项目源码、视频教程)
——————————正文分割线———————————–
1. 引言
拥有健康的身体是每个人最朴素最根本的需求,心率监测耳机是一款服务大众医疗健康的智能可穿戴产品,拥有较广阔的应用前景。
2. 主要功能
- 蓝牙音乐播放
- 蓝牙语音通话
- 手机心率监测
- 自定义BLE server
系统框图如下:
整个系统由CSR8670和AFE4410组成。AFE4410是一款用于可穿戴连续的光学心率监测等光学生物传感应用的模拟前端。芯片系统框图如下:
AFE4410芯片的工作机制很简单,概括来说一句话:读取LED传感器的值缓存在FIFO中,触发PIO中断请求CSR8670通过I2C读取并处理。
3. 项目难点
3.1. I2C通信
参考博客
https://blog.csdn.net/wzz4420381/article/details/79250137
AFE4410 I2C读参考代码如下:
int32_t AFE4410_Reg_Read(uint8_t RegAddress)
{
uint8_t tx_buf;
uint8_t rx_buf[3];
int32_t retVal;
uint8_t i2c_result = FALSE;
tx_buf = RegAddress;
i2c_result = I2cTransfer(AFE4410_DEVICE_ADDR, &tx_buf, 1, rx_buf, 3);
#ifdef PRINT_I2C_LOG
AFE4410_DEBUG (( "AFE4410 : read addr:%x, reg:%x, i2c_result:%d
", AFE4410_DEVICE_ADDR, tx_buf, i2c_result));
if (i2c_result)
{
AFE4410_DEBUG (( "AFE4410 : I2C RX[0]:%x, RX[1]:%x, RX[2]:%x
", rx_buf[0], rx_buf[1], rx_buf[2]));
}
#endif
retVal = rx_buf[0];
retVal = (retVal << 8) | rx_buf[1];
retVal = (retVal << 8) | rx_buf[2];
return retVal;
}
AFE4410 I2C写参考代码:
uint8_t AFE4410_Reg_Write(uint8_t RegAddress, uint32_t WriteData)
{
uint8_t tx_buf[4];
uint8_t i2c_result = FALSE;
tx_buf[0] = RegAddress;
tx_buf[1] = (uint8_t) (WriteData >> 16);
tx_buf[2] = (uint8_t) ((WriteData & 0x00FFFF) >> 8);
tx_buf[3] = (uint8_t) (WriteData & 0x0000FF);
i2c_result = I2cTransfer(AFE4410_DEVICE_ADDR, tx_buf, 4, NULL, 0);
#ifdef PRINT_I2C_LOG
AFE4410_DEBUG (( "AFE4410 : write addr:%x, reg:%x, i2c_result:%d
", AFE4410_DEVICE_ADDR, tx_buf[0], i2c_result));
if (i2c_result)
{
AFE4410_DEBUG (( "AFE4410 : I2C TX[0]:%x, TX[1]:%x, TX[2]:%x
", tx_buf[1], tx_buf[2], tx_buf[3]));
}
#endif
return i2c_result;
}
3.2. 关联AFE4410 FIFO读中断请求
将AFE4410的AFE_ADC_RDY连接到CSR8670的PIO口(建议PIO0-PIO15),在ADK Configuration tool中将此PIO口关联到一个event,并将触发方式设定为下降沿触发:
将这个事件内容替换成读取AFE4410的FIFO缓冲区:
case EventUsr3DEnhancementEnableDisableToggle:
AFE4410_ADC_RDY_MsgProcess();
break;
在event中读取AFE4410的FIFO缓冲区:
#define AFE_FIFO_DEPTH 20
void AFE4410_ADC_RDY_MsgProcess(void)
{
uint8_t index;
int32_t * pDataBuf = NULL;
pDataBuf = malloc(sizeof(int32_t) * AFE_FIFO_DEPTH);
if(!pDataBuf)
{
AFE4410_DEBUG (( "AFE4410_ADC_RDY_MsgProcess : pDataBuf not valid"));
return;
}
AFE4410_DEBUG (( "AFE4410_ADC_RDY_MsgProcess :
"));
for (index = 0; index < AFE_FIFO_DEPTH; index++)
{
pDataBuf[index] = AFE4410_Reg_Read(0xFF);
AFE4410_DEBUG(("%lx, ", pDataBuf[index]));
}
AFE4410_DEBUG (( "
"));
AFE4410_SetHrsValue((int8)(pDataBuf[0] & 0xFF));
free(pDataBuf);
}
对传感器采集到的数据需要进行FFT等处理,可在读取到FIFO的值后直接在VM层完成计算,也可以通过发送KalimbaSendLongMessage的方式发送给dsp处理,处理结果由DSP通过消息机制返回给VM层。
3.3. 使能GATT_HEART_RATE_SERVER
- 在sink工程的属性页中设置enable_heart_rate_server=1,编译后的固件即可支持gatt hrs server;
- 注意在ADK configuration tool的BLE profiles->BLE Advertising Report Filter中勾选HRS;
- 在EventUsrPowerOn事件中添加“MessageSendLater(&theSink.task, EventUsrBleStartBonding, 0, 2000);”打开BLE bonding,使得手机可以通过BLE连接到8670并使能此服务。
3.4. 定制BLE服务
参考文章:
https://blog.csdn.net/wzz4420381/article/details/78359481
4. 总结
- 在设置AFE4410的FIFO填充速度时,需要考虑CSR8670的最小可接受的外部中断间隔,这里不建议小于200ms。
- 读取到FIFO的值后,可以在VM层计算,也可以在DSP里计算;前者的好处是计算结果可以方便地通过BLE发送给手机,坏处是由于需要缓冲的数据较多,可能需要增加SRAM;后者的好处是可使用DSP的SRAM缓冲数据,坏处是需要维护DSP工程,开发难度大。
- 在使能BLE bonding事件后,手机只有在与耳机配对后才能获取到HRS的值,否则会提示BLE连接断开。