Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Request] Support for RPi Pico #727

Closed
mateo4778 opened this issue Feb 8, 2021 · 89 comments · Fixed by #772
Closed

[Request] Support for RPi Pico #727

mateo4778 opened this issue Feb 8, 2021 · 89 comments · Fixed by #772

Comments

@mateo4778
Copy link

Has anyone tried using this library with the new Raspberry Pi Pico and its new RP2040 chip? It seems like it should be easy, but since I have only personally used the RF24 library inside the Arduino environment I am not sure what I need to do to integrate this library into a separate C/C++ project or what type of dependencies are needed etc.

Any advice or comments on how I would go about trying to get this working would be much appreciated.

@2bndy5
Copy link
Member

2bndy5 commented Feb 8, 2021

Last I checked, we were still waiting for the Arduino RP2040 core to get finished (RP2040 has its own C++ SDK that Arduino folks had to use to to extend support for the IDE).

The RP2040 exposes multiple hardware SPI buses, so we may have to chew on that a bit.

@mateo4778
Copy link
Author

Yea I don't necessarily need to use the Arduino IDE for this. Or is this library written in such a way that it utilizes Arduino IDE build tool components or api?

As you said it seems easy enough to access the RP2040 hardware SPI bus so would it be as easy as adapting the RF24 library to the RP2040 SPI access syntax? Or maybe I am missing something big.

@2bndy5
Copy link
Member

2bndy5 commented Feb 8, 2021

I was thinking this library wouldn't need to change much if we rely on the Arduino core for RP2040.

If you want to add native platform support you could have a look at the docs about porting RF24 library to new platforms

@2bndy5
Copy link
Member

2bndy5 commented Mar 16, 2021

@mateo4778 Have made progress on this? Or have you also decided to wait for the official Arduino Core to be published?

I ask because I'm currently working on allowing non-primary SPI buses to be specified for the RF24 lib, but this means abstracting the SPI bus object's datatype (to use as a pointer) instead of directly using an instantiated singleton object...

@kripton
Copy link

kripton commented Mar 31, 2021

Hi, I've started working on this. Current status: master...kripton:rpi-pico

I do have one nRF24L01+ attached. I'm using SPI0 and the GPIOs used are currently hardcoded in the SPI class (SCK on GPIO2, MOSI on GPIO3, MISO on GPIO4). CSN and CE are (as usual) given to the RF24 ctor. SPI baudrate is fixed to 250kbit/s.

I cannot say that I've proven this to work since today I just achieved the current status with one nRF24 module. There hasn't been yet a second module to receive/reply the packages. But I've attached a logic sniffer to the SPI bus and the initialization and sending (one packet each second) look fine in pulseview (using the integrated SPI and nRF24L01+ protocol decoders).

The code isn't yet beautiful or optimized and contains debugging printfs. I also had to copy the includes.h file to utilities/ since I didn't figure out how the include chain works otherwise. Please feel free to fix or improve.

And of course, thank you all for providing this awesome library. I can't wait to have multiple RPi Picos working with RF24Mesh :D

@kripton
Copy link

kripton commented Mar 31, 2021

Screenshot of pulseview showing the communication between a RPi Pico (using the patched RF24 library) and an nRF24L01+:
image

@2bndy5
Copy link
Member

2bndy5 commented Mar 31, 2021

I also had to copy the includes.h file to utilities/ since I didn't figure out how the include chain works otherwise.

the /configure bash script does auto detection of current platform, then copies the appropriate includes.h into the repo root folder.

I actually had a thought about trying to detect the SDK at compile time (not during ./configure) using the RP2040 SDK's macros that describe the SDK version (which are set using CMake). This would be similar to how other microcontroller platforms are detected (because Arduino's GCC commands include -DARDUINO or -DARDUINO_ARCH_xxx). Additionally, the inclusion of the RP2040's includes.h could be automatic within RF24_config.h:

#if defined (PICO_SDK_VERSION_MAJOR)
#include "utility/rp2040/includes.h"
#endif

There might be a better macro to use for this like PICO_PLATFORM, I'm not too familiar with the SDK (yet).

@kripton
Copy link

kripton commented Mar 31, 2021

Ah, right, in the configure script. I didn't look there since as you correctly pointed out, the cmake based Pico projects compile all libraries and the SDK itself together. So I basically added the RF24 lib as a git submodule to the project.
The idea with checking the defines and automatically including the correct file is great. I will try that tomorrow.
I'd propose to use "rpi-rp2" for the platform.name, as done here: https://github.com/micropython/micropython/tree/master/ports/rp2 since "rp2040" designates the chips memory size as well and in future there might be a "rp2060" or so

@2bndy5
Copy link
Member

2bndy5 commented Mar 31, 2021

ok, now I'm excited!

did you have a chance to look over #743 so we could specify a secondary SPI bus (this feature will be merged with #750).

@2bndy5 2bndy5 changed the title [Question] Support for RPi Pico? [Request] Support for RPi Pico Apr 1, 2021
@2bndy5
Copy link
Member

2bndy5 commented Apr 1, 2021

@kripton I've added your fork to my local clone's remotes, and I'm still reading through the SDK docs... You might see a PR from me for your fork.

Also, I recently got a Feather RP2040 from Adafruit, so hopefully I'll also be able to do some testing 🤞🏼. Although, I don't have a fancy oscilloscope to look at the SPI pulses (yet).

Thank you for taking the lead on this. BTW, we're also trying to upgrade to CMake (#676) , but I'm not sure how useful that would be yet (concerning the Pico SDK).

@2bndy5
Copy link
Member

2bndy5 commented Apr 1, 2021

