Просмотр исходного кода

Merge pull request #1 from alteracd/main

feat: chipset:BlueNRG2 HCI:SPI
bobwenstudy 2 лет назад
Родитель
Сommit
d7fbfe5e3c

+ 8 - 0
chipset/bluenrg2/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(CHIPSET_PATH)
+
+# define include directory
+INCLUDE	+= $(CHIPSET_PATH)
+
+# define lib directory
+LIB		+=

+ 283 - 0
chipset/bluenrg2/chipset_bluenrg2.c

@@ -0,0 +1,283 @@
+#include <errno.h>
+
+#include "chipset_bluenrg2.h"
+#include <logging/bt_log_impl.h>
+
+#define STATE_POLLING_NONE      0
+#define STATE_POLLING_BOOTING   1
+#define STATE_POLLING_PREPARING 2
+
+int state;
+int step;
+
+#define CONFIG_DATA_LL_WITHOUT_HOST         (0x2C) /**< Switch on/off Link Layer only mode. Set to 1 to disable Host. */
+#define CONFIG_DATA_LL_WITHOUT_HOST_LEN     (1)
+
+static int bluenrg2_config_without_host()
+{
+    uint8_t cmd_buffer[CONFIG_DATA_LL_WITHOUT_HOST_LEN + 2];
+    struct net_buf *buf;
+
+    cmd_buffer[0] = CONFIG_DATA_LL_WITHOUT_HOST;                //offset
+    cmd_buffer[1] = CONFIG_DATA_LL_WITHOUT_HOST_LEN;            //config len
+    cmd_buffer[2] = 1;                                          //Set to 1 to disable Host
+
+    uint16_t ogf = 0x3f, ocf = 0x00c;
+    uint16_t opcode = (uint16_t)((ocf & 0x03ff)|(ogf << 10));
+
+    buf = bt_hci_cmd_create(opcode, sizeof(cmd_buffer));
+    if (!buf)
+    {
+        return -ENOBUFS;
+    }
+    net_buf_add_mem(buf, cmd_buffer, sizeof(cmd_buffer));
+
+    return bt_hci_cmd_send(opcode, buf);
+}
+
+#define BLE_MAC_ADDR                                                                               \
+    {                                                                                              \
+        {                                                                                          \
+            0xf5, 0x00, 0x00, 0xE1, 0x80, 0x02                                                   \
+        }                                                                                          \
+    }
+#define CONFIG_DATA_PUBADDR_OFFSET          (0x00) /**< Bluetooth public address */
+#define CONFIG_DATA_PUBADDR_LEN             (6)
+
+static int bluenrg2_config_set_public_addr()
+{
+    //uint8_t cmd_buffer[258];
+    uint8_t cmd_buffer[CONFIG_DATA_PUBADDR_LEN + 2];
+    struct net_buf *buf;
+    bt_addr_t addr = BLE_MAC_ADDR;
+
+    cmd_buffer[0] = CONFIG_DATA_PUBADDR_OFFSET;                 //offset
+    cmd_buffer[1] = CONFIG_DATA_PUBADDR_LEN;                    //config len
+    memcpy(cmd_buffer + 2, addr.val, CONFIG_DATA_PUBADDR_LEN);   // addr
+
+    uint16_t ogf = 0x3f, ocf = 0x00c;
+    uint16_t opcode = (uint16_t)((ocf & 0x03ff)|(ogf << 10));
+
+    buf = bt_hci_cmd_create(opcode, sizeof(cmd_buffer));
+    if (!buf)
+    {
+        return -ENOBUFS;
+    }
+    net_buf_add_mem(buf, cmd_buffer, sizeof(cmd_buffer));
+
+    return bt_hci_cmd_send(opcode, buf);
+}
+
+/**
+ * @brief This command sets the TX power level of the device. By controlling the
+ *        EN_HIGH_POWER and the PA_LEVEL, the combination of the 2 determines
+ *        the output power level (dBm).  When the system starts up or reboots,
+ *        the default TX power level will be used, which is the maximum value of
+ *        8 dBm. Once this command is given, the output power will be changed
+ *        instantly, regardless if there is Bluetooth communication going on or
+ *        not. For example, for debugging purpose, the device can be set to
+ *        advertise all the time. And use this command to observe the signal
+ *        strength changing. The system will keep the last received TX power
+ *        level from the command, i.e. the 2nd command overwrites the previous
+ *        TX power level. The new TX power level remains until another Set TX
+ *        Power command, or the system reboots.
+ * @param En_High_Power Enable High Power mode.  High power mode should be
+ *        enabled only to reach the maximum output power.
+ *        Values:
+ *        - 0x00: Normal Power
+ *        - 0x01: High Power
+ * @param PA_Level Power amplifier output level. The allowed PA levels depends
+ *        on the device (see user manual to know wich output power is expected
+ *        at a given PA level). The obtained output power can also depend on PCB
+ *        layout and associated components.
+ *        Values:
+ *        - 0: -14 dBm (High Power)
+ *        - 1: -11 dBm (High Power)
+ *        - 2: -8 dBm (High Power)
+ *        - 3: -5 dBm (High Power)
+ *        - 4: -2 dBm (High Power)
+ *        - 5: 2 dBm (High Power)
+ *        - 6: 4 dBm (High Power)
+ *        - 7: 8 dBm (High Power)
+ * @retval Value indicating success or error code.
+ */
+static int bluenrg2_set_tx_power_level(uint8_t En_High_Power, uint8_t PA_Level)
+{
+    //uint8_t cmd_buffer[258];
+    uint8_t cmd_buffer[2];
+    struct net_buf *buf;
+
+    cmd_buffer[0] = En_High_Power;      //En_High_Power
+    cmd_buffer[1] = PA_Level;           //config PA_Level
+
+    uint16_t ogf = 0x3f, ocf = 0x00f;
+    uint16_t opcode = (uint16_t)((ocf & 0x03ff)|(ogf << 10));
+
+    buf = bt_hci_cmd_create(opcode, sizeof(cmd_buffer));
+    if (!buf)
+    {
+        return -ENOBUFS;
+    }
+    net_buf_add_mem(buf, cmd_buffer, sizeof(cmd_buffer));
+
+    return bt_hci_cmd_send(opcode, buf);
+}
+
+
+static int  bluenrg2_gatt_init(void)
+{
+    uint16_t ogf = 0x3f, ocf = 0x101;
+    uint16_t opcode = (uint16_t)((ocf & 0x03ff)|(ogf << 10));
+
+    return bt_hci_cmd_send(opcode, NULL);
+}
+
+/**
+ * @brief Initialize the GAP layer. Register the GAP service with the GATT. All
+ *        the standard GAP characteristics will also be added: - Device Name -
+ *        Appearance - Peripheral Preferred Connection Parameters (peripheral
+ *        role only)  WARNING: A section of the Flash memory (pointed by
+ *        stored_device_id_data_p) is used by this procedure. When this section
+ *        is empty, data are written inside. This normally happens once during
+ *        the lifetime of the device, when the command is executed for the first
+ *        time (or every time it is called after that section has been erased).
+ *        Do not power off the device while this function is writing into Flash
+ *        memory. If the functions returns FLASH_WRITE_FAILED, it means that the
+ *        flash area pointed by stored_device_id_data_p is corrupted (probably
+ *        due to a power loss during the first call to aci_gap_init()). To fix
+ *        the problem, that flash area has to be erased, so that the
+ *        aci_gap_init() can reinitialize it correctly.
+ * @param Role Bitmap of allowed roles.
+ *        Flags:
+ *        - 0x01: Peripheral
+ *        - 0x02: Broadcaster
+ *        - 0x04: Central
+ *        - 0x08: Observer
+ * @param privacy_enabled Specify if privacy is enabled or not and which one .
+ *        Values:
+ *        - 0x00: Privacy disabled
+ *        - 0x01: Privacy host enabled
+ *        - 0x02: Privacy controller enabled
+ * @param device_name_char_len Length of the device name characteristic
+ *        Values:
+ *        - 0 ... 248
+ * @param[out] Service_Handle Handle of the GAP service
+ * @param[out] Dev_Name_Char_Handle Device Name Characteristic handle
+ * @param[out] Appearance_Char_Handle Appearance Characteristic handle
+ * @retval Value indicating success or error code.
+ */
+#define GAP_PERIPHERAL_ROLE                     (0x01)
+#define GAP_BROADCASTER_ROLE                    (0x02)
+#define GAP_CENTRAL_ROLE                        (0x04)
+#define GAP_OBSERVER_ROLE                       (0x08)
+#define privacy_enabled                         (0x00)
+#define device_name_char_len                    (0x08)
+
+static int bluenrg2_gap_init()
+{
+    uint8_t cmd_buffer[3];
+    struct net_buf *buf;
+
+    cmd_buffer[0] = GAP_PERIPHERAL_ROLE;    //role
+    cmd_buffer[1] = privacy_enabled;        //privacy
+    cmd_buffer[2] = device_name_char_len;   //device_name_char_len
+
+    uint16_t ogf = 0x3f, ocf = 0x08a;
+    uint16_t opcode = (uint16_t)((ocf & 0x03ff)|(ogf << 10));
+
+    buf = bt_hci_cmd_create(opcode, sizeof(cmd_buffer));
+    if (!buf)
+    {
+        return -ENOBUFS;
+    }
+    net_buf_add_mem(buf, cmd_buffer, sizeof(cmd_buffer));
+
+    return bt_hci_cmd_send(opcode, buf);
+}
+
+void init_work(void){
+    state = STATE_POLLING_BOOTING;
+    step = 0;
+}
+
+void boot_start(void) {
+    state = STATE_POLLING_BOOTING;
+    // nothing to do
+    bt_hci_set_boot_ready();          //finish boot
+}
+
+void prepare_start(void) {
+    state = STATE_POLLING_PREPARING;
+    step = 1;
+    // step 1 close host
+    bluenrg2_config_without_host(); // It can be written only if aci_hal_write_config_data() is the first command after reset.
+}
+
+void event_process(uint8_t event, struct net_buf *buf)
+{
+    if(state == STATE_POLLING_PREPARING) // boot do nothing
+    {
+        if (event == BT_HCI_EVT_CMD_COMPLETE)  //only complete
+        {
+            printk("prepare_event_process, step: %d\n", step);
+            switch (step)
+            {
+            case 1: //close host just now
+                bluenrg2_config_set_public_addr();  //step2  set_public_addr
+                step = 2;
+                break;
+            case 2:
+                bluenrg2_set_tx_power_level(1, 4);  //step3  set_public_addr
+                step = 3;
+                break;
+            case 3:
+                bluenrg2_gatt_init();               //step4  gatt_ini
+                step = 4;
+                break;
+            case 4:
+                bluenrg2_gap_init();                //step5  gap_ini
+                step = 5;
+                break;
+            case 5:
+                bt_hci_set_prepare_ready();          //finish prepare
+                step = 0;
+                break;
+            }
+        }
+    }
+}
+
+
+static const struct bt_hci_chipset_driver chipset_drv = {
+        init_work, boot_start, prepare_start, event_process,
+};
+
+// public drv API
+const struct bt_hci_chipset_driver *bt_hci_chipset_impl_local_instance(void)
+{
+    return &chipset_drv;
+}
+
+// For test, you can set your customor setting here.
+static const bt_usb_interface_t usb_interface = {0, 0};
+
+const bt_usb_interface_t *bt_chipset_get_usb_interface(void)
+{
+    return &usb_interface;
+}
+
+// For test, you can set your customor setting here.
+static const bt_uart_interface_t uart_interface = {115200, 8, 1, 0, true};
+const bt_uart_interface_t *bt_chipset_get_uart_interface(void)
+{
+    return &uart_interface;
+}
+
+// For test, you can set your customor setting here.
+static const bt_BlueNRG_SPI_interface_t spi_interface = {1, 0, 1 * 1000 * 1000, 8, 1, 0, 0, 1};
+//for Nucleo-L476RG BLUENRG2:  {PA1(1), PA0(0), 1MHz, 8bits, MSB, Master, CPOL = 0, CPHA = 1};
+
+const bt_BlueNRG_SPI_interface_t *bt_BlueNRG_get_SPI_interface(void)
+{
+    return &spi_interface;
+}

