はじめに
picoprobeでRAMに直接プログラムがロードできるようになったので、難しいboot2のことはおいておいて、 ベアメタルでLチカを試みる。
ホントは、コンパイル済みのboot2を組み込んでLチカしようと頑張ったが、現時点では挫折した。
心の師匠の成果物の丸パクリにならないように頑張ったが初期化コードの一部をまるっと拝借した。
あと、SysTickの設定なども手が回らなかったのでチカチカのタイミングは適当。
ディレクトリ構成
下記のようにフラットな構造とした。
├── Makefile ├── main.c ├── memmap_ram.ld ├── pico.gdbinit ├── regs.h └── start.S
リンカスクリプト
memmap_ram.ld
を下記の内容で作成する。
MEMORY { RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k } ENTRY(reset) SECTIONS { .text : { *(.text*) } > RAM }
単純にtextセクションをRAM上に配置する。
エントリポイントにreset
を設定している。
スタートアップ
start.S
を下記の内容で作成する。
.cpu cortex-m0plus .thumb .global reset .thumb_func reset: ldr r0, =0x20001000 mov sp, r0 bl main b hang .thumb_func hang: b .
デバッガで実行すると、ENTRYから開始されるのでreset
の先頭から実行される。
resetではスタックポインタを初期化してmain関数を呼び出している。
レジスタ定義
regs.h
を下記の内容で作成する。
#ifndef REGS_H #define REGS_H #define OP_RW (0x0000) #define OP_XOR (0x1000) #define OP_SET (0x2000) #define OP_CLR (0x3000) #define RESETS_BASE (0x4000C000) #define RESETS_RESET (RESETS_BASE+0x0) #define RESETS_RESET_DONE (RESETS_BASE+0x8) #define SIO_BASE (0xD0000000) #define SIO_GPIO_OUT_SET (SIO_BASE+0x14) #define SIO_GPIO_OUT_CLR (SIO_BASE+0x18) #define SIO_GPIO_OUT_XOR (SIO_BASE+0x1C) #define SIO_GPIO_OE_SET (SIO_BASE+0x24) #define SIO_GPIO_OE_CLR (SIO_BASE+0x28) #define PADS_BANK0_BASE (0x4001C000) #define PADS_BANK0_GPIO (0x68) #define PADS_GPIO25 (PADS_BANK0_BASE + PADS_BANK0_GPIO) #define IO_BANK0_BASE (0x40014000) #define IO_BANK_GPIO25_CTRL (0xCC) #define IO_GPIO25_CTRL (IO_BANK0_BASE + IO_BANK_GPIO25_CTRL) #endif //REGS_H
Lチカに必要なレジスタの定義をregs.h
に切り出している。
メインプログラム
main.c
を下記の内容で作成する。
#include "regs.h" #include <stdint.h> uint32_t read_reg(uint32_t addr) { return (*((volatile uint32_t *)addr)); } void write_reg(uint32_t addr, uint32_t value) { *((volatile uint32_t *)addr) = value; } void write_reg_op(uint32_t addr, uint32_t value, uint32_t op) { write_reg(addr | op, value); } int main(void) { ///////////////////// // This initialise code is ported from https://github.com/dwelch67/raspberrypi-pico/blob/master/blinker00/notmain.c // release reset on IO_BANK0 write_reg_op(RESETS_RESET, 1<<5, OP_CLR); //IO_BANK0 //wait for reset to be done while(1) { if((read_reg(RESETS_RESET_DONE)&(1<<5))!=0) break; } write_reg_op(RESETS_RESET, (1<<8), OP_CLR); //PADS_BANK0 while(1) { if((read_reg(RESETS_RESET_DONE)&(1<<8))!=0) break; } ///////////////////// // GPIO init write_reg(SIO_GPIO_OE_CLR, (1ul<<25)); write_reg(SIO_GPIO_OUT_CLR, (1ul<<25)); uint32_t ra = read_reg(PADS_GPIO25); write_reg_op(PADS_GPIO25, (ra^0x40)&0xC0, OP_XOR); write_reg(IO_GPIO25_CTRL, 0x5); uint32_t v = read_reg(IO_GPIO25_CTRL); // Blink write_reg(SIO_GPIO_OE_SET, (1ul<<25)); while (1) { for (int i = 100000; i != 0; i--) ; write_reg(SIO_GPIO_OUT_XOR, (1ul<<25)); } return 0; }
基本的にはpico-examplesのblinkの処理を分解して必要な処理だけにしたが、
試行錯誤の結果、初期化コードだけはdwelch67先生の成果物を丸パクリ参考にした。
Makefile
Makefile
を下記の内容で作成する。
CROSS_COMPILE ?= arm-none-eabi- MCPU = -mcpu=cortex-m0plus ASMOPT = $(MCPU) -g COPT = $(MCPU) -ffreestanding -g -O0 LOPT = -nostdlib -nostartfiles all: ram clean: rm -f *.o rm -f *.elf rm -f *.list rm -f *~ start.o: start.S $(CROSS_COMPILE)as $(ASMOPT) start.S -o start.o main.o: main.c $(CROSS_COMPILE)gcc $(COPT) -fpic -mthumb -c main.c -o main.o ram: start.o main.o $(CROSS_COMPILE)ld $(LOPT) start.o main.o -T memmap_ram.ld -o led.elf
gdb初期化スクリプト
pico.gdbinit
を下記の内容で作成する。
target remote :3333 mon reset init load
ビルドと実行
ビルド
makeでビルドできる。
$ make
実行
まずopenocdを起動する。
$ cd ${PICO_SDK_PATH}/../openocd $ src/openocd -f interface/picoprobe.cfg -f target/rp2040.cfg -s tcl
別のターミナルでgdb-multiarch
を起動する。
$ gdb-multiarch -x pico.gdbinit led.elf ... (snip) ... Type "apropos word" to search for commands related to "word"... Reading symbols from led.elf... 0x20000116 in main () at main.c:83 83 for (int i = 100000; i != 0; i--) ; target halted due to debug-request, current mode: Thread xPSR: 0xf1000000 pc: 0x000000ee msp: 0x20041f00 target halted due to debug-request, current mode: Thread xPSR: 0xf1000000 pc: 0x000000ee msp: 0x20041f00 Loading section .text, size 0x158 lma 0x20000000 Start address 0x20000000, load size 344 Transfer rate: 2752 bits in <1 sec, 344 bytes/write. (gdb)
これでPicoにプログラムがロードされるので、下記で実行する。
(gdb) c Continuing.
LEDがチカチカする。
まとめ
boot2を使わない、RAMで直接するLチカを試した。
SysTickやタイマーを使っていないためタイミングは適当。 Pico SDKで作る場合と違い、ボードの初期化処理は自分でしないといけない。
コアは1個しか動いていないはず。(何もしてないので。)