ついに、ファームウェア開発まで興味のレベルが下がった。 そのため、アケコン自作を目標に置いて、ファームウェア開発に取り組むことにした。
当記事執筆現在の進捗は、Rasberry Pi Picoとアケコンのボタンを接続し、ボタンを押してボード上のLEDを光らせる、という段階である。 つまり、まだUSB通信について全く触れていない。 とはいえ、このレベルの開発はド素人であるため、今後とも気長に学習することにする。
なお、開発環境はUbuntu 24.04である。
わざわざ書くまでもないが、回路は次のようである。
私のような電子系ド素人にとっては、電源→ボタン→インプットピン、という回路の方が直感的である。 しかし、これはボタンが上がっているときに、インプットピンが回路から外れてしまう。 これを解決するために、多くのマイコンボードはプルアップ抵抗を用いている。 次のような原理で、ボタンが上がっているときにHIGH・下がっているときにLOWとなる。 ただし、インプットピンの原理はその電圧を計測することであり、電圧計の内部抵抗は原理的にプルアップ抵抗より大きく、ボタンの抵抗は常識的に考えて極めて小さい。
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;
以上で環境構築終了である。 以降、次の手順で実行できる。
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();
}
}
}
■