@kripton could you put a copy of the example your working with in a "examples_pico" folder (kinda like we have a "examples_linux" folder) on your fork? I just want to see the full breadth of your work so far. My hope is that we could use the Linux examples also for the RP2xxx if I trade all my cout usage for printf() (using CMake of course).

The SDK comes with board definitions for all the popular variants using the RP2040 chip. Targeting a board was made freaking easy using cmake -DPICO_BOARD=adafruit_feather_rp2040.

  • Looking at your code and the board definition for the RPi Pico, I can see you're not using the default SPI pins that are defined. We should probably use these macros in SPI::begin(), and overload it with SPI::begin(hw_id, sclk, mosi, miso) which could also apply to a SoftSPI implementation (maybe even using the PIO ASM). But softSPI is way down on the list of priorities; for an example I would look to the MicroPython SPI docs.
  • Further comparison to the Arduino common SPI API, the SDK's spi_init() and spi_deinit() should be used to implement SPI::beginTransaction() and SPI::endTransaction, so we can still share the SPI bus with another SPI slave. The beginTransaction would have to also internally call spi_set_format() as it resembles Arduino API's SPISettings offering.

These points are just what I've got spinning in my head, and I wanted to jot them down somewhere (so you're not blindsided by a PR from me). This SDK & chip are soooo promising!! 😍 I'll probably start a how-to doc for this lib when I understand everything you did to get the example code compiled.

@kripton
Copy link

kripton commented Apr 1, 2021

@kripton could you put a copy of the example your working with in a "examples_pico" folder (kinda like we have a "examples_linux" folder) on your fork? I just want to see the full breadth of your work so far. My hope is that we could use the Linux examples also for the RP2xxx if I trade all my cout usage for printf() (using CMake of course).

Oh wow, you're faster than I thought :) I was also working on this to have the conditional include in RF24_config.h
So to see my current usage of the library, this would be in: https://github.com/kripton/rp2040-dongle/blob/kripton-rf24/src/wireless.cpp. So it's not a complete example, it's just the bare minimal code to get it up and running.

Yes, I did see your work on the overload-begin-branch. I didn't yet jump onto it to do the Pico-enabling work since I don't know the timeframe, when you plan to merge it into main branch. But sure, it would be great to have the flexibility to configure the SPI hardware and pins used 👍

I agree that switching RF24 to cmake would be desirable but it probably won't make much difference when using it with a rp2040-based board. Where we could take a look is how to make RF24 compatible with the link-libraries cmake-command that the pico-examples use to access TinyUSB: https://github.com/raspberrypi/pico-examples/blob/master/usb/device/dev_hid_composite/CMakeLists.txt#L8. For the moment, in my project's cmake-file, I'm referencing the cpp files directly: https://github.com/kripton/rp2040-dongle/blob/kripton-rf24/src/CMakeLists.txt#L19

Looking at your code and the board definition for the RPi Pico, I can see you're not using the default SPI pins that are defined. We should probably use these macros in SPI::begin(), and overload it with SPI::begin(hw_id, sclk, mosi, miso) which could also apply to a SoftSPI implementation (maybe even using the PIO ASM). But softSPI is way down on the list of priorities; for an example I would look to the MicroPython SPI docs.

Further comparison to the Arduino common SPI API, the SDK's spi_init() and spi_deinit() should be used to implement SPI::beginTransaction() and SPI::endTransaction, so we can still share the SPI bus with another SPI slave. The beginTransaction would have to also internally call spi_set_format() as it resembles Arduino API's SPISettings offering.

Yes, defining the SPI pins via overload definitely makes sense. Honestly, I don't know that the default pins of SPI0 are. I assume that GPIO0 and GPIO1 are UART by default, even though they also support SPI0.

Sure, the SPI changes you are proposing all make sense to me. SPI is quite new to me, I've rather used I2C in the past.

These points are just what I've got spinning in my head, and I wanted to jot them down somewhere (so you're not blindsided by a PR from me). This SDK & chip are soooo promising!! heart_eyes I'll probably start a how-to doc for this lib when I understand everything you did to get the example code compiled.

Great, I also prefer early any open communication :) Agreed, the rp2040 is amazing (especially the PIOs) and also with a very good price point.

Awesome, having an easy and well documented solution to interface with nRF24-radios would be perfect!

@kripton
Copy link

kripton commented Apr 1, 2021

I pushed my latest changes to my RF24-branch and to https://github.com/kripton/rp2040-dongle/tree/kripton-rf24. Now, the includes.h is no longer required in the utility-folder and I've renamed RPi-Pico to rp2.

@kripton
Copy link

kripton commented Apr 1, 2021

Also, I recently got a Feather RP2040 from Adafruit, so hopefully I'll also be able to do some testing 🤞🏼. Although, I don't have a fancy oscilloscope to look at the SPI pulses (yet).

Great that you also ordered a RP2040-based board 🎉
About the "scope": It's actually the sigrok/pulseview open-source software + a ~$5 "logic analyzer": https://sigrok.org/wiki/Fx2lafw https://sigrok.org/wiki/Lcsoft_Mini_Board. Just search for "fx2lp" on eBay or similar shops ;)

@2bndy5
Copy link
Member

2bndy5 commented Apr 1, 2021

I just had an idea that might ease testing: Use Github actions to build the examples' executable binaries against the Pico SDK (for all boards defined in the SDK) and save the build artifacts (*.elf, *.uf2) on success.

This would help others that don't have the development environment setup locally but want to quickly test this library's examples on their RP2040-based boards!

@2bndy5
Copy link
Member

2bndy5 commented Apr 2, 2021

