Introduction to the initialization process of the Bluetooth protocol stack (taking CSR8311 as an example)

I. Statement

We will continue to update this column by serialization. The planned update of this column is as follows:

The first article: Comprehensive introduction to Bluetooth, mainly introduces some concepts of Bluetooth, its background, development track, introduction to Bluetooth on the market, and introduction to Bluetooth development boards.

The second part: Introduction to the Transport layer, mainly introduces the Bluetooth protocol stack and the hardware transmission protocols before the Bluetooth chip, such as UART-based H4,H5,BCSP, USB-based H2, etc.

The third part: Introduction of traditional Bluetooth controller, mainly introduces the introduction of traditional Bluetooth chips, including radio frequency layer (RF), baseband layer (baseband), link management layer (LMP), etc.

Part 4: Introduction to traditional Bluetooth host, mainly introduces the traditional Bluetooth protocol stack, such as HCI,L2CAP,SDP,RFCOMM,HFP,SPP,HID,AVDTP,AVCTP,A2DP,AVRCP,OBEX,PBAP,MAP, etc. Agreement.

Part 5: Introduction to Bluetooth low energy controller, mainly introduces Bluetooth low energy chips, including physical layer (PHY), link layer (LL)

Part 6: Introduction to low-power Bluetooth host, introduction of low-power Bluetooth protocol stack, including HCI,L2CAP,ATT,GATT,SM, etc.

Part 7: Introduction to Bluetooth chips, mainly introduces the initialization process of some Bluetooth chips, based on the extension of HCI vendor command

Chapter 8: Appendix, which mainly introduces the introduction of the above common terms and the introduction of some special processes.

In addition, the development board is shown below, which is the best set for those who want to learn the Bluetooth protocol stack. In order to better learn the Bluetooth protocol stack, believe me, after learning this set of videos, you will have the ability to modify any protocol stack (such as bluez under Linux, bluedroid under Android).

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

CSDN Academy link (enter to select the course you want to study): https://edu.csdn.net/lecturer/5352?spm=1002.2001.3001.4144

Bluetooth AC button group: 970324688

Github code: https://github.com/sj15712795029/bluetooth_stack

Start the development board: https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-22329603896.18.5aeb41f973iStr&id=622836061708

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

2. Introduction to traditional Bluetooth initialization

It is estimated that you will have a little sense of the Bluetooth protocol stack at the beginning of this section, and it does not seem to be that difficult. In this section, we will explain the initialization. After completing this section, you will be surprised to find that the Bluetooth device can be searched.

The author has also figured out a way to get the bluetooth chip to be searched without writing a line of code, so let's start this section (take the CSR8X11 bluetooth chip as an example, if it is a different chip, then the HCI vendor The command part will be different, we will explain more vendor command s of Bluetooth chips in the follow-up)!

The order of initialization command s for each Bluetooth protocol stack is slightly different, these are irrelevant. Take Snoop captured by our Bluetooth protocol stack as an example, the whole steps are as follows

It can be summed up as follows:

1) First of all, ensure that the hardware connection is normal. There is nothing to say about this. You can treat it as nonsense, haha, but I still want to mention two points of attention:

* Hardware wiring corresponding to Transport: If it is the transport of H4, then the TX/RX/CTS/RTS of the Bluetooth chip needs to be connected to the RX/TX/RTS/CTS of the MCU respectively. If it is H5 and BCSP, then only TX is connected /RX is enough (note that some chips in this part of the wiring have special requirements, so there will be changes), if it is H2, then there is nothing to talk about, just plug it into the USB port, SDIO is the same

*Bluetooth Enable/Reset pin is the hardware enable Bluetooth chip

2) Initialization of the corresponding Transport driver (UART/USB/SDIO, etc.)

3) Continue to send HCI_RESET until the chip responds and receives command complete with command opcode

4) Send Vendor command, then what is vendor command? It is the HCI command extended by the original chip manufacturer to set some behaviors of the chip, such as CSR's called BCCMD/PSKEY, TI's called BTS, BCM's called HCD, etc. We describe these in detail later

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

Starting from the following is the use of the command part of the HCI core document. The definition of each protocol stack will be different. Mine is the most simplified.

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