+ 14 - 0
chipset/bluenrg2/chipset_bluenrg2.h

@@ -0,0 +1,14 @@
+#ifndef _CHIPSET_BLUENRG2_H_
+#define _CHIPSET_BLUENRG2_H_
+
+#include "chipset_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_CHIPSET_BLUENRG2_H_

+ 13 - 0
chipset/chipset_interface.h

@@ -23,8 +23,21 @@ typedef struct
     bool flowcontrol;
 } bt_uart_interface_t;
 
+typedef struct
+{
+    int cs_pin_num;         /* RT-Thread drv_gpio number of SPI CS PIN */
+    int irq_pin_num;        /* RT-Thread drv_gpio number of SPI IRQ PIN */
+    uint32_t rate;
+    int data_width;         /* Data width: 8bits, 16bits, 32bits */
+    int LSB_MSB;            /* Data transmission order: LSB:0 MSB:1 */
+    int Master_Slave;       /* Set the master-slave mode of SPI:  Master:0 Slave:1 */
+    int CPOL;               /* Set clock polarity(CPOL):  0 1 */
+    int CPHA;               /* Set clock phase(CPHA):  0 1 */
+} bt_BlueNRG_SPI_interface_t;
+
 const bt_usb_interface_t *bt_chipset_get_usb_interface(void);
 const bt_uart_interface_t *bt_chipset_get_uart_interface(void);
+const bt_BlueNRG_SPI_interface_t *bt_BlueNRG_get_SPI_interface(void);
 
 const struct bt_hci_chipset_driver *bt_hci_chipset_impl_local_instance(void);
 

+ 364 - 0
platform/rtthread/rtthread_driver_spi.c

@@ -0,0 +1,364 @@
+
+#ifndef APPLICATIONS_HCI_INTERFACE_C_
+#define APPLICATIONS_HCI_INTERFACE_C_
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include "drv_gpio.h"
+#include "rtthread_driver_spi.h"
+
+#include "drivers/hci_driver.h"
+#include "drivers/hci_h4.h"
+
+#include "logging/bt_log_impl.h"
+#include "common/bt_buf.h"
+
+struct hci_trans_spi_config {
+    const char *device_name;    /* spi device name, i.e. "spi1" */
+    const char *bus_name;       /* spi BUS name, i.e. "spi10" */
+    int cs_pin_num;         /* RT-Thread drv_gpio number of SPI CS PIN */
+    int irq_pin_num;        /* RT-Thread drv_gpio number of SPI IRQ PIN */
+    uint32_t rate;
+    int data_width;         /* Data width: 8bits, 16bits, 32bits */
+    int LSB_MSB;            /* Data transmission order: LSB:0 MSB:1 */
+    int Master_Slave;       /* Set the master-slave mode of SPI:  Master:0 Slave:1 */
+    int CPOL;               /* Set clock polarity(CPOL):  0 1 */
+    int CPHA;               /* Set clock phase(CPHA):  0 1 */
+};
+
+static struct hci_trans_spi_config hci_config;
+struct rt_spi_device *ble_spi = RT_NULL;
+
+int32_t IsDataAvailable(void);
+
+int32_t HCI_TL_SPI_Init(void* pConf)
+{
+    /******PIN******/
+    rt_pin_mode(hci_config.irq_pin_num, PIN_MODE_INPUT); // IRQ input
+    rt_pin_mode(hci_config.cs_pin_num, PIN_MODE_OUTPUT); // CS output
+
+    /*******SPI******/
+    RT_ASSERT(hci_config.device_name);
+    RT_ASSERT(hci_config.bus_name);
+
+    ble_spi = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
+    if(RT_NULL == ble_spi)
+    {
+        printk("Failed to malloc the spi device.\n");
+        return -RT_ENOMEM;
+    }
+
+    if (RT_EOK != rt_spi_bus_attach_device(ble_spi, hci_config.device_name, hci_config.bus_name, RT_NULL))
+    {
+        printk("Failed to attach the spi device.\n");
+        return -RT_ERROR;
+    }
+
+    /*******SPI Device Config*******/
+    struct rt_spi_configuration cfg;
+    cfg.data_width = hci_config.data_width;
+    cfg.mode = (hci_config.Master_Slave << 3) |
+            ((hci_config.CPOL << 1) | (hci_config.CPHA << 0)) |
+            (hci_config.LSB_MSB << 2);
+    cfg.max_hz =  hci_config.rate;                           /* 1M */
+
+    if (RT_EOK != rt_spi_configure(ble_spi, &cfg)) {
+        printk("Failed to config the spi device.\n");
+        return -RT_ERROR;
+    }
+
+    return RT_EOK;
+}
+
+/**
+ * @brief  Reads from BlueNRG SPI buffer and store data into local buffer.
+ *
+ * @param  buffer : Buffer where data from SPI are stored
+ * @param  size   : Buffer size
+ * @retval int32_t: Number of read bytes
+ */
+int32_t HCI_TL_SPI_Receive(uint8_t* buffer, uint16_t size)
+{
+  uint16_t byte_count;
+  uint8_t len = 0;
+  uint8_t char_00 = 0x00;
+  volatile uint8_t read_char;
+
+  uint8_t header_master[HEADER_SIZE] = {0x0b, 0x00, 0x00, 0x00, 0x00};
+  uint8_t header_slave[HEADER_SIZE];
+
+  /* CS reset */
+  rt_pin_write(HCI_TL_SPI_CS_PIN, PIN_LOW);
+
+  /* Read the header */
+  rt_spi_transfer(ble_spi, &header_master, &header_slave, HEADER_SIZE); //RTAPI
+
+  /* device is ready */
+  byte_count = (header_slave[4] << 8)| header_slave[3];
+
+  if(byte_count > 0)
+  {
+    /* avoid to read more data than the size of the buffer */
+    if (byte_count > size)
+    {
+      byte_count = size;
+    }
+
+    for(len = 0; len < byte_count; len++)
+    {
+      rt_spi_transfer(ble_spi, &char_00, (uint8_t*)&read_char, 1);
+      buffer[len] = read_char;
+    }
+  }
+
+  /**
+   * To be aligned to the SPI protocol.
+   * Can bring to a delay inside the frame, due to the BlueNRG-2 that needs
+   * to check if the header is received or not.
+   */
+  uint32_t tickstart = rt_tick_get();
+  while ((rt_tick_get() - tickstart) < TIMEOUT_IRQ_HIGH) {
+    if (rt_pin_read(HCI_TL_SPI_IRQ_PIN) == PIN_LOW) {
+      break;
+    }
+  }
+
+  /* Release CS line */
+  rt_pin_write(HCI_TL_SPI_CS_PIN, PIN_HIGH);
+
+  return len;
+}
+
+/**
+ * @brief  Writes data from local buffer to SPI.
+ *
+ * @param  buffer : data buffer to be written
+ * @param  size   : size of first data buffer to be written
+ * @retval int32_t: Number of read bytes
+ */
+int32_t HCI_TL_SPI_Send(uint8_t* buffer, uint16_t size)
+{
+  int32_t result;
+  uint16_t rx_bytes;
+
+  uint8_t header_master[HEADER_SIZE] = {0x0a, 0x00, 0x00, 0x00, 0x00};
+  uint8_t header_slave[HEADER_SIZE];
+
+  static uint8_t read_char_buf[MAX_BUFFER_SIZE];
+  uint32_t tickstart = rt_tick_get();
+
+
+  do
+  {
+    uint32_t tickstart_data_available = rt_tick_get();
+
+    result = 0;
+
+    /* CS reset */
+    rt_pin_write(HCI_TL_SPI_CS_PIN, PIN_LOW);
+
+    /*
+     * Wait until BlueNRG-2 is ready.
+     * When ready it will raise the IRQ pin.
+     */
+    while(!IsDataAvailable())
+    {
+      if((rt_tick_get() - tickstart_data_available) > TIMEOUT_DURATION)
+      {
+        printk("%d timeout\r\n", rt_tick_get() - tickstart_data_available);
+        result = -3;
+        break;
+      }
+    }
+    if(result == -3)
+    {
+      /* The break causes the exiting from the "while", so the CS line must be released */
+      rt_pin_write(HCI_TL_SPI_CS_PIN, PIN_HIGH);
+      break;
+    }
+
+    /* Read header */
+    rt_spi_transfer(ble_spi, &header_master, &header_slave, HEADER_SIZE);
+
+    printk("Send header size: %d buffer: %02x", HEADER_SIZE, header_slave[0]);
+    for (int i = 1; i < HEADER_SIZE; ++i) {
+        printk("%02x", header_slave[i]);
+    }
+    printk("\r\n");
+
+    rx_bytes = (((uint16_t)header_slave[2])<<8) | ((uint16_t)header_slave[1]);
+
+    if(rx_bytes >= size)
+    {
+      /* Buffer is big enough */
+      rt_spi_transfer(ble_spi, buffer, &read_char_buf, size);
+    }
+    else
+    {
+      /* Buffer is too small */
+      result = -2;
+    }
+
+    /* Release CS line */
+    rt_pin_write(HCI_TL_SPI_CS_PIN, PIN_HIGH);
+
+    if((rt_tick_get() - tickstart) > TIMEOUT_DURATION)
+    {
+      result = -3;
+      break;
+    }
+  } while(result < 0);
+
+  /**
+   * To be aligned to the SPI protocol.
+   * Can bring to a delay inside the frame, due to the BlueNRG-2 that needs
+   * to check if the header is received or not.
+   */
+  tickstart = rt_tick_get();
+  while ((rt_tick_get() - tickstart) < TIMEOUT_IRQ_HIGH) {
+    if (rt_pin_read(HCI_TL_SPI_IRQ_PIN) == PIN_LOW) {
+      break;
+    }
+  }
+
+  return result;
+}
+
+
+/**
+ * @brief  Reports if the BlueNRG has data for the host micro.
+ *
+ * @param  None
+ * @retval int32_t: 1 if data are present, 0 otherwise
+ */
+int32_t IsDataAvailable(void)
+{
+  return (rt_pin_read(HCI_TL_SPI_IRQ_PIN) == PIN_HIGH);
+}
+
+static int hci_driver_open(void)
+{
+    HCI_TL_SPI_Init(NULL); // RT SPI init
+
+    printk("hci_driver_open, SPI_config_finish\n");
+
+    return 0;
+}
+
+int switch_net_buf_type(uint8_t type)
+{
+    switch (type)
+    {
+    case BT_BUF_ACL_OUT:
+        return HCI_ACLDATA_PKT;
+    case BT_BUF_CMD:
+        return HCI_COMMAND_PKT;
+    default:
+        printk("Unknown buffer type");
+    }
+    return 0;
+}
+static int hci_driver_send(struct net_buf *buf)
+{
+    uint8_t type = bt_buf_get_type(buf);
+
+//    net_buf_push_u8(buf, type);
+//    uint8_t* data = buf->data;
+
+    uint8_t len = buf->len;
+
+    if(len >= MAX_BUFFER_SIZE)
+    {
+        return -1;
+    }
+
+    uint8_t data[MAX_BUFFER_SIZE];
+    data[0] = switch_net_buf_type(type);
+    memcpy(data + 1, buf->data, len); //data[0] is the type  copy to data[1]
+
+    printk("hci_driver_send, type: %d, len: %d, data: %02x:%02x:%02x:%02x:%02x:%02x\n", type, len, data[0], data[1], data[2], data[3], data[4], data[5]);
+
+    if (HCI_TL_SPI_Send(data, len + 1) < 0) { // type +1
+        return -1;
+    }
+    net_buf_unref(buf);
+    return 0;
+}
+
+static int hci_driver_recv(uint8_t *buf, uint16_t len)
+{
+    return HCI_TL_SPI_Receive(buf, len);
+}
+
+void hci_driver_init_loop(void)
+{
+    uint8_t data[MAX_BUFFER_SIZE];
+    uint8_t len = MAX_BUFFER_SIZE;
+    int ret = HCI_TL_SPI_Receive(data, len); //ret: bytes num Recv
+    if(ret > 0 && (data[0] != 0)) // type cant be 0
+    {
+        printk("hci_driver_init_loop, ret: %d, data: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ret, data[0], data[1], data[2], data[3], data[4], data[5],data[6],data[7]);
+
+        struct net_buf *buf;
+        switch(data[0])
+        {
+            case HCI_EVENT_PKT:
+                buf = bt_buf_get_controller_tx_evt();
+                break;
+            case HCI_ACLDATA_PKT:
+                buf = bt_buf_get_controller_tx_acl();
+                break;
+            default:
+                return;
+        }
+
+        if (buf)
+        {
+            net_buf_add_mem(buf, data + 1, ret - 1);
+            bt_recv(buf);
+        }
+    }
+}
+
+static const struct bt_hci_driver drv = {
+        .open = hci_driver_open,
+        .send = hci_driver_send,
+};
+
+static char device_name[NAME_SIZE];
+static char bus_name[NAME_SIZE];
+
+int hci_driver_init(bt_BlueNRG_SPI_interface_t *hci_cfg, int device_idx, int spi_index)
+{
+
+    rt_sprintf(bus_name, "spi%d", spi_index);
+    hci_config.bus_name = bus_name;
+    rt_sprintf(device_name, "spi%d%d", spi_index, device_idx);
+    hci_config.device_name = device_name;
+
+    hci_config.rate = hci_cfg->rate;
+    hci_config.data_width = hci_cfg->data_width;
+    hci_config.LSB_MSB = hci_cfg->LSB_MSB;
+    hci_config.Master_Slave = hci_cfg->Master_Slave;
+    hci_config.CPOL = hci_cfg->CPOL;
+    hci_config.CPHA = hci_cfg->CPHA;
+
+    hci_config.cs_pin_num = hci_cfg->cs_pin_num;
+    hci_config.irq_pin_num = hci_cfg->irq_pin_num;
+
+    printk("SPI_init_process device_name: %s, spi_name: %s, rate: %d, databits: %d, LSB_MSB: %d, Master_Slave: %d, CPOL: %d, CPHA: %d\n",
+            hci_config.device_name, hci_config.bus_name, hci_config.rate, hci_config.data_width,
+            hci_config.LSB_MSB, hci_config.Master_Slave, hci_config.CPOL, hci_config.CPHA);
+
+    printk("SPI_init_process cs_pin_num: %d, irq_pin_num: %d\n",
+            hci_config.cs_pin_num, hci_config.irq_pin_num);
+
+    if (bt_hci_driver_register(&drv) != 0)
+    {
+        return -1;
+    }
+    return 0;
+}
+
+
+#endif /* APPLICATIONS_HCI_INTERFACE_C_ */

+ 34 - 0
platform/rtthread/rtthread_driver_spi.h

@@ -0,0 +1,34 @@
+
+#ifndef APPLICATIONS_HCI_INTERFACE_H_
+#define APPLICATIONS_HCI_INTERFACE_H_
+
+#include "chipset_interface.h"
+
+/* SPI Trans Defines -------------------------------------------------------------------*/
+#define HEADER_SIZE       5U
+#define MAX_BUFFER_SIZE   255U
+#define TIMEOUT_DURATION  100U
+#define TIMEOUT_IRQ_HIGH  1000U
+
+/* HCI Packet types */
+#define HCI_NONE_PKT        0x00
+#define HCI_COMMAND_PKT     0x01
+#define HCI_ACLDATA_PKT     0x02
+#define HCI_SCODATA_PKT     0x03
+#define HCI_EVENT_PKT       0x04
+#define HCI_ISO_PKT         0x05
+#define HCI_VENDOR_PKT      0xff
+
+/* GET PIN  -----------------------------------------------*/
+#define HCI_TL_SPI_IRQ_PIN      GET_PIN(A, 0)  /* IRQ PIN OF BLUENRG*/
+#define HCI_TL_SPI_CS_PIN       GET_PIN(A, 1)  /* SPI CS PIN */
+
+#define NAME_SIZE       10U
+
+/* Exported Functions --------------------------------------------------------*/
+int32_t HCI_TL_SPI_Init    (void* pConf);
+int32_t HCI_TL_SPI_Receive (uint8_t* buffer, uint16_t size);
+int32_t HCI_TL_SPI_Send    (uint8_t* buffer, uint16_t size);
+int hci_driver_init(bt_BlueNRG_SPI_interface_t *, int, int);
+
+#endif /* PACKAGES_ZEPHYR_POLLING_LATEST_PLATFORM_RTTHREAD_RTTHREAD_DRIVER_SPI_H_ */

+ 146 - 0
porting/rtthread_spi/main.c

@@ -0,0 +1,146 @@
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <rtthread.h>
+
+#include "rtthread_driver_spi.h"
+
+#include "chipset_interface.h"
+#include "platform_interface.h"
+
+#include "base/types.h"
+#include "utils/spool.h"
+#include <logging/bt_log_impl.h>
+#include <drivers/hci_driver.h>
+#include "host/hci_core.h"
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+
+extern void bt_ready(int err);
+extern void app_polling_work(void);
+
+int bt_init_hci_driver(void)
+{
+    printk("bt_init_hci_driver \r\n");
+
+    bt_BlueNRG_SPI_interface_t *p_interface = NULL;
+    uint8_t spi_num;
+    uint8_t device_num;
+
+    p_interface = (bt_BlueNRG_SPI_interface_t *)bt_BlueNRG_get_SPI_interface();
+    bt_BlueNRG_SPI_interface_t tmp = {0, 0, 0, 0, 0, 0, 0, 0};
+
+    tmp.LSB_MSB = p_interface->LSB_MSB;
+    tmp.Master_Slave = p_interface->Master_Slave;
+
+    tmp.cs_pin_num = PKG_ZEPHYR_POLLING_HCI_SPI_CS_PIN_NUM;
+    tmp.irq_pin_num = PKG_ZEPHYR_POLLING_HCI_SPI_IRQ_PIN_NUM;
+    tmp.rate = PKG_ZEPHYR_POLLING_HCI_SPI_BAUDRATE;
+    tmp.data_width = PKG_ZEPHYR_POLLING_HCI_SPI_DATA_WIDTH;
+    tmp.CPOL = PKG_ZEPHYR_POLLING_HCI_SPI_CPOL;
+    tmp.CPHA = PKG_ZEPHYR_POLLING_HCI_SPI_CPHA;
+
+    spi_num = PKG_ZEPHYR_POLLING_HCI_SPI_BUS_INDEX;
+    device_num = PKG_ZEPHYR_POLLING_HCI_SPI_DEVICE_INDEX;
+
+    if (hci_driver_init(&tmp, device_num, spi_num) != 0)
+    {
+        printk("Error, SPI open failed.");
+        return -1;
+    }
+
+    return 0;
+}
+
+
+void zephyr_polling_main(void* parameter)
+{
+    int err = 0;
+
+    bt_log_impl_register(bt_log_impl_local_instance());
+
+    if (bt_init_hci_driver() < 0)
+    {
+        return;
+    }
+    bt_hci_chipset_driver_register(bt_hci_chipset_impl_local_instance());
+    bt_storage_kv_register(bt_storage_kv_impl_local_instance());
+    bt_timer_impl_local_init();
+
+    /* Initialize the Bluetooth Subsystem */
+    err = bt_enable(bt_ready);
+    if(err)
+    {
+        printk("bt_enable(), err: %d\n", err);
+    }
+
+#if defined(CONFIG_BT_MONITOR_SLEEP)
+    bt_init_monitor_sleep();
+#endif
+
+    while (1)
+    {
+#if defined(CONFIG_BT_MONITOR_SLEEP)
+        if (!bt_check_is_in_sleep())
+        {
+            bt_polling_work();
+
+            if (bt_is_ready() && bt_check_allow_sleep())
+            {
+                bt_sleep_prepare_work();
+            }
+        }
+#else
+        bt_polling_work();
+#endif
+
+        app_polling_work();
+
+        extern void hci_driver_init_loop(void);
+        hci_driver_init_loop();
+
+        // rt_thread_yield();
+        rt_thread_delay(1);
+    }
+}
+
+int zephyr_polling_init(void)
+{
+    static rt_thread_t tid = RT_NULL;
+
+    tid = rt_thread_create("zephyr_polling_main",
+                            zephyr_polling_main, RT_NULL,
+                            4096,
+                            5, 5);
+    if (tid != RT_NULL)
+    {
+        rt_thread_startup(tid);
+    }
+
+    return 0;
+}
+// INIT_APP_EXPORT(zephyr_polling_init);
+MSH_CMD_EXPORT(zephyr_polling_init, "zephyr_polling start");
+
+
+static int zephyr(void) {
+
+    static rt_thread_t tid = RT_NULL;
+
+    rt_kprintf("zephyr_polling_init \r\n");
+
+    tid = rt_thread_create("zephyr_polling_main",
+                                zephyr_polling_main, RT_NULL,
+                                4096,
+                                5, 5);
+    if (tid != RT_NULL)
+    {
+        rt_thread_startup(tid);
+    }
+
+    return 0;
+}
+MSH_CMD_EXPORT(zephyr, "zephyr_polling_init sample");
+

+ 5 - 0
src/host/hci_core.c

@@ -2910,6 +2910,11 @@ static void hci_send_cmd(void)
     struct net_buf *buf;
     int err;
 
+    if(bt_dev.ncmd_sem.count == 0)
+    {
+        return; // Send only one cmd at a time
+    }
+
     /* Get next command */
     BT_DBG("send_cmd, calling net_buf_get");
     buf = net_buf_get(&bt_dev.cmd_tx_queue, Z_FOREVER);