Just found out that someone wrote an unofficial ArduinoCore that uses the Pico SDK. Although, I haven't tried it...

@2bndy5
Copy link
Member

2bndy5 commented Apr 2, 2021

@kripton I just created an untested branch called rp2xxx based on your work. Because you aren't using the Pico board's default SPI0 pins, the code you are running will need some modification about which pins are used by the SPI bus.

The SPI frequency should now be specified from the RF24 c'tor:

RF24 radio(28, 5, 250000); // default frequency is 10000000

Based on the pin numbers your code currently uses, the modification can be either 1 of 2 ways:

  1. in your project (probably best in wireless.cpp) you can re-define the default pins
    #define PICO_DEFAULT_SPI_SCK_PIN 2
    #define PICO_DEFAULT_SPI_TX_PIN 3
    #define PICO_DEFAULT_SPI_RX_PIN 4
  2. alter the SPI.begin() call in wireless.cpp, then pass the modified SPI object to RF24::begin()
    SPI.begin(spi0, 2, 3, 4);
    
    if (!radio.begin(&SPI)) {
        printf("Radio hardware is not responding!\n");
        // ...
    }

Questions & Notes

  • I noticed you infinitely retry to call radio.begin() in your code. Do you often see the

    Radio hardware is not responding!

    prompt before radio.begin() returns true? Or was this tactic helpful (& now an artifact) in developing the basic support?

  • I'm guessing that you never saw any

    PicoRF24: SPI::transfernb(char* tbuf, char* rbuf, uint32_t len: <size>)

    prompts in your development. It looked like the RF24.cpp SPI functions never triggered tansfers with uint8_t* buffers. You should definitely see those prompts now.

  • I hope its ok if I "borrow" some work from your projects' pico-build.yml to create a more generic CI build for RF24 examples (when they're written/ready).

  • The way your project includes the RF24 lib as a submodule (& given that the branch I just published is on upstream), I don't think a PR into your fork is really warranted. I could issue a PR if you want, but I'm afraid of some merge conflicts since I merged the overload-begin branch's changes with changes from your branch before making any additional changes.

@kripton
Copy link

kripton commented Apr 2, 2021

@kripton I just created an untested branch called rp2xxx based on your work.

Wow, amaging work! I needed to do some fixes to get it compile (kripton@1f40cb7) but well done!

  1. in your project (probably best in wireless.cpp) you can re-define the default pins
    #define PICO_DEFAULT_SPI_SCK_PIN 2
    #define PICO_DEFAULT_SPI_TX_PIN 3
    #define PICO_DEFAULT_SPI_RX_PIN 4

I tried that. gcc warned me that the values are redefined but SPI comms to the radio didn't work. Also nothing SPI was in the logic analyzer.

  1. alter the SPI.begin() call in wireless.cpp, then pass the modified SPI object to RF24::begin()
    SPI.begin(spi0, 2, 3, 4);
    
    if (!radio.begin(&SPI)) {
        printf("Radio hardware is not responding!\n");
        // ...
    }

That worked. SPI communication took place and raduo was detected (at 10MHz SPI).

Questions & Notes

Yep, that was before I attached the logic analyzer and didn't know why it failed. Probably bad cabling. By now, the command succeeds on the first call.

  • I'm guessing that you never saw any

    PicoRF24: SPI::transfernb(char* tbuf, char* rbuf, uint32_t len: )

    prompts in your development. It looked like the RF24.cpp SPI functions never triggered tansfers with uint8_t* buffers. You should definitely see those prompts now.

Both true. With my old code, it didn't do transactions at all. With your code, it does. Looks nice in pulseview as well :)

  • I hope its ok if I "borrow" some work from your projects' pico-build.yml to create a more generic CI build for RF24 examples (when they're written/ready).

Of course that's okay. This is why we develop Open Source: so others can also profit from what we do :)

  • The way your project includes the RF24 lib as a submodule (& given that the branch I just published is on upstream), I don't think a PR into your fork is really warranted. I could issue a PR if you want, but I'm afraid of some merge conflicts since I merged the overload-begin branch's changes with changes from your branch before making any additional changes.

Perfectly fine.

