One year ago (January 21, 2021), the Raspberry Pi Foundation launched the $4 Raspberry Pi Pico development board. This is the first RP2040 microcontroller product and a brand new chip developed by the Raspberry Pi Foundation.
A year later, the Pico development board has sold nearly 1.5 million units, with thousands of people using the RP2040 in their electronic projects and products.
With the launch of the Raspberry Pi Direct official channel (the retail price of the RP2040 chip is $1, and the bulk price is $0.7), we will soon see more applications. Although the hardware ecosystem around the RP2040 is not yet mature, it has begun to develop rapidly, and a year after its release, we have seen a surge of various ported languages.
When starting to write software on hardware, the first program that usually runs in a new programming environment is to blink an LED. Below is a brief introduction to controlling the Pico’s blinking light (the LED is connected to pin 25 of the RP2040 chip).
The Raspberry Pi Pico C/C++ SDK is the foundation for Pico and other RP2040-based hardware.
#include "pico/stdlib.h"
const uint LED_PIN = 25;
int main() { gpio_init(LED_PIN); gpio_set_dir(LED_PIN, GPIO_OUT); while (1) { gpio_put(LED_PIN, 0); sleep_ms(250); gpio_put(LED_PIN, 1); sleep_ms(1000); } }
In January last year, the official port of MicroPython was released alongside the Raspberry Pi Pico and C SDK.
from machine import Pin, Timer
led = Pin(25, Pin.OUT)
timer = Timer()
def blink(timer): led.toggle()
timer.init(freq=2.5, mode=Timer.PERIODIC, callback=blink
Another Python implementation running on the Raspberry Pi Pico and other RP2040 boards is CircuitPython. CircuitPython was released alongside the Pico last year, and while it is somewhat similar to MicroPython, it also has some differences.
If you need advanced features like interrupts and threads, or need complete access to RP2040’s programmable I/O (PIO) in Python, you generally need to use MicroPython. For sensors and USB, CircuitPython is recommended. It has strong support from Adafruit.
import time
import board
import digitalio
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
while True: led.value = True time.sleep(0.5) led.value = False time.sleep(0.5)
Kaluma is a micro JavaScript runtime for microcontrollers supported by JerryScript, just released. If you are a JavaScript developer familiar with Node.js, you can now use Raspberry Pi Pico without learning a new language.
There is excellent documentation on how to get started with Kaluma and its web development environment, or if you prefer to develop locally rather than in the browser, you can use the command line interface.
var led = 25;
pinMode(led, OUTPUT);
setInterval(() => { digitalToggle(led); }, 1000);
Interestingly, the Arduino core actually has two completely independent versions, one for the RP2040 chip and one for the Raspberry Pi Pico.
The first to appear was a community port based on the pure C SDK, along with a custom toolchain based on GCC 10.3 and Newlib 4.0. There is a lot of documentation on how to get started with the community version and how to integrate it with the ongoing PlatformIO.
The official Arduino version was released a few weeks after the community version, and like many recent Arduino platform ports, the core is based on Arm Mbed rather than the direct C SDK. If you have the Arduino environment installed, you can install the official RP2040 version directly through the Boards Manager menu.
In either case, the code to make the onboard LED blink is exactly the same.
#define LED 25
void setup() { pinMode(LED, OUTPUT); }
void loop() { digitalWrite(LED, HIGH); delay(1000); digitalWrite(LED, LOW); delay(1000); }
As one of the earliest products to appear after the release of the Raspberry Pi Pico, Rust now has quite mature support for the RP2040, with a hardware abstraction layer (HAL) for the RP2040 chip, as well as board support packages for many RP2040-based development boards. This includes the Raspberry Pi Pico. In addition, there is a project template that can serve as a starting point for development based on the RP2040 HAL.
For those who are not yet familiar with Rust, there is not a lot of introductory documentation, but there are some good tutorials.
#![no_std]
#![no_main]
use cortex_m_rt::entry;
use defmt::*;
use defmt_rtt as _;
use embedded_hal::digital::v2::OutputPin;
use embedded_time::fixed_point::FixedPoint;
use panic_probe as _;
use rp2040_hal as hal;
use hal::{ clocks::{init_clocks_and_plls, Clock}, pac, io::Sio, watchdog::Watchdog, };
#[link_section = ".boot2"]
#[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
#[entry] fn main() -> ! { let mut pac = pac::Peripherals::take().unwrap(); let core = pac::CorePeripherals::take().unwrap(); let mut watchdog = Watchdog::new(pac.WATCHDOG); let sio = Sio::new(pac.SIO);
let external_xtal_freq_hz = 12_000_000u32; let clocks = init_clocks_and_plls( external_xtal_freq_hz, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut watchdog, ) .ok() .unwrap();
let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer());
let pins = hal::gpio::Pins::new( pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS, );
let mut led_pin = pins.gpio25.into_push_pull_output();
loop { led_pin.set_high().unwrap(); delay.delay_ms(500); led_pin.set_low().unwrap(); delay.delay_ms(500); } }
As some early community-built firmware for the Espressif ESP8266 chip, Lua has become increasingly popular on embedded hardware. With the arrival of NodeMCU, the ESP8266 has become a microcontroller in its own right, not just a way to provide cheap WiFi connectivity to other microcontrollers.
The Lua environment is still in the proof-of-concept stage, but it can be built and documented from the source code in the Github project repository. In addition to the Lua runtime, the project also includes a basic shell that accepts Linux-like commands, a fullscreen editor, and basic file management tools. It supports general polling GPIO operations, digital I/O, analog input, I2C read/write, and hardware PWM. It runs on one core, leaving another core idle. Currently, DMA, interrupts, threads, or multi-core operations are not supported.
Just a few lines of code can blink an LED.
gpio_pin = 25
pico.gpio_set_function(gpio_pin, GPIO_FUNC_SIO)
pico.gpio_set_dir(gpio_pin, GPIO_OUT)
while true do pico.gpio_put(gpio_pin, HIGH) pico.sleep_ms(300) pico.gpio_put(gpio_pin, LOW) pico.sleep_ms(300) end
TinyGo brings the Go programming language to embedded systems by creating a new compiler based on LLVM. There is introductory documentation, and there is also a great demonstration on YouTube to help you get started blinking an LED.
package main
import ( "machine" "time" )
func main() { led := machine.LED led.Configure(machine.PinConfig{Mode: machine.PinOutput}) for { led.Low() time.Sleep(time.Millisecond * 500) led.High() time.Sleep(time.Millisecond * 500) } }
FreeRTOS is not a language, it is a complete microcontroller real-time operating system (RTOS) that supports SMP for the two cores of the RP2040.
#include
#include
#include
#include "pico/stdlib.h"
void led_task() { const uint LED_PIN = PICO_DEFAULT_LED_PIN; gpio_init(LED_PIN); gpio_set_dir(LED_PIN, GPIO_OUT); while (true) { gpio_put(LED_PIN, 1); vTaskDelay(100); gpio_put(LED_PIN, 0); vTaskDelay(100); } }
int main() { stdio_init_all(); xTaskCreate(led_task, "LED_Task", 256, NULL, 1, NULL); vTaskStartScheduler(); while(1){}; }
In addition, languages such as .NET, Forth, and Ada are also being ported.
In addition to the official listings, enthusiasts have also added the following:
▶ Free Pascal
The open-source, cross-platform Free Pascal inherits the essence of Delphi and now supports Pico.
program blinky;
{$MODE OBJFPC}
{$H+}
{$MEMORY 10000,10000}
uses pico_gpio_c, pico_timer_c;
begin gpio_init(TPicoPin.LED); gpio_set_dir(TPicoPin.LED,TGPIODirection.GPIO_OUT); repeat gpio_put(TPicoPin.LED,true); busy_wait_us_32(500000); gpio_put(TPicoPin.LED,false); busy_wait_us_32(500000); until 1=0; end.
▶ Lisp
The ARM version of uLisp includes an ARM assembler that allows you to generate machine code functions integrated with Lisp and write in ARM thumb code. The assembler itself is written in Lisp to facilitate extending it or adding new instructions.
uLisp needs to be installed through the Arduino IDE.
(defun blink (&optional x) (pinmode 25 t) (digitalwrite 25 x) (delay 1000) (blink (not x)))
Leave a Comment
Your email address will not be published. Required fields are marked *