diff --git a/Makefile b/Makefile index 2dc82c4..5f0d95b 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,13 @@ # Project: stm8gal CC = gcc -CFLAGS = -c -Wall -I./STM8_Routines +CFLAGS = -c -Wall -I./RAM_Routines #CFLAGS += -DDEBUG LDFLAGS = -g3 -lm -SOURCES = bootloader.c hexfile.c main.c misc.c serial_comm.c spi_Arduino_comm.c -INCLUDES = misc.h bootloader.h hexfile.h serial_comm.h spi_spidev_comm.h spi_Arduino_comm.h main.h -STM8FLASH = STM8_Routines/E_W_ROUTINEs_128K_ver_2.1.s19 STM8_Routines/E_W_ROUTINEs_128K_ver_2.0.s19 STM8_Routines/E_W_ROUTINEs_256K_ver_1.0.s19 STM8_Routines/E_W_ROUTINEs_32K_ver_1.3.s19 STM8_Routines/E_W_ROUTINEs_32K_ver_1.4.s19 STM8_Routines/E_W_ROUTINEs_128K_ver_2.2.s19 STM8_Routines/E_W_ROUTINEs_32K_ver_1.0.s19 STM8_Routines/E_W_ROUTINEs_128K_ver_2.4.s19 STM8_Routines/E_W_ROUTINEs_32K_ver_1.2.s19 STM8_Routines/E_W_ROUTINEs_32K_verL_1.0.s19 STM8_Routines/E_W_ROUTINEs_8K_verL_1.0.s19 -STM8INCLUDES = $(STM8FLASH:.s19=.h) +SOURCES = bootloader.c hexfile.c main.c misc.c serial_comm.c spi_Arduino_comm.c verify_CRC32.c +INCLUDES = misc.h bootloader.h hexfile.h serial_comm.h spi_spidev_comm.h spi_Arduino_comm.h verify_CRC32.h main.h +RAMROUTINES = RAM_Routines/E_W_ROUTINEs_128K_ver_2.1.s19 RAM_Routines/E_W_ROUTINEs_128K_ver_2.0.s19 RAM_Routines/E_W_ROUTINEs_256K_ver_1.0.s19 RAM_Routines/E_W_ROUTINEs_32K_ver_1.3.s19 RAM_Routines/E_W_ROUTINEs_32K_ver_1.4.s19 RAM_Routines/E_W_ROUTINEs_128K_ver_2.2.s19 RAM_Routines/E_W_ROUTINEs_32K_ver_1.0.s19 RAM_Routines/E_W_ROUTINEs_128K_ver_2.4.s19 RAM_Routines/E_W_ROUTINEs_32K_ver_1.2.s19 RAM_Routines/E_W_ROUTINEs_32K_verL_1.0.s19 RAM_Routines/E_W_ROUTINEs_8K_verL_1.0.s19 +RAMINCLUDES = $(RAMROUTINES:.s19=.h) OBJDIR = Objects OBJECTS = $(patsubst %.c, $(OBJDIR)/%.o, $(SOURCES)) BIN = stm8gal @@ -17,7 +17,7 @@ RM = rm -fr #CFLAGS += -DUSE_SPIDEV #SOURCES += spi_spidev_comm.c -# add optional GPIO reset via wiringPi library (Raspberry only) +# add optional GPIO reset via wiringPi library (Raspberry only) #CFLAGS += -DUSE_WIRING #LDFLAGS += -lwiringPi @@ -28,21 +28,21 @@ RM = rm -fr default: $(BIN) $(OBJDIR) -all: $(STM8INCLUDES) $(SOURCES) $(BIN) - +all: $(RAMINCLUDES) $(SOURCES) $(BIN) + $(OBJDIR): mkdir -p $(OBJDIR) clean: - ${RM} $(OBJECTS) $(OBJDIR) $(BIN) $(BIN).exe *~ .DS_Store - -%.h: %.s19 $(STM8FLASH) + ${RM} $(OBJECTS) $(OBJDIR) $(BIN) $(BIN).exe *~ .DS_Store + +%.h: %.s19 $(RAMROUTINES) xxd -i $< > $@ - + # link application $(BIN): $(OBJECTS) $(OBJDIR) $(CC) $(LDFLAGS) $(OBJECTS) -o $@ # compile all *c files -$(OBJDIR)/%.o: %.c $(SOURCES) $(INCLUDES) $(STM8INCLUDES) $(OBJDIR) +$(OBJDIR)/%.o: %.c $(SOURCES) $(INCLUDES) $(RAMINCLUDES) $(OBJDIR) $(CC) $(CFLAGS) -c $< -o $@ diff --git a/RAM_Routines/verify_CRC32_ihx.h b/RAM_Routines/verify_CRC32_ihx.h new file mode 100644 index 0000000..8659d23 --- /dev/null +++ b/RAM_Routines/verify_CRC32_ihx.h @@ -0,0 +1,57 @@ +unsigned char bin_verify_CRC32_ihx[] = { + 0x3a, 0x32, 0x30, 0x30, 0x32, 0x30, 0x30, 0x30, 0x30, 0x38, 0x38, 0x43, + 0x45, 0x30, 0x33, 0x35, 0x36, 0x43, 0x33, 0x30, 0x33, 0x35, 0x32, 0x43, + 0x36, 0x30, 0x33, 0x35, 0x35, 0x43, 0x32, 0x30, 0x33, 0x35, 0x31, 0x43, + 0x36, 0x30, 0x33, 0x35, 0x34, 0x43, 0x32, 0x30, 0x33, 0x35, 0x30, 0x32, + 0x35, 0x31, 0x31, 0x41, 0x45, 0x37, 0x46, 0x46, 0x46, 0x43, 0x33, 0x30, + 0x33, 0x35, 0x36, 0x41, 0x36, 0x30, 0x32, 0x43, 0x32, 0x30, 0x33, 0x35, + 0x35, 0x37, 0x31, 0x0a, 0x3a, 0x32, 0x30, 0x30, 0x32, 0x32, 0x30, 0x30, + 0x30, 0x34, 0x46, 0x43, 0x32, 0x30, 0x33, 0x35, 0x34, 0x32, 0x34, 0x30, + 0x45, 0x35, 0x46, 0x43, 0x46, 0x30, 0x33, 0x35, 0x42, 0x43, 0x46, 0x30, + 0x33, 0x35, 0x39, 0x33, 0x35, 0x30, 0x31, 0x30, 0x33, 0x35, 0x38, 0x43, + 0x43, 0x30, 0x32, 0x43, 0x33, 0x43, 0x36, 0x35, 0x30, 0x43, 0x36, 0x36, + 0x42, 0x30, 0x31, 0x33, 0x35, 0x30, 0x30, 0x35, 0x30, 0x43, 0x36, 0x41, + 0x45, 0x46, 0x46, 0x46, 0x46, 0x30, 0x43, 0x0a, 0x3a, 0x32, 0x30, 0x30, + 0x32, 0x34, 0x30, 0x30, 0x30, 0x43, 0x46, 0x30, 0x33, 0x35, 0x42, 0x41, + 0x45, 0x46, 0x46, 0x46, 0x46, 0x43, 0x46, 0x30, 0x33, 0x35, 0x39, 0x43, + 0x45, 0x30, 0x33, 0x35, 0x36, 0x43, 0x33, 0x30, 0x33, 0x35, 0x32, 0x43, + 0x36, 0x30, 0x33, 0x35, 0x35, 0x43, 0x32, 0x30, 0x33, 0x35, 0x31, 0x43, + 0x36, 0x30, 0x33, 0x35, 0x34, 0x43, 0x32, 0x30, 0x33, 0x35, 0x30, 0x32, + 0x35, 0x33, 0x46, 0x38, 0x38, 0x39, 0x32, 0x42, 0x43, 0x42, 0x42, 0x0a, + 0x3a, 0x32, 0x30, 0x30, 0x32, 0x36, 0x30, 0x30, 0x30, 0x30, 0x33, 0x35, + 0x31, 0x43, 0x37, 0x30, 0x33, 0x35, 0x38, 0x38, 0x34, 0x33, 0x42, 0x30, + 0x33, 0x35, 0x38, 0x43, 0x45, 0x30, 0x33, 0x35, 0x42, 0x38, 0x39, 0x43, + 0x45, 0x30, 0x33, 0x35, 0x39, 0x38, 0x39, 0x43, 0x44, 0x30, 0x32, 0x45, + 0x32, 0x35, 0x42, 0x30, 0x35, 0x43, 0x46, 0x30, 0x33, 0x35, 0x42, 0x39, + 0x30, 0x43, 0x46, 0x30, 0x33, 0x35, 0x39, 0x43, 0x45, 0x30, 0x33, 0x35, + 0x32, 0x36, 0x41, 0x0a, 0x3a, 0x32, 0x30, 0x30, 0x32, 0x38, 0x30, 0x30, + 0x30, 0x31, 0x43, 0x30, 0x30, 0x30, 0x31, 0x39, 0x30, 0x43, 0x45, 0x30, + 0x33, 0x35, 0x30, 0x32, 0x34, 0x30, 0x32, 0x39, 0x30, 0x35, 0x43, 0x43, + 0x46, 0x30, 0x33, 0x35, 0x32, 0x39, 0x30, 0x43, 0x46, 0x30, 0x33, 0x35, + 0x30, 0x33, 0x35, 0x41, 0x41, 0x35, 0x30, 0x45, 0x30, 0x33, 0x35, 0x37, + 0x46, 0x35, 0x30, 0x44, 0x31, 0x32, 0x30, 0x41, 0x44, 0x43, 0x36, 0x30, + 0x33, 0x35, 0x43, 0x34, 0x33, 0x38, 0x46, 0x0a, 0x3a, 0x32, 0x30, 0x30, + 0x32, 0x41, 0x30, 0x30, 0x30, 0x39, 0x37, 0x43, 0x36, 0x30, 0x33, 0x35, + 0x42, 0x34, 0x33, 0x39, 0x35, 0x43, 0x36, 0x30, 0x33, 0x35, 0x41, 0x34, + 0x33, 0x39, 0x30, 0x39, 0x37, 0x43, 0x36, 0x30, 0x33, 0x35, 0x39, 0x34, + 0x33, 0x39, 0x30, 0x39, 0x35, 0x43, 0x46, 0x30, 0x33, 0x35, 0x42, 0x39, + 0x30, 0x43, 0x46, 0x30, 0x33, 0x35, 0x39, 0x37, 0x32, 0x35, 0x46, 0x30, + 0x33, 0x35, 0x38, 0x41, 0x45, 0x35, 0x30, 0x43, 0x36, 0x42, 0x43, 0x0a, + 0x3a, 0x32, 0x30, 0x30, 0x32, 0x43, 0x30, 0x30, 0x30, 0x37, 0x42, 0x30, + 0x31, 0x46, 0x37, 0x33, 0x35, 0x30, 0x31, 0x35, 0x33, 0x30, 0x34, 0x43, + 0x36, 0x35, 0x33, 0x30, 0x32, 0x33, 0x35, 0x30, 0x30, 0x35, 0x33, 0x30, + 0x32, 0x33, 0x35, 0x30, 0x31, 0x35, 0x33, 0x32, 0x34, 0x43, 0x36, 0x35, + 0x33, 0x32, 0x32, 0x33, 0x35, 0x30, 0x30, 0x35, 0x33, 0x32, 0x32, 0x37, + 0x32, 0x35, 0x46, 0x30, 0x30, 0x39, 0x39, 0x43, 0x43, 0x36, 0x30, 0x32, + 0x45, 0x32, 0x33, 0x0a, 0x3a, 0x32, 0x30, 0x30, 0x32, 0x45, 0x30, 0x30, + 0x30, 0x38, 0x34, 0x38, 0x31, 0x37, 0x42, 0x30, 0x37, 0x31, 0x38, 0x30, + 0x36, 0x36, 0x42, 0x30, 0x36, 0x31, 0x45, 0x30, 0x35, 0x31, 0x36, 0x30, + 0x33, 0x41, 0x36, 0x30, 0x38, 0x39, 0x30, 0x35, 0x34, 0x35, 0x36, 0x32, + 0x34, 0x31, 0x31, 0x30, 0x31, 0x41, 0x38, 0x32, 0x30, 0x30, 0x31, 0x41, + 0x38, 0x38, 0x33, 0x30, 0x31, 0x39, 0x30, 0x30, 0x31, 0x41, 0x38, 0x42, + 0x38, 0x39, 0x30, 0x30, 0x31, 0x31, 0x37, 0x0a, 0x3a, 0x30, 0x38, 0x30, + 0x33, 0x30, 0x30, 0x30, 0x30, 0x41, 0x38, 0x45, 0x44, 0x39, 0x30, 0x30, + 0x31, 0x34, 0x41, 0x32, 0x36, 0x45, 0x37, 0x38, 0x31, 0x46, 0x37, 0x0a, + 0x3a, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x46, 0x46, 0x0a +}; +unsigned int bin_verify_CRC32_ihx_len = 648; diff --git a/README.md b/README.md index 0090e43..a0f2a95 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Non ANSI-C extensions: - [wiringPi](http://wiringpi.com/) library, which is [Raspberry Pi](https://www.raspberrypi.org/) specific, and allows automatic reset of the STM8 via GPIO header pin. Is pre-installed for Raspbian Stretch and above. To activate remove comment in Makefile -- [spidev](https://www.kernel.org/doc/Documentation/spi/spidev) kernel library for interfacing to the SPI. To activate remove comment in Makefile. The [Raspberry Pi](https://www.raspberrypi.org/) and other "embedded PCs" provide direct SPI pin access, so no extra hardware is required. For "normal" PCs, an extra hardware and likely an adaptation of the SPI send/receive routines is required (volunteers?) +- [spidev](https://www.kernel.org/doc/Documentation/spi/spidev) kernel library for interfacing to the SPI. To activate remove comment in Makefile. The [Raspberry Pi](https://www.raspberrypi.org/) and other "embedded PCs" provide direct SPI pin access, so no extra hardware is required. For "normal" PCs, an extra hardware and likely an adaptation of the SPI send/receive routines is required (volunteers?) A code reference can be generated by running [Doxygen](http://www.doxygen.org) with input file 'Doxyfile'. Then open file './doxygen/html/index.html' with a webbrowser. For other output formats, e.g. PDF, modify 'Doxyfile' accordingly. @@ -67,7 +67,7 @@ Same as Linux above, but with additional option: - specify `CFLAGS += -DUSE\_SPIDEV` and `SOURCES += spi\_spidev\_comm.c` in file "Makefile" - enable SPI access via `raspi-config` - add user to group spi (`sudo usermod -a -G spi $(whoami)`) - + *** ## Windows @@ -84,9 +84,9 @@ Note: Windows commandline (cmd.exe) requires a path on a mounted drive, i.e. pat ## MacOSX Same as for Linux above. However, for double-click rename files "*.sh" to "*.command" - -Note: Due to lack of a Macintosh, compatibility with MacOSX is no longer tested. Therefore, please provide feedback if you have experience with _stm8gal_ on a Mac. Also a Mac binary for distribution is highly appreciated. Thanks! - + +Note: Due to lack of a Macintosh, compatibility with MacOSX is no longer tested. Therefore, please provide feedback if you have experience with _stm8gal_ on a Mac. Also a Mac binary for distribution is highly appreciated. Thanks! + *** # Using the Software @@ -99,23 +99,25 @@ _stm8gal_ is a commandline tool without graphical interface (volunteers...?). Th -v/-verbose [level] set verbosity level 0..3 (default: 2) -B/-background skip prompts and colors for background operation (default: foreground) -q/-exit-prompt prompt for prior to exit (default: no prompt) - -R/-reset [rst] reset for STM8: 0=skip, 1=manual, 2=DTR line (RS232), 3=send 'Re5eT!' @ 115.2kBaud, 4=Arduino pin pin 8, 5=Raspi pin 12, 6=RTS line (RS232) (default: manual) - -i/-interface [line] communication interface: 0=UART, 1=SPI via Arduino, 2=SPI via spidev (default: UART) + -R/-reset [rst] reset for STM8: 0=skip, 1=manual, 2=DTR line (RS232), 3=send 'Re5eT!' @ 115.2kBaud, 4=Arduino pin pin 8, 6=RTS line (RS232) (default: manual) + -i/-interface [line] communication interface: 0=UART, 1=SPI via Arduino (default: UART) -u/-uart-mode [mode] UART mode: 0=duplex, 1=1-wire, 2=2-wire reply, other=auto-detect (default: auto-detect) -p/-port [name] communication port (default: list available ports) -b/-baudrate [speed] communication baudrate in Baud (default: 115200) - -V/-no-verify don't verify code in flash after upload (default: verify) - -j/-jump-addr [address] jump address before exit of stm8gal, or -1 for skip (default: flash) - -w/-write-file [file [addr]] upload file from PC to uController. For binary file (*.bin) with address offset (as hex) - -W/-write-byte [addr value] change value at given address (as dec or hex) - -r/-read [start stop output] read memory range (as hex) and save to file or print (output=console) - -e/-erase-sector [addr] erase flash sector containing given address. Use carefully! + -V/-verify verify flash content after upload: 0=skip, 1=CRC32 checksum, 2=read back (default: read back) + -j/-jump-addr [address] jump to address (as dec or hex) before exit of stm8gal, or -1 for skip (default: flash) + -w/-write-file [file [addr]] upload file from PC to uController. For binary file (*.bin) with address offset (as dec or hex) + -W/-write-byte [addr value] change value at given address (both as dec or hex) + -r/-read [start stop output] read memory range (as dec or hex) and save to file or print (output=console) + -e/-erase-sector [addr] erase flash sector containing given address (as dec or hex). Use carefully! -E/-erase-full mass erase complete flash. Use carefully! -Notes: +Notes: - reset via RasPi GPIO (`-R 5`) is only available on a Raspberry Pi and if _stm8gal_ was built with _wiringPi_ support (see [Building the Software](#building-the-software) - interface spidev (`-i 2`) is only available if _stm8gal_ was built with _spidev_ support (see [Building the Software](#building-the-software) - SPI via Arduino (`-i 1`) and reset via Arduino GPIO (`-R 4`) requires an additional Arduino programmed as [SPI bridge](https://github.com/gicking/Arduino_SPI_bridge) + - flash write/erase routines in RAM use addresses 0x00-0x1FF. Don't use this range for custom RAM code + - CRC32 checksum routine in RAM use addresses 0x200-0x0x35C. In case you use verify via CRC32 ('-V 1') don't use this range for custom RAM code *** @@ -140,22 +142,22 @@ intermediate exports only contain the memory content up to that point in time. *** -## Examples +## Examples ### Program custom [_muBoard_](https://frosch.piandmore.de/en/pam9/call/public-media/event_media/160611_Vortrag_Interpreter.pdf) via USB with manual reset 1. supply the [_muBoard_](http://www.cream-tea.de/presentations/160305_PiAndMore.pdf) via USB from the PC, here a RasPi. This also establishes the USB<->UART connection via an on-board [FT232](http://www.ftdichip.com/Products/ICs/FT232R.htm) adapter - + 2. note name of serial port, e.g. COM10 (Win) or /dev/ttyUSB0 (Linux). Hint: launching _stm8gal_ without argument lists the available ports -

+

3. software usage: -`stm8gal -p /dev/ttyUSB0 -w main.ihx` (Linux) - + -`stm8gal -p COM10 -w main.ihx` (Windows) *** @@ -163,23 +165,23 @@ intermediate exports only contain the memory content up to that point in time. ### Program [STM8S Discovery Board](http://www.st.com/en/evaluation-tools/stm8s-discovery.html) via UART pins from [Raspberry Pi](https://www.raspberrypi.org/) with reset via GPIO 1. connect the [STM8S Discovery Board](http://www.st.com/en/evaluation-tools/stm8s-discovery.html) to the [Raspberry Pi](https://www.raspberrypi.org/) in the same sequence as shown below. Notes: - - configure STM8S Discovery for 3.3V supply to avoid damage to the Raspberry Pi 3.3V GPIOs + - configure STM8S Discovery for 3.3V supply to avoid damage to the Raspberry Pi 3.3V GPIOs - for direct GPIO and UART access [add user to groups 'gpio' and 'dialout'](#raspberry-pi) - in addition, reset via header pin requires [wiringPi installed with user access](#raspberry-pi) - for pinning of the Raspberry Pi GPIO header type "[gpio readall](http://wiringpi.com/the-gpio-utility/)" on the command line, or see e.g. [here](https://pinout.xyz) - -

