tinygo icon indicating copy to clipboard operation
tinygo copied to clipboard

Support for Raspberry Pi Pico W with Wireless

Open efectn opened this issue 3 years ago • 42 comments

Pico W has been released today with included wirless chip. It would be great if tinygo supports it. It uses CYW43439 as wireless chip.

https://www.raspberrypi.com/news/raspberry-pi-pico-w-your-6-iot-platform/

efectn avatar Jun 30 '22 14:06 efectn

Hmm? Maybe we need PIO support first?

https://github.com/raspberrypi/pico-sdk/tree/master/src/rp2_common/cyw43_driver

sago35 avatar Jul 01 '22 09:07 sago35

I've got my hands on one. Using the Pico target in tinygo does the basics (as you'd expect):

  • UART is functional (GPIO 0 / GPIO 1)
  • Blinky is not functional (because on-board LED is via the wireless chip and GPIO25 is not an LED)

Wireless (obviously) not tested.

To properly support will need at least:

  • [ ] A new target (picow ?)
  • [ ] Figure what to do about on-board LED (if anything), given it's not a pico GPIO
  • [ ] Add support for the wireless chipset

kenbell avatar Jul 04 '22 16:07 kenbell

If this is worked on, and requires someone to test, I'm more than happy to commit some time to test on a Pico W.

charathram avatar Jul 13 '22 03:07 charathram

If this is worked on, and requires someone to test, I'm more than happy to commit some time to test on a Pico W.

Ready to participate in testing as well

pobochiigo avatar Aug 09 '22 17:08 pobochiigo

I've got a couple of Pico W here as well. Ready to help testing

rgerardi avatar Aug 31 '22 16:08 rgerardi

https://github.com/georgerobotics/cyw43-driver

sago35 avatar Sep 02 '22 12:09 sago35

Is someone already working on this?

asap2Go avatar Dec 06 '22 06:12 asap2Go

Guys anyone working on this? I think the supply chain issues at least for Pico W seems to be resolved as they are available everywhere now.

quaintdev avatar Dec 10 '22 17:12 quaintdev

