jbentham / picowi

Standalone WiFi driver for the Pi Pico-W
MIT License
91 stars 11 forks source link

Bluetooth support (feature request, not an issue) #1

Open amitv87 opened 1 year ago

amitv87 commented 1 year ago

Hi, thanks for writing this elegant and minimal wifi driver in the first place.

Recently, bluetooth support was added in pico-sdk with relevant firmwares. I tried the new wifi firmware with your driver, and it worked without any hassle. There's a patchram code that needs to be applied that enables an HCI transport layer over the same physical spi transport in a shared manner.

As I am very new to brcm/cyw devices, can you help implement a minimal HCI layer similar to the existing SDPCM layer?

jbentham commented 1 year ago

Yes, that'd be a useful addition to my code, though I'm not encouraged by the comment in the SDK code that says "Bluetooth register corruption occurs if both wifi and bluetooth are fully utilised", so clearly there are some problems with the way the data streams are being multiplexed.

I'm currently implementing TCP, then I need to speed up the SPI interface by adding DMA; while doing that, I'll take a look at HCI transport.

On 16/02/23 11:04, boggyb wrote:

Hi, thanks for writing this elegant and minimal wifi driver in the first place.

Recently, bluetooth support was added in pico-sdk https://github.com/raspberrypi/pico-sdk/releases/tag/1.5.0 with relevant firmwares https://github.com/georgerobotics/cyw43-driver/tree/main/firmware. I tried the new wifi firmware with your driver, and it worked without any hassle. There's a patchram https://github.com/georgerobotics/cyw43-driver/blob/main/firmware/cyw43_btfw_43439.h code that needs to be applied that enables an HCI transport layer over the same physical spi transport in a shared https://github.com/raspberrypi/pico-sdk/tree/1.5.0/src/rp2_common/pico_cyw43_driver/cybt_shared_bus manner.

As I am very new to brcm/cyw devices, can you help implement a minimal HCI layer similar to the existing SDPCM layer?

— Reply to this email directly, view it on GitHub https://github.com/jbentham/picowi/issues/1, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACNUSET4PZCRT5H2FOHYD5TWXYCTJANCNFSM6AAAAAAU6A2A2A. You are receiving this because you are subscribed to this thread.Message ID: @.***>

paulhamsh commented 10 months ago

Hi To @amitv87 there is good support for bluetooth in C/C++ and Micropython now - so is your request still needed?

@jbentham this is a very interesting project and your webpage on it is amazing! I have read it over and over to get an understanding of the SPI interface.

I am trying to write a basic bluetooth stack in Micropython for the Pico Pi W - just for my own interest. I can use the HCI layer provided by the Pico drivers, but also wanted to understand how this chip works - or at least how the Pico W talks to it.

So, now I'm writing a SPI bit-banging interface in Micropython, at the moment just to try and read the FEEDBEAD response - and it 'nearly' works but seems to by 4 bits out and I have no idea on mapping the command with the little-endian big-endian swapping.

I'm wondering if you could point me in the right direction for where I might be going wrong. I can share the code, but this is what I am seeing. I send 0x0A000400 (no idea why that works - I think I should be sending 0x4000A004 or some endian mangled version of that). And this is the response. It seems to be 4 bits out - but no idea how that could happen! I guess the extra returned information is the 32 bit status, even though I think I am asking for 4 bytes only. (I have no access to anything but the datasheet (which isn't too helpful) and the code I can find on github)

Even copies of your own bit-banging code would help - there are some bits not in your webpage or on here, I think.

0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0  0x0A000400

0 0 0 0 1 0 1 1 1 1 1 0 1 0 1 0 1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 0  0x0BEADFEE
1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  0xD0000000
0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  0x00400000
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  0x00000000
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  0x00000000
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  0x00000000
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  0x00000000
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  0x00000000
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  0x00000000
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  0x00000000
from machine import Pin
import time

cs = Pin(25, Pin.OUT)
clk = Pin(29, Pin.OUT)
pwr = Pin(23, Pin.OUT)

TIMING_DELAY = 1

def make_cmd(wr, inc, fn, addr, size):
    return (wr << 31) | (inc << 30) | (fn << 28) | ((addr & 0x1ffff) << 11) | (size & 0x3ff)

def swap_bytes(dat):
    return ((dat & 0xff000000) >> 8) | ((dat & 0xff0000) << 8) | ((dat & 0xff00) >>8) | ((dat & 0xff) << 8)

def write_cyw(dat):
    shift = 31
    data_pin = Pin(24, Pin.OUT)
    s = ""
    while shift >= 0:
        bit = (dat >> shift) & 1
        s = s + '{0:01b} '.format(bit)
        data_pin.value(bit)
        time.sleep_us(TIMING_DELAY)
        clk.value(1)
        time.sleep_us(TIMING_DELAY)
        clk.value(0)
        shift -= 1
    return s

def read_cyw():
    dat = 0
    shift = 31
    data_pin = Pin(24, Pin.IN)
    s = ""
    while shift >= 0:
        bit = data_pin.value()
        time.sleep_us(TIMING_DELAY)
        clk.value(1)
        time.sleep_us(TIMING_DELAY)
        dat += (bit << shift)
        s = s + '{0:01b} '.format(bit)
        clk.value(0)
        shift -= 1
    return dat, s

def init():
    clk.value(0)
    data_pin=Pin(24, Pin.OUT)
    data_pin.value(0)
    time.sleep_us(TIMING_DELAY)
    pwr.value(0)
    time.sleep_ms(20)
    pwr.value(1)
    time.sleep_ms(250)

def deinit():
    pwr.value(0)

init()

#cmd = make_cmd(0, 1, 0, 0x14, 4)
#swap_cmd = swap_bytes(cmd)

times = 1

while times > 0:
    cs.value(0)

    time.sleep_ms(10)
    times -= 1

    cmd = 0x0A000400
    s = write_cyw(cmd)    
    print(s, '0x{0:08X}'.format(cmd))

    v=[]
    s=[]
    #time.sleep_ms(0)
    print()
    for i in range(0, 10):
        val, st = read_cyw()
        v.append(val)
        s.append(st)

    for i in range(0, 10):
        print(s[i], '0x{0:08X}'.format(v[i]))
    print()
    time.sleep_ms(250)

    cs.value(1)

deinit()
paulhamsh commented 10 months ago

I discovered what was happening - this is why most code tries to read FEEDBEAD more than once - it seems the first write to the chip wants 4 extra bits at the start, which made my reads 4 bits shifted. If you make the first write 32+4 bits long, with the first 4 bits beings 0s, then it works fine - and subsequent write/reads are fine as well. I still don't understand the high speed SPI mode or the description in the product specification.