RP2040 MicroPython: mpremote
An updated look at the utility called mpremote used to communicate with a board running MicroPython.
Review
A tool which has improved a great deal with the 1.20 release is mpremote - micropython remote control. From using it extensively, I’ve found its biggest issue is more the lack of documentation as compared to its capability. (See below)
Hint 1: Use a .config file
For example, after reading about mpremote on the GitHub Discussions and Discord, a powerful aspect of mpremote is its config file. See below for more details.
Hint 2: Understand raw REPL vs. REPL
The single biggest “aha!” I have found from developing code in MicroPython was raw REPL. It happened when I was attempting to write mpbuild, a program which can automatically load your Pico with the desired files. I tried multiple methods of automating the copy process, using a python exec call on mpremote, creating a subprocess call on mpremote…etc. I knew I was going down the wrong path when I saw this comment “I do not recommend using mpremote via subprocess! Everything you need should be available from pyboard.py.”
Ok, fine. I began to explore using pyboard.py, same issues remained. I wasn’t able to get my version of the example to work. In my version, I wanted to copy a file and not print(1 + 1)
.
I gave up for a few hours and did a little bit more searching. And bless Dave Hylands…in 2014, he had this to say: “Primarily - yeah. You can think of raw REPL as a programmatic interface, and regular REPL as a human interface. The raw REPL also makes it much easier (from the script’s perspective) to determine exactly what the real output of a command (like print) is.”
With that the lightbulb went off, and I changed my code. In the example, there was a call to raw_repl, which I wasn’t doing as I wasn’t “attempting to execute code” such as the example. Wrong! If you want to execute the pyboard code, you need to be in raw_repl mode, then everything works!
So my example became (this is the key code in the program mpbuild):
from mpremote.pyboard import Pyboard
pyb = Pyboard(os.environ['PYBOARD_DEVICE'], 115200)
pyb.enter_raw_repl()
pyb.fs_put(s, d)
pyb.exit_raw_repl()
pyb.close()
It works great! And mpbuild works exactly as I wish. If you wish to create your own interface Python programs to communicate between your MicroPython microcontroller board and your PC, I highly recommend “playing” the pyboard tool, just remember to use raw_repl.
Help Command
For documentation (from help command):
mpremote help
mpremote -- MicroPython remote control
See https://docs.micropython.org/en/latest/reference/mpremote.html
List of commands:
connect connect to given device
disconnect disconnect current device
edit edit files on the device
eval evaluate and print the string
exec execute the string
fs execute filesystem commands on the device
help print help and exit
mip install packages from micropython-lib or third-party sources
mount mount local directory on device
repl connect to given device
resume resume a previous mpremote session (will not auto soft-reset)
run run the given local script
soft-reset perform a soft-reset of the device
umount unmount the local directory
version print version and exit
Installation
# to install
pip3 install mpremote
# to upgrade
pip3 install --upgrade mpremote
Commands Usage
Confirm Board
Its helpful to confirm you are connected to a board, particularly, if you have mulitple boards connected to your computer. I use a version of the blink program to do this. The program is here and I use it in this manner:
mpremote repl
# now I'm in mpremote connected to a board
# if I don't have the REPL, hit Ctrl-B
>>> import blink
>>> Blink()
# and now the board connected to the mpremote program is blinking!
Copy a file
Copy your file to main.py, if you wish the program to always execute on boot. Remember the destination requires a preceding “:”. It is helpful to execute a ls following, to ensure the program was copied.
# to copy a file
mpremote fs cp pintest.py :main.py
cp pintest.py :main.py
# to show contents of Pico filesystem
mpremote fs ls
ls :
2332 main.py
Mount folder
Using the mount command, “mpremote mount .”, you can mount the folder on the PC as local storage to the microcontroller. Here is an example:
mpremote mount .
Local directory . is mounted at /remote
Connected to MicroPython at /dev/cu.usbmodem141201
Use Ctrl-] or Ctrl-x to exit this shell
>
MicroPython v1.20.0 on 2023-04-26; Raspberry Pi Pico W with RP2040
Type "help()" for more information.
>>> import os
>>> os.listdir()
['hello.py', 'serial_test.py', 'index.html', '.DS_Store', 'config.py', 'delay.txt', 'blink.py', 'wlan.py', 'favicon.png', 'microdot.py', '.gitignore', 'secrets.py', 'light_leds.py', 'blink_wo_delay.py', 'bulma.min.css', 'pin_test.py', 'computer.svg', '.git']
>>> from blink import Blink
>>> Blink()
This allows me to immediately determine if my “empty” Pico can execute a command. I don’t need to load it with the blink program, I am able to import it and execute it locally!
A single line program is this:
mpremote mount . exec "from blink import Blink; Blink()"
However I have found that it requires a bit of work to stop it. I’ve had to use a Ctrl-C to kill the mpremote program.
Edit file
If you set your editor in the system environmental variable $EDITOR, mpremote will use it to enabling editing a file on the microcontroller. You use the EXPORT command in bash or the set command in the fish shell to do so. Once I did, I was able to enter mpremote edit main.py and the Pico version of main.py opened in my editor. Cool!
I wouldn’t recommend you use this as a code development practice, however, it works great for testing a quick and dirty fix to a program. For example, let’s say you are attempting to connect to a new wireless LAN and you use the secrets file for the SSID and password. You could use mpremote edit secrets.py to edit the file on the Pico and quickly change the SSID/password to new values.
Specific Connection
The mpremote connect command is of value when you have multiple microcontrollers attached to you PC. Here is an example, where I have two Picos attached:
ls /dev/cu.*
/dev/cu.BLTH /dev/cu.JabraEvolve65 /dev/cu.usbmodem141301
/dev/cu.Bluetooth-Incoming-Port /dev/cu.usbmodem141201
mpremote connect /dev/cu.usbmodem141201 fs ls
ls :
206838 bulma.min.css
2837 computer.svg
18 config.py
1245 draw.html
1264 lost.html
4165 main.py
46276 microdot.py
1331 microdot_utemplate.py
36 secrets.py
0 templates/
0 utemplate/
1464 wlan.py
1241 won.html
Or combine the hint using blink along with the connect command to blink a specific Pico led:
mpremote connect /dev/cu.usbmodem141201 mount . exec "from blink import Blink; Blink()"
Execute local files
A local file is one which resides on your PC, not on the microcontroller. The run command provides the capability of running the local file on your microcontroller without downloading it first. For example, another way to blink the led on a connected board would be:
# you may also use the run command to execute the local file on the Pico
mpremote connect /dev/cu.usbmodem141201 run blink.py
Notice that the blink.py file is not on the Pico (see the fs ls example above), and the run command is executing the local file (one which resides on your PC) on the microcontroller. Again, I needed to use Ctrl-C to disconnect from the board.
config file
The config file for mpremote may contain shortcuts and they can be quite powerful! For example, based on an entry by @jimmo, I used his shortcut on the Pico W to clear file memory. The command is a simple, yet powerful way to remove all files from the Pico, in order to fix a problem or start anew on a project. Be sure you want to erase your Pico program files, if you use this command!
I also simplified commands I use quite often such as mpremote fs ls
to mpr fl
, for which, I had to do two things, first, setup an alias of mpremote
to mpr
(I’ll use mpr going forward instead of mpremote, their use is identical.) then create the shortcut fl
in the mpremote config file.
The other two examples are extremely handy for using a file on your computer on the microcontroller. The first mpr test
will execute the program test.py in my local directory on my computer on the Pico. The second mpr info
will execute a program which prints the informaton on local file storage on the Pico. This command is valuable to help you understand the storage impact of program components.
Local directory . is mounted at /remote
Attempting to determine filesystem
Littlefs v2 filesystem
0008 magic littlefs
0014 version 0x20000
0018 block_size 4096
001c block_count 212
0020 name_max 255
0024 file_max 2147483647
0028 attr_max 1022
0000 program memory 868352
0000 used memory 151552
0000 free memory 716800
When you run mpr devs
, it will list the serial ports on your computer along with an ID of each MicroPython board. You can use the ID to connect with a specific board using the shortcut shown in the config file, as in mpr A
, will connect to the board with the specific ID e6614864d3323634.
Finally, I am also able to combine some commands shown above into a specific command which will blink the connected board.
~/.config/mpremote/config.py
commands = {
"A": "connect id:e6614864d3323634",
"fl": "fs ls",
"littlefs_rp2": [
"exec",
"--no-follow",
"import os, machine, rp2; os.umount('/'); bdev = rp2.Flash();\
os.VfsLfs2.mkfs(bdev, progsize=256); \
vfs = os.VfsLfs2(bdev, progsize=256); \
os.mount(vfs, '/'); machine.reset()",
],
"test": ["mount", ".", "exec", "import test"],
"info": ["mount", ".", "run", "fs_info.py"],
"blink": ["mount", ".", "exec",
"from blink import Blink; Blink()"]
}
Comments powered by Talkyard.