So while the code compiles, detects the module just fines and queses payloads for transmitting (looks good to my unexperienced eyes in pulseview as well), the packets are not received by an Arduino Mega running the "getting started" example. Took me a while to realize why the radio module was not detected on the Arduino: The mega has SPI on Pins 50, 51 and 52. Then, radio module wqs detected just fine but no RX reported. Next step: Have two Arduinos with the example to proof RX is working on the first place. It's a pity my RTL SDRs don't tune up to 2400MHz :(

@2bndy5
Copy link
Member

2bndy5 commented Apr 2, 2021

radio module was detected just fine but no RX reported.

The gettingStarted example had the payload size set to something different than 16 (actually set to 4 IIRC). need to make this setting match

Option 2 is from the overload-begin branch, so I'm glad that worked. Option 1 was from reading the SDK docs, but maybe cmake's include order would be detrimental there (evident by the gcc warning).

I'll grab your fixes into upstream before continuing. Thanks for being patient with my rookie #ifdef soup recipes; the de-referencing * and missing scope resolution (SPI::) were just things that I missed.

@kripton
Copy link

kripton commented Apr 6, 2021

Just a short status update so you know where I stand:

radio module was detected just fine but no RX reported.

The gettingStarted example had the payload size set to something different than 16 (actually set to 4 IIRC). need to make this setting match

Yes, I assumed that and matched payloadsize, channel and datarate from the wireless.cpp code running on the RP2040 and the Getting started example running on the Arduino. Still no luck.

However, I tried the Getting started example with two Arduinos and 250kHz SPI clock. They both find their respective nRF24-module but don't seem to be able to exchange radio messages. So it seems that there is a more general problem than just the code for the rp2040 :(

I've also tried to get the https://github.com/BastilleResearch/mousejack / https://github.com/BastilleResearch/nrf-research-firmware running on my CrazyRadio PA dongle (nRF24LU1+). It could then be used as a scanner + sniffer. The code seems to work after some Python-3-updating (BastilleResearch/nrf-research-firmware#28). The scanner also displays few frames and the payload looks what I would expect to be sent by the rf2040-dongle. Sadly, not nearly as much frames as expected are displayed.

Option 2 is from the overload-begin branch, so I'm glad that worked. Option 1 was from reading the SDK docs, but maybe cmake's include order would be detrimental there (evident by the gcc warning).

I'll grab your fixes into upstream before continuing. Thanks for being patient with my rookie #ifdef soup recipes; the de-referencing * and missing scope resolution (SPI::) were just things that I missed.

I've retried Option 1 (re-#define the default SPI0 pins) with the defines after the #include but it still doesn't work.

Sure, no problems about the coding woes. Most of them were easy fixes. Basically all but the missing #defines. That required some more code reading than expected.

Have you already been able to test your code on your Adafruit feather powered by the rp2040?

@2bndy5
Copy link
Member

2bndy5 commented Apr 6, 2021

Have you already been able to test your code on your Adafruit feather powered by the rp2040?

TBH, I took a break to return some focus to our RF24Log lib (we're trying to replace the limited printf() support that the RF24* libs use for general stdout usage). In fact, I was so excited to start this new platform support that I haven't even gotten around to soldiering the header/SWD pins to my Feather RP2040 🤦🏼‍♂️

I have been focusing more on porting the attachInterrupt() & detachInterrupt() methods to use the Pico SDK. I also briefly looked into redirecting stdout to UART instead of USB (for the same reason we're developing the RF24Log lib) which is what led me to pass on that lead (on your rpdongle project) about resetting the Pico into bootloader mode.

They both find their respective nRF24-module but don't seem to be able to exchange radio messages. So it seems that there is a more general problem than just the code for the rp2040 :(

This seems like standard troubleshooting. My usual questions to help people assess the problem would be:

  1. what capacitors are you using? Or are you using an adapter board for the nRF24 radios?
  2. What type of nRF24 module are you using? Is it the PA/LNA modules?

Both questions are concerned with power supply stability because If you're running the same code on both MCUs driving the radios, then its probably a power supply issue.

Yes, I assumed that and matched payloadsize, channel and datarate

So I see you read the COMMON_ISSUES.md file about "settings the must match", but there is other advice below that focuses on capacitors and PA/LNA modules.

@2bndy5
Copy link
Member

2bndy5 commented Apr 6, 2021

I've retried Option 1 (re-#define the default SPI0 pins) with the defines after the #include but it still doesn't work.

It may be better to do this on the CLI:

-DPICO_DEFAULT_SPI_SCK_PIN=2 -DPICO_DEFAULT_SPI_TX_PIN=3 -DPICO_DEFAULT_SPI_RX_PIN=4

@2bndy5
Copy link
Member

2bndy5 commented Apr 7, 2021

Looks like the RPi Pico board uses a RT6150B-33GQW (rated for 800mA nominal output) to regulate the USB voltage (VBus) down to 3.3V.

I soldiered the header pins to my Feather RP2040 and used the USB voltage to power my adapter board (which independently regulates 5V to 3.3V with inherent capacitors) for the nRF24L01. At first there was no power being delivered, but I think that was a wiring issue because I moved wires around and it delivered power from USB.

Initially, I tried CircuitPython firmware v6.2.0 (released yesterday) with my circuitpython_nrf24l01 library and I was able to run the gettingStarted.ino sketch on an Arduino Nano to successfully communicate with my lib's simple_test.py example 👍🏼 I intentionally wrote them to be compatible with each other (excluding library default differences like dynamic_payloads).

Next, I'll try the rp2xx branch, but I want to write a gettingStarted.cpp example to compile with CMake first... Mainly to learn about using CMake but mostly to reduce the program running on the RP2040 to minimal tasks (I'm not sure what else is going on with your rpdongle project).

ps. @kripton Does DMX stand for Digital muxer/ing (assuming it has nothing to do with the musician)? Your project's readme never explains what DMX stands for. Coming from an english tutor background its good to know your audience but bad to assume what your audience knows.

@kripton
Copy link

kripton commented Apr 7, 2021

TBH, I took a break to return some focus to our RF24Log lib (we're trying to replace the limited printf() support that the RF24* libs use for general stdout usage). In fact, I was so excited to start this new platform support that I haven't even gotten around to soldiering the header/SWD pins to my Feather RP2040 🤦🏼‍♂️

Don't worry :) Working on a good common logging library is also worth a ton. Thank you :)

I have been focusing more on porting the attachInterrupt() & detachInterrupt() methods to use the Pico SDK. I also briefly looked into redirecting stdout to UART instead of USB (for the same reason we're developing the RF24Log lib) which is what led me to pass on that lead (on your rpdongle project) about resetting the Pico into bootloader mode.

Cool. Didn't yet care too much around the interrupts on the Pico. I do have some sample code running that works with interrupts to shove data via DMA to the PIO.

Yeah, that's (stdout either via hardware UART or USB) a thing that the Pico-SDK makes really easy. Just compare https://github.com/raspberrypi/pico-examples/tree/master/hello_world/serial against https://github.com/raspberrypi/pico-examples/tree/master/hello_world/usb. The https://github.com/OpenLightingProject/rp2040-dongle code needs a bit more stuff copied from the SDK since it's using custom USB identifiers and interfaces.

Yep, thanks for the lead regarding entering the bootloader 👍 Actually, in the SDK there is a specific command for that: https://datasheets.raspberrypi.org/pico/raspberry-pi-pico-c-sdk.pdf#%5B%7B%22num%22%3A228%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C115%2C167.598%2Cnull%5D (function reset_usb_boot).

This seems like standard troubleshooting. My usual questions to help people assess the problem would be:
1. what capacitors are you using? Or are you using an adapter board for the nRF24 radios?
2. What type of nRF24 module are you using? Is it the PA/LNA modules?
Both questions are concerned with power supply stability because If you're running the same code on both MCUs driving the radios, then its probably a power supply issue.

Indeed, I also read a lot on that lately. Answers:

  1. I didn't use any caps until today, assuming that the Pico's LDO is powerful enough for the nRF24-dongle.
  2. I have both here, trying the non-PA/LNAs first since they should consume less power

In the meantime (yesterday) I already ordered the nRF24-adapter boards so I can power the modules with 5V. They didn't yet arrive.
Nevertheless I found some 85µF/10V-caps around here and soldered them directly onto two of the modules. Result: it's all working perfectly fine now!. In between I assumed I had counterfeit chips and the library doesn't handle them properly. But with the caps, the GettingStarted example between two Arduinos works and also sending 16 byte payload from the RP2040 to one Arduino is working like a charm! I'm so happy :D

Will you be writing a getting-started example for the rp2040 or shall I start? Just want to avoid the work being done twice in case you are already at it.

Looks like the RPi Pico board uses a RT6150B-33GQW (rated for 800mA nominal output) to regulate the USB voltage (VBus) down to 3.3V.

I soldiered the header pins to my Feather RP2040 and used the USB voltage to power my adapter board (which independently regulates 5V to 3.3V with inherent capacitors) for the nRF24L01. At first there was no power being delivered, but I think that was a wiring issue because I moved wires around and it delivered power from USB.

The Pico datasheet says that it should be safe to draw 300mA from the board's regulator: https://datasheets.raspberrypi.org/pico/pico-datasheet.pdf, chapter 2.1: "3V3 is the main 3.3V supply to RP2040 and its I/O, generated by the on-board SMPS. This pin can be used to powerexternal circuitry (maximum output current will depend on RP2040 load and VSYS voltage, it is recommended to keepthe load on this pin less than 300mA)."

Initially, I tried CircuitPython firmware v6.2.0 (released yesterday) with my circuitpython_nrf24l01 library and I was able to run the gettingStarted.ino sketch on an Arduino Nano to successfully communicate with my lib's simple_test.py example 👍🏼 I intentionally wrote them to be compatible with each other (excluding library default differences like dynamic_payloads).

Next, I'll try the rp2xx branch, but I want to write a gettingStarted.cpp example to compile with CMake first... Mainly to learn about using CMake but mostly to reduce the program running on the RP2040 to minimal tasks (I'm not sure what else is going on with your rpdongle project).

Great to hear. Yes, the rp2040-dongle does quite a bit besides RF already and it's planned to do a lot more ;)

ps. @kripton Does DMX stand for Digital muxer/ing (assuming it has nothing to do with the musician)? Your project's readme never explains what DMX stands for. Coming from an english tutor background its good to know your audience but bad to assume what your audience knows.

Right, DMX is not about the musician. It's about https://en.wikipedia.org/wiki/DMX512 (so DMX stands for digital multiplex) and used to control stage lighting mainly. The plan for the rp2040-dongle is to be connected via USB to a PC that generates the light control signals and convert them to the RS-485-based signals understood by the lighting fixtures. And in addition, wireless DMX is becoming more and more common, so why not play around with it if we can simply add a nRF24-dongle to the boards for very cheap ;)
The main discussions currently happen here: https://github.com/OpenLightingProject/rp2040-dongle/discussions

You are right that the README should explain this, I will add it the coming days. Main reason it's not there is that the repo is in the context of https://github.com/OpenLightingProject / https://www.openlighting.org/. That makes it clear to people used to such things what it's about. But I fully agree that the repo itself should at least mention it.

@2bndy5
Copy link
Member

2bndy5 commented Apr 7, 2021

But with the caps, the GettingStarted example between two Arduinos works and also sending 16 byte payload from the RP2040 to one Arduino is working like a charm! I'm so happy :D

That's f***in awesome!!

The Pico datasheet says that it should be safe to draw 300mA from the board's regulator ... it is recommended to keepthe load on this pin less than 300mA).

Good find! I don't foresee a problem with the PA/LNA modules under a 300mA restriction.

Will you be writing a getting-started example for the rp2040 or shall I start?

Actually I put together a gettingStarted example, but got stumped on the CMake process... I'll commit what I have to rp2xxx branch.

Furthermore, in writing the example specifically for the Pico SDK, I decided to try to stick with functions native to the SDK. ie. using sleep_ms() instead of calling delay() in the examples' code. This conception led me to believe that attachInterrupt() and detachInterrupt() shouldn't be ported; its only the RF24 lib src code that needs to follow Arduino convention.

And in addition, wireless DMX is becoming more and more common, so why not play around with it if we can simply add a nRF24-dongle to the boards for very cheap ;)

What you describe sounds like an interesting project. And the nRF24Lxx is a commonly used transceiver in many manufactured solutions; I found that my Steam Controller uses a nRF24LU1 in its receiving dongle as does all Logitech unifying receiver dongles (though they switched to an even cheaper knock-off from Texas Instruments -- OTA compatible -- a few years ago).

@2bndy5
Copy link
Member

2bndy5 commented Apr 13, 2021

I'm stumped; There are 2 problematic examples

manualAck example

While the TX role works perfectly, I tried looking into why RF24::txStandby(uint32_t timeout) always returns a false-positive during the RX role of the manualAck example:

  • txStandby() seems to re-transmit 6 (or more) times in 150 ms; debug output showed about 170 ms but measurement was taken with a slight delay (basically a duplicated call to millis() - start)
  • counterpart program (TX role on Arduino Nano) showed payload was received (with payload.counter properly incremented) despite what the RP2040 program (as RX role) was saying.
  • Its worth noting that this example has always been a bit buggy for me (especially when testing an Arduino Nano with an RPi). I usually defer to a second opinion for more accuracy (it might be a capacitor problem for me).

IRQ example

This one is always difficult to debug because it happens so freaking fast! Also there are usually stipulations about what a MCU can do during an ISR callback (I'm guessing the RP2040 has trouble accessing the USB serial connection during an ISR function).

  • TX role works, but the ISR callback function isn't always printing anything it should. The fact that this role completes tells me that the ISR is triggered and the radio's IRQ event is cleared 😕
  • RX role works but doesn't always complete. I have observed that the counterpart (TX role on Arduino Nano) outputs successful prompts, but the RP2040 sometimes doesn't go into printRxFifo() when the RX FIFO is completely full 😕 Again the ISR function doesn't always print what it should during RX role.
  • I'm using pin 6 for the radio's IRQ connection.

I'd post output results, but this post is already long and the description above is more accurate than the output can show. Its worth noting that the ISR callback function's parameters are receiving

gpio = 6, event = 4

for a FALLING event on the IRQ pin

@Avamander
Copy link
Member

but the ISR callback function isn't always printing anything it should.

Yeah, it probably requires setting a variable and using that variable to print the message later in the main loop.

@2bndy5
Copy link
Member

2bndy5 commented Apr 13, 2021

I'm using a volatile bool to hold the main loop while expecting an IRQ event, and a iterator for traversing the predefined payloads. So, I think I can revise the example to take most of the printf() stuff out; it's just the status flags that are specific to calling whatHappened() in the ISR function.

It's a little strange because the Pico SDK example (for IRQ callback) does nothing but print the event and pin in the ISR. Maybe the if block that waits for user input (like Serial.available()) is holding things up; I currently have all pico examples set to wait up to 500 ms for user input on each loop() iteration. I don't think a timeout is required though because I vaguely remember the SDK saying that the Serial connection is buffered.

@2bndy5
Copy link
Member

2bndy5 commented Apr 13, 2021

I just bought a QtPy 2040 😍 from adafruit (I love the form factor of their QtPy board which are basically clones of the Seeeduino Xiao). I also bought some extra SWD headers, so maybe I can debug these examples properly (I seem to have lost the other SWD headers I had).

@kripton
Copy link

kripton commented Apr 13, 2021

Oh, that sounds great! Maybe I should also order some other rp2040-based boards besides my Picos. Today waa just soldering time for me since my PCBs arrived <3. So, unfortunately still no time to test the examples :(
But boards are working as expected, so now I have 3 Picos with nRF modules right besides them.

@kripton
Copy link

kripton commented Apr 14, 2021

Again, no big testing session today, but a PR for the howto document: #761

About the Qt Py: Shipping to Germany from adafruit.com directly is way too expensive and the European distributors don't yet have Adafruit's rp2040-based boards :(

@2bndy5
Copy link
Member

2bndy5 commented Apr 14, 2021

Left a review for that PR...

Sorry to hear about shipping to Germany; that's a bummer. I also always choose the cheapest shipping (I'm usually not in a rush).

@2bndy5
Copy link
Member

2bndy5 commented Apr 16, 2021

I think that soft SPI can be implemented based on the pico-examples/pio/spi/ code.

This is officially the 3rd longest thread in the history of this repo. We can keep going for the gold (by surpassing 122 comments) or I was thinking of creating a github project (basically a Kanban board) and subsequent issues to make it easier for others to follow up/along. Oops, @Avamander I can't create a github project (on upstream or at org level) because I lack the privileges.

@Avamander
Copy link
Member

I was thinking of creating a github project (basically a Kanban board) and subsequent issues to make it easier for others to follow up/along.

@2bndy5, if it's about things related to RF24, RF24's Kanban board could be enabled.

@2bndy5
Copy link
Member

2bndy5 commented Apr 17, 2021

Well this issue is currently colliding with the CMake issue, and kripton is looking into RF24Network and RF24Mesh for Pico SDK support (which will also need a CMake implementation). And then there will be that automated install script the TMRh20 hosts in TMRh20.github.io repo that will need adjusting... Basically we're beginning to polish this issue, but doing so will entail solving other issues (some of which haven't been created yet).

@kripton
Copy link

kripton commented Apr 17, 2021

Regarding SoftSPI and a task board: I would personally prefer to release the rp2xxxx-support "quite soon" with the features currently available and implement additional stuff (such as SoftSPI) later. How that work is then tracked (via a new issue or some kind of Kanban-board) is up to you ;)

I'm not sure if the current implementation collides with the CMake-implementation proposed in #676 . I've seen that you pinged me there. The work indeed looks interesting and well done but my cmake-skills are too basic to actually judge it. I might try it on my Pis once.

CMake for RF24Network and RF24Mesh is actually done: https://github.com/kripton/RF24Network/blob/603c3af7c19db0b4b8eeb804c24594aa78891b01/CMakeLists.txt and https://github.com/kripton/RF24Mesh/blob/0b041cb0a4c79ed15c6b37e26fea7daa26486d10/CMakeLists.txt. However, if cmake-support should be added to those as well (which I would assume), that might collide as well. That's the main reason I didn't yet raise them as PR. I can of course and we can discuss that in those repos then.

@2bndy5
Copy link
Member

2bndy5 commented Apr 18, 2021

I'm not sure if the current implementation collides with the CMake implementation proposed in #676

The rp2xxx branch declares RF24 as an INTERFACE lib while #676 proposal declares RF24 as a STATIC lib. The main difference is that an INTERFACE lib needs all the necessary files explicitly named for CMake (STATIC libs don't require this).

My initial thought is that we should use the RF24_DRIVER var (from #676 proposal) to determine if the RF24 lib should be a STATIC or INTERFACE lib in the top level CMakeLists.txt. This would also require modifying the current how-to doc we put together for the rp2xxx branch.

Its worth saying that (I think) RF24 as an INTERFACE lib would suite the Pico SDK build paradigm (because all Pico SDK libs are INTERFACE libs), and only 1 program will be using the RF24 lib (on the RP2040 based boards). But to build on Linux, RF24 (I think) should be a STATIC lib that's built for the user-specified or automatically defaulted Linux driver (RF24_DRIVER which is declared as a INTERFACE lib in #676 proposal) because any multitude of programs (on the target machine) can simply #include "RF24/RF24.h".

CMake for RF24Network and RF24Mesh is actually done: kripton/RF24Network/CMakeLists.txt and kripton/RF24Mesh/CMakeLists.txt.

Personally, I think this modification should be PR'd into their respective repos before calling Pico SDK support complete (or at least a stable foundation). If RF24 gets outfitted with CMake (for building on Linux or Pico SDK), then all other Linux-applicable RF24* libs should get the same treatment. With the current modification proposed by @kripton for RF24Mesh & RF24Network, CMake will only work for the Pico SDK, and the current Makefile will still work as it always has.

I would personally prefer to release the rp2xxxx-support "quite soon" with the features currently available and implement additional stuff (such as SoftSPI) later.

I still haven't fleshed out the manACK & IRQ examples' problems. However, you're right; we could keep the current build system in place for Linux and patch in CMake for Linux later. I imagine the CMake implementation for Linux would nullify/break using the current RF24/Makefile and RF24/configure files. I just don't want people to assume (since we're using CMake for the Pico SDK) that CMake would also work for Linux builds. However, if we stagger the release of CMake integration, then we might attract other CMake aficionados to help realize the CMake implementation for Linux builds.


I have ulterior motives for wanting a CMake implementation for Linux builds (see this comment).

@kripton
Copy link

kripton commented Apr 18, 2021

Thanks, that were some very good explanations.

I do completely understand and support migrating the current build system to CMake. And I also understand and support that on "standard" Linux, a shared library will be the result while for the Pico-sdk, it will be an INTERFACE library.

There are two points we could check to know for which target we are building (deciding between pico-sdk and other build systems). I currently don't know how Android is handled by cmake but I will check the CMake files at https://github.com/AndruePeters/RF24/tree/use-cmake to understand.

  • For Linux, the CMakeLists.txt file in RF24's root folder will be the top-level one wheres for a pico-sdk build, the file will be included via the one in the project being built. Checking for top-level can be done as in https://stackoverflow.com/a/42716588 for example
  • For a pico-sdk based build and with the include('../lib/RF24/CMakeLists.txt) happening after initializing/bootstrapping the pico-sdk, there are variables set relating to the pico-sdk. If those are set, one could behave as an INTERFACE-library or build a SHARED library otherwise.

I will try to implement the second case on top of https://github.com/AndruePeters/RF24/tree/use-cmake this evening. Will keep you updated and hoping to crack the 122 comments soon :D

@kripton
Copy link

kripton commented Apr 18, 2021

Done :D
kripton@443b08f

What I did:

  • In the rp2xxx-branch, move the CMakeLists.txt-file from the root folder to "utility/rp2"
  • Rebase @AndruePeter's "use-cmake"-branch on top of "rp2xxx" (actually only one commit, so basically a cherry-pick). The other way around would have been a lot harder to do. This leaves his "CMakeLists.txt" file in the root folder
  • Adapt both CMakeLists files so they place nicely together

GitHub-Action results look good to me:
Linux build action
and
rp2xxx build action

I haven't tested the build results yet but would be surprised if that broke anything. Comments in the CMakeLists files could be nicer but all relevant docs should still be valid.

@kripton kripton mentioned this issue Apr 18, 2021
@2bndy5
Copy link
Member

2bndy5 commented Apr 18, 2021

FYI, the Linux build action still employs the configure & Makefile system (not the CMake system).

@kripton This an interesting solution, and I'm ok with it (because if it works then it works). Its worth saying that I don't have any idea about CMake conventional standards. Every time you do something with CMake, I'm reminded how little I know about CMake 😆 .

@kripton
Copy link

kripton commented Apr 18, 2021

Ah, okay, I see. This is how far I get with building it locally with the merged cmake-files:

kripton@momo ~/git/rp2040-dongle/lib/RF24/build $ cmake .. -DRF24_DRIVER=SPIDEV
-- The CXX compiler identification is GNU 10.3.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Setting build type to 'RelWithDebInfo' as none was specified.
-- ccache found and enabled
Using driver: SPIDEV
-- Configuring done
-- Generating done
-- Build files have been written to: /home/kripton/git/rp2040-dongle/lib/RF24/build
kripton@momo ~/git/rp2040-dongle/lib/RF24/build $ make -j4
[ 16%] Building CXX object utility/SPIDEV/CMakeFiles/SPIDEVDriver.dir/compatibility.cpp.o
[ 33%] Building CXX object utility/SPIDEV/CMakeFiles/SPIDEVDriver.dir/spi.cpp.o
[ 50%] Building CXX object utility/SPIDEV/CMakeFiles/SPIDEVDriver.dir/gpio.cpp.o
[ 66%] Building CXX object CMakeFiles/RF24.dir/RF24.cpp.o
In file included from /home/kripton/git/rp2040-dongle/lib/RF24/RF24.cpp:10:
/home/kripton/git/rp2040-dongle/lib/RF24/RF24_config.h:59:14: fatal error: utility/includes.h: No such file or directory

So I assume it's still working as good as in the "use-cmake"-branch without the pico-sdk compatibility.

Nice that you would approve that :) Now the only things left is getting the cmake-support merged and the interrupt examples (didn't yet have a closer look at them)?

Yeah, I also don't know much about cmake. Never actually used it before. Learning as we go, but it's fun and cmake looks quite flexible and powerful 👍

@2bndy5
Copy link
Member

2bndy5 commented Apr 18, 2021

So I assume it's still working as good as in the "use-cmake"-branch without the pico-sdk compatibility.

yep

I noticed this line in examples_pico/CMakeLists.txt

project(gettingStarted)

I'm not sure this is needed as it is never referenced again. If it is needed then it should probably be

project(pico_examples)

I think this line is a relic from one of my commits...

@kripton
Copy link

kripton commented Apr 18, 2021

I noticed this line in examples_pico/CMakeLists.txt

project(gettingStarted)

I'm not sure this is needed as it is never referenced again. If it is needed then it should probably be

project(pico_examples)

It might be that this is not needed, since we loop over the examples further down. However, it might be that the pico_sdk_init function/macro depends on it. Try removing it and see what the GitHub Action tells you ;)

@2bndy5
Copy link
Member

2bndy5 commented Apr 18, 2021

It was needed because the top-level CmakeLists.txt didn't declare a project(), so I renamed the project "examples_pico" and specified it as a C/C++/ASM project -> action runs fine now 😄

@2bndy5
Copy link
Member

2bndy5 commented Apr 23, 2021

Narrowed down the ISR problem(s) with the IRQ example:

  • RX role was crashing when it entered a function that invovled a supposed non-busy wait call
  • TX role was hindered by the timeout value in getting user input
    char input = getchar_timeout_us(0); // get char from buffer for user input
    if (input != PICO_ERROR_TIMEOUT) { /* parse input */ }
    the above snippet still works to get user input but doesn't lock up the Serial terminal.

Thanks to @kripton's lead, I also added the ability to reboot to bootloader when 'b' oor 'B' is pressed (during all examples).

I went as far setting txDelay and RF24_POWER_UP_DELAY to 0, so I could handle the entire RX role in the ISR callback. This quickly started looking sloppy and didn't yeild any more reliable results.

Thus I've disabled triggering the ISR (via radio API - not via Pico SDK) during the RX role IRQ example. The TX role in the IRQ example works [almost] like a charm now.

@2bndy5
Copy link
Member

2bndy5 commented May 26, 2021

just a quick update here: the rp2xxx branch is almost ready for a PR to main, but

  1. I'm waiting for the next release of the PicoSDK (which I think will be dubbed v1.2.0 set for this month's end) because there are some changes in the PicoSDK's develop branch that would greatly benefit newcomers (specifically some missing info in the board headers about default SPI pins). So, we would be pinning to v1.2.0 of the PicoSDK, but obviously the rp2xxx branch will work with the current stable release of PicoSDK.
  2. I'm also incorporating the CMake for Linux implementation (based off @AndruePeters work) on the rp2xxx branch. So, the pending PR will satisfy more than just this issue 🚀 (aiming to resolve Library doesn't compile for ubuntu-64bit on RPi3 & RPi4 #642 CMake Support #676 also).
  3. As far as RF24Network and RF24Mesh libs, we still need a patch to make them work with CMake (at least for the PicoSDK - CMake for Linux shouldn't be as complicated as the RF24 lib is).

@kripton
Copy link

kripton commented May 27, 2021

Thanks for the update!
Regarding your point 3, those are actually ready:
nRF24/RF24Network@master...kripton:kripton-rp2xxx
nRF24/RF24Mesh@master...kripton:kripton-rp2xxx

I will rebase those branches on the latest master's (since the conditional defines have been merged) and modify the CMake-files to match what we have in the RF24 library.

@2bndy5
Copy link
Member

2bndy5 commented May 28, 2021

@kripton thanks for the reminding links (I remember you posted these somewhere in this long thread). Take you time, I'm still trying to work out the 64-bt vs 32-bit problem in #642 for CMake.

@kripton
Copy link

kripton commented May 28, 2021

PRs are here:
nRF24/RF24Network#174
nRF24/RF24Mesh#185

@2bndy5 2bndy5 linked a pull request Jun 5, 2021 that will close this issue
@2bndy5
Copy link
Member

2bndy5 commented Aug 13, 2021

I added PicoSDK CI workflows to the RF24Network & RF24Mesh libs (on their respective CMake-4-Linux branches). These workflows only build 2 examples for each lib (examples' src code should be adjusted to use to_ms_since_boot(get_absolute_time()) instead of millis() & user input is non-existent), but at least I can verify that all the current bleeding-edge changes haven't broken anything.

I have been cleaning up RF24Network quite a bit lately (while porting Network/Mesh to pure python). And now I'm off to making new python wrappers with pybind11 (pip-installable) to realize my ulterior motive for wanting CMake in these libs 😈

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants