Skip to content

Commit b816e6e

Browse files
authored
Rework/fix in-console executable upload via UART (#1484)
2 parents dd2ac42 + ca4fcda commit b816e6e

File tree

4 files changed

+133
-91
lines changed

4 files changed

+133
-91
lines changed

docs/datasheet/software.adoc

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -179,54 +179,59 @@ For more complex projects, it may be useful to use explicit `source` and `includ
179179
Invoking a project-local makefile (executing `make` or `make help`) will show the help menu that lists all
180180
available targets as well as all variable including their _current_ setting.
181181

182-
[source,makefile]
182+
[source,bash]
183183
----
184184
neorv32/sw/example/hello_world$ make
185185
NEORV32 Software Makefile
186186
Find more information at https://github.com/stnolting/neorv32
187-
Use make V=1 or set BUILD_VERBOSE to increase build verbosity
187+
Use 'make V=1' or set BUILD_VERBOSE to increase build verbosity
188188
189189
Targets:
190190
191-
help show this text
192-
check check toolchain and list supported ISA extensions
193-
info show project/makefile configuration
194-
gdb start GNU debugging session
195-
asm compile and generate <main.asm> assembly listing file for manual debugging
196-
elf compile and generate <main.elf> ELF file
197-
exe compile and generate <neorv32_exe.bin> executable image file for bootloader upload (includes a HEADER!)
198-
bin compile and generate <neorv32_raw_exe.bin> executable memory image
199-
hex compile and generate <neorv32_raw_exe.hex> executable memory image
200-
coe compile and generate <neorv32_raw_exe.coe> executable memory image
201-
mem compile and generate <neorv32_raw_exe.mem> executable memory image
202-
mif compile and generate <neorv32_raw_exe.mif> executable memory image
203-
image compile and generate VHDL IMEM application boot image <neorv32_imem_image.vhd> in local folder
204-
install compile, generate and install VHDL IMEM application boot image <neorv32_imem_image.vhd>
205-
sim in-console simulation using default/simple testbench and GHDL
191+
help show this text
192+
check check toolchain and list supported ISA extensions
193+
info show project/makefile configuration
194+
gdb start GNU debugging session
195+
asm build and generate <main.asm> assembly listing file
196+
elf build and generate <main.elf> ELF file
197+
exe build and generate <neorv32_exe.bin> executable file for bootloader upload
198+
bin build and generate <neorv32_raw_exe.bin> executable memory image
199+
hex build and generate <neorv32_raw_exe.hex> executable memory image
200+
coe build and generate <neorv32_raw_exe.coe> executable memory image
201+
mem build and generate <neorv32_raw_exe.mem> executable memory image
202+
mif build and generate <neorv32_raw_exe.mif> executable memory image
203+
image build and generate VHDL IMEM application memory image <neorv32_imem_image.vhd> in local folder
204+
install build, generate and install VHDL IMEM application memory image <neorv32_imem_image.vhd>
205+
clean clean up project home folder
206+
clean_all clean up project home folder and image generator
207+
all clean_all + elf + asm + exe + hex + bin + coe + mem + mif + image + install
208+
209+
Additional targets:
210+
211+
sim in-console simulation using default testbench (sim folder) and GHDL
206212
hdl_lists regenerate HDL file-lists (*.f) in NEORV32_HOME/rtl
207-
all exe + install + hex + bin + asm
213+
upload upload executable to bootloader via UART (/dev/ttyUSB1)
208214
elf_info show ELF layout info
209215
elf_sections show ELF sections
210-
clean clean up project home folder
211-
clean_all clean up project home folder and image generator
212-
bl_image compile and generate VHDL BOOTROM bootloader boot image <neorv32_bootrom_image.vhd> in local folder
213-
bootloader compile, generate and install VHDL BOOTROM bootloader boot image <neorv32_bootrom_image.vhd>
216+
bl_image build and generate VHDL BOOTROM bootloader memory image <neorv32_bootrom_image.vhd> in local folder
217+
bootloader build, generate and install VHDL BOOTROM bootloader memory image <neorv32_bootrom_image.vhd>
214218
215219
Variables:
216220
217-
BUILD_VERBOSE Set to increase build verbosity: 0
221+
BUILD_VERBOSE Set to increase build verbosity: "0"
218222
USER_FLAGS Custom toolchain flags [append only]: "-ggdb -gdwarf-3 -Wl,--defsym,__neorv32_rom_size=16k -Wl,--defsym,__neorv32_ram_size=8k"
219223
USER_LIBS Custom libraries [append only]: ""
220224
EFFORT Optimization level: "-Os"
221225
MARCH Machine architecture: "rv32i_zicsr_zifencei"
222226
MABI Machine binary interface: "ilp32"
223227
APP_INC C include folder(s) [append only]: "-I ."
224228
APP_SRC C source folder(s) [append only]: "./main.c "
225-
APP_OBJ Object file(s) [append only]
229+
APP_OBJ Object file(s) [append only]: ""
226230
ASM_INC ASM include folder(s) [append only]: "-I ."
227231
RISCV_PREFIX Toolchain prefix: "riscv-none-elf-"
228232
NEORV32_HOME NEORV32 home folder: "../../.."
229-
GDB_ARGS GDB (connection) arguments: "-ex target extended-remote localhost:3333"
233+
GDB_ARGS GDB arguments: "-ex target extended-remote localhost:3333"
234+
UART_TTY Serial port for upload to bootloader: "/dev/ttyUSB1"
230235
GHDL_RUN_FLAGS GHDL simulation run arguments: ""
231236
----
232237

@@ -236,7 +241,7 @@ All _intermediate_ build artifacts (like object files and binaries) will be plac
236241
folder named `build`. The _resulting_ build artifacts (like executable, the main ELF and all memory
237242
initialization/image files) will be placed in the root project folder.
238243

239-
.Increse Verbosity
244+
.Increase Verbosity
240245
[TIP]
241246
Use `make V=1` or set `BUILD_VERBOSE` in your environment to increase build verbosity.
242247

docs/datasheet/software_bootloader.adoc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,14 @@ Make sure the terminal sends the executable in raw binary mode.
163163
. The executable is now in the instruction memory of the processor. To execute the program right
164164
now run the "start executable" command by typing `e`.
165165

166+
.Uploading via `make upload` right from the console
167+
[TIP]
168+
The <<_application_makefile>> provides an "`upload`" target that allows you to transfer a compiled executable directly
169+
to the bootloader via UART right from the console. This script handles the communication with the bootloader and is
170+
based on a simple shell helper script `neorv32/sw/image_gen/uart_upload.sh`. Example:
171+
`neorv32/sw/example/demo_blink_led$ make UART_TTY=/dev/ttyUSB1 upload`.
172+
The serial interface device is defined by `UART_TTY` .
173+
166174

167175
:sectnums:
168176
==== Programming an SPI (/TWI) Flash

sw/common/common.mk

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ GDB_ARGS ?= -ex "target extended-remote localhost:3333"
4949
# GHDL simulation run arguments
5050
GHDL_RUN_FLAGS ?=
5151

52+
# Serial device for UART bootloader upload
53+
UART_TTY ?= /dev/ttyUSB1
54+
5255
# -----------------------------------------------------------------------------
5356
# NEORV32 framework
5457
# -----------------------------------------------------------------------------
@@ -120,8 +123,8 @@ SET = set
120123
CP = cp
121124
RM = rm
122125
MKDIR = mkdir
123-
SH = sh
124126
WC = wc
127+
CHMOD = chmod
125128

126129
# NEORV32 executable image generator
127130
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen
@@ -160,7 +163,7 @@ mem: $(APP_MEM)
160163
mif: $(APP_MIF)
161164
image: $(APP_VHD)
162165
install: image install-$(APP_VHD)
163-
all: $(APP_ELF) $(APP_ASM) $(APP_EXE) $(APP_HEX) $(APP_BIN) $(APP_COE) $(APP_MEM) $(APP_MIF) $(APP_VHD) install hex bin
166+
all: clean_all elf asm exe hex bin coe mem mif image install
164167

165168
# -----------------------------------------------------------------------------
166169
# Verbosity
@@ -186,6 +189,7 @@ endif
186189
$(IMAGE_GEN): $(NEORV32_EXG_PATH)/image_gen.c
187190
$(ECHO) Compiling image generator...
188191
$(Q)$(CC_HOST) $< -o $(IMAGE_GEN)
192+
$(Q)$(CHMOD) +rx $(IMAGE_GEN)
189193

190194
# -----------------------------------------------------------------------------
191195
# Build targets: Assemble, compile, link, dump
@@ -296,7 +300,8 @@ bootloader: bl_image
296300

297301
sim: $(APP_VHD)
298302
$(ECHO) "Simulating processor using default testbench..."
299-
$(Q)$(SH) $(NEORV32_SIM_PATH)/ghdl.sh $(GHDL_RUN_FLAGS)
303+
$(Q)$(CHMOD) +rx $(NEORV32_SIM_PATH)/ghdl.sh
304+
$(Q)./$(NEORV32_SIM_PATH)/ghdl.sh $(GHDL_RUN_FLAGS)
300305

301306
# Install VHDL memory initialization file
302307
install-$(APP_VHD): $(APP_VHD)
@@ -309,7 +314,8 @@ install-$(APP_VHD): $(APP_VHD)
309314
# -----------------------------------------------------------------------------
310315

311316
hdl_lists:
312-
$(Q)$(SH) $(NEORV32_RTL_PATH)/generate_file_lists.sh
317+
$(Q)$(CHMOD) +rx $(NEORV32_RTL_PATH)/generate_file_lists.sh
318+
$(Q)./$(NEORV32_RTL_PATH)/generate_file_lists.sh
313319

314320
# -----------------------------------------------------------------------------
315321
# Show final ELF details (just for debugging)
@@ -321,6 +327,14 @@ elf_info: $(APP_ELF)
321327
elf_sections: $(APP_ELF)
322328
$(Q)$(READELF) -S $(APP_ELF)
323329

330+
# -----------------------------------------------------------------------------
331+
# Upload to bootloader via UART
332+
# -----------------------------------------------------------------------------
333+
334+
upload: $(APP_EXE)
335+
$(Q)$(CHMOD) +rx $(NEORV32_EXG_PATH)/uart_upload.sh
336+
$(Q)./$(NEORV32_EXG_PATH)/uart_upload.sh $(UART_TTY) $(APP_EXE)
337+
324338
# -----------------------------------------------------------------------------
325339
# Run GDB
326340
# -----------------------------------------------------------------------------
@@ -430,27 +444,31 @@ help:
430444
$(ECHO) ""
431445
$(ECHO) "Targets:"
432446
$(ECHO) ""
433-
$(ECHO) " help show this text"
434-
$(ECHO) " check check toolchain and list supported ISA extensions"
435-
$(ECHO) " info show project/makefile configuration"
436-
$(ECHO) " gdb start GNU debugging session"
437-
$(ECHO) " asm build and generate <$(APP_ASM)> assembly listing file"
438-
$(ECHO) " elf build and generate <$(APP_ELF)> ELF file"
439-
$(ECHO) " exe build and generate <$(APP_EXE)> executable file for bootloader upload"
440-
$(ECHO) " bin build and generate <$(APP_BIN)> executable memory image"
441-
$(ECHO) " hex build and generate <$(APP_HEX)> executable memory image"
442-
$(ECHO) " coe build and generate <$(APP_COE)> executable memory image"
443-
$(ECHO) " mem build and generate <$(APP_MEM)> executable memory image"
444-
$(ECHO) " mif build and generate <$(APP_MIF)> executable memory image"
445-
$(ECHO) " image build and generate VHDL IMEM application memory image <$(APP_VHD)> in local folder"
446-
$(ECHO) " install build, generate and install VHDL IMEM application memory image <$(APP_VHD)>"
447+
$(ECHO) " help show this text"
448+
$(ECHO) " check check toolchain and list supported ISA extensions"
449+
$(ECHO) " info show project/makefile configuration"
450+
$(ECHO) " gdb start GNU debugging session"
451+
$(ECHO) " asm build and generate <$(APP_ASM)> assembly listing file"
452+
$(ECHO) " elf build and generate <$(APP_ELF)> ELF file"
453+
$(ECHO) " exe build and generate <$(APP_EXE)> executable file for bootloader upload"
454+
$(ECHO) " bin build and generate <$(APP_BIN)> executable memory image"
455+
$(ECHO) " hex build and generate <$(APP_HEX)> executable memory image"
456+
$(ECHO) " coe build and generate <$(APP_COE)> executable memory image"
457+
$(ECHO) " mem build and generate <$(APP_MEM)> executable memory image"
458+
$(ECHO) " mif build and generate <$(APP_MIF)> executable memory image"
459+
$(ECHO) " image build and generate VHDL IMEM application memory image <$(APP_VHD)> in local folder"
460+
$(ECHO) " install build, generate and install VHDL IMEM application memory image <$(APP_VHD)>"
461+
$(ECHO) " clean clean up project home folder"
462+
$(ECHO) " clean_all clean up project home folder and image generator"
463+
$(ECHO) " all clean_all + elf + asm + exe + hex + bin + coe + mem + mif + image + install"
464+
$(ECHO) ""
465+
$(ECHO) "Additional targets:"
466+
$(ECHO) ""
447467
$(ECHO) " sim in-console simulation using default testbench (sim folder) and GHDL"
448468
$(ECHO) " hdl_lists regenerate HDL file-lists (*.f) in NEORV32_HOME/rtl"
449-
$(ECHO) " all exe + install + hex + bin + asm"
469+
$(ECHO) " upload upload executable to bootloader via UART ($(UART_TTY))"
450470
$(ECHO) " elf_info show ELF layout info"
451471
$(ECHO) " elf_sections show ELF sections"
452-
$(ECHO) " clean clean up project home folder"
453-
$(ECHO) " clean_all clean up project home folder and image generator"
454472
$(ECHO) " bl_image build and generate VHDL BOOTROM bootloader memory image <$(BLD_VHD)> in local folder"
455473
$(ECHO) " bootloader build, generate and install VHDL BOOTROM bootloader memory image <$(BLD_VHD)>"
456474
$(ECHO) ""
@@ -469,5 +487,6 @@ help:
469487
$(ECHO) " RISCV_PREFIX Toolchain prefix: \"$(RISCV_PREFIX)\""
470488
$(ECHO) " NEORV32_HOME NEORV32 home folder: \"$(NEORV32_HOME)\""
471489
$(ECHO) " GDB_ARGS GDB arguments: \"$(GDB_ARGS)\""
490+
$(ECHO) " UART_TTY Serial port for upload to bootloader: \"$(UART_TTY)\""
472491
$(ECHO) " GHDL_RUN_FLAGS GHDL simulation run arguments: \"$(GHDL_RUN_FLAGS)\""
473492
$(ECHO) ""

sw/image_gen/uart_upload.sh

Lines changed: 54 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,74 @@
11
#!/usr/bin/env bash
22

3+
# Simple script to upload an executable to the default NEORV32 bootloader
4+
35
set -e
46

5-
# Simple script to upload executable via bootloader
7+
# Default baud rate
8+
BAUD=19200
69

10+
# check arguments; show help text
711
if [ $# -ne 2 ]
812
then
9-
printf "Upload and execute application image via serial port (UART) to the NEORV32 bootloader.\n"
13+
printf "Upload an executable via serial port (UART) to the NEORV32 bootloader.\n"
14+
printf "If the upload is successful, the executable will be run automatically.\n"
1015
printf "Reset processor before starting the upload.\n\n"
11-
printf "Usage: sh uart_upload.sh <serial port> <NEORV32 executable>\n"
12-
printf "Example: sh uart_upload.sh /dev/ttyS6 path/to/project/neorv32_exe.bin\n"
16+
printf "Usage: ./uart_upload.sh <serial port> <NEORV32 executable>\n"
17+
printf "Example: ./uart_upload.sh /dev/ttyS6 path/to/neorv32_exe.bin\n"
1318
exit 0
1419
fi
1520

16-
# configure serial port
17-
stty -F "$1" 19200 -hup raw -echo -echoe -echok -echoctl -echoke -ixon cs8 -cstopb noflsh clocal cread
21+
# timeout to make sure there is enough time for the file to be sent in background
22+
# "BAUD" bits per second; 10 bits per byte (incl START and STOP bits); plus safety margin
23+
FILESIZE=$(stat -c%s "$2")
24+
TIMEOUT=$(( (FILESIZE / (BAUD/10)) + 2 ))
1825

19-
# abort autoboot sequence
20-
printf " " > $1 # send any char that triggers no command
26+
# setup serial port
27+
printf "Opening serial port ($1)... "
28+
stty -F $1 $BAUD -hup raw -echo cs8 -cstopb -ixon clocal cread
29+
exec 3<>$1
30+
printf "OK\n"
2131

22-
# execute upload command and get response
23-
exec 3<$1 # redirect serial output to fd 3
24-
cat <&3 > uart_upload.response.tmp & # redirect serial output to file
25-
PID=$! # save pid to kill cat later
26-
printf "u" > $1 # send upload command to serial port
27-
sleep 0.5s # wait for bootloader response
28-
kill $PID # kill cat process
32+
# send executable
33+
printf "Uploading executable ($FILESIZE bytes)... "
34+
printf " u" >&3 # skip auto-boot (SPACE) and start upload ('u')
35+
cat $2 >&3 # send executable
2936

30-
exec 3<&- # free fd 3
37+
# wait for upload to complete and check bootloader response
38+
UPOLOAD_OK=0
39+
EXPIRED=$(( SECONDS + TIMEOUT ))
40+
PATTERN="OK"
41+
BUFFER=""
42+
while [ $SECONDS -lt $EXPIRED ]; do
43+
if read -r -n 1 -u 3 -t 1 CH; then
44+
BUFFER+=$CH
45+
UPOLOAD_OK=-1
46+
if [[ "$BUFFER" == *"$PATTERN"* ]]; then
47+
UPOLOAD_OK=1
48+
break
49+
fi
50+
fi
51+
done
3152

32-
# check response
33-
if ! grep -Fq "Awaiting neorv32_exe.bin" uart_upload.response.tmp;
34-
then
35-
printf "Bootloader response error!\n"
36-
printf "Reset processor before starting the upload.\n"
37-
rm -f uart_upload.response.tmp
38-
exit 1
53+
if [ $UPOLOAD_OK -eq 1 ]; then
54+
printf "OK\n" >&2
55+
elif [ $UPOLOAD_OK -eq -1 ]; then
56+
printf "\nERROR! Invalid bootloader response.\n" >&2
57+
else
58+
printf "\nERROR! Bootloader response timeout ($TIMEOUT seconds).\n" >&2
3959
fi
4060

41-
# send executable and get response
42-
printf "Uploading executable..."
43-
exec 3<$1 # redirect serial output to fd 3
44-
cat <&3 > uart_upload.response.tmp & # redirect serial output to file
45-
PID=$! # save pid to kill cat later
46-
cat "$2" > "$1" # send executable to serial port
47-
sleep 3s # wait for bootloader response
48-
kill $PID # kill cat process
49-
50-
exec 3<&- # free fd 3
61+
# start executable
62+
if [ $UPOLOAD_OK -eq 1 ]; then
63+
printf "Booting executable...\n"
64+
printf "e" >&3
65+
fi
5166

52-
# check response
53-
if ! grep -Fq "OK" uart_upload.response.tmp;
54-
then
55-
printf " FAILED!\n"
56-
rm -f uart_upload.response.tmp
57-
exit 1
58-
else
59-
printf " OK\n"
60-
echo "Starting application..."
61-
printf "e" > $1
62-
rm -f uart_upload.response.tmp
67+
# done
68+
exec 3>&-
69+
if [ $UPOLOAD_OK -eq 1 ]; then
6370
exit 0
71+
else
72+
printf "Check configuration, reset processor and try again.\n" >&2
73+
exit 1;
6474
fi

0 commit comments

Comments
 (0)