5) Send Read Buffer Size command and receive command complete with command opcode

6) Send Read BT address command and receive command complete with command opcode.

7) Send Write code command and receive command complete with comand opcode.

8) Send Change Local Name command and receive command complete with comand opcode.

9) Send Write page timeout command and receive command complete with comand opcode.

10) Send Write set Event Mask command and receive command complete with comand opcode.

11) Send Write Write Simple Pairing command, receive command complete with comand

12) Send Write Scan Enable command and receive command complete with comand opcode.

Below we describe the steps in detail:

Step 1) Ensure that the hardware connection is normal

Step 2) Initialization of the corresponding Transport driver (UART/USB/SDIO, etc.)

Let's take UART, Transport H4 as an example, first look at the UART initialization of STM32F103

/******************************************************************************
 * 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)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    if(reconfig == 0)
        ringbuffer_init(&bt_ring_buf,bt_rx_buf,BT_RX_BUF_SIZE);
    /* Enable USART2,GPIOA,DMA1 RCC clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    USART_DeInit(USART2);
    USART_Cmd(USART2, DISABLE);
    /* Initialize the GPIOA0,GPIOA1,GPIOA2,GPIOA3 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* 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;

    /* Enable USART interrupts, mainly for idle interrupts */
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=BT_PREE_PRIO;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = BT_SUB_PRIO;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* Initializes USART2 to enable USART,USART idle interrupts, and USART RX DMA */
    USART_Init(USART2, &USART_InitStructure);
    USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);
    USART_DMACmd(USART2,USART_DMAReq_Rx,ENABLE);
    USART_Cmd(USART2, ENABLE);

    /* Initializes DMA and enables it */
    hw_memset(&DMA_UART2,0,sizeof(DMA_InitTypeDef));
    DMA_DeInit(DMA1_Channel6);
    DMA_UART2.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR;
    DMA_UART2.DMA_MemoryBaseAddr = (uint32_t)bt_dma_rx_buf;
    DMA_UART2.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_UART2.DMA_BufferSize = BT_DMA_BUF_SIZE;
    DMA_UART2.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_UART2.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_UART2.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_UART2.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_UART2.DMA_Mode = DMA_Mode_Normal;
    DMA_UART2.DMA_Priority = DMA_Priority_Medium;
    DMA_UART2.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel6, &DMA_UART2);

    DMA_Cmd(DMA1_Channel6, ENABLE);

    return BT_ERR_OK;

}

Let's take Linux UART Transport H4 as an example



uint8_t hw_uart_bt_init(uint32_t baud_rate,uint8_t reconfig)
{
    speed_t baudrate;
    int flags = O_RDWR | O_NOCTTY;

    struct termios toptions;
    if(baud_rate == 115200)
        baudrate =  B115200;
    else
        baudrate =  B921600;
    if(reconfig == 0)
    {
        ringbuffer_init(&bt_ring_buf,bt_rx_buf,BT_RX_BUF_SIZE);
    }

    printf("phybusif_open /dev/ttyUSB0\n");

    uart_if.phyuart_fd = open("/dev/ttyUSB0", flags);
    if (uart_if.phyuart_fd == -1)
    {
        printf("ERROR:Unable to open port /dev/ttyUSB0\n");
        return -1;
    }

    printf("uart_if.phyuart_fd %d\n",uart_if.phyuart_fd);
    if (tcgetattr(uart_if.phyuart_fd, &toptions) < 0)
    {
        printf("ERROR:Couldn't get term attributes\n");
        return -1;
    }

    cfmakeraw(&toptions);

    // 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;

    if(tcsetattr(uart_if.phyuart_fd, TCSANOW, &toptions) < 0)
    {
        printf("ERROR:Couldn't set term attributes\n");
        return -1;
    }

    if (tcgetattr(uart_if.phyuart_fd, &toptions) < 0)
    {
        printf("ERROR:Couldn't get term attributes\n");
        return -1;
    }
    cfsetospeed(&toptions, baudrate);
    cfsetispeed(&toptions, baudrate);


    if( tcsetattr(uart_if.phyuart_fd, TCSANOW, &toptions) < 0)
    {
        printf("ERROR:Couldn't set term attributes\n");
        return -1;
    }

    return BT_ERR_OK;

}

