embassy
embassy copied to clipboard
cyw43: Bluetooth support
Are there plans to support bluetooth as well? As far as I understand, the CYW43439 chip on the Pico W supports it.
Bluetooth would be nice!
I took a look at the driver we use currently for the cyw43 and it doesn't seem like it supports bluetooth, but that's just a cursory search through the repo.
Well actually, it seems like the driver does have a structure for some bluetooth stuff:
https://infineon.github.io/wifi-host-driver/html/structwhd__btwt__config__params__t.html
https://github.com/raspberrypi/pico-sdk/releases/tag/1.5.1 looks like it was "added"/made official around here
I think what we'd need to translate/implement is here:
https://github.com/raspberrypi/pico-sdk/tree/master/src/rp2_common/pico_btstack https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_cyw43_driver/include/pico/btstack_cyw43.h
Not sure if a new .bin/different .bin would be needed here: https://github.com/embassy-rs/embassy/tree/main/cyw43-firmware
One concern I see is, that just gets the rp2040 / cyw43
in a state where you can now speak btstack
to it, something else that isn't implement in Rust https://github.com/bluekitchen/btstack
Not sure if it'd be easier to write btstack-sys
bindings?
edit:
looks like this is of interest https://github.com/raspberrypi/pico-sdk/commit/c8ccefb9726b89d35d230d194d6977705908ffe7
The meat for sending/receiving HCI packets over SPI is here https://github.com/raspberrypi/pico-sdk/tree/master/src/rp2_common/pico_cyw43_driver/cybt_shared_bus
The issue is that will get us only "send/receive HCI packets to the bluetooth controller". We then need a bluetooth host stack on top of that. (the host stack is what implements the higher layers of BLE, like L2CAP, ATT, GATT...).
Pico-sdk is using BTStack as the host stack. It is proprietary, requires licensing to use. RPi and BlueKitchen (the company behind BTStack) have entered some agreement to license BTStack for free on Pico W-based hardware only.
This license does NOT cover other hardware, and we're in the same situation for other hardware: STM32WB[^1] and nRF52/53[^2]'s controller blobs also speak HCI, we also need a host stack for them.
[^1]: they have some kind of higher-level vendor-specific commands for higher-layer protocols. I dunno how complete they are or how nice they're to use compared to a real BLE host stack.
[^2]: the "old" softdevice (what's implemented in nrf-softdevice
) does have implementations for higher-layer protocols, but it's in "maintenance mode" according to Nordic, doesn'd support nRF53 nor newer Bluetooth features. The newer "softdevice controller" blob is HCI only.
So I think the Embassy project should focus its efforts in getting some bluetooth stack that's freely usable for all hardware we support, not BTstack. There's Bluedroid, NimBLE (C, but I believe the Espressif folks have worked in Rust bindings?) or write one from scratch in Rust, which is a giant undertaking, bleps is one attempt at it.
So, I will take PRs for exposing raw HCI in cyw43, or for integrating some FOSS bluetooth stacks. I will NOT accept PRs working towards integrating BTStack. (if raw HCI is exposed, nothing prevents someone from doing that on their own, of course)
I found this project which looks like has setup cbindgen FFI for NimBLE: https://github.com/benbrittain/apache-nimble-sys
Whether or not this is what we need is another question.
@Dirbaio I beat the snot out of pico-sdk by littering it hardcore with a bunch of custom uart_printf
as well as turning on some debug flags and I got basically how the C pico-sdk library does "bluetooth HCI init" https://gist.github.com/brandonros/b4b952ee97049def55e073e0d8a2f75d
In the name of replicating it for our uses in Rust:
I am a little confused on one thing. I could be wrong but I think the current order of operations on how we split cyw43
init between runner
and control
makes this hard to implement? Or am I mistaken? I don't really have bus
to be able to do bp_read
/ bp_write
to write the Bluetooth firmware in the control
context, and I need the clm
loaded first, which means I can't do it from runner
The order of operations seems to be (from C land, redacted logs from the gist comments):
cyw43_ll_bus_init
cyw43_spi_init
cyw43_spi_gpio_setup
cyw43_spi_reset
chip_up
...
backplane ready
ALP is set
...
cyw43_clm_load start
...
cyw43_btbus_init
cybt_fw_download
The really painful part about cybt_fw_download
is it isn't one continuous .bin we can flash into memory. It's a custom format where it's a bunch of non-4 aligned writes size wise + address wise, so we have to read what is in memory, blend that together with what we want to write, and upload it.
I'll keep hitting on it, just wanted to know if you had any easy guidance to make this a bit less painful. :D
I am with you, we will target bleps
, all we need is to implement
use bleps::HciConnection;
impl HciConnection for Cyw43HciConnection {
fn read(&self) -> Option<u8> {
panic!("TODO")
}
fn write(&self, data: u8) {
panic!("TODO")
}
fn millis(&self) -> u64 {
panic!("TODO")
}
}
I saw your PR, pretty excited to see progress on this! :star_struck:
and I need the clm loaded first
are you sure that's needed? Intuitively I'd say the wifi CLM doesn't affect Bluetooth at all. (the cyw43 is more like a bluetooth chip and a wifi chip glued together, each has its own core with different firmware and RAM). If you try initializing BT without loading the CLM it probably works anyway.
If that's not the case, it could be workarounded by putting the bus in an async Mutex so it can be used from both runner and control, but I'd really really like to avoid that.
Are you sure the cyw43 Bluetooth core isn't the same as the WLAN core?
they aren't, the datasheet has some details, plus the fact that there's two firmwares.
Could you check https://github.com/georgerobotics/cyw43-driver/blob/main/src/cyw43_ll.c and tell me where you see the additional Bluetooth core? Based on my logs, I do not see anything about any additional cores being brought up/reset but maybe I missed it. I only see device_core_is_up(self, CORE_WLAN_ARM);
Or sorry, it'd probably be here https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_cyw43_driver/cybt_shared_bus/cybt_shared_bus.c#L112
I am working on writing Rust to be able to read/write the needed parsed Bluetooth firmware padded correctly from https://github.com/georgerobotics/cyw43-driver/blob/main/firmware/cyw43_btfw_43439.h, will PR it
the datasheet literally says there's 2 cores.
I think the bluetooth core starts on its own. In a more standard setup (ie not Pico's weird bluetooth-over-SPI) you talk to it via the bluetooth UART, which works even if you haven't initialized the wifi part. That'd explain why there's no code to explicitly start the BT core. It seems the wifi backplane has a window into BT stuff, so the Pico W is (ab?)using that to do bluetooth over SPI.
Any movement on this? It would be awesome to have BLE on the Pico W.
#1820 was the latest PR for this, but was unfortunately closed 3 weeks ago. My guess is that no maintainer is actively prioritizing it at the moment. I hope it gets picked back up before long, since it's been 8 months since it was actively worked on and embassy has progressed a lot since then.
See #2865 for latest status. Help is needed to finish it, contributors welcome!