Does the introduction of the Pico W warrant a separate page from the current Pico page (https://tinygo.org/docs/reference/microcontrollers/pico/)?

andoks avatar Dec 16 '22 18:12 andoks

Seems that still the Wifi module of raspberry pi pico is not supported. Any plans to implement this?

rtitz avatar Jan 22 '23 12:01 rtitz

is it plan to be supported this year ?

MushiTheMoshi avatar Jan 25 '23 05:01 MushiTheMoshi

Like @sago35 said, PIO would go a long way to having wifi as envisioned by the Raspberry Pi engineers since the CY43's SPI data in and out are shared by pin 24 of the pico, so peripheral SPI is not a possibility. I'm out of my element when it comes to PIO, very excited about it (bought a logic analyzer recently with 500MHz sampling for PIO debugging in future).

The other option is using software SPI, which I will try to test out the pico W once I get back from vacations and settled in. That may take while to get working, if at all possible- that depends on how far the software spi can go and what the cy43 interface can tolerate.

I've documented helpful info in a repo for anyone interested in maybe helping out https://github.com/soypat/cyw43439. I've bought 10 of these Pico W's with hopes that wifi will work on it in the near future, for some definition of "near".

soypat avatar Jan 26 '23 02:01 soypat

Little update. Work on the aforementioned repo is coming along nicely. I've managed to communicate with the CYW43439 and read from its general purpose registers. I have but one blocker: The gSPI to communicate via the backplane interface. I have replicated the backplane communications the best I can to my knowledge. The I/O of my implementation and the pico-sdk looks identical when looking at the verbose log of gSPI communications but I keep getting data-unavailable status on backplane writes. I must have a off-by-one error somewhere.

To solve this as fast and painless as possible I have fast tracked the delivery of a new logic analyzer I bought a couple months ago. The one I'm using now is a Logic Saleae 8 which has 100MHz sampling frequency which is too low to debug the pico-sdk's implementation of the gSPI (they use PIO). The new logic analyzer arrives 6th of March according to DHL. As soon as I get it and my buddy @trippas at work solders some test leads to the pico-w's<->CYW43439 SPI bus I'll be ready to tackle this problem again.

If we're being optimistic I might have it by this months end. But who knows really. I'd really like to have it early march for some things I want to test at work...

We should also get the Netdev2 #3452 PR ready by then which needs some more work

soypat avatar Mar 03 '23 22:03 soypat

Supporting Pico W should also lead a long way to supporting Pimoroni Badger 2040 W, which is basically a Badger 2040 with a Pico W and a few other tweaks.

Crocmagnon avatar Mar 17 '23 23:03 Crocmagnon

Seeing I gave a few bold statements in my last comment I think a follow up is deserving.

The difficulty of porting the wifi driver was more than I had imagined. Not because the act of porting is hard but because small mistakes can cost a lot of time. Most of the time I have spent developing can be traced to several != that should have been a == in code, or a conversion of a integer that should be LittleEndian, not BigEndian.

That said, today I've reached a major milestone. I have succesfully initialized the on-board wifi chip and controlled the GPIOs on it- which means now users are able to turn the Pico W's LED on and off via TinyGo code.[^A] This also validates most of the IO of the wifi chip.

What remains is implementing the wifi logic. This means porting over lots of functions which make use of the already ported IO. I'll be taking a short break from developing this for now. If anyone is interested in helping out in the effort please reach out at the Gophers Slack .[^B]

[^A]: Link to the blinky example. Note: The initialization duration is around 20 seconds. [^B]: https://invite.slack.golangbridge.org/, find me as Patricio Whittingslow or on the #tinygo-dev channel.

soypat avatar Apr 02 '23 19:04 soypat

To solve this as fast and painless as possible I have fast tracked the delivery of a new logic analyzer I bought a couple months ago. The one I'm using now is a Logic Saleae 8 which has 100MHz sampling frequency which is too low to debug the pico-sdk's implementation of the gSPI (they use PIO).

Probably useless advice by now, but the way I usually solve this is by lowering the clock speed. Usually there is a single place where the clock speed is controlled. I would assume there is something similar for PIO.

(I have a Logic 4 which has a sample rate of 25MHz, so can read up to 8MHz or so).

aykevl avatar Apr 03 '23 23:04 aykevl

I did take a look around the code but it was not immediately apparent where i could tinker with the baud. Ended up using it as an excuse to get myself my very own logic analyzer 😅

soypat avatar Apr 04 '23 04:04 soypat

Dropped a bounty for the implementation of Wifi with the pico, was much more than what I could take on. Apparently also needs a lwip like library which I'm unfamiliar with implementations in Go.

soypat avatar Apr 30 '23 15:04 soypat

Dropped a bounty for the implementation of Wifi with the pico, was much more than what I could take on. Apparently also needs a lwip like library which I'm unfamiliar with implementations in Go.

@soypat What do you have working currently and where can that be found? It might make it easier to scope out what is missing. I think it's unlikely that we will have an implementation of lwip in go, but maybe we can wrap it. I'm not sure if tinygo is wrapping other C libraries currently?

Edit: Seems like it's doable making the initial wrappers: https://github.com/xlab/c-for-go

cmol avatar Apr 30 '23 17:04 cmol

@cmol It's all in the cyw43439 repo. Issue has more information here: https://github.com/soypat/cyw43439/issues/1.

lwip stand-in can be brought to Go via one of the following:

  • Generating wrappers that bind C code to Go, though this may prove hard if lwip expects external functions to be linked in
  • Porting lwip via a tool like ccgo.
  • Porting lwip manually.
  • Writing a Go ip/tcp handler from scratch. This can prove hard. I tried a while back and got thus far: ether-swtch. Note: Does not work too well, when it does.

I am not sure which way would be the best. I'm far from being a Cgo power user. I usually port stuff manually when it's small enough. lwip is 88k lines long... So judging from this data, I think rewriting lwip is out of the question.

But- could it be rewritten from scratch? 88k sounds like a lot but keep in mind we can avoid a lot of complexity in TCP if we stick to the basics. My ether-swtch implementation was once working for the ENC28J60 which let me host http pages on an arduino uno back in the day and thats only 750 lines of code (excluding tests). What's more, there's a rust implementation of TCP in just under 750 lines of code (what a coincidence!), and there's a video series howing how the programmer did it.

So lwip might seem scary- but I think the TCP/ethernet marshaller could prove to be the easiest part of this whole shenanigan since it could be kept as simple as possible and it would be really easy to test (no need for hardware; test on your PC/laptop).

soypat avatar May 01 '23 02:05 soypat

@soypat I think my biggest worry with a rewrite is supporting a full IPv4 and IPv6 stack including all the DHCP / SLAAC stuff. I'm not sure how lwip works though, so the idea of generating wrappers might sound easier than it is.

I'll do some reading on lwip to see if it's possible to wrap it (my guess is that the python implementation does that).

Honestly, Ethernet, IPv6 and UDP would likely be the simple start since we would not need connections or handshakes or anything, but wrapping a well know and maintained lib is likely better in the long run.

cmol avatar May 01 '23 03:05 cmol

LwIP is a bit of PITA, but it supports three different levels of abstraction - the lowest being a threadless callback model.

I'd also suggest looking at what Earle Philhower did for the Arduino adaptation. He built a shim on top of the CYW43 library:

https://github.com/earlephilhower/arduino-pico/blob/master/libraries/lwIP_CYW43/src/utility/CYW43shim.cpp

timboldt avatar May 01 '23 04:05 timboldt

Honestly, Ethernet, IPv6 and UDP would likely be the simple start since we would not need connections or handshakes or anything, but wrapping a well know and maintained lib is likely better in the long run.

Wrapping lwip would be very nice. That said, as far as the bounty goes I'd want focus hard on having a solid ethernet interface on the CYW43439, even if it means incomplete TCP support. This would be the first step to having good TCP support- if the ethernet layer is shaky then the TCP can't possibly perform well.

I guess we could organize a bounty to get TCP/UDP/IP up to speed after the current one ends.

soypat avatar May 01 '23 19:05 soypat

@soypat happy to contribute testing or cgo translation if needed - otherwise I’m cheering your work from the sidelines

Notargets avatar May 25 '23 01:05 Notargets

As I did the whole worst-case-of-everything-run the PicoW != Pico just somewhat freaked me out.

Running NixOS and neovim rendered things not working at all:

  • tinygo build --target=pico producing hello.elf output
  • tinygo flash --target=pico was unable to shift it over the Pico on NixOS due to whatever
  • tinygo flash --work --target=pico && sudo cp <WORK/main.uf2> ~/usb did the trick, but no blinking LED

As @kenbell stated correctly the LED is not GP25 but WL_GPIO0 on the embedded Infineon 43439 wireless chip. In fact I wasn't able to find GP25 on the pinout documentation, thus it may be used for the wireless chip: See https://datasheets.raspberrypi.com/picow/PicoW-A4-Pinout.pdf

So rewriting the Blinky to GP22 with an external LED and tinygo flash --work --target=pico && sudo cp <WORK/main.uf2> ~/usb finally made the LED blink.

For the flashing I'll bring the setup to GopherConEU and we can figure it out.

For the Blinky I'd love to see the --target=picow support with machine.LED := machine.WL_GPIO0 for beginners, so even if things sum up they won't get upset for the non-functional sample.

marcofeltmann avatar Jun 19 '23 22:06 marcofeltmann

@marcofeltmann See the cyw43439 library for a blinky on the pico w. We're working on this with @scottfeldman, still needs some more work before it is ready to integrate with tinygo.

soypat avatar Jun 20 '23 17:06 soypat

@soypat how’s the TCP + ethernet work going? Need coding help? Is the bounty resolved?

Notargets avatar Jun 22 '23 17:06 Notargets

Hey @Notargets! I've put a pause on the TCP+Ethernet work (dgrams) for now until the ethernet interface is up on the CYW43439 which would greatly help me debug it since working with linux TUN/TAP did not work too well for me. If you want to pick it back up feel free to do so, just be aware as soon as cyw43439 driver is finished I plan on going back to work on it again. Think it'd be great to have lots of people working on it since there is separation of concerns between different protocol implementations, we can work in parallel on TCP/IP and ARP without stepping on our toes. So far dgrams consists of decoding/encoding of tcp/ip packets and a non-functional TCP/IP stack.

One thing to note- to facilitate development we will be moving dgrams into its own subpackage withing cyw43439 so we don't have to manage go versions between two separate repos, which I feel would complicate things. If you are willing to help out with TCP/IP, DHCP or any other interesting internet protocol feel free to file an issue under cyw43439/issues so we can plan the development out!

soypat avatar Jun 23 '23 12:06 soypat

Time for a little update about your favorite microcontroller's wifi chip Go driver!

Switching reference - Bye C, hello Rust

Thanks to some of @scottfeldman 's key insight we've switched References. Initially we were taking inspiration from Damien's cyw43-driver + Pico-SDK mix. This began taking a toll after hitting a certain project size as the source code was hard to follow at times.

It's been barely more than a week since I heard Scott mention the Rust CYW43439 implementation at (embassy-rs) as being "really clean". After taking a look myself it did not take me long to convince myself to switch over to using the rust implementation as the reference- and I can't stress enough how much more easier and pleasant rust is to read than C. Even was able to find a bug in the rust implementation.

You can now find the latest rewrite under the cyrw directory in the repo (stands for CY ReWrite)

Rusty blink

One can run a blinky program using the new version. There's a test program that displays this functionality in action.

Wifi

Since we are switching references we are leaving a lot of progress on the original driver. We had even got the C driver to connect to a wifi network a couple weeks ago!

That said, it's been barely a week with the rust rewrite and we've already made it farther than 2 months in with the original driver. I think we're making the right choice. The new implementation is much easier to follow and has a readable reference, which in itself might not sound like much but I feel there is huge value in it. The rust version is active and is still receiving updates. I've talked with the lead maintainer and the guy is super helpful, even with the most basic of questions. I've asked about everything from basics on generic type instantiation on rust structs all the way to the internals of embassy-rs, and always gotten a quick, helpful response over at the matrix.to channel.

I think there's room to work hand in hand with the rust community to make the best of the Pico W hardware!

Hello... C? Again?!

So... we might not be completely done with C. The rust implementation is great and all but it makes heavy use of asynchronous APIs for Ioctl calls. This can be hard to follow at times since the driver initialization stops being linear. The Rust reference also sometimes takes shortcuts (rarely) and leaves room for questions... in that case we can always recur to the source- the wifi-host-driver.

This is the mother of all drivers- the rust implementation uses it as reference. If I'm not mistaken, even Damien's cyw43-driver is based off the WHD. I've occasionally fallen back to reading the WHD when I'm unsure on how the rust version is doing things.

Vacations / Help wanted

I'm taking a 2 week vacation starting 26 of August and coming back 10 of September. That means that development will slow down by some- it also means things will be more stable.

Dear reader, if you stand to benefit greatly from this driver like myself or anyone who writes embedded Go code and loves cheap, flexible, general purpose compute microcontrollers- consider lending a hand!

Things that help:

  • Reading through the code and comparing with the reference for any differences. This is without a doubt the most helpful task one can do:
    • Example: here's bus.go- if one opens this file one can find links to the reference implementations. Most Go functions have similar, if not identical names to their rust counterpart (yes, even snake_case identifiers!)
  • Porting code! Not all functions have been written. There's some low hanging fruits, like AP functions such as start_ap.
    • If you plan on contributing code please join the Gophers Slack and talk to me or Scott Feldman. Alternatively file an issue at the cyw43439 repo.

Closing remarks

This last month has been hard- but switching from reading C to reading rust has given me a second wind of sorts. From what I can tell we are very near from being able to send and receive ethernet packets with the rust rewrite.

  • By looking at the data on the bus there seems to be differences between what we read over the wlan interface. This could be due to non-reproducibility... that said we are not reading Async packets correctly, so there's likely a bug somewhere there. This could be happening anywhere between wlan_read and check_status... but that's anyone's guess

I think the bug above may very well be the last "hard" bug left (if it really is the last bug behind ioctl calls). The rest of the rust driver is pretty straightforward and simple, relying on the ioctl calls as the backbone of all communications.

soypat avatar Aug 23 '23 03:08 soypat

Time for a little update-

It's alive

After a very succesful bughunt led by @scottfeldman, we now have a fully functional Ethernet interface working on the Pico W #14-- both as a wifi client and with access point functionality (#18) (again, thanks @scottfeldman).

We have implemented our own lightweight IP stack with working DHCP over UDP support (17) and have a working TCP socket (#19) implementation which still needs stateful logic.

What does this mean?

It is not done. This still cannot be used for solving problems as the APIs are still experimental and subject to change. What can be done is testing! @cmol has been lending a hand by running the DHCP client example (info below) and actually found that the same program that does not crash for us crashes for him. It'd be interesting to see if others can start testing with their own Tinygo+PicoW setup to see if there are any latent bugs.

Steps going forward

I'm quite busy the coming weeks preparing for Gophercon 2023 where I'll be giving a talk so it might be a couple weeks before I can resume work.

@scottfeldman will be working on adding more functionality to the Pico W, so that would include like Wifi Scan and any remaining AP/STA functionality we are missing.

Click to see more on the DHCP example

More on the DHCP example

NOTE: You have to add a secret.go file based on the template file in the directory with your wifi credentials for the program to work!

Flash the DHCP example by running

tinygo flash -monitor -target pico -stack-size=8kb -size short  ./examples/dhcp/

This will attach your terminal to the pico W and you'll see a lot of logs printed out. Look for the one that says:

========
DHCP done, your IP:  192.168.1.145 
========

After that the Pico W will turn on it's LED every time it receives a packet. You can try running ping linux/windows utility from terminal to turn on the LED:

$ ping 192.168.1.145
PING 192.168.1.145 (192.168.1.145) 56(84) bytes of data.
From 192.168.1.147 icmp_seq=1 Destination Host Unreachable
From 192.168.1.147 icmp_seq=2 Destination Host Unreachable
From 192.168.1.147 icmp_seq=3 Destination Host Unreachable
From 192.168.1.147 icmp_seq=5 Destination Host Unreachable
From 192.168.1.147 icmp_seq=6 Destination Host Unreachable
^C
--- 192.168.1.145 ping statistics ---
7 packets transmitted, 0 received, +5 errors, 100% packet loss, time 6143ms
pipe 4

The pico W will not respond to ping packets, but will flash it's LED.

soypat avatar Sep 16 '23 22:09 soypat