Step 3) Send HCI Reset and response, HCI reset format is as follows

There are no parameters, let's take a look at the btsnoop directly captured by Wireshark

The response is as follows:

Step 4) Send Vendor command

We will not talk about the vendor command in detail here, just list the raw data of the CSR8X11 vendor command first.

/*************************************************************************************************
HCI command  PACKETS Format:
	opcode 16 bit
	para total len 8 bit
	para 0
**************************************************************************************************/

/*************************************************************************************************
BCCMD PACKETS Format:
           |	  type   |	length   |	seqno   |		varid	|	status   |	payload···	|
 uint 16   |	    1    |       2     |      3     |       4       |     5      |        6~        |
**************************************************************************************************/

/*************************************************************************************************
BCCMD PS PACKETS Format:
           |	  header  |	key   |	length    |	stores      |		ps value  	|
 uint 16   |	    1-5   |    6    |      7     |       8        |      9~           |
**************************************************************************************************/
// minimal CSR init script to configure PSKEYs and activate them
uint8_t csr8x11_initscript[] =
{
    //  Set PSKEY_DEEP_SLEEP_STATE never deep sleep
    0x13, 0xc2, 0x02, 0x00, 0x09, 0x00, 0x02, 0x00, 0x03, 0x70, 0x00, 0x00, 0x29, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,

    //  Set ANA_Freq to 26MHz
    0x13, 0xc2, 0x02, 0x00, 0x09, 0x00, 0x03, 0x00, 0x03, 0x70, 0x00, 0x00, 0xfe, 0x01, 0x01, 0x00, 0x08, 0x00, 0x90, 0x65,

    //  Set CSR_PSKEY_ANA_FTRIM 0x24 for csr8811
    0x13, 0xc2, 0x02, 0x00, 0x09, 0x00, 0x04, 0x00, 0x03, 0x70, 0x00, 0x00, 0xf6, 0x01, 0x01, 0x00, 0x08, 0x00, 0x24, 0x00,

    // Set CSR_PSKEY_DEFAULT_TRANSMIT_POWER 0x4
    0x13, 0xc2, 0x02, 0x00, 0x09, 0x00, 0x05, 0x00, 0x03, 0x70, 0x00, 0x00, 0x21, 0x00, 0x01, 0x00, 0x08, 0x00, 0x04, 0x00,

    // Set CSR_PSKEY_MAXIMUM_TRANSMIT_POWER 0x4
    0x13, 0xc2, 0x02, 0x00, 0x09, 0x00, 0x06, 0x00, 0x03, 0x70, 0x00, 0x00, 0x17, 0x00, 0x01, 0x00, 0x08, 0x00, 0x04, 0x00,

    // Set CSR_PSKEY_BLE_DEFAULT_TRANSMIT_POWER 0x4
    0x13, 0xc2, 0x02, 0x00, 0x09, 0x00, 0x07, 0x00, 0x03, 0x70, 0x00, 0x00, 0xc8, 0x22, 0x01, 0x00, 0x08, 0x00, 0x04, 0x00,

    // Set CSR_PSKEY_BDADDR
    0x19, 0xc2, 0x02, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x03, 0x70, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x08, 0x00, 0x20, 0x00, 0x99, 0x1a, 0x86, 0x00, 0x1d, 0x00,

    // Set CSR_PSKEY_PCM_CONFIG32
    0x15, 0xc2, 0x02, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x03, 0x70, 0x00, 0x00, 0xb3, 0x01, 0x02, 0x00, 0x08, 0x00, 0x80, 0x08, 0x80, 0x18,

    // Set CSR_PSKEY_PCM_FORMAT 0x60
    0x13, 0xc2, 0x02, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x03, 0x70, 0x00, 0x00, 0xb6, 0x01, 0x01, 0x00, 0x08, 0x00, 0x60, 0x00,

    // Set CSR_PSKEY_USER_LOW_JITTER_MODE
    0x13, 0xc2, 0x02, 0x00, 0x09, 0x00, 0x0b, 0x00, 0x03, 0x70, 0x00, 0x00, 0xc9, 0x23, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00,

    //  Set HCI_NOP_DISABLE
    0x13, 0xc2, 0x02, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x03, 0x70, 0x00, 0x00, 0xf2, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00,

    // Set UART baudrate to 921600
    0x15, 0xc2, 0x02, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x03, 0x70, 0x00, 0x00, 0xea, 0x01, 0x02, 0x00, 0x08, 0x00,0x0e,0x00,0x00,0x10,/*0x1b, 0x00, 0x40, 0x77,*/

    //  WarmReset
    0x13, 0xc2, 0x02, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

Step 5) Send Read Buffer Size command and receive command complete with command opcode