+ +

-

+

2. software usage: -`stm8gal -p /dev/ttyAMA0 -w main.ihx -R 5` (RasPi 1+2) - + -`stm8gal -p /dev/serial0 -w main.ihx -R 5` (RasPi 3) *** @@ -187,16 +189,16 @@ intermediate exports only contain the memory content up to that point in time. ### Program [STM8S Discovery Board](http://www.st.com/en/evaluation-tools/stm8s-discovery.html) via SPI pins from [Raspberry Pi](https://www.raspberrypi.org/) using spidev with reset via GPIO 1. connect the [STM8S Discovery Board](http://www.st.com/en/evaluation-tools/stm8s-discovery.html) to the [Raspberry Pi](https://www.raspberrypi.org/) in the same sequence as shown below. Notes: - - configure STM8S Discovery for 3.3V supply to avoid damage to the Raspberry Pi 3.3V GPIOs + - configure STM8S Discovery for 3.3V supply to avoid damage to the Raspberry Pi 3.3V GPIOs - for direct GPIO and SPI access [add user to groups 'gpio' and 'spi'](#raspberry-pi) - in addition, reset via header pin requires [wiringPi installed with user access](#raspberry-pi) - for pinning of the Raspberry Pi GPIO header type "[gpio readall](http://wiringpi.com/the-gpio-utility/)" on the command line, or see e.g. [here](https://pinout.xyz) - -

+ +

-

+

