RP2040 MicroPython: Getting Started
Where I begin to develop programs for the RP2040 (Pi Pico and Pi Pico W) using Micropython.
I already have quite a few entries on Micropython. While I’ve experimented with multiple boards using the language, ESP32, FIDI, and the Adafruit Feather RP2040, this entry begins a set of entries on using Micropython as a development language with the Pi Pico W as the development microcontroller. The cost ($6) of the Pico W along with it’s computing power coupled with ease of development of Micropython, makes this experiment compelling.
I highly recommend having documentation to help you on this journey. These two books are free and are extremely valuable:
- Raspberry Pi Pico Python SDK
- Get Started with MicroPython on Raspberry Pi Pico [Search for book title on site, if link does not work.]
In addition to the books above, the following links will be important:
- Pico W Pinout
- MicroPython home
- MicroPython documentation
- MicroPython Pi Pico W download
- Code for this page on GitHub
The most important thing to download is the UF2 file which contains MicroPython for the Pico W. It can be found under Firmware, on the link above (…Pico W download). If you want the code discussed in this entry, you may download it here.
Install a RESET button
For ease of use, I recommend the following steps:
- Install header pins or purchase your Pico W with header pins.
- Plug your board into a breadboard.
- Create GND rails [See Note:] on your breadboard by connecting wires (gray wires in image) from a GND pin on the Pico to the blue “-” rail on the breadboard. (I use pin 3 on one side and pin 38, on the other side).
- Plug a push button spanning the center channel into your bread board at the end of the Pico
- Connect a wire (gray wire in image) into one end of the push button to GND
- Connect a wire (blue wire in image) into the breadboard row diagonally opposite the GND connection to pin 30 RUN on the Pico.
Note: The value of creating GND rails, is that it makes it easy to ground other components as you extend the functionality of your Pico with hardware. The blinkenleds are a good example below.
Having a reset button enables you to easily put the PICO W into USB mode. With a USB cable plugged between your PICO and your computer:
- Press and hold the BOOTSEL button on the Pico W.
- Press and release your reset button
- Release BOOTSEL.
Your board will show up on your computer as a USB drive labeled RPI-RP2. If the board doesn’t show up, check your connections to the Reset button.
- Is there a wire from GND on the Pico to the GND rail on the breadboard?
- Is there a wire from the GND rail on the breadboard to the button?
- Is there a wire from pin 30 RUN to the button?
- Are the connections to the button diagonally opposite? (as compared to straight across)
- Did you follow the 3-step sequence above exactly? The timing is critical.
Drag and Drop
Now drag the .uf2 file you downloaded from the MicroPython site and drop it on the USB drive RPI-RP2. It will take several seconds to copy the 1MB+ size file on to the Pico and the board will restart, automatically ejecting itself from the computer. (For which the computer might complain, however, its not a big deal.)
A nice advantage of Python is to be able to test out snippets of code using REPL (Read-Evaluate-Print-Loop). To use this mode, connect to the Pico using a serial program such as Serial (macOS), Thonny Python IDE (multi-platform), PuTTY (Windows) or MoSerial (Linux). You may also use the REPL mode in mpremote, which we will discuss in a moment. For my work, I will be using Serial, I recommend the Arduino IDE Serial Monitor as a great multi-platform serial program.
>>> print("Hello, World!") Hello, World! >>> for i in range(5): ... print("Printed", i+1, "time(s)") ... ... ... Printed 1 time(s) Printed 2 time(s) Printed 3 time(s) Printed 4 time(s) Printed 5 time(s) >>>
The Get Started… book (above) book discusses using the REPL along with Thonny, quite well. I recommend reviewing it if you need help with Python.
Edit and Upload
If you are new to Python, I highly recommend you begin to use Thonny as your development environment. It provides tremendous capability in a easy to use interface. All of the work I do could be done just as well in Thonny as compared to Sublime Text (ST). I continue to use ST as I started using it years ago and its become muscle memory.
The method I use for developing programs is to use a editor (Sublime Text) and a communication tool (mpremote). The former is quite good for developing Python programs, I have used it for over 20 years. The latter is a tool developed by the MicroPython team to communicate with a microcontroller board running MicroPython. See this page for more information on mpremote.
- Edit the file in Sublime Text
- Ensure Serial is disconnected from the board (Cmd-D)
- Use MicroPython build system to upload the file using mpremote
- Build system will reconnect with board, use Serial to view output
- To start program on board, press reset button to automatically execute main.py
(A key feature of MicroPython, is that it automatically executes main.py upon boot. There are two programs which it will execute on boot, first it will execute boot.py then main.py)
from machine import Pin import time def Blink(): led = Pin("LED", Pin.OUT) while True: led.toggle() time.sleep_ms(250) if __name__ == '__main__': Blink()
This version of blink is slightly more complicated than the typical blink. It allows you to use the program via an import method, which is valuable in debugging.
For example, if I have multiple boards connected to my PC and I want to determine which board is connected to a specific port or I want to confirm which board the program mpremote is connected to, I do the following:
mpremote repl # now I'm in mpremote connected to a board # if I don't have the REPL, hit Ctrl-B >>>> from blink import Blink >>>> Blink() # and now the board connected to the mpremote program is blinking!
I also like to test out the board using external LEDs, so I attach an LED to one of the GPIO pins 2-22, to view the blink program. Be sure to attach a resistor between the LED and GND. (I use a blinkenled as described by Elliot Williams, I solder a resistor to the end of an LED, see image below.)
I was having issues having a prompt show up at the beginning of a program, the program seemed to be skipping my initialization code. After other tests, I realized it might be how I was calling print, so I wrote a program which would simply loop printing “hello world” with a delay. It seemed to work fine…until I realized I wasn’t sure when the first “hello world” was printing. I added a counter to determine, when the first print would appear:
import time i = 0 while True: print(i, "Hello World!") time.sleep_ms(1000) i += 1
[Connected] 2 Hello World! 3 Hello World! 4 Hello World! 5 Hello World! 6 Hello World!
Oh, my. I was able to see the “Hello World!” only after the third time through the loop! I need to delay my print statements for about 2 seconds for the serial port to connect.
After a series of tests, using Thonny, mpremote and my macOS serial application called Serial, its clear that the fault lies with Serial. Both Thonny and mpremote will show the first two lines of text accurately. Good to know!
I wanted to know with greater precision, how much time do I need to allow. So I wrote a new program which would begin to print at 1 second (1000 ms). After printing, it would perform a hard reset, increment the delay by 10 ms then print a message along with the delay value. I used a machine.reset() to hard reset the board via software.
# determines delay required for serial connection # uses file delay.txt to contain a integer delay i.e; 1000 # program will: # read delay from delay.txt # pause delay ms # print 'hello world' and delay value # incr delay # hard reset to repeat # this will continue until 'Hello World' and delay are seen # the delay shown is the ms required to sleep prior to using serial # in testing 1390 was the delay shown # Added max test to ensure test completes, otherwise # Thonny required to stop the microcontroller import time import machine import sys f = open('delay.txt', 'r') delay = int(f.readline()) delta = 10 time.sleep_ms(delay) print("Hello World!", delay) f.close() f = open('delay.txt', 'w') delay += delta f.write(str(delay)) f.close() if delay <= 1700: machine.reset() else: sys.exit()
As I note in the comments above, given the board would hard reset every second, it wasn’t easy to reconnect to the board. I eventually used Thonny to reconnect to the board and stop the program. Good to know that Thonny has this capability.
To resolve the infinite run issue, I added a test which would end the loop and exit to the REPL, if a value was exceeded. In my testing, it appeared that I was able to consistently see print statements after a 1700ms delay.
Interactive Pin Test
This is the program, which had the non-printing header bug. With the fix from above, it is now a very capable program which tests any Pico (or Pico W) pin. The program will prompt for a pin number (1-40), if it is a GPIO pin, it will identify the GP number and will provide the capability to set the pin HIGH, LOW or BLINK (once). If the pin is not a GPIO pin, it will advise its name such as UART0 TX or GND, and await a new pin number. To exit testing the specific pin, enter 0 at the test prompt to select another pin.
I developed the program using another microcontroller board to provide a simple test on each pin, to ensure my soldering work as competent. For the complete code, see here.
Here is an example of the printout as I test pins 4 (GP02) and 15 (GP11).
Running Pin Test: Tests: 0=> new pin 1=> High 2=> Low 3=> Blink once Enter pin number (1-40) to test: 4 Pin 4 GP2 enabled as Output Enter test to run: 1 Pin(GPIO2, mode=OUT) is High Enter test to run: 2 Pin(GPIO2, mode=OUT) is LOW Enter test to run: 3 Pin(GPIO2, mode=OUT) will blink once Enter test to run: 0 Restarting Running Pin Test: Tests: 0=> new pin 1=> High 2=> Low 3=> Blink once Enter pin number (1-40) to test: 15 Pin 15 GP11 enabled as Output Enter test to run: 1 Pin(GPIO11, mode=OUT) is High Enter test to run: 2 Pin(GPIO11, mode=OUT) is LOW Enter test to run: 3 Pin(GPIO11, mode=OUT) will blink once Enter test to run: 0
Comments powered by Talkyard.