Hi there!
I'm trying to modify the bootloader to also look at one of the IO pins when determining whether or not to enter DFU mode, and I can't seem to produce a bitstream that actually /works/. Particularly, I can run the entire compilation process, create a bitstream, upload it with dfu-util
, but once it loads, the RGB LED seems to just get stuck at green (which doesn't seem to actually correspond to any state of the bootloader), regardless if the IOs are tied high, low, or left floating. I'm not sure if I'm doing something wrong, or if that's an expected behavior of the bootloader when running from the "user" section. I'm hoping to avoid having to actually flash it as the real bootloader to test it. I have a Segger J-LINK if it turns out to be necessary to use JTAG to recover the bootloader (i.e., not super worried about bricking the device), but I'm similarly hoping to avoid having to go down that road if possible.
Below are all the changes I've made to in my attempts to get this working. Any help would be appreciated!
These are divided into two sections, system-specific tweaks I had to make to the Makefile and linker script to get it building on my machine, and then the changes I attempted to make to the bitstream to try and get it to look at IO pins besides the onboard button
Build environment
parallels@parallels-Parallels-Virtual-Platform:~$ uname -a
Linux parallels-Parallels-Virtual-Platform 4.15.0-34-generic #37-Ubuntu SMP Mon Aug 27 15:21:48 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
parallels@parallels-Parallels-Virtual-Platform:~$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.5 LTS"
parallels@parallels-Parallels-Virtual-Platform:~$ yosys --version
Yosys 0.9+3521 (git sha1 4f2b78e1, clang 6.0.0-1ubuntu2 -fPIC -Os)
parallels@parallels-Parallels-Virtual-Platform:~$ nextpnr-ecp5 --version
nextpnr-ecp5 -- Next Generation Place and Route (Version f6d436d5)
parallels@parallels-Parallels-Virtual-Platform:~$ ecppack --version
Project Trellis ecppack Version 1.0-182-g8c0a638
parallels@parallels-Parallels-Virtual-Platform:~$ riscv32-unknown-elf-gcc --version
riscv32-unknown-elf-gcc (GCC) 10.1.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
parallels@parallels-Parallels-Virtual-Platform:~$ riscv32-unknown-elf-ld --version
GNU ld (GNU Binutils) 2.35
Copyright (C) 2020 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.
My build-and-flash command is:
python3 foboot-bitstream.py --platform orangecrab --revision 0.2 --device 25F && \
cp build/gateware/orangecrab.bit build/gateware/orangecrab.dfu && \
dfu-suffix -v 1209 -p 5af0 -a build/gateware/orangecrab.dfu && \
dfu-util -D build/gateware/orangecrab.dfu
System-specific changes
Modified sw/Makefile
to support my system:
diff --git a/sw/Makefile b/sw/Makefile
index a08bf1a..04d478e 100644
--- a/sw/Makefile
+++ b/sw/Makefile
@@ -1,5 +1,5 @@
# Earlier versions of the Raspberry Pi image only had riscv32-gcc
-ifneq (,$(wildcard /usr/bin/riscv32-unknown-elf-gcc))
+ifneq (,$(wildcard /opt/riscv/bin/riscv32-unknown-elf-gcc))
TRGT ?= riscv32-unknown-elf-
else
TRGT ?= riscv64-unknown-elf-
Modified the linker script so that it actually links
Not sure if this is because I'm using the most recent riscv-gnu-toolchain
, but ld
was complaining about .srodata.landing_url_descriptor
overflowing into .data
. I had to tweak the rodata
section to look like:
diff --git a/sw/ld/linker.ld b/sw/ld/linker.ld
index 5796f16..7282043 100644
--- a/sw/ld/linker.ld
+++ b/sw/ld/linker.ld
@@ -21,7 +21,7 @@ SECTIONS
_frodata = .;
*(.rodata .rodata.* .gnu.linkonce.r.*)
*(.rodata1)
- *(.srodata)
+ *(.srodata .srodata.*)
_erodata = .;
} > rom
Changes to the actual bitstream
Then I made a few changes to the platform scripts to support treating IO0
and IO1
as readable peripherals via a CSR
much like the usr_btn
is.
Added two IOs to hw/deps/litex-boards/litex_boards/platforms/orangecrab.py
Just adding these two pins to be able to reference them later in the stack
diff --git a/litex_boards/platforms/orangecrab.py b/litex_boards/platforms/orangecrab.py
index efdd103..4cae9d8 100644
--- a/litex_boards/platforms/orangecrab.py
+++ b/litex_boards/platforms/orangecrab.py
@@ -84,6 +84,8 @@ _io_r0_2 = [
("rst_n", 0, Pins("V17"), IOStandard("LVCMOS33")),
("usr_btn", 0, Pins("J17"), IOStandard("SSTL135_I")),
+ ("io_0", 0, Pins("GPIO:0"), IOStandard("LVCMOS33")),
+ ("io_1", 0, Pins("GPIO:1"), IOStandard("LVCMOS33")),
("rgb_led", 0,
Subsignal("r", Pins("K4"), IOStandard("LVCMOS33")),
Added the two IOs to hw/rtl/plaform/orangecrab.py
Modified add_button
to make two more "buttons" that read those two pins similar to how the real button is added
diff --git a/hw/rtl/platform/orangecrab.py b/hw/rtl/platform/orangecrab.py
index 40fb8e4..47cc86c 100644
--- a/hw/rtl/platform/orangecrab.py
+++ b/hw/rtl/platform/orangecrab.py
@@ -91,7 +91,12 @@ class Platform(LatticePlatform):
def add_button(self, soc):
try:
btn = self.request("usr_btn")
+ io0 = self.request("io_0")
+ io1 = self.request("io_1")
+
soc.submodules.button = Button(btn)
+ soc.submodules.io0 = Button(io0)
+ soc.submodules.io1 = Button(io1)
except:
...
Added the two new "button" CSRs to hw/foboot-bitstream.py
diff --git a/hw/foboot-bitstream.py b/hw/foboot-bitstream.py
index d2c1512..241474c 100755
--- a/hw/foboot-bitstream.py
+++ b/hw/foboot-bitstream.py
@@ -75,6 +75,8 @@ class BaseSoC(SoCCore, AutoDoc):
"lxspi": 15,
"messible": 16,
"button": 17,
+ "io0": 18,
+ "io1": 19,
}
SoCCore.mem_map = {
Finally, modified sw/src/main.c
to consider the new IO pins when determining whether to enter DFU mode
diff --git a/sw/src/main.c b/sw/src/main.c
index ca77fd1..2f216a4 100644
--- a/sw/src/main.c
+++ b/sw/src/main.c
@@ -117,7 +117,14 @@ static int nerve_pinch(void) {
static int button_pressed(void){
#ifdef CSR_BUTTON_BASE
+# ifdef CSR_IO0_BASE
+# ifdef CSR_IO1_BASE
+ return button_i_read() != 1 || io0_i_read() != 1 || io1_i_read() != 1;
+# else
+ return button_i_read() != 1 || io0_i_read() != 1;
+# endif
return button_i_read() != 1;
+# endif
#else
return 1;
#endif
Thanks for taking a look at this! Any insight would be appreciated, and hopefully this can go on to serve a power user in the future if they want to try this!