Using Arduino on the RP2040: Notes

2 minute read


Where I share various observations as to how to use the Pico with the Arduino software framework and the legacy (~1.8.19) Arduino IDE.

Pico Reset Button

While most RP2040 boards will have a Reset button, the Pico does not. Why? To save costs. It also has a micro-USB connector instead of a USB C connector for the same reason. The single best way to ensure your Pico uploads properly (or more accurately) the Arduino IDE uploads to the Pico, properly is to press and hold the Boot/Sel button then unplug and plug-in the Pico. This can be required a great deal when testing I2C and the unplug/plug-in is a bit of a pain.

This is easily fixed with a Reset button! Find you common variety bread board button and place it in your breadboard. Connect one side to Ground and the other side to pin 30, Reset. That’s it.

What can you do with Reset?

  1. Rerun your program without having to upload or doing anything with the IDE.
  2. Press and hold Boot/Sel (the only button on the Pico) then press/release Reset then release Boot/Sel. This will ensure your Pico is ready to receive an upload. I have found that if the Pico is in an undetermined state, its best to follow this procedure. Works everytime!

Simplify Code with a struct

In this code, I created two struct arrays to simplify dealing with either hardware or messaging. My process is this:

  1. Use an enum to create a text index such as:
#define max_messages 4
enum message {start, error, success, next};

The number of elements in the enum needs to match the #define

  1. Write a struct which contains the specific variables required:
struct blink
  unsigned int delay;   // seconds for message (also a delay)
  unsigned int times;   // number of blinks to indicate message
} ;
  1. Use the struct to create an array of structs
struct blink messages[max_messages];
  1. Write a function which uses the struct
void status(unsigned int msg)
    for (unsigned int i = 0; i < messages[msg].delay; i++) 
        for (unsigned int j = 0; j < messages[msg].times; j++) 
            digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on 
            delay(1000/messages[msg].times/2); // delay seconds/2, blink n * 2 
            digitalWrite(LED_BUILTIN, LOW);    // turn the LED off 
            delay(1000/messages[msg].times/2); // delay seconds/2, blink n * 2 

In this example, I use the function status() to blink an LED based on the message desired. Fast blinks for an error, slow blink on boot etc. Using this approach I can easily insert a status(msg) anywhere in my code to blink the LED. This means I don’t need the serial port to track program progress.

I used the same approach in setting up the I2C devices. All of the I2C Wire interfaces need to have the SDA pin, the SCL pin and address identified and having them all in one line makes it easy to setup.

Comments powered by Talkyard.