蓝牙H4传输层协议
蓝牙几种不同接口的传输协议:H2/H4/H5/BCSP/SDIO及区别
H2:基于USB的传输
H4:基于五线UART(RX/TX/CTS/RTS/GND带硬件流控)的传输,最简单的传输方式,只在HCI raw data前面加上一个type;
H5: 基于三线UART(RX/TX/GND)的传输,需要软件协议层加一个数据完整性校验机制;
BCSP: 基于UART的传输
SDIO :基于SDIO的传输
TRANSPORT层:在硬件接口(UART/USB/SDIO)实现HOST跟CONTROLLER的交互
H2: USB的transport
H4:UART的transport(是UART传输种最简的一个Transport,只是在HCI raw data的前面加一个type就行,如下HCI一共有五种HCI data)
* HCI COMMAND:由蓝牙协议栈发送给芯片的命令
* HCI EVENT:由蓝牙芯片上报给蓝牙协议栈的事件
* HCI ACL:蓝牙协议栈跟蓝牙芯片双向交互的普通数据* HCI SCO:蓝牙芯片跟蓝牙协议栈双向交互的通话/语音识别等音频数据
* HCI ISO(这部分是在core5.2才添加):LE audio用的数据包格式
蓝牙传输介质Transport UART H4(RS232)介绍
https://www.52bluetooth.com/portal.php?mod=view&aid=179&mobile=no
Transport H4介绍
1. 概念介绍
整个Transport在蓝牙架构中的位置如下图红框位置:
蓝牙Transport就是蓝牙的硬件发送协议,硬件的传输介质有:UART/USB/SDIO,那么Transport就是在特定的硬件传输介质上增加了一些协议,比如我们本节将的H4就是在UART上增加了一个小协议,H4算是最简单的一个协议,只是在数据前面加一个Type,了解过蓝牙HCI的一般都会知道蓝牙协议栈(Host)跟芯片(Controller)一般是通过HCI数据来沟通,那么H4就是在HCI数据前面加上一个TYPE。一共有5中type,如下:
1)HCI COMMAND:由蓝牙协议栈发送给芯片的命令
2)HCI EVENT:由蓝牙芯片上报给蓝牙协议栈的事件
3)HCI ACL:蓝牙协议栈跟蓝牙芯片双向交互的普通数据
4)HCI SCO:蓝牙芯片跟蓝牙协议栈双向交互的通话/语音识别等音频数据
5)HCI ISO(这部分是在core5.2才添加):用于发送LE audio
在Core文档截图如下:
交互数据格式为:
所以我们看下代码在这部分的实现:
1)通过宏配置协议栈的TRANSPORT type,可以看到以下代码是配置的H4
/** BT_PBUF_TRANSPORT_H2 = 0x01,BT_PBUF_TRANSPORT_H4 = 0x02,BT_PBUF_TRANSPORT_H5 = 0x03,BT_PBUF_TRANSPORT_BCSP = 0x04,*/ #define BT_TRANSPORT_TYPE 0x02
2)举例说明HCI reset发送(HCI raw data为0x03 0x0c 0x00)
err_t hci_reset(void) { struct bt_pbuf_t *p; /* 申请Transport的buffer,比HCI数据多了一个byte */ if((p = bt_pbuf_alloc(BT_TRANSPORT_TYPE, HCI_RESET_PLEN, BT_PBUF_RAM)) == NULL) { BT_HCI_TRACE_ERROR("ERROR:file[%s],function[%s],line[%d] bt_pbuf_alloc fail\n",__FILE__,__FUNCTION__,__LINE__); return BT_ERR_MEM; } /* Assembling command packet */ p = hci_cmd_ass(p, HCI_RESET, HCI_HOST_C_N_BB, HCI_RESET_PLEN); pcb->timer = utimer_create(HCI_RESET_TIMEOUT, hci_reset_timeout, 0); /* Assembling cmd prameters */ /* 发送HCI raw data在底层处理增加了1个byte */ phybusif_output(p, p->tot_len,PHYBUSIF_PACKET_TYPE_CMD); bt_pbuf_free(p); return BT_ERR_OK; }3)到了Transport的处理void phybusif_output(struct bt_pbuf_t *p, uint16_t len,uint8_t packet_type) { /* 后退1个byte */ bt_pbuf_header(p, 1); /* 填写上type */ ((uint8_t *)p->payload)[0] = packet_type; uint8_t *tx_buffer = bt_get_tx_buffer(); bt_pbuf_copy_partial(p, tx_buffer, p->tot_len, 0); BT_TRANSPORT_TRACE_DEBUG("BT TX LEN:%d\n",p->tot_len); bt_hex_dump(tx_buffer,p->tot_len); /* 通过UART发送出去 */ uart_bt_send(tx_buffer,p->tot_len); }2. 硬件要求
UART硬件配置要求总结:
1)数据位8bit
2)无奇偶校验
3)停止位1bit
4)需要有硬件流控
所以MCU跟蓝牙芯片的接线需要:
我们来看下代码的实现:
1)在STM32的UART初始化(只贴出关键位置)
/****************************************************************************** * func name : hw_uart_bt_init * para : baud_rate(IN) --> Baud rate of uart1 * return : hw_uart_bt_init result * description : Initialization of USART2.PA0->CTS PA1->RTS PA2->TX PA3->RX ******************************************************************************/ uint8_t hw_uart_bt_init(uint32_t baud_rate,uint8_t reconfig) { ............. /* Data format :1:8:1, no parity check, hardware flow control */ USART_InitStructure.USART_BaudRate = baud_rate; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_RTS_CTS; USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; ......... return BT_ERR_OK; }
2)在Linux的UART初始化(只贴出关键位置)
uint8_t hw_uart_bt_init(uint32_t baud_rate,uint8_t reconfig) { ...... // 8N1 toptions.c_cflag &= ~CSTOPB; toptions.c_cflag |= CS8; toptions.c_cflag |= CREAD | CLOCAL | CRTSCTS; toptions.c_iflag &= ~(IXON | IXOFF | IXANY); toptions.c_cflag &= ~PARENB; toptions.c_cc[VMIN] = 1; toptions.c_cc[VTIME] = 0; ....... return BT_ERR_OK; }
3. 纠错
如果主机或主机控制器在 RS232 通信上失去同步,则需要复位。失去同步意味着已检测到错误的 HCI 分组指示器,或 HCI 分组的长度域超出范围。如果在主机到主机控制器的通信中丢失 UART 同步,那么主机控制器将发送硬件故障(HCI hardware error)事件,以将同步错误告诉主机。主机控制器将需要从主机接收一个HCI_RESET 指令以执行复位。主机控制器也将在从主机到主机控制器的字节流中使用 HCI-RESET 指令,以实现重新同步。
如果在从主机控制器到主机的通信中失去 UART 同步,主机将发送 HCL_RESET指令以复位主机控制器。主机也将通过在从主机控制器到主机的字节流中查找HCI_Reset 指令的 HCL 指令完成事件,进行重新同步