@@ -216,13 +218,13 @@ intermediate exports only contain the memory content up to that point in time. 4. Note name of serial port, e.g. COM10 (Win) or /dev/ttyUSB0 (Linux). Hint: launching _stm8gal_ without argument lists the available ports -5. connect the [STM8S Discovery Board](http://www.st.com/en/evaluation-tools/stm8s-discovery.html) to the Arduino in the same sequence as shown below. - -

+5. connect the [STM8S Discovery Board](http://www.st.com/en/evaluation-tools/stm8s-discovery.html) to the Arduino in the same sequence as shown below. + +

-

+

@@ -235,19 +237,19 @@ intermediate exports only contain the memory content up to that point in time. ### Memory dump [_muBoard_](https://frosch.piandmore.de/en/pam9/call/public-media/event_media/160611_Vortrag_Interpreter.pdf) via USB with manual reset 1. supply the [_muBoard_](http://www.cream-tea.de/presentations/160305_PiAndMore.pdf) via USB from the PC, here a RasPi. This also establishes the USB<->UART connection via an on-board [FT232](http://www.ftdichip.com/Products/ICs/FT232R.htm) adapter - + 2. note name of serial port, e.g. COM10 (Win) or /dev/ttyUSB0 (Linux). Hint: launching _stm8gal_ without argument lists the available ports -

+

3. software usage: -`stm8gal -p /dev/ttyUSB0 -r 0x8000 0x8FFF dump.s19` (Linux, Motorola S19 format) - + -`stm8gal -p /dev/ttyUSB0 -r 0x8000 0x8FFF dump.txt` (Linux, table format) - + -`stm8gal -p COM10 -r 0x8000 0x8FFF dump.s19` (Windows, Motorola S19 format) *** @@ -256,14 +258,14 @@ intermediate exports only contain the memory content up to that point in time. - bootloader programming via UART, SPI or CAN is supported by most STM8 devices. However, not all devices support each interface. A full description of the bootloaders can be found in [UM0560](http://www.st.com/st-web-ui/static/active/en/resource/technical/document/user_manual/CD00201192.pdf), including an overview of STM8 devices with respective bootloader mode. For _stm8gal_ >=v1.2.0 the UART mode can optionally be auto-detected: -

+

- To program via _stm8gal_, communication between PC and STM8 must be possible. On the STM8 side this is via [UART](https://en.wikipedia.org/wiki/UART) or [SPI](https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus), on the PC side this is generally via USB or RS232. - On some boards, e.g. the [_muBoard_](http://www.cream-tea.de/presentations/160305_PiAndMore.pdf), an USB<->UART bridge is already present. In this case, no additional hardware is required - + - However, e.g. the popular [STM8S Discovery](http://www.st.com/en/evaluation-tools/stm8s-discovery.html) and [STM8L Discovery](http://www.st.com/en/evaluation-tools/stm8l-discovery.html) boards connect to a standard PC via SWIM (=debug) interface. In this case a separate adapter is required to connect to the respective STM8 UART or SPI pins, e.g. [UM232R](https://www.ftdichip.com/Support/Documents/DataSheets/Modules/DS_UM232R.pdf). When connecting, make sure that the voltage levels of STM8 and the adapter are compatible. **Exposing a 3.3V device to 5V signals may damage the 3.3V device**. - Exception is the [Raspberry Pi](https://www.raspberrypi.org) or similar “embedded PCs“ with direct access to UART and SPI pins via the GPIO header. In this case make sure that the voltage levels of STM8 and embedded PC are compatible, e.g. for RasPi with 3.3V pins also supply the STM8 with Vdd=3.3V. As noted above, **never expose a 3.3V device to 5V signals**. @@ -277,12 +279,12 @@ intermediate exports only contain the memory content up to that point in time. - [stm8flash](https://github.com/vdudouyt/stm8flash) by Valentin Dudouyt to upload and run the STM8 program in subfolder './BSL_activate' - Notes - - - Virgin devices (i.e. flash completely erased) automatically have the bootloader enabled + + - Virgin devices (i.e. flash completely erased) automatically have the bootloader enabled - The BSL can be entered only within 1s after reset or power-on. Exception are virgin devices, which remain in bootloader mode indefinitely. -- The UART "reply" mode (see above) supports single-wire interfaces like LIN or ISO9141. It requires a "Rx echo" for each sent byte. Using the reply mode with dual wires therefore requires _stm8gal_ to echo each received byte individually, which results in low upload speeds. +- The UART "reply" mode (see above) supports single-wire interfaces like LIN or ISO9141. It requires a "Rx echo" for each sent byte. Using the reply mode with dual wires therefore requires _stm8gal_ to echo each received byte individually, which results in low upload speeds. - The STM32 uses a very similar bootloader protocol, so adapting the flasher tool for STM32 should be straightforward. However, I have no board available, but please feel free to go ahead... @@ -290,9 +292,9 @@ intermediate exports only contain the memory content up to that point in time. # Test Overview -_stm8gal_ has recently been tested only for the below STM8 devices and operating systems. Theoretically it should work for all STM8 devices with bootloader, especially since STM8AF, STLUX, STNRG and STM8SPLNB seem to be test variants of the STM8S, and STM8AL and STM8T seem to be test variants of the STM8L. However, this has not been tested, so if you use _stm8gal_ in another setup, any feedback is highly appreciated! +_stm8gal_ has recently been tested only for the below STM8 devices and operating systems. Theoretically it should work for all STM8 devices with bootloader, especially since STM8AF, STLUX, STNRG and STM8SPLNB seem to be test variants of the STM8S, and STM8AL and STM8T seem to be test variants of the STM8L. However, this has not been tested, so if you use _stm8gal_ in another setup, any feedback is highly appreciated! -

+

@@ -316,6 +318,18 @@ If you are aware of bugs, please drop me a note or start an [issue](https://gith # Revision History +v1.4.2 (2020-12-26) + - support re-synchronization w/o STM8 reset + - add option verify via CRC32 checksum (see https://github.com/gicking/stm8gal/issues/20) + - add parameter to verify option (-V/-verify). Is required due to new CRC32 check + +---------------- + +v1.4.1 (2020-12-13) + - minor bugfix + +---------------- + v1.4.0 (2020-04-09) - improved S19 export for >16bit addresses - added IHX export option @@ -366,7 +380,7 @@ v1.1.5 (2017-12-20) v1.1.4 (2017-12-14) - added SPI support via spidev (currently only POSIX) - add user-space access to RasPi GPIOs via wiringPi for automatic reset. Use header numbering scheme (="physical") - - removed verbose commandline option (-V). Always print verbose + - removed verbose commandline option (-V). Always print verbose - added listing of /dev/serial0 (new in Pi3, see https://raspberrypi.stackexchange.com/questions/45570/how-do-i-make-serial-work-on-the-raspberry-pi3) ---------------- @@ -395,4 +409,3 @@ v1.1.0 (2015-06-22): v1.0.0 (2014-12-21): - initial release by Georg Icking-Konert under the Apache License 2.0 - diff --git a/bootloader.c b/bootloader.c index d7e5f9f..bce28a2 100644 --- a/bootloader.c +++ b/bootloader.c @@ -5,9 +5,9 @@ \date 2014-03-14 \version 0.1 - \brief implementation of STM bootloader routines + \brief implementation of STM8 bootloader routines - implementation of of STM bootloader routines + implementation of STM8 bootloader routines */ @@ -925,7 +925,7 @@ uint8_t bsl_flashSectorErase(HANDLE ptrPort, uint8_t physInterface, uint8_t uart Tx[3] = (Tx[0] ^ Tx[1] ^ Tx[2]); lenRx = 1; */ - + // measure time for sector erase tStart = millis(); diff --git a/bootloader.h b/bootloader.h index 26b1508..a4bfce3 100644 --- a/bootloader.h +++ b/bootloader.h @@ -1,13 +1,13 @@ /** \file bootloader.h - + \author G. Icking-Konert \date 2014-03-14 \version 0.1 - - \brief declaration of STM bootloader routines - - declaration of of STM bootloader routines + + \brief declaration of STM8 bootloader routines + + declaration of STM8 bootloader routines */ // for including file only once @@ -29,7 +29,7 @@ // BSL command codes #define GET 0x00 //< gets version and commands supported by the BSL -#define READ 0x11 //< read up to 256 bytes of memory +#define READ 0x11 //< read up to 256 bytes of memory #define ERASE 0x43 //< erase flash program memory/data EEPROM sectors #define WRITE 0x31 //< write up to 128 bytes to RAM or flash #define GO 0x21 //< jump to a specified address e.g. flash diff --git a/main.c b/main.c index 13cbf0b..3680667 100644 --- a/main.c +++ b/main.c @@ -64,6 +64,7 @@ #include "spi_Arduino_comm.h" #include "bootloader.h" #include "hexfile.h" +#include "verify_CRC32.h" #include "version.h" @@ -107,7 +108,7 @@ int main(int argc, char ** argv) { int uartMode; // UART bootloader mode: 0=duplex, 1=1-wire, 2=2-wire reply, other=auto-detect int resetSTM8; // reset STM8: 0=skip, 1=manual, 2=DTR line (RS232), 3=send 'Re5eT!' @ 115.2kBaud, 4=Arduino pin 8, 5=Raspi pin 12, 6=RTS line (RS232) (default: manual) uint16_t *imageBuf; // global RAM image buffer (high byte != 0 indicates value is set) - bool verifyUpload; // verify memory after upload + int verifyUpload; // verify method after upload (0=skip, 1=CRC32, 2=read-out) uint64_t jumpAddr; // address to jump to before exit program bool printHelp; // flag for printing help page int paramHelp=-1; // parameter index to print help for @@ -132,7 +133,7 @@ int main(int argc, char ** argv) { baudrate = 115200; // default baudrate verbose = INFORM; // verbosity level medium resetSTM8 = 1; // manual reset of STM8 - verifyUpload = true; // verify memory content after upload + verifyUpload = 2; // read back memory after upload (0=skip, 1=CRC32, 2=read-out) jumpAddr = PFLASH_START; // by default jump to start of P-flash (see bootloader.h) @@ -276,10 +277,20 @@ int main(int argc, char ** argv) { } // baudrate - // no verify of memory content after upload - else if ((!strcmp(argv[i], "-V")) || (!strcmp(argv[i], "-no-verify"))) { - verifyUpload = false; - } // no-verify + // set verify method after upload + else if ((!strcmp(argv[i], "-V")) || (!strcmp(argv[i], "-verify"))) { + + // get memory verify method + if (i+1 2) verifyUpload = 2; + + } // verify method // jump adress before program termination (-1 or 0xFFFFFFFF == skip jump) @@ -405,7 +416,7 @@ int main(int argc, char ** argv) { printf(" -u/-uart-mode [mode] UART mode: 0=duplex, 1=1-wire, 2=2-wire reply, other=auto-detect (default: auto-detect)\n"); printf(" -p/-port [name] communication port (default: list available ports)\n"); printf(" -b/-baudrate [speed] communication baudrate in Baud (default: 115200)\n"); - printf(" -V/-no-verify don't verify code in flash after upload (default: verify)\n"); + printf(" -V/-verify verify flash content after upload: 0=skip, 1=CRC32 checksum, 2=read back (default: read back)\n"); printf(" -j/-jump-addr [address] jump to address (as dec or hex) before exit of %s, or -1 for skip (default: flash)\n", appname); printf(" -w/-write-file [file [addr]] upload file from PC to uController. For binary file (*.bin) with address offset (as dec or hex)\n"); printf(" -W/-write-byte [addr value] change value at given address (both as dec or hex)\n"); @@ -446,10 +457,10 @@ int main(int argc, char ** argv) { // read back after writing doesn't work for SPI (don't know why) #if defined(USE_SPIDEV) if ((physInterface == SPI_ARDUINO) || (physInterface == SPI_SPIDEV)) - verifyUpload = false; + verifyUpload = 0; #else if (physInterface == SPI_ARDUINO) - verifyUpload = false; + verifyUpload = 0; #endif // for background operation avoid prompt on exit @@ -932,9 +943,9 @@ int main(int argc, char ** argv) { } - // skip verify flag w/o parameter, is handled in 1st run - else if ((!strcmp(argv[i], "-V")) || (!strcmp(argv[i], "-no-verify"))) { - i += 0; // dummy + // skip verify method with 1 parameter, is handled in 1st run + else if ((!strcmp(argv[i], "-V")) || (!strcmp(argv[i], "-verify"))) { + i += 1; } @@ -994,8 +1005,14 @@ int main(int argc, char ** argv) { bsl_memWrite(ptrPort, physInterface, uartMode, imageBuf, addrStart, addrStop, verbose); // optionally verify upload - if (verifyUpload) + if (verifyUpload == 0) // skip verify + ; + else if (verifyUpload == 1) // compare CRC32 checksums + verify_crc32(ptrPort, physInterface, uartMode, imageBuf, addrStart, addrStop, verbose); + else if (verifyUpload == 2) // read back memory and compare bsl_memVerify(ptrPort, physInterface, uartMode, imageBuf, addrStart, addrStop, verbose); + else + Error("Unknown memory verify method %d", verifyUpload); // clear memory image again memset(imageBuf, 0, (LENIMAGEBUF + 1) * sizeof(*imageBuf)); @@ -1039,8 +1056,14 @@ int main(int argc, char ** argv) { bsl_memWrite(ptrPort, physInterface, uartMode, imageBuf, addrStart, addrStop, verbose); // optionally verify upload - if (verifyUpload) + if (verifyUpload == 0) // skip verify + ; + else if (verifyUpload == 1) // compare CRC32 checksums + bsl_memVerify(ptrPort, physInterface, uartMode, imageBuf, addrStart, addrStop, verbose); + else if (verifyUpload == 2) // read back memory and compare bsl_memVerify(ptrPort, physInterface, uartMode, imageBuf, addrStart, addrStop, verbose); + else + Error("Unknown memory verify method %d", verifyUpload); // clear memory image again memset(imageBuf, 0, (LENIMAGEBUF + 1) * sizeof(*imageBuf)); @@ -1160,7 +1183,7 @@ int main(int argc, char ** argv) { SLEEP(500); #endif - // jumpt to application + // jump to application bsl_jumpTo(ptrPort, physInterface, uartMode, jumpAddr, verbose); } // jump to STM8 address diff --git a/verify_CRC32.c b/verify_CRC32.c new file mode 100644 index 0000000..985da10 --- /dev/null +++ b/verify_CRC32.c @@ -0,0 +1,255 @@ +/** + \file verify_CRC32.c + + \author G. Icking-Konert + \date 2020-12-25 + \version 0.1 + + \brief implementation of verify via CRC32 routines + + implementation of routines to verify memory via comparing CRC32 checksums. +*/ + +// include files +#include +#include +#include +#include "main.h" +#include "hexfile.h" +#include "bootloader.h" +#include "misc.h" +#include "verify_CRC32.h" +#include "verify_CRC32_ihx.h" + + +uint8_t upload_crc32_code(HANDLE ptrPort, uint8_t physInterface, uint8_t uartMode) +{ + uint64_t addrStart, addrStop, numData; + + // allocate and clear temporary RAM buffer (>1MByte requires dynamic allocation) + uint16_t *imageBuf; // RAM image buffer (high byte != 0 indicates value is set) + if (!(imageBuf = malloc(LENIMAGEBUF * sizeof(*imageBuf)))) + Error("Cannot allocate image buffer, try reducing LENIMAGEBUF"); + + // clear image buffer + memset(imageBuf, 0, (LENIMAGEBUF + 1) * sizeof(*imageBuf)); + + // convert array containing ihx file to RAM image + convert_ihx((char*) bin_verify_CRC32_ihx, bin_verify_CRC32_ihx_len, imageBuf, MUTE); + + // get image size + get_image_size(imageBuf, 0, LENIMAGEBUF, &addrStart, &addrStop, &numData); + + // upload RAM routines to STM8 + bsl_memWrite(ptrPort, physInterface, uartMode, imageBuf, addrStart, addrStop, MUTE); + + // release temporary memory image + free(imageBuf); + + // avoid compiler warnings + return(0); + +} // upload_crc32_code() + + + +uint8_t upload_crc32_address(HANDLE ptrPort, uint8_t physInterface, uint8_t uartMode, uint64_t addrStart, uint64_t addrStop) +{ + uint64_t AddrStart, AddrStop, NumData; + + // allocate and clear temporary RAM buffer (>1MByte requires dynamic allocation) + uint16_t *imageBuf; // RAM image buffer (high byte != 0 indicates value is set) + if (!(imageBuf = malloc(LENIMAGEBUF * sizeof(*imageBuf)))) + Error("Cannot allocate image buffer, try reducing LENIMAGEBUF"); + + // clear image buffer + memset(imageBuf, 0, (LENIMAGEBUF + 1) * sizeof(*imageBuf)); + + // store start addresses for CRC32 at fixed RAM address (big endian = MSB first) + imageBuf[ADDR_START_CRC32] = ((uint16_t) (addrStart >> 24)) | 0xFF00; // start address, byte 3 + imageBuf[ADDR_START_CRC32+1] = ((uint16_t) (addrStart >> 16)) | 0xFF00; // start address, byte 2 + imageBuf[ADDR_START_CRC32+2] = ((uint16_t) (addrStart >> 8)) | 0xFF00; // start address, byte 1 + imageBuf[ADDR_START_CRC32+3] = ((uint16_t) (addrStart )) | 0xFF00; // start address, byte 0 + + // store last addresses for CRC32 at fixed RAM address (big endian = MSB first) + imageBuf[ADDR_STOP_CRC32] = ((uint16_t) (addrStop >> 24)) | 0xFF00; // stop address, byte 3 + imageBuf[ADDR_STOP_CRC32+1] = ((uint16_t) (addrStop >> 16)) | 0xFF00; // stop address, byte 2 + imageBuf[ADDR_STOP_CRC32+2] = ((uint16_t) (addrStop >> 8)) | 0xFF00; // stop address, byte 1 + imageBuf[ADDR_STOP_CRC32+3] = ((uint16_t) (addrStop )) | 0xFF00; // stop address, byte 0 + + // get image size + get_image_size(imageBuf, 0, LENIMAGEBUF, &AddrStart, &AddrStop, &NumData); + + // upload RAM routines to STM8 + bsl_memWrite(ptrPort, physInterface, uartMode, imageBuf, AddrStart, AddrStop, MUTE); + + // release temporary memory image + free(imageBuf); + + // avoid compiler warnings + return(0); + +} // upload_crc32_address() + + + +uint8_t read_crc32(HANDLE ptrPort, uint8_t physInterface, uint8_t uartMode, uint8_t *status, uint32_t *CRC32) +{ + // allocate and clear temporary RAM buffer (>1MByte requires dynamic allocation) + uint16_t *imageBuf; // RAM image buffer (high byte != 0 indicates value is set) + if (!(imageBuf = malloc(LENIMAGEBUF * sizeof(*imageBuf)))) + Error("Cannot allocate image buffer, try reducing LENIMAGEBUF"); + + // clear image buffer + memset(imageBuf, 0, (LENIMAGEBUF + 1) * sizeof(*imageBuf)); + + // read status and CRC result + bsl_memRead(ptrPort, physInterface, uartMode, STATUS_CRC32, RESULT_CRC32+3, imageBuf, MUTE); + + // get status and CRC result from image buffer + *status = (uint8_t) (imageBuf[STATUS_CRC32]); + *CRC32 = ((uint32_t) (imageBuf[RESULT_CRC32] & 0x00FF)) << 24; + *CRC32 += ((uint32_t) (imageBuf[RESULT_CRC32+1] & 0x00FF)) << 16; + *CRC32 += ((uint32_t) (imageBuf[RESULT_CRC32+2] & 0x00FF)) << 8; + *CRC32 += ((uint32_t) (imageBuf[RESULT_CRC32+3] & 0x00FF)); + + // release temporary memory image + free(imageBuf); + + // avoid compiler warnings + return(0); + +} // read_crc32() + + +// from https://www.mikrocontroller.net/attachment/61520/crc32_v1.c +uint32_t calculate_crc32(uint16_t *imageBuf, uint64_t addrStart, uint64_t addrStop) +{ + uint32_t crc32; + + // initialize CRC32 checksum + crc32 = 0xffffffff; + + for(uint64_t addr=addrStart; addr<=addrStop; addr++) + { + uint8_t value = (uint8_t) (imageBuf[addr] & 0x00FF); + for (int i=0; i<8; ++i) + { + if ((crc32 & 1) != (value & 1)) + crc32 = (crc32 >> 1) ^ CRC32_POLYNOM; + else + crc32 >>= 1; + value >>= 1; + } + } + + // finalize CRC32 checksum + crc32 ^= 0xffffffff; + + // return result + return(crc32); + +} // calculate_crc32() + + + +/// compare CRC32 over microcontroller memory vs. CRC32 over RAM image +uint8_t verify_crc32(HANDLE ptrPort, uint8_t physInterface, uint8_t uartMode, uint16_t *imageBuf, uint64_t addrStart, uint64_t addrStop, uint8_t verbose) +{ + uint8_t status; + uint32_t crc32_uC, crc32_PC; + //uint64_t tStart, tStop; // measure time [ms] + + // print collective message + if ((verbose == SILENT) || (verbose == INFORM)) + printf(" CRC32 check ... "); + fflush(stdout); + + // upload CRC32 RAM routine + upload_crc32_code(ptrPort, physInterface, uartMode); + + // get start time [ms] + //tStart = millis(); + + // loop over image and check all consecutive data blocks. Skip undefined data + uint64_t addr = addrStart; + while (addr <= addrStop) { + + // find next data byte in image (=start address for next read) + while (((imageBuf[addr] & 0xFF00) == 0) && (addr <= addrStop)) + addr++; + + // end address reached -> done + if (addr > addrStop) + break; + + // set length of next check + uint64_t lenCheck = 1; + while (((addr+lenCheck) <= addrStop) && (imageBuf[addr+lenCheck] & 0xFF00)) { + lenCheck++; + } + + // print verbose message for each block + if (verbose == CHATTY) + printf(" CRC32 check 0x%" PRIx64 " to 0x%" PRIx64 " ... ", addr, addr+lenCheck); + fflush(stdout); + + // upload address range for CRC32 calculation + upload_crc32_address(ptrPort, physInterface, uartMode, addr, addr+lenCheck-1); + + // jump to CRC32 routine in RAM + bsl_jumpTo(ptrPort, physInterface, uartMode, START_CODE_CRC32, MUTE); + + // wait before re-synchronizing (time checked empirically) + SLEEP(4500*lenCheck/(128*1024)); + + // re-synchronize after re-start of ROM-BSL + bsl_sync(ptrPort, physInterface, MUTE); + + // for 2-wire reply mode reply NACK echo + if (uartMode == 2) + { + char Tx = NACK; + send_port(ptrPort, 0, 1, &Tx); + } + + // read out CRC32 status and checksum + read_crc32(ptrPort, physInterface, uartMode, &status, &crc32_uC); + if (status != 0) + Error("in 'verify_crc32()': CRC32 status from uC failed (expect 0, received %d)", status); + //printf("\nuC status = %d, CRC = 0x%08x\n", (int) status, crc32_uC); + + // calculate CRC32 checksum over corresponding range in RAM image + crc32_PC = calculate_crc32(imageBuf, addr, addr+lenCheck-1); + //printf("\nPC CRC = 0x%08x\n", crc32_PC); + + // check if CRC32 checksums match + if (crc32_uC != crc32_PC) + Error("in 'verify_crc32()': CRC32 checksum mismatch (0x%08X vs. 0x%08X)", crc32_uC, crc32_PC); + + // go to next potential block + addr += lenCheck; + + // print verbose message + if (verbose == CHATTY) + printf("passed (0x%08X)\n", crc32_uC); + fflush(stdout); + + } // loop over image + + // get end time [ms] + //tStop = millis(); + //printf("\ntime (%1.1fs)\n", (float) (tStop - tStart)*0.001); + + // print collective message + if ((verbose == SILENT) || (verbose == INFORM)) + printf("passed\n"); + fflush(stdout); + + // avoid compiler warnings + return(0); + +} // verify_crc32() + + +// end of file diff --git a/verify_CRC32.h b/verify_CRC32.h new file mode 100644 index 0000000..7a97d2c --- /dev/null +++ b/verify_CRC32.h @@ -0,0 +1,49 @@ +/** + \file bootloader.h + + \author G. Icking-Konert + \date 2020-12-25 + \version 0.1 + + \brief declaration of verify via CRC32 routines + + declaration of routines to verify memory via comparing CRC32 checksums. +*/ + +// for including file only once +#ifndef _VERIFY32_H_ +#define _VERIFY32_H_ + +// include files +#include +#include "serial_comm.h" + +// RAM routine parameters +#define START_CODE_CRC32 0x200 // start address of CRC32 routine in RAM +#define ADDR_START_CRC32 0x350 // location of CRC32 start address (@ 0x350 - 0x353) +#define ADDR_STOP_CRC32 0x354 // location of CRC32 stop address (@ 0x354 - 0x357) +#define STATUS_CRC32 0x358 // location of CRC32 status (0=ok, 1=error) (@ 0x358) +#define RESULT_CRC32 0x359 // location of calculated CRC32 checksum (@ 0x359 - 0x35C) + +// CRC32 polynom (for little-endian). TO DO: version for big-endian +#define CRC32_POLYNOM 0xEDB88320 + + +/// upload RAM routine to calculate CRC32 checksum +uint8_t upload_crc32_code(HANDLE ptrPort, uint8_t physInterface, uint8_t uartMode); + +/// upload address range to calculate CRC32 over +uint8_t upload_crc32_address(HANDLE ptrPort, uint8_t physInterface, uint8_t uartMode, uint64_t addrStart, uint64_t addrStop); + +/// read out CRC2 status and result from microcontroller +uint8_t read_crc32(HANDLE ptrPort, uint8_t physInterface, uint8_t uartMode, uint8_t *status, uint32_t *CRC32); + +/// calculate CRC2 checksum over RAM image +uint32_t calculate_crc32(uint16_t *imageBuf, uint64_t addrStart, uint64_t addrStop); + +/// compare CRC32 over microcontroller memory vs. CRC32 over RAM image +uint8_t verify_crc32(HANDLE ptrPort, uint8_t physInterface, uint8_t uartMode, uint16_t *imageBuf, uint64_t addrStart, uint64_t addrStop, uint8_t verbose); + +#endif // _VERIFY32_H_ + +// end of file diff --git a/verify_CRC32/CRC_test.txt b/verify_CRC32/CRC_test.txt new file mode 100644 index 0000000..4ed4607 --- /dev/null +++ b/verify_CRC32/CRC_test.txt @@ -0,0 +1,16 @@ +# CRC test data +0x8000 0x66 +0x8001 0x6f +0x8002 0x6f +# +# addr_start = 0x8000 +0x350 0x00 +0x351 0x00 +0x352 0x80 +0x353 0x00 +# +# addr_stop = 0x8008 +0x354 0x00 +0x355 0x00 +0x356 0x80 +0x357 0x02 diff --git a/verify_CRC32/Makefile b/verify_CRC32/Makefile new file mode 100644 index 0000000..3701cda --- /dev/null +++ b/verify_CRC32/Makefile @@ -0,0 +1,53 @@ +CC = sdcc +CFLAGS = -mstm8 --opt-code-size --max-allocs-per-node 25000 +AS = sdasstm8 +ASFLAGS = -o +LD = sdldstm8 +LDFLAGS = -n +SOURCES = \ + verify_CRC32.c \ + verify_CRC32.h +OBJDIR = obj +OBJECTS = $(patsubst %,$(OBJDIR)/%.rel,$(basename $(filter %.c %.s,$(SOURCES)))) +# TODO: use $(wildcard ...) to auto-populate this list from link dir contents? +LINKTARGETS = \ + ./linker.lk +BINDIR = bin +BINARY = $(BINDIR)/verify_CRC32.ihx +HEADER = $(BINDIR)/verify_CRC32_ihx.h +ifeq ($(OS),Windows_NT) + RM = cmd.exe /C del /Q + MKDIRFLAGS = +else + RM = rm -fr + MKDIRFLAGS = -p +endif + +.PHONY: all clean + +all: $(BINARY) $(HEADER) + +$(BINARY): $(LINKTARGETS) $(OBJECTS) $(BINDIR) + $(LD) $(LDFLAGS) -i $@ -f $(LINKTARGETS) + +$(HEADER): $(BINARY) + xxd -i $(BINARY) > $(HEADER) + cp $(HEADER) ../RAM_Routines + +$(OBJECTS): $(SOURCES) $(OBJDIR) + +$(OBJDIR)/%.rel: %.c + $(CC) $(CFLAGS) -o $@ -c $(basename $( 0x27FFF)) + ldw x, _addr_stop+2 + cpw x, _addr_start+2 + ld a, _addr_stop+1 + sbc a, _addr_start+1 + ld a, _addr_stop+0 + sbc a, _addr_start+0 + jrc 00104$ + ldw x, #0x7fff + cpw x, _addr_stop+2 + ld a, #0x02 + sbc a, _addr_stop+1 + clr a + sbc a, _addr_stop+0 + jrnc 00105$ +00104$: +; verify_CRC32.c: 15: crc32 = 0x00000000; + clrw x + ldw _crc32+2, x + ldw _crc32+0, x +; verify_CRC32.c: 16: status = ERROR; + mov _status+0, #0x01 + jp 00106$ +00105$: +; verify_CRC32.c: 23: uint8_t oldCLK = CLK_CKDIVR; + ld a, 0x50c6 + ld (0x01, sp), a +; verify_CRC32.c: 24: CLK_CKDIVR = 0x00; + mov 0x50c6+0, #0x00 +; verify_CRC32.c: 27: crc32 = crc32_init(); + ldw x, #0xffff + ldw _crc32+2, x + ldw x, #0xffff + ldw _crc32+0, x +; verify_CRC32.c: 30: while (addr_start<=addr_stop) +00101$: + ldw x, _addr_stop+2 + cpw x, _addr_start+2 + ld a, _addr_stop+1 + sbc a, _addr_start+1 + ld a, _addr_stop+0 + sbc a, _addr_start+0 + jrc 00103$ +; verify_CRC32.c: 39: __endasm; + push a + ldf a,[_addr_start+1].e + ld _status, a + pop a +; verify_CRC32.c: 42: crc32 = crc32_update(crc32, status); + push _status+0 + ldw x, _crc32+2 + pushw x + ldw x, _crc32+0 + pushw x + call _crc32_update + addw sp, #5 + ldw _crc32+2, x + ldw _crc32+0, y +; verify_CRC32.c: 45: addr_start++; + ldw x, _addr_start+2 + addw x, #0x0001 + ldw y, _addr_start+0 + jrnc 00128$ + incw y +00128$: + ldw _addr_start+2, x + ldw _addr_start+0, y +; verify_CRC32.c: 48: SERVICE_IWDG; + mov 0x50e0+0, #0xaa +; verify_CRC32.c: 49: SERVICE_WWDG; + mov 0x50d1+0, #0x7f + jra 00101$ +00103$: +; verify_CRC32.c: 54: crc32 = crc32_final(crc32); + ld a, _crc32+3 + cpl a + ld xl, a + ld a, _crc32+2 + cpl a + ld xh, a + ld a, _crc32+1 + cpl a + ld yl, a + ld a, _crc32+0 + cpl a + ld yh, a + ldw _crc32+2, x + ldw _crc32+0, y +; verify_CRC32.c: 57: status = SUCCESS; + clr _status+0 +; verify_CRC32.c: 60: CLK_CKDIVR = oldCLK; + ldw x, #0x50c6 + ld a, (0x01, sp) + ld (x), a +00106$: +; verify_CRC32.c: 65: TIM2_EGR = 0x01; // refresh TIM2 prescaler shadow registers to 1 + mov 0x5304+0, #0x01 +; verify_CRC32.c: 66: TIM2_SR1; + ld a, 0x5302 +; verify_CRC32.c: 67: TIM2_SR1 = 0x00; + mov 0x5302+0, #0x00 +; verify_CRC32.c: 68: TIM3_EGR = 0x01; // refresh TIM3 prescaler shadow registers to 1 + mov 0x5324+0, #0x01 +; verify_CRC32.c: 69: TIM3_SR1; + ld a, 0x5322 +; verify_CRC32.c: 70: TIM3_SR1 = 0x00; + mov 0x5322+0, #0x00 +; verify_CRC32.c: 71: BL_timeout = 0x00; // no ROM-BL timeout + clr _BL_timeout+0 +; verify_CRC32.c: 74: __asm__("jp 0x602E"); // jump back to ROM-BL after checking ROP + jp 0x602E +; verify_CRC32.c: 76: } // verify() + pop a + ret +; verify_CRC32.c: 84: uint32_t crc32_update(uint32_t crc, uint8_t data) __naked { +; ----------------------------------------- +; function crc32_update +; ----------------------------------------- +_crc32_update: +; naked function: no prologue. +; verify_CRC32.c: 156: __endasm; +; XOR the LSB of the CRC with data byte, and put it back in the CRC. + ld a, (3 +4, sp) + xor a, (3 +3, sp) + ld (3 +3, sp), a +; Load CRC variable from stack into X & Y regs for further work. + ldw x, (3 +2, sp) + ldw y, (3 +0, sp) + .macro crc32_update_shift_xor skip_lbl +; Shift CRC value right by one bit. + srlw y + rrcw x +; Jump if least-significant bit of CRC is now zero. + jrnc skip_lbl +; XOR the CRC value with the polynomial value. + rrwa x + xor a, #0x20 + rrwa x + xor a, #0x83 + rrwa x + rrwa y + xor a, #0xB8 + rrwa y + xor a, #0xED + rrwa y + skip_lbl: + .endm +; Initialise counter to loop 8 times, once for each bit of data byte. + ld a, #8 + 0001$: + crc32_update_shift_xor 0002$ +; Decrement counter and loop around if it is not zero. + dec a + jrne 0001$ +; The X and Y registers now contain updated CRC value, so leave them +; there as function return value. + ret +; verify_CRC32.c: 157: } + .area CODE + .area CONST + .area INITIALIZER + .area CABS (ABS) diff --git a/verify_CRC32/verify_CRC32.c b/verify_CRC32/verify_CRC32.c new file mode 100644 index 0000000..e9bc21f --- /dev/null +++ b/verify_CRC32/verify_CRC32.c @@ -0,0 +1,157 @@ +#pragma codeseg VERIFY_SEG +#pragma callee_saves erase + +#include "verify_CRC32.h" + + +void verify_CRC32(void) +{ + uint8_t tmp=0; + + // parameter error + if ((addr_stop < addr_start) || (addr_stop > 0x27FFF)) + { + // set return status + crc32 = 0x00000000; + status = ERROR; + } + + // calculate checksum over memory content + else + { + // switch to 16MHz, store old setting + uint8_t oldCLK = CLK_CKDIVR; + CLK_CKDIVR = 0x00; + + // initialize CRC32 checksum + crc32 = crc32_init(); + + // calculate CRC32 checksum + while (addr_start<=addr_stop) + { + // read from memory. Use inline assembler due to lack of far pointers in SDCC + // store data in variable "status" + __asm + push a + ldf a,[_addr_start+1].e + ld _status, a + pop a + __endasm; + + // update CRC32 checksum + crc32 = crc32_update(crc32, status); + + // increment address + addr_start++; + + // service watchdogs + SERVICE_IWDG; + SERVICE_WWDG; + + } // loop over memory + + // finalize CRC32 checksum + crc32 = crc32_final(crc32); + + // set return status + status = SUCCESS; + + // restore old clock setting; + CLK_CKDIVR = oldCLK; + + } // if calculate checksum + + // return to bootloader (see UM0560, appendix B) + TIM2_EGR = 0x01; // refresh TIM2 prescaler shadow registers to 1 + TIM2_SR1; + TIM2_SR1 = 0x00; + TIM3_EGR = 0x01; // refresh TIM3 prescaler shadow registers to 1 + TIM3_SR1; + TIM3_SR1 = 0x00; + BL_timeout = 0x00; // no ROM-BL timeout + //__asm__("jp 0x6000"); // jump back to start of ROM-BL + //__asm__("jp 0x601E"); // jump back to ROM-BL after checking BL activation + __asm__("jp 0x602E"); // jump back to ROM-BL after checking ROP + +} // verify() + + +// Copied from https://github.com/basilhussain/stm8-crc +// CRC32 (aka GZIP, PKZIP, PNG, ZMODEM) +// Polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1 (0xEDB88320, reversed) +// Initial value: 0xFFFFFFFF +// XOR out: 0xFFFFFFFF +uint32_t crc32_update(uint32_t crc, uint8_t data) __naked { + + // Avoid compiler warnings for unreferenced args. + (void)crc; + (void)data; + + // For return value/arg: 0xAABBCCDD + // x = 0xCCDD (xh = 0xCC, xl = 0xDD) + // y = 0xAABB (yh = 0xAA, yl = 0xBB) + + __asm + ; XOR the LSB of the CRC with data byte, and put it back in the CRC. + ld a, (ASM_ARGS_SP_OFFSET+4, sp) + xor a, (ASM_ARGS_SP_OFFSET+3, sp) + ld (ASM_ARGS_SP_OFFSET+3, sp), a + + ; Load CRC variable from stack into X & Y regs for further work. + ldw x, (ASM_ARGS_SP_OFFSET+2, sp) + ldw y, (ASM_ARGS_SP_OFFSET+0, sp) + + .macro crc32_update_shift_xor skip_lbl + ; Shift CRC value right by one bit. + srlw y + rrcw x + + ; Jump if least-significant bit of CRC is now zero. + jrnc skip_lbl + + ; XOR the CRC value with the polynomial value. + rrwa x + xor a, #0x20 + rrwa x + xor a, #0x83 + rrwa x + rrwa y + xor a, #0xB8 + rrwa y + xor a, #0xED + rrwa y + + skip_lbl: + .endm + +#ifdef ASM_UNROLL_LOOP + + crc32_update_shift_xor 0001$ + crc32_update_shift_xor 0002$ + crc32_update_shift_xor 0003$ + crc32_update_shift_xor 0004$ + crc32_update_shift_xor 0005$ + crc32_update_shift_xor 0006$ + crc32_update_shift_xor 0007$ + crc32_update_shift_xor 0008$ + +#else + + ; Initialise counter to loop 8 times, once for each bit of data byte. + ld a, #8 + + 0001$: + + crc32_update_shift_xor 0002$ + + ; Decrement counter and loop around if it is not zero. + dec a + jrne 0001$ + +#endif + + ; The X and Y registers now contain updated CRC value, so leave them + ; there as function return value. + ASM_RETURN + __endasm; +} diff --git a/verify_CRC32/verify_CRC32.h b/verify_CRC32/verify_CRC32.h new file mode 100644 index 0000000..074d94f --- /dev/null +++ b/verify_CRC32/verify_CRC32.h @@ -0,0 +1,65 @@ +#include +#include +#include +#include + +// definition of peripheral register +#define _SFR(mem_addr) (*(volatile uint8_t *)(mem_addr)) + +// CLK prescaler +#define CLK_CKDIVR _SFR(0x50c6) + +// IWDG watchdog +#define IWDG_KR _SFR(0x50e0) +#define SERVICE_IWDG IWDG_KR = 0xAA + +// WWDG watchdog +#define WWDG_CR _SFR(0x50d1) +#define SERVICE_WWDG WWDG_CR = 0x7F + +// TIM2 (must be cleared prior to return to ROM-BL) +#define TIM2_SR1 _SFR(0x5302) +#define TIM2_EGR _SFR(0x5304) + +// TIM3 (must be cleared prior to return to ROM-BL) +#define TIM3_SR1 _SFR(0x5322) +#define TIM3_EGR _SFR(0x5324) + +// return value (stored in global variable "status") +#define SUCCESS 0 +#define ERROR 1 + + +#ifdef __SDCC_MODEL_LARGE + #define ASM_ARGS_SP_OFFSET 4 + #define ASM_RETURN retf +#else + #define ASM_ARGS_SP_OFFSET 3 + #define ASM_RETURN ret +#endif + + +// Initial value for the CRC32 implementation. +#define CRC32_INIT ((uint32_t)0xFFFFFFFF) + +// Function-like macro to return the initial value. +#define crc32_init() CRC32_INIT + +// Value used to finalise the CRC32, being XOR-ed with the CRC. +#define CRC32_XOROUT ((uint32_t)0xFFFFFFFF) + +// Function-like macro to do the final XOR of the CRC value. +#define crc32_final(c) ((c) ^ CRC32_XOROUT) + +// Update of CRC32 value +uint32_t crc32_update(uint32_t crc, uint8_t data); + + +// Parameters passed from ROM-BL to RAM-verify and results passed back. +// Locations are specified at link time according to compatibility with ROM +// bootloader version. See *.lk command files. +extern uint32_t addr_start; // first address for checksum (@ 0x350 - 0x353) +extern uint32_t addr_stop; // last address for checksum (@ 0x354 - 0x357) +extern uint8_t status; // return status (0=ok, 1=error) (@ 0x358) +extern uint32_t crc32; // calculated CRC32 checksum (@ 0x359 - 0x35C) +extern uint8_t BL_timeout; // ROM-BL timeout (0=no timeout; 1=1s timeout) diff --git a/version.h b/version.h index d8f069a..724ebdf 100644 --- a/version.h +++ b/version.h @@ -19,7 +19,7 @@ #define _SW_VERSION_H_ /// 16b SW version identifier -#define VERSION ((1<<14) | (4<<6) | (1<<1) | 1) // -> v1.4.1 +#define VERSION ((1<<14) | (4<<6) | (2<<1) | 1) // -> v1.4.2 #endif // _SW_VERSION_H_ @@ -29,9 +29,15 @@ Revision History ---------------- -v1.4.0 (2020-04-09) - - improved S19 export for >16bit addresses - - added IHX export option +v1.4.2 (2020-12-26) + - support re-synchronization w/o STM8 reset + - add option verify via CRC32 checksum (see https://github.com/gicking/stm8gal/issues/20) + - add parameter to verify option (-V/-verify). Is required due to new CRC32 check + +---------------- + +v1.4.1 (2020-12-13) + - minor bugfix ----------------