Let's take a look at the packet format of the Read Buffer Size command (OGF=0x04)

Grab Wireshark btsnoop as follows:

The response is as follows:

Sep 6) Send Read BT address command and receive command complete with command opcode.

Let's take a look at the packet format of the Read BT address command (OGF=0x04)

Grab Wireshark btsnoop as follows:

The response is as follows:

Step 7) Send Write code command and receive command complete with comand opcode.

Let's take a look at the packet format of Write cod command (OGF=0x04)

Grab Wireshark btsnoop as follows:

The response is as follows:

Step 8) Send Change Local Name command and receive command complete with comand opcode.

Let's take a look at the packet format of the Change Local Name command (OGF=0x03)

The parameter is a bit special, especially posted, no matter how long your name is, for example, it is called Wireless_link, but it must be enough to 248byte, this is the definition of SIG's core document, but there is one point, I have tested it myself, do not need 248byte It's okay, but it's better to follow the SIG specification. There is no problem with the CSR8311 chip, which does not mean that other chips can.

Grab Wireshark btsnoop as follows:

The response is as follows:

Step 9) Send Write page timeout command and receive command complete with comand opcode.

Let's take a look at the packet format of the Write page timeout command (OGF=0x03)

The parameters are as follows:

Grab Wireshark btsnoop as follows:

The response is as follows:

Step 10) Send Set Event Mask and receive command complete with comand opcode.

Let's take a look at the packet format of Set Event Mask (OGF=0x03)

parameter:

Event_Mask: The time mask generated by the chip

Grab Wireshark packets:

The response is as follows:

Step 11) Send Write Simple Pairing command and receive command complete with comand opcode.

Let's take a look at the packet format of Write Simple Pairing (OGF=0x03)

parameter:

Simple_Pairing_mode: Set the parameters of SSP

Grab Wireshark packets:

The response is as follows:

This part of the code is configured in bt_conf.h

/***********   bluetooth function option **************************************/
/** BT_PBUF_TRANSPORT_H2 = 0x01,BT_PBUF_TRANSPORT_H4 = 0x02,BT_PBUF_TRANSPORT_H5 = 0x03,BT_PBUF_TRANSPORT_BCSP = 0x04,*/
#define BT_ENABLE_SNOOP 1
#define BT_TRANSPORT_TYPE 0x02
#define BT_ENABLE_SSP 0 /************This place configures SSP********************/
/* IO_CAP_DISPLAY_ONLY->0x00 IO_CAP_DISPLAY_YES_NO->0x01 IO_CAP_KEYBOARD_ONLY->0x02 IO_CAP_NOINPUT_OUTPUT->0x03 */
#define BT_SSP_IOCAP_CONF 3
#define BT_CLASS_OF_DEVICE 0x200408;
#define BT_LOCAL_NAME "BT_DEMO"
#define BT_PIN_CODE "0000"
#define BT_TIMER_COUNT 64 /* TIMER COUNT */

If this part is configured as 1, then the default SSP pairing, if it is 0, then the PINCODE pairing

Step 12) Send Write Scan Enable command and receive command complete with comand opcode.

Let's take a look at the packet format of Write Scan enablecommand (OGF=0x03)

The parameters are as follows:

Grab Wireshark btsnoop as follows:

The response is as follows:

Speaking of this, the initialization of the Bluetooth protocol stack is basically completed, but the vendor command part of each chip is slightly different (that is, Step 4). Later, we will slowly expand more chips, thank you.

Posted by bumbar on Wed, 25 May 2022 22:44:40 +0300