#cynthion #risc-v #luna

无 std 程序+库 moondancer

Great Scott Gadgets Cynthion USB 测试仪的 Moondancer 固件

4 个版本

新增 0.1.5 2024年8月20日
0.1.4 2024年8月19日
0.1.3 2024年8月19日
0.1.1 2024年7月8日
0.0.0 2024年5月28日

#125 in 硬件支持

Download history 108/week @ 2024-05-23 27/week @ 2024-05-30 4/week @ 2024-06-06 110/week @ 2024-07-04 15/week @ 2024-07-11 5/week @ 2024-07-25 310/week @ 2024-08-15

每月315 次下载

BSD-3-Clause

715KB
15K SLoC

moondancer

Great Scott Gadgets Cynthion 的 Moondancer 固件。

构建和运行

构建 SoC 位流

在您运行任何固件之前,您首先需要构建 Moondancer SoC 位流

cd cynthion.git/cynthion/python

make soc

执行固件

一旦构建了 SoC 位流,您可以使用

cargo run --release

以下命令执行您的固件:cargo run 如果由 runner 参数在 .cargo/config.toml 文件中控制。

默认情况下,它使用 .cargo/cynthion.sh 脚本来按以下顺序执行以下步骤

  1. 将 Rust 编译器生成的 ELF 可执行文件转换为固件二进制镜像。
  2. 使用 cynthion 命令行工具将固件二进制镜像闪存到 Cynthion 的 SPI 闪存。
  3. 使用 cynthion 命令行工具使用 SoC 位流配置 Cynthion 的 FPGA。
  4. 启动一个串行终端以查看固件日志输出。

使用 Cynthion 的控制端口 (USB2)

默认情况下,Cynthion 的控制端口被 Apollo 使用。

如果您想从 Apollo 接管控制并用于自己的固件,可以使用以下命令禁用 ApolloAdvertiser 外设

let peripherals = pac::Peripherals::take().unwrap();

let advertiser = peripherals.ADVERTISER;
advertiser.enable().write(|w| w.enable().bit(true));

请注意,在这种情况下,您将无法通过 Apollo 访问 SoC 的 UART0 外设,需要改用 UART1。

固件调试

Moondancer SoC 在 Cynthion 的 PMOD B 连接器上公开了第二个 UART 和一个 JTAG 连接器

PMOD B
+-----+-----+----+----+----+----+
| 3v3 | gnd |  4 |  3 |  2 |  1 |
+-----+-----+----+----+----+----+
| 3v3 | gnd | 10 |  9 |  8 |  7 |
+-----+-----+----+----+----+----+

Pin 1:  UART rx
Pin 2:  UART tx

Pin 7:  JTAG tms
Pin 8:  JTAG tdi
Pin 9:  JTAG tdo
Pin 10: JTAG tck

UART

Cynthion SoC 提供了两个 UART 端口。

UART0 连接到 Cynthion 的 SAMD11 微控制器,并且只有在 SoC 固件不使用 Cynthion 的控制端口 (USB2) 时才能访问。

UART1 连接到 Cynthion PMOD B 端口的引脚 1 和 2,可以通过串行适配器访问。

picocom --imap lfcrlf -b 115200 /dev/cu.usbserial-1301

JTAG

JTAG 端口直接连接到 Vexriscv 处理器,可用于加载固件和调试 CPU。

使用此功能的详细步骤将取决于您使用的特定JTAG探头和调试软件,但以示例来说,您可以使用openocdgdb,如下所示

1. 配置openocd

要为FTDI适配器配置openocd,您需要类似以下内容

#
# .cargo/openocd.cfg
#

# select adapter driver
adapter driver ftdi

# configure adapter driver
ftdi vid_pid 0x0403 0x6011
ftdi channel 0
ftdi layout_init 0xfff8 0xfffb
ftdi tdo_sample_edge falling

# configure transport
transport select jtag
adapter speed 25000

# configure jtag tap
set _CHIPNAME riscv
set _TARGETNAME $_CHIPNAME.cpu

# create jtag tap
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10002FFF
target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME

然后您可以使用以下方式运行openocd

openocd -f .cargo/openocd.cfg

如果一切正常,应该会得到类似以下内容

