Let's suppose that you have written your code, and written it to to memory of the chip, and you now have a chip you can power off and restart and it comes up and does something useful for you in your prototype circuit. Well, you basically have created a binary that lives in memory on the chip. If you just read a copy off, you can write it to another chip and you're on your way to production automation.
I bootstrapped this whole process by first writing the mecrisp binary to the chip. I used st-flash as such:
st-flash erase st-flash write ~/work/projects/mecrisp/mecrisp-stellaris-stm32g031f4.bin 0x8000000 st-flash reset
You must remember to erase the chip first with some utilities, so I always do it just in case the write command does not. Once reset, the chip is running forth. You can now use e4thcom or whatever your preference is to connect to it via serial and begin programming. Once you have it programmed, you can read off a binary to flash to other chips.
st-flash read ~/work/projects/mecrisp/adc-v.bin 0x8000000 16K st-flash reset
Now I have a binary image of a programmed forth instance that comes up and measures my voltage at the ADC. I can program other micros to do the same thing. I can move my programmer, stllinkv2 or whatever you have, to another micro, and now I can flash that new one, and it will be a clone of all the working code so far.
st-flash write ~/work/projects/mecrisp/adc-v.bin 0x8000000
This is about where some things started to go awry for me. Option Bytes. I wanted to read the option bytes and check to see what some of the default settings were compared to what the datasheet says they should be. I could not get st-flash to spit out the right stuff. Furthermore, I wanted to program/read/check more than one chip at a time. The contraption we have built actually has two micros on it that do different things. I could not get st-flash to correctly index more than one st-linkv2 consistently across my various build/dev/prog environments, a linux pc, a raspberry pi 3, and a pi 4, etc. But here are the ways you would do this in theory.
Option Byte st-flash --area=optcr1 read # red echo "flashing red" st-flash erase --serial 55FF66064887575412270787 adc-a.bin 0x8000000 st-flash write --serial 55FF66064887575412270787 adc-a.bin 0x8000000 # ./st-flash reset # gold echo "flashing gold" st-flash erase --serial 151115002C135437334D4E00 adc-v.bin 0x8000000 st-flash write --serial 151115002C135437334D4E00 adc-v.bin 0x8000000 # ./st-flash reset
Enter openocd. It's what everybody's using, but in my laziness, hubris, and impatience, I had previously failed to muster the required activation energy to hurdle the learning curve. Then I stumbled across this in a search: OpenOCD for STM32G0 and STM32G4
Next thing you know, I started reading the openocd user's guide. And it has been very much the best solution for a number of tasks. There's a bit of a learning curve, but I assure you it is worth it. Here's what I ended up with, maybe it will save you some time. First my first config file for openocd:
source [find /usr/local/share/openocd/scripts/interface/stlink.cfg] source [find /usr/local/share/openocd/scripts/target/stm32g0x.cfg] gdb_memory_map enable gdb_flash_program enable init reset_config trst_and_srst jtag configure stm32g0x.jrc -event setup "jtag tapenable stm32g0x.cpu" jtag tapisenabled stm32g0x.cpu dap create CPU -chain-position stm32g0x.cpu
Next, the tailored version, one for each programmer, here's one: "openocd-1.cfg". Some of the items are commented out. And I'm still not exactly 100% sure if all these lines do what I want/think or if they are all necessary. But it's working, so there's that.
source [find /usr/local/share/openocd/scripts/interface/stlink.cfg] source [find /usr/local/share/openocd/scripts/target/stm32g0x.cfg] gdb_memory_map enable gdb_flash_program enable hla_serial "\x55\x3f\x66\x06\x48\x3f\x57\x54\x12\x27\x07\x3f" gdb_port disabled tcl_port disabled telnet_port disabled #gdb_port 3333 #tcl_port 6666 #telnet_port 4444 init #reset_config trst_and_srst jtag configure stm32g0x.jrc -event setup "jtag tapenable stm32g0x.cpu" dap create CPU -chain-position stm32g0x.cpu
I did still use st-info to find the serial numbers for my st-linkv2 programmers.
et:bin$ ./st-info --probe Found 2 stlink programmers serial: 553f6606483f57541227073f hla-serial: "\x55\x3f\x66\x06\x48\x3f\x57\x54\x12\x27\x07\x3f" flash: 16384 (pagesize: 2048) sram: 8192 chipid: 0x0466 descr: G030/G031/G041 serial: 151115002c135437334d4e00 hla-serial: "\x15\x11\x15\x00\x2c\x13\x54\x37\x33\x4d\x4e\x00" flash: 16384 (pagesize: 2048) sram: 8192 chipid: 0x0466 descr: G030/G031/G041
By using a 2nd config file with a different hla_serial (and different port numbers), I can directly choose which st-linkv2 I'm working with. Here is a short script that programs two different chips with two distinct binary images.
echo "programming voltage chip" openocd -d0 -f openocd-1.cfg -c "program adc-v.bin 0x08000000 verify reset exit" echo "" echo "programming current chip" openocd -d0 -f openocd-2.cfg -c "program adc-a.bin 0x08000000 verify reset exit
One other surprise to me was the speed at which it programs. It's visibly faster than st-flash. Program two micros with code verification and a reset in under a second.
et:option-bytes$ time ./prog-1 Open On-Chip Debugger 0.10.0+dev-00937-g8021aef90 (2021-11-03-16:13) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html debug_level: 1 target halted due to debug-request, current mode: Thread xPSR: 0xf1000000 pc: 0x00003660 msp: 0x20000330 ** Programming Started ** Warn : block write succeeded ** Programming Finished ** ** Resetting Target ** shutdown command invoked Open On-Chip Debugger 0.10.0+dev-00937-g8021aef90 (2021-11-03-16:13) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html debug_level: 1 target halted due to debug-request, current mode: Thread xPSR: 0xf1000000 pc: 0x00003660 msp: 0x20000330 ** Programming Started ** Warn : block write succeeded ** Programming Finished ** ** Resetting Target ** shutdown command invoked real 0m0.992s user 0m0.113s sys 0m0.153s
Now that's pretty slick and I'm happy with it. The environment is fast, pretty compact, and it comes with some good "bells and whistles" like actually verifying the code on the chip.