• stm32g0, openocd, and mecrisp stellaris - part 5

    11/24/2021 at 00:54 0 comments

    So just a short one today to describe briefly how to change option bytes.  The documentation does not seem to have examples, but I was finally able to stumble my way into getting it working by looking at the methods and steps of a few different articles about changing option bytes for other stm32 chips.

    With the stm32g031, you must use the stm32l4x flash driver.  This may vary for your chip, so research that.  Since I found that out the long way round, I hope it saves you time.  Using my new friend openocd, I wanted to enable the BOR enable bit in the option bytes (change from 0xfffffeaa to 0xffffffaa).  It's a one bit change, how hard could it be?

    Earlier I showed how you can read option bytes. You can verify they are set at the default. This command:

    openocd -d0 -f read-opt-bytes-1 -c "stm32l4x option_read 0 0x20" -c "exit"

    gives this result:

    Option Register: <0x40022020> = 0xfffffeaa

    And this matches the datasheet RM0444 p. 81.  Hooray!

    I've tried every combination of option_write and option_load I can think of based on what others had got to work for them, and I was finally able to toggle one single bit in the option bytes. I had to use these two commands in order:

    openocd -f read-opt-bytes-1 -c "stm32l4x option_write 0 0x20 0xffffffaa 0xffffffaa" -c "reset" -c "exit"

    openocd -f read-opt-bytes-1 -c "stm32l4x option_load 0 0x20" -c "reset" -c "exit"

    Then we have the new values: Option Register: <0x40022020> = 0xffffffaa

    Recall from earlier, that I had made my own read-opt-bytes-1 config file for openocd.  It basically just sets some defaults, but more importantly, let's me specify exactly which st-linkv2 interface I want to use when there are more than one plugged in at one time.  This is done with the hla_serial line in the config file...

    hla_serial "\x55\x3f\x66\x06\x48\x3f\x57\x54\x12\x27\x07\x3f"

    It would be nice if openocd could read this style ID instead: 55FF66064887575412270787, but I'll take what I can get. 

    Cheers!

    ... also, the BOR default settings did help with power ups when the supply voltage ramps up slowly.  If you have something like that, be sure to turn on the BOR EN bit.  :-)

  • stm32g0, openocd, and mecrisp stellaris - part 4

    11/17/2021 at 00:18 0 comments

    One of the cool things about using openocd is that you can interact with it, say to figure stuff out for the first time.  Then you can program it to be consistent.  For example, reading the option bytes worked out like this.

    1) Make this openocd.cfg:

    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

    2) Now, fire up openocd.

    et:option-bytes$ openocd
    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
    Info : auto-selecting first available session transport "hla_swd". To override use 'transport select '.
    Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
    Info : clock speed 2000 kHz
    Info : STLINK V2J38S7 (API v2) VID:PID 0483:3748
    Info : Target voltage: 3.278873
    Info : stm32g0x.cpu: hardware has 4 breakpoints, 2 watchpoints
    Info : Listening on port 3333 for gdb connections
    1
    Info : Listening on port 6666 for tcl connections
    Info : Listening on port 4444 for telnet connections

     3) In another window, connect to it via telnet:

    telnet localhost 4444
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    Open On-Chip Debugger
    > jtag tapisenabled stm32g0x.cpu
    1
    > stm32l4x option_read 0 0x00
    device id = 0x10016466
    flash size = 16kbytes
    Single Bank 16 kiB STM32G03x/G04x/G07x/G08x found
    Option Register: <0x40022000> = 0x40600
    > exit
    Connection closed by foreign host.
    
    

    I verified that the config worked, and the trap is enabled, just nice to know.  Then I read the option bytes.  Now that I have figured out exactly what was needed to read the option bytes, I don't want to have to fire up openocd and telnet to the instance every time.  That would be great for doing some real time debug work, but I am using forth, which pretty much does that for me already.  So, I want a convenient way to get the option bytes.  I have the command I want the output of, so I just tell openocd to run the command and exit.

    et:option-bytes$ openocd -d0 -f read-opt-bytes-1 -c "stm32l4x option_read 0 0x20" -c "exit"
    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: 0
    
    Option Register: <0x40022020> = 0xfffffeaa
    
    et:option-bytes$ openocd -d0 -f read-opt-bytes-2 -c "stm32l4x option_read 0 0x20" -c "exit"
    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: 0
    
    Option Register: <0x40022020> = 0xfffffeaa

    So there it is, running the same process interactively, then programming it to be a scripted command that can be run.  I hope you find this information useful.

  • stm32g0, openocd, and mecrisp stellaris - part 3

    11/17/2021 at 00:04 0 comments

    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]
    ...
    Read more »