Open On-Chip Debugger 0.12.0
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
riscv.cpu
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : clock speed 25000 kHz
Info : JTAG tap: riscv.cpu tap/device found: 0x10002fff (mfg: 0x7ff (<invalid>), part: 0x0002, ver: 0x1)
Info : datacount=1 progbufsize=2
Info : Disabling abstract command reads from CSRs.
Info : Examined RISC-V core; found 1 harts
Info :  hart 0: XLEN=32, misa=0x40000042
Info : starting gdb server for riscv.cpu.0 on 3333
Info : Listening on port 3333 for gdb connections

2. 配置gdb

您需要一个基本的gdb配置文件,其外观可能如下

#
# .cargo/openocd.gdb
#

# connect to openocd
target extended-remote :3333

# print demangled symbols
set print asm-demangle on

# detect unhandled exceptions, hard faults and panics
break DefaultHandler
break HardFault
break rust_begin_unwind

# load firmware into memory
load

3. 配置cargo以使用gdb

默认情况下,固件使用cynthion命令行工具来将固件和位流烧写到Cynthion。

因此,您需要修改.cargo/config.toml配置文件,以便使用gdb作为固件的运行器

#
# .cargo/config.toml
#

[target.riscv32imac-unknown-none-elf]
runner = "cynthion.sh"                     # <==
rustflags = [
  "-C", "link-arg=-Tmemory.x",
  "-C", "link-arg=-Tlink.x",
]

[build]
target = "riscv32imac-unknown-none-elf"

找到runner参数并按以下方式修改它

runner = "riscv64-unknown-elf-gdb -q -x .cargo/openocd.gdb"

4. 配置memory.x

通常,固件从Cynthion的SPI闪存启动,但在使用JTAG时,您将直接将其加载到SoC主内存中。

但是,要执行此操作,您首先需要让Rust链接器了解您的计划!

在顶层cynthion.git/firmware/目录中,您应该看到一个名为memory.x的文件,该文件包含Rust链接器使用的内存布局

#
# memory.x
#

MEMORY {
    ...
}

REGION_ALIAS("REGION_TEXT", spiflash);    # <==
REGION_ALIAS("REGION_RODATA", spiflash);  # <==
REGION_ALIAS("REGION_DATA", mainram);
REGION_ALIAS("REGION_BSS", mainram);
REGION_ALIAS("REGION_HEAP", mainram);
REGION_ALIAS("REGION_STACK", mainram);

您需要修改此文件,并将指向spiflash的两个REGION_ALIAS指令更改为指向mainram

REGION_ALIAS("REGION_TEXT", mainram);
REGION_ALIAS("REGION_RODATA", mainram);

如果不这样做,gdb将尝试将您的固件加载到spiflash地址,考虑到SoC的SPI控制器外围设备是只读的,这会导致轻微的荒谬。

5. 配置Cynthion位流

您几乎完成了!在能够调试固件之前,您需要执行的最后一步是构建SoC并使用位流配置Cynthion

cd cynthion.git/cynthion/python

make soc
make load

6. 启动gdb

如果您已成功完成上述所有步骤,并通过openocd与SoC建立了功能连接,您现在应该能够通过以下方式执行固件

cargo run --release --bin hello

如果一切顺利,您将进入一个熟悉的gdb外壳

Reading symbols from target/riscv32imac-unknown-none-elf/release/hello
_start () at asm.S:27
Breakpoint 1 at 0x4000109a: file src/lib.rs, line 498.
Function "HardFault" not defined.
Make breakpoint pending on future shared library load? (y or [n]) [answered N; input not from terminal]
Breakpoint 2 at 0x40001054: file moondancer/src/panic_log.rs, line 15.
Loading section .text, size 0x1172 lma 0x40000000
Loading section .rodata, size 0x2f4 lma 0x40001174
Loading section .data, size 0x10 lma 0x40001468
Start address 0x40000000, load size 5238
Transfer rate: 196 KB/sec, 1746 bytes/write.
(gdb)

要开始执行,只需键入continue,如果您打开了一个连接到Cynthion UART端口的串行终端,您将看到类似以下内容

INFO    Peripherals initialized, entering main loop.
INFO    left: 3
INFO    right: 7
INFO    left: 11
...

有关嵌入式Rust调试的更多信息,请参阅嵌入式Rust书籍 - 硬件

依赖关系

~2.7–4MB
~68K SLoC