ついに、ファームウェア開発まで興味のレベルが下がった。 そのため、アケコン自作を目標に置いて、ファームウェア開発に取り組むことにした。
当記事執筆現在の進捗は、Rasberry Pi Picoとアケコンのボタンを接続し、ボタンを押してボード上のLEDを光らせる、という段階である。 つまり、まだUSB通信について全く触れていない。 とはいえ、このレベルの開発はド素人であるため、今後とも気長に学習することにする。
なお、開発環境はUbuntu 24.04である。
Rasberry Pi Pico H
アケコンのボタン
ブレッドボード
ジャンプワイヤ
ミノムシクリップ
Micro USB
わざわざ書くまでもないが、回路は次のようである。

私のような電子系ド素人にとっては、 電源→ボタン→インプットピン 、という回路の方が直感的である。 しかし、これはボタンが上がっているときに、インプットピンが回路から外れてしまう。 これを解決するために、多くのマイコンボードはプルアップ抵抗を用いている。 次のような原理で、ボタンが上がっているときにHIGH・下がっているときにLOWとなる。 ただし、インプットピンの原理はその電圧を計測することであり、電圧計の内部抵抗は原理的にプルアップ抵抗より大きく、ボタンの抵抗は常識的に考えて極めて小さい。

MicroPythonを用いることで、簡単にプログラムを実行できる。 実行までの手順は次の通りである。
Thonnyをインストールする
BOOTSELボタンを押しながらRasberry Pi Picoをマシンに接続する
Rasberry Pi Pico内のINDEX.HTMLを頼りにMicroPythonのUF2ファイルをダウンロードする
UF2ファイルをRasberry Pi PicoにD&Dする
Thonnyを起動する
MicroPythonを書いて実行ボタンを押す
Lチカのコードは次のようである。
import machine import utime led = machine.Pin(25, machine.Pin.OUT) while True: led.value(1) utime.sleep(0.5) led.value(0) utime.sleep(0.5)
ボタンを押したときにLEDを光らせるコードは次のようである。
import machine import utime led = machine.Pin(25, machine.Pin.OUT) button = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_UP) while True: if button.value() == 1: led.value(0) else: led.value(1)
私の性格上MicroPythonで開発するのは気分が良くないので、Rustにリファクタリングすることにした。 rp-picoというクレートを用いると、比較的簡単に開発できるようである。 近いうちにembedded-halまで落ちたいものだ。
thumbv6m-none-eabiターゲットを追加する必要がある。 また、elf2uf2-rsとflip-linkをインストールする。 なお、そのためにはlibudev-devのインストールが必要だった。
$ sudo apt install libudev-dev $ rustup target add thumbv6m-none-eabi $ cargo install elf2uf2-rs flip-link
Cargo.tomlは次のようである。
[package] name = "led" version = "0.1.0" edition = "2021" [dependencies] rp-pico = "0.9.0" cortex-m = "0.7.7" cortex-m-rt = "0.7.3" embedded-hal = "1.0.0"
DXのためにも、次の.cargo/config.tomlを作る。
[build] target = "thumbv6m-none-eabi" [target.thumbv6m-none-eabi] runner = "elf2uf2-rs -d" rustflags = [ "-C", "linker=flip-link", "-C", "link-arg=--nmagic", "-C", "link-arg=-Tlink.x", ]
ルートディレクトリに次のmemory.xを作る。
MEMORY { BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100 RAM : ORIGIN = 0x20000000, LENGTH = 256K } EXTERN(BOOT2_FIRMWARE) SECTIONS { .boot2 ORIGIN(BOOT2) : { KEEP(*(.boot2)); } > BOOT2 } INSERT BEFORE .text;
以上で環境構築終了である。 以降、次の手順で実行できる。
BOOTSELボタンを押しながらRasberry Pi Picoをマシンに接続する
cargo runを実行する
Lチカのコードは次のようである。
#![no_std] #![no_main] use core::panic::PanicInfo; use cortex_m::delay::Delay; use embedded_hal::digital::OutputPin; use rp_pico::{ entry, hal::{ clocks::{self, Clock}, pac::{CorePeripherals, Peripherals}, watchdog::Watchdog, Sio, }, Pins, }; const XOSC_CRYSTAL_FREQ: u32 = 12_000_000; const DELAY_TIME: u32 = 500; #[panic_handler] fn panic(_: &PanicInfo) -> ! { loop {} } #[entry] fn main() -> ! { let core = CorePeripherals::take().unwrap(); let mut pac = Peripherals::take().unwrap(); // get pins let pins = Pins::new( pac.IO_BANK0, pac.PADS_BANK0, Sio::new(pac.SIO).gpio_bank0, &mut pac.RESETS, ); // get an LED pin let mut led = pins.led.into_push_pull_output(); // create Delay to wait let clocks = clocks::init_clocks_and_plls( XOSC_CRYSTAL_FREQ, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut Watchdog::new(pac.WATCHDOG), ) .ok() .unwrap(); let mut delay = Delay::new(core.SYST, clocks.system_clock.freq().to_Hz()); loop { led.set_low().unwrap(); delay.delay_ms(DELAY_TIME); led.set_high().unwrap(); delay.delay_ms(DELAY_TIME); } }
ボタンを押したときにLEDを光らせるコードは次のようである。
#![no_std] #![no_main] use core::panic::PanicInfo; use embedded_hal::digital::{InputPin, OutputPin}; use rp_pico::{ entry, hal::{pac::Peripherals, Sio}, Pins, }; #[panic_handler] fn panic(_: &PanicInfo) -> ! { loop {} } #[entry] fn main() -> ! { let mut pac = Peripherals::take().unwrap(); // get pins let pins = Pins::new( pac.IO_BANK0, pac.PADS_BANK0, Sio::new(pac.SIO).gpio_bank0, &mut pac.RESETS, ); // get an LED pin and a button pin let mut led = pins.led.into_push_pull_output(); let mut button = pins.gpio14.into_pull_up_input(); loop { if button.is_high().ok().unwrap() { led.set_low().unwrap(); } else { led.set_high().unwrap(); } } }
■