bluekitchen / btstack

Dual-mode Bluetooth stack, with small memory footprint.
http://bluekitchen-gmbh.com
Other
1.66k stars 599 forks source link

H4 SPI/UART for Zephyr #475

Open KlemenDEV opened 1 year ago

KlemenDEV commented 1 year ago

Is it possible to use this stack using H4 HCI protocol via SPI for connection to a Zephyr-based HCI_SPI controller?

I have checked hci_transport.h and based on hci_transport_config_type_t only USB and UART are supported. Is it possible to use this project for SPI-based communication and if yes, where should I start looking for some guidance?

mringwal commented 1 year ago

Good question. HCI over SPI isn't standardized, but if you use SPI Master, there are not too many options on how you can send HCI packets over it.

As far as I know, Zephyr implements the H4 SPI from ST Micro's BlueNRG Controller.

In any case, we currently don't have an implementation for it, but we have an H4 SPI for EM Microelectronics Controllers (src/hci_transport_em9304_spi.c) including an relative generic SPI driver (src/btstack_spi_em9304.c) and we also have "H4 Zephyr" on our "nice to have" list.

Which Controller do you want to use? I guess it's possible to use the Controller with Zephry's H4 UART implementation.

What do you use as a host? Asides from an embedded linux system, most OS usually lack support for SPI + GPIO.

Please have a look at the mentioned sources. The closest port is probably the port/stm32-l073rz-nucleo-em9304.

I've been wondering if it makes sense to add support for GPIOs and then use the MultiBus project for a desktop implementation: https://github.com/mringwal/multibus

KlemenDEV commented 1 year ago

Thank you for the quick response and the details :)

I would like to use it with the STM32 host (with a custom RTOS on it). The controller is one of the nRF modules running Zephyr in HCI_SPI mode. The controller can indeed run in both UART and SPI modes.

I prefer to use SPI because it technically allows for faster data rates. But if this complicates things a lot, I guess I could also use UART.

we also have "H4 Zephyr" on our "nice to have" list.

In case I go with H4 UART (nRF controller to STM32 host), what would be the starting point/reference chipset/port/ you would recommend?

mringwal commented 1 year ago

I prefer to use SPI because it technically allows for faster data rates. But if this complicates things a lot, I guess I could also use UART.

Well, although it depends on your application, I haven't seen faster than 1 mbps transfers over LE, so the 1 mbps UART of the nRF5x should not be a real issue.

For H4 UART, you could look at the stm32-f4 port with CC2564 (dual mode), and after getting it to work, disable support for Classic. Please also check our manual as well as the blog posts, esp. the one on the F4 port.

KlemenDEV commented 1 year ago

I have sort of successfully ported "stm32-f4 port with CC2564 (dual mode)" to our use case with L4 STM32 and Zephyr via UART H4.

However, now I am trying to run the gap_inqury.c example and have hit a roadblock. No devices are found and the sample stays at "Starting inquiry scan..".

According to

disable support for Classic.

I have tried disabling ENABLE_CLASSIC, but then most of the methods of GAP become inaccessible, however, BLE implements those GAP methods as far as I know (scanning should work).

Here is btstack_config.h if it helps:

// Port related features
#define HAVE_EMBEDDED_TIME_MS

// BTstack features that can be enabled
#define ENABLE_BLE
#define ENABLE_LE_PERIPHERAL
#define ENABLE_LE_CENTRAL
#define ENABLE_CLASSIC // we only use BLE, but this seems to be needed for gap_inquiry_start to be included in build
#define ENABLE_PRINTF_HEXDUMP
#define ENABLE_LOG_ERROR
#define ENABLE_LOG_INFO
#define ENABLE_LOG_DEBUG

// BTstack configuration. buffers, sizes, ...
#define HCI_ACL_PAYLOAD_SIZE (1691 + 4)
#define MAX_NR_AVDTP_CONNECTIONS 1
#define MAX_NR_AVDTP_STREAM_ENDPOINTS 1
#define MAX_NR_AVRCP_CONNECTIONS 2
#define MAX_NR_BNEP_CHANNELS 1
#define MAX_NR_BNEP_SERVICES 1
#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES  2
#define MAX_NR_GATT_CLIENTS 1
#define MAX_NR_HCI_CONNECTIONS 2
#define MAX_NR_HFP_CONNECTIONS 1
#define MAX_NR_L2CAP_CHANNELS  4
#define MAX_NR_L2CAP_SERVICES  3
#define MAX_NR_RFCOMM_CHANNELS 1
#define MAX_NR_RFCOMM_MULTIPLEXERS 1
#define MAX_NR_RFCOMM_SERVICES 1
#define MAX_NR_SERVICE_RECORD_ITEMS 4
#define MAX_NR_SM_LOOKUP_ENTRIES 3
#define MAX_NR_WHITELIST_ENTRIES 1

