SYD8801是一款低功耗高性能蓝牙低功耗SOC,集成了高性能2.4GHz射频收发机、32位ARM Cortex-M0处理器、128kB Flash存储器、以及丰富的数字接口。SYD8801片上集成了Balun无需阻抗匹配网络、高效率DCDC降压转换器,适合用于可穿戴、物联网设备等。具体可咨询:http://www.sydtek.com/
ble_sched_execute函数
该函数把要写进flash的数据写到falsh中,因为写flash的操作比较耗时,如果把比较耗时的工作放到协议栈中进行的话这些操作将会阻塞蓝牙协议栈的正常运行,造成蓝牙工作异常。所以SYD8801的协议栈在要写数据到flash的时候只是把数据放到内存中,然后在主循环中调用ble_sched_execute把放在内存的数据写到flash中,这样错开了比较耗时的flash操作和要求快速响应的协议栈操作。
另外注意:
操作内部3Kfalsh的API是ReadProfileData和WriteProfileData,这两个函数的最终操作依旧是在ble_sched_execute函数中进行的,所以不会阻塞协议栈,可以在中断函数中调用。
操作内部24Kfalsh的API是ble_flash_erase、ble_flash_read和ble_flash_write,这三个函数直接操作falsh并没有在ble_sched_execute函数中进行的,所以这三个函数会阻塞协议栈的,不能在任何中断服务函数中调用。
相关的内部3K和24Kflash的操作请看:http://blog.csdn.net/chengdong1314/article/details/60957122
BLE_SendData函数
BLE_SendData函数是蓝牙发送函数,这里调用GATTDataSend协议栈函数来做具体的发送操作,GATTDataSend函数API解析如下:
uint8_t GATTDataSend(uint8_t type, struct gap_att_report* p_report, uint8_t len, uint8_t *p_data);
Transmit packet.发送数据包函数,既可以通过notify形式发送,也可以通过INDICATION形式发送
Parameters
[in] | type | 1 : BLE_GATT_NOTIFICATION 通知形式发送数据 |
2 : BLE_GATT_INDICATION 指示形式发送数据 | ||
[in] | p_report | Pointer to report structure. 配置发送的gap_att_report结构体 |
[in] | len | Data length for p_data. 要发送的数据长度 |
[in] | p_data | Raw data to be transmit. 要发送的数据的指针 |
Returns
1 : setup success.
0 : invalid pointer supplied.
其中gap_att_report结构体定义如下:
struct gap_att_report {
uint16_t primary; //要发送的蓝牙通道的主要服务的UUID
uint16_t uuid; //要发送的蓝牙通道的特性的UUID
uint16_t hdl; //要发送的蓝牙通道的特性的VAL handle
uint16_t config; //发送的时候没用
uint16_t value; //发送数据的形式 BLE_GATT_NOTIFICATION:通知形式发送数据;BLE_GATT_INDICATION:指示形式发送数据
};
这里的hdl是特性下面的val_hdl的意思,如果在工具中的定义:
协议栈底层做有了数据缓冲区,当在上一个数据包没有发送完成的时候又调用了GATTDataSend函数,那么根据蓝牙规范将会使用更加快速的more data数据传输方式。所以只要GATTDataSend函数没有返回0,那么应用层就可以再次调用该函数进行数据的填充,这样速度更加的快!
比如这里有一个要发送的很大的数据块,数据存放在Send_char_buf数组中,可以通过下面的方式把这个超大的数组发送出去:
void synch_data(void){
if(synch_history_data==1){
if(send_section_cur_num<=send_section_num)
{
uint8_t send_buffer[20]={0};
uint8_t i=0,num=send_section_num-send_section_cur_num+1;
for(i=0;i
if(send_section_cur_num>=send_section_num)
{
if(BLE_SendData(send_buffer,((Send_char_buf[1]+3)%20))){
send_section_cur_num=0;
send_section_num=0;
synch_history_data=0;
}
else break;
}
else
{
if(BLE_SendData(send_buffer,20)) send_section_cur_num++;
else break;
}
}
}else synch_history_data=0;
}
}
这里的BLE_SendDa函数源代码如下:
uint8_t BLE_SendData(uint8_t *buf, uint8_t len)
{
if(start_tx == 1)
{
struct gap_att_report report;
if(wechat_tx)
{
report.primary = BLE_SERVICE_UUID_WECHAT;
report.uuid = BLE_SERVICE_UUID_WECHAT_INDICATE;
report.hdl = BLE_HANDLE;
report.value = BLE_GATT_INDICATION;
if(len > 20) len = 20;
return GATTDataSend(BLE_GATT_INDICATION, &report, len, buf);
}
else
{
report.primary = BLE_SERVICE_UUID_UART;
report.uuid = BLE_SERVICE_UUID_UART_NOTIFICATION;
report.hdl = 0x0001F;
report.value = BLE_GATT_NOTIFICATION;
return GATTDataSend(BLE_GATT_NOTIFICATION, &report, len, buf);
}
}
return 0;
}
注意:上面的办法是在不改蓝牙连接参数的情况下提高SYD8801发送数据到手机APP的速度,如果要更加彻底的提速就要修改蓝牙连接参数。提高蓝牙连接参数的方式如下:http://blog.csdn.net/chengdong1314/article/details/68941988
ble_init函数是SYD8801的协议栈初始化函数,该函数初始化BLE协议栈并且设置广播,扫描,地址等等,具体注释如下:
static void ble_init() //应用层初始化函数接口(在用户代码中)
{
struct gap_evt_callback evt;
struct smp_pairing_req sec_params;
struct gap_wakeup_config pw_cfg;
struct gap_ble_addr ble_addr;
BleInit(); //调用协议栈的初始化,该函数封装在协议栈中,属于底层的初始化函数
/*因为SYD8801的广播要通过定时器来控制(具体请看:https://blog.csdn.net/chengdong1314/article/details/60871037中《蓝牙广播的实现》这节),如果时钟的选择放在ble_init函数,那么不免对时间的准确度造成一定的影响,关于这方面的优化请看:https://blog.csdn.net/chengdong1314/article/details/73929998中《时钟源准确度的优化》这节,定时器的时钟源如果选择内部的RC振荡器可能会带来定时器不准确等问题,定时器不准确对BLE的连接也是有影响的,所以如果选择内部RC振荡器的话必须要进行校准的工作,具体校准方式请看:https://blog.csdn.net/chengdong1314/article/details/60871037中《使用内部晶振》这节 */
MCUClockSwitch(SYSTEM_CLOCK_8M_RCOSC); //设置MCS的时钟为8M
ClockSwitch(SYSTEM_32K_CLOCK_XOSC); //设置定时器的时钟源外外部晶振
/*SYD8801的profile把notify和indicate两种GATT service行为集合称为report,专门设立结构体gap_att_report_handle保存了report的相应属性信息,每个CCCD对应着结构体gap_att_report_handle中的一个数组成员。包括本CCCD所在的位置(其主要服务,特性,val_hdl)等,GetGATTReportHandle函数获取gap_att_report_handle结构体*/
GetGATTReportHandle(&g_report); //获取gap_att_report_handle
/* security parameters */
sec_params.io = IO_NO_INPUT_OUTPUT;
sec_params.oob = OOB_AUTH_NOT_PRESENT;
sec_params.flags = AUTHREQ_BONDING;
sec_params.mitm = 0;
sec_params.max_enc_sz = 16;
sec_params.init_key = 0;
sec_params.rsp_key = (SMP_KEY_MASTER_IDEN |SMP_KEY_ADDR_INFO);
SetSecParams(&sec_params); //设置安全参数 具体可看:https://blog.csdn.net/chengdong1314/article/details/78821868中《安全参数的设置说明》这节
evt.evt_mask=(GAP_EVT_CONNECTION_SLEEP|GAP_EVT_CONNECTION_INTERVAL);//屏蔽的事件,目前请如此设置
evt.p_callback=&ble_evt_callback; //协议栈回调函数(接口) 是个函数指针
SetEvtCallback(&evt); //设置协议栈事件回调
/* bluetooth address */ //设置蓝牙地址,如果这里设置了地址,那么最后设备将使用该地址
ble_addr.type = RANDOM_ADDRESS_TYPE;
ble_addr.addr[0] = 0x55;
ble_addr.addr[1] = 0x44;
ble_addr.addr[2] = 0x33;
ble_addr.addr[3] = 0x22;
ble_addr.addr[4] = 0x11;
ble_addr.addr[5] = 0xff;
SetDevAddr(&ble_addr);
/* Bond Manager (MAX:10) */ //设置绑定索引,这里默认设置为0
SetBondManagerIndex(0x00);
setup_adv_data(); //设置广播数据 具体请看:https://blog.csdn.net/chengdong1314/article/details/60871037中《蓝牙广播的实现》这节
pw_cfg.wakeup_type = SLEEP_WAKEUP;
pw_cfg.timer_wakeup_en = 1;
pw_cfg.gpi_wakeup_en = 0;
pw_cfg.gpi_wakeup_cfg = 0x00C00000;
WakeupConfig(&pw_cfg); //设置睡眠以及唤醒源,具体请看:https://blog.csdn.net/chengdong1314/article/details/70233652
}