#define NVM_NUM_DEVICE_DB_ENTRIES 16
#define NVM_NUM_LINK_KEYS 16
#define MAX_ATT_DB_SIZE 200

here is port_main

void port_main(void) {
    // start with BTstack init - especially configure HCI Transport
    btstack_memory_init();
    btstack_run_loop_init(btstack_run_loop_embedded_get_instance());

    // uncomment to enable packet logger
    hci_dump_init(hci_dump_embedded_stdout_get_instance());

    // init HCI
    hci_init(hci_transport_h4_instance(btstack_uart_block_embedded_instance()), (void*) &config);
    hci_set_chipset(btstack_chipset_zephyr_instance());

    const btstack_tlv_t * btstack_tlv_impl = btstack_tlv_none_init_instance();
    btstack_tlv_set_instance(btstack_tlv_impl, NULL);
    le_device_db_tlv_configure(btstack_tlv_impl, NULL);

    // inform about BTstack state
    btstack_packet_callback_registration_t hci_event_callback_registration;
    hci_event_callback_registration.callback = &packet_handler;
    hci_add_event_handler(&hci_event_callback_registration);

    // hand over to btstack embedded code
    btstack_main(0, NULL);

    // go
    btstack_run_loop_execute();
}

Here is log output on UART2 (I put it on pastebin due to big length): https://pastebin.com/g5hVGaYc

Thank you for helping out :)

mringwal commented 1 year ago

Hi. The nRF5x Controllers are LE-only, that's why I suggested to disable Classic. gap_inquiry demo does a Classic Bluetooth device discovery. Please try gap_le_advertisments.c instead or gatt_counter which implements a simple LE Peripheral.

KlemenDEV commented 1 year ago

It works now, thank you for the assistance :)

Unless you want to keep this open in case SPI is supported one day, from my side this issue can be closed.

KlemenDEV commented 1 year ago

So I think I still have some problems.

While gap_le_advertisments.c worked perfectly (finds all other nearby BLE devices), gatt_counter.c does not work for me.

I am building it with gatt_counter.c and gatt_counter.h generated using compile_gatt.py. It builds fine and logs show no errors, but the BLE scanner app on my phone does not find the peripheral or its name.

Here is m gatt_counter.h: https://pastebin.com/VVTq1hqY

Here is the log with ERR,INFO, and DEBUG enabled: https://pastebin.com/E61c8DRS

I have also tried nordic and ublox counter examples, but none work. Seems I am missing something to be able to use the Zephyr controller in peripheral mode.

BTStack config header file is the same as in my comment above.

mringwal commented 1 year ago

Zephyr nRF Controller does not have a unique public BD ADDR and e.g. iOS ignores advertisements from devices with BD ADDR 00:00:00:00:00:00. Either enable (non-)resolvable private addresses or enable Zephyr Chipset support and use the unique address stored in the Controller as shown by port/posix-h4-zephyr/main.c.

amorniroli commented 1 year ago

Good question. HCI over SPI isn't standardized, but if you use SPI Master, there are not too many options on how you can send HCI packets over it.

As far as I know, Zephyr implements the H4 SPI from ST Micro's BlueNRG Controller.

Hi @mringwal @KlemenDEV ,

not sure if Zephyr use the same of BlueNRG2. Anyway, attached you'll find SPI transport instance for using ST BlueNRG2 chipset. I've tested it succesfully with X-NUCLEO B

For sure it may be improved, but it's a solid start.

image

Please feel free to share any feedback or improvements.

P.S. Just a notice for SPI driver implementation: when deasserting CS, be sure that IRQ line is logical HIGH.

Alessandro hci_transport_bluenrg2_spi.zip

KlemenDEV commented 1 year ago

Right now I am exploring the library itself using UART, but I will definitely look into your SPI implementation once this is done, thanks for your work.

Zephyr uses BlueNRG-inspired HCI via SPI so technically it should work to some degree.

image

KlemenDEV commented 1 year ago

I have ran into some issues that are probably related to the Zephyr side, so I may not be able to test SPI straight away: https://github.com/zephyrproject-rtos/zephyr/issues/58236

mringwal commented 1 year ago

@KlemenDEV you could post an HCI trace from BTstack after converting into a .pklg file with tool/create_packet_log.py on the Zephyr issue.

KlemenDEV commented 1 year ago

Do you prefer it here or at zephyr issue?

mringwal commented 1 year ago

Well, zephyr could need them. I'm curious, too, but can check there as well. :) At Zephyr repo.