Have to upload twice holding reset the first time

I’m not quite sure how to give any better title, probably because I’m so lost on the cause.

I have a board with an STM32L431 and I’m using an ft2232h to connect through USB to give me a JTAG connection and UART. I don’t have any reset pin that the ft2232 can control. I’m assuming any reset can be managed through the JTAG interface since I’ve used SWD before without any reset connection.

When I upload it will fail saying the jtag scan chain interrogation failed.
But if I hold down the MCU reset with the button on my board and try to upload again it will of course say that it failed to halt. But if I then release the reset and try another upload it works just fine. So I feel like there is something happening while I’m holding the reset and it tries to upload, like something is cleared or initialized that it doesn’t seem capable of doing otherwise.

And it isn’t enough to just press the reset for a little while and then perform an upload. I have to try an upload while holding reset.

Summary:

Try an upload → fails
Try an upload while holding MCU reset → fails
Try another upload after releasing MCU reset → success!

My OpenOCD config that I copied from the mini module using the same ftdi chip and just added the target config. I’ve tried to fiddle with various nSRST settings but no luck so far.

devboard_jtag.cfg

adapter driver ftdi

ftdi vid_pid 0x0403 0x6010

# Every pin set as high impedance except TCK, TDI, TDO and TMS
#ftdi channel 0
ftdi layout_init 0x0008 0x000b

source [find target/stml4x.cfg]

# nSRST defined on pin CN2-13 of the MiniModule (pin ADBUS5 [AD5] on the FT2232H chip)
# This choice is arbitrary. Use other GPIO pin if desired.
#ftdi layout_signal nSRST -data 0x0020 -oe 0x0020

My upload settings in platformio.ini

upload_protocol = custom
upload_command =
    ${platformio.packages_dir}/tool-openocd/bin/openocd -d -s ${platformio.packages_dir}/tool-openocd/openocd/scripts/ -f interface/devboard_jtag.cfg -c "program {$SOURCE} 0x8000000 verify reset; shutdown;"

Processing genericSTM32L431RC (platform: ststm32; board: stm32l431rc; framework: stm32cube)

Verbose mode can be enabled via -v, --verbose option
CONFIGURATION: https://docs.platformio.org/page/boards/ststm32/stm32l431rc.html
PLATFORM: ST STM32 (17.0.0) > STM32L431RC (64k RAM. 256k Flash)
HARDWARE: STM32L431RCT6 80MHz, 64.00KB RAM, 256KB Flash
DEBUG: Current (custom) External (cmsis-dap, jlink, stlink)
PACKAGES:

  • framework-stm32cubel4 @ 1.17.0
  • tool-dfuutil @ 1.11.0
  • tool-dfuutil-arduino @ 1.11.0
  • tool-ldscripts-ststm32 @ 0.2.0
  • tool-openocd @ 3.1200.0 (12.0)
  • tool-stm32duino @ 1.0.1
  • toolchain-gccarmnoneeabi @ 1.70201.0 (7.2.1)
    LDF: Library Dependency Finder → Library Dependency Finder (LDF) — PlatformIO latest documentation
    LDF Modes: Finder ~ chain, Compatibility ~ soft
    Found 60 compatible libraries
    Scanning dependencies…
    Dependency Graph
    |-- bit_manip @ 0.0.1
    |-- time @ 0.0.1
    |-- stm32l431rc @ 0.0.1
    |-- button @ 0.0.1
    |-- mem @ 0.0.1
    |-- spi @ 0.0.1
    |-- lis2dh12 @ 0.0.1
    Building in release mode
    Checking size .pio/build/genericSTM32L431RC/firmware.elf
    Advanced Memory Usage is available via “PlatformIO Home > Project Inspect”
    RAM: [ ] 1.4% (used 932 bytes from 65535 bytes)
    Flash: [= ] 12.7% (used 33236 bytes from 262144 bytes)
    Configuring upload protocol…
    AVAILABLE: cmsis-dap, custom, ftdi, jlink, stlink
    CURRENT: upload_protocol = custom
    Uploading .pio/build/genericSTM32L431RC/firmware.bin
    Uploading .pio/build/genericSTM32L431RC/firmware.bin
    xPack Open On-Chip Debugger 0.12.0-01004-g9ea7f3d64-dirty (2023-01-30-15:03)
    Licensed under GNU GPL v2
    For bug reports, read
    OpenOCD: Bug Reporting
    User : 3 17 options.c:52 configuration_output_handler(): debug_level: 3
    User : 4 17 options.c:52 configuration_output_handler():
    Debug: 5 17 configuration.c:33 add_script_search_dir(): adding /home/simon/.platformio/packages/tool-openocd/openocd/scripts/
    Debug: 6 17 options.c:233 add_default_dirs(): bindir=/__w/openocd-xpack/openocd-xpack/build/linux-x64/application/bin
    Debug: 7 17 options.c:234 add_default_dirs(): pkgdatadir=/__w/openocd-xpack/openocd-xpack/build/linux-x64/application/openocd
    Debug: 8 17 options.c:235 add_default_dirs(): exepath=/home/simon/.platformio/packages/tool-openocd/bin
    Debug: 9 17 options.c:236 add_default_dirs(): bin2data=…/openocd
    Debug: 10 18 configuration.c:33 add_script_search_dir(): adding /home/simon/.config/openocd
    Debug: 11 18 configuration.c:33 add_script_search_dir(): adding /home/simon/.openocd
    Debug: 12 18 configuration.c:33 add_script_search_dir(): adding /home/simon/.platformio/packages/tool-openocd/bin/…/openocd/site
    Debug: 13 18 configuration.c:33 add_script_search_dir(): adding /home/simon/.platformio/packages/tool-openocd/bin/…/openocd/scripts
    Debug: 14 18 command.c:155 script_debug(): command - ocd_find interface/devboard_jtag.cfg
    Debug: 15 18 configuration.c:88 find_file(): found /home/simon/.platformio/packages/tool-openocd/openocd/scripts//interface/devboard_jtag.cfg
    Debug: 16 19 command.c:155 script_debug(): command - adapter driver ftdi
    Debug: 17 19 command.c:155 script_debug(): command - ftdi vid_pid 0x0403 0x6010
    Debug: 18 19 command.c:155 script_debug(): command - ftdi layout_init 0x0008 0x000b
    Debug: 19 19 command.c:155 script_debug(): command - ocd_find target/stm32l4x.cfg
    Debug: 20 19 configuration.c:88 find_file(): found /home/simon/.platformio/packages/tool-openocd/openocd/scripts//target/stm32l4x.cfg
    Debug: 21 19 command.c:155 script_debug(): command - ocd_find target/swj-dp.tcl
    Debug: 22 20 configuration.c:88 find_file(): found /home/simon/.platformio/packages/tool-openocd/openocd/scripts//target/swj-dp.tcl
    Debug: 23 20 command.c:155 script_debug(): command - transport select
    Info : 24 20 transport.c:265 jim_transport_select(): auto-selecting first available session transport “jtag”. To override use ‘transport select ’.
    Debug: 25 20 command.c:155 script_debug(): command - ocd_find mem_helper.tcl
    Debug: 26 21 configuration.c:88 find_file(): found /home/simon/.platformio/packages/tool-openocd/openocd/scripts//mem_helper.tcl
    Debug: 27 21 command.c:155 script_debug(): command - add_usage_text mrw address
    Debug: 28 21 command.c:155 script_debug(): command - add_help_text mrw Returns value of word in memory.
    Debug: 29 21 command.c:155 script_debug(): command - add_usage_text mrh address
    Debug: 30 21 command.c:155 script_debug(): command - add_help_text mrh Returns value of halfword in memory.
    Debug: 31 21 command.c:155 script_debug(): command - add_usage_text mrb address
    Debug: 32 21 command.c:155 script_debug(): command - add_help_text mrb Returns value of byte in memory.
    Debug: 33 21 command.c:155 script_debug(): command - add_usage_text mmw address setbits clearbits
    Debug: 34 21 command.c:155 script_debug(): command - add_help_text mmw Modify word in memory. new_val = (old_val & ~clearbits) | setbits;
    Debug: 35 21 command.c:155 script_debug(): command - transport select
    Debug: 36 21 command.c:155 script_debug(): command - expr [ string first “jtag” $_TRANSPORT ] != -1
    Debug: 37 21 command.c:155 script_debug(): command - transport select
    Debug: 38 21 command.c:155 script_debug(): command - expr [ string first “jtag” $_TRANSPORT ] != -1
    Debug: 39 21 command.c:155 script_debug(): command - transport select
    Debug: 40 21 command.c:155 script_debug(): command - expr [ string first “swd” $_TRANSPORT ] != -1
    Debug: 41 21 command.c:155 script_debug(): command - jtag newtap stm32l4x cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x4ba00477
    Debug: 42 21 tcl.c:557 jim_newtap_cmd(): Creating New Tap, Chip: stm32l4x, Tap: cpu, Dotted: stm32l4x.cpu, 8 params
    Debug: 43 21 tcl.c:582 jim_newtap_cmd(): Processing option: -irlen
    Debug: 44 21 tcl.c:582 jim_newtap_cmd(): Processing option: -ircapture
    Debug: 45 21 tcl.c:582 jim_newtap_cmd(): Processing option: -irmask
    Debug: 46 21 tcl.c:582 jim_newtap_cmd(): Processing option: -expected-id
    Debug: 47 21 core.c:1474 jtag_tap_init(): Created Tap: stm32l4x.cpu @ abs position 0, irlen 4, capture: 0x1 mask: 0xf
    Debug: 48 21 command.c:155 script_debug(): command - dap create stm32l4x.dap -chain-position stm32l4x.cpu
    Debug: 49 21 command.c:155 script_debug(): command - transport select
    Debug: 50 21 command.c:155 script_debug(): command - expr [ string first “jtag” $_TRANSPORT ] != -1
    Debug: 51 21 command.c:155 script_debug(): command - jtag newtap stm32l4x bs -irlen 5
    Debug: 52 21 tcl.c:557 jim_newtap_cmd(): Creating New Tap, Chip: stm32l4x, Tap: bs, Dotted: stm32l4x.bs, 2 params
    Debug: 53 21 tcl.c:582 jim_newtap_cmd(): Processing option: -irlen
    Debug: 54 21 core.c:1474 jtag_tap_init(): Created Tap: stm32l4x.bs @ abs position 1, irlen 5, capture: 0x1 mask: 0x3
    Debug: 55 21 command.c:155 script_debug(): command - target create stm32l4x.cpu cortex_m -endian little -dap stm32l4x.dap
    Debug: 56 22 command.c:289 register_command(): command ‘tpiu’ is already registered
    Debug: 57 22 command.c:289 register_command(): command ‘rtt’ is already registered
    Debug: 58 23 command.c:155 script_debug(): command - stm32l4x.cpu configure -work-area-phys 0x20000000 -work-area-size 0xa000 -work-area-backup 0
    Debug: 59 23 target.c:2199 target_free_all_working_areas_restore(): freeing all working areas
    Debug: 60 23 target.c:2199 target_free_all_working_areas_restore(): freeing all working areas
    Debug: 61 23 target.c:2199 target_free_all_working_areas_restore(): freeing all working areas
    Debug: 62 23 command.c:155 script_debug(): command - flash bank stm32l4x.flash stm32l4x 0x08000000 0 0 0 stm32l4x.cpu
    Debug: 63 24 tcl.c:1305 handle_flash_bank_command(): ‘stm32l4x’ driver usage field missing
    Debug: 64 24 command.c:155 script_debug(): command - flash bank stm32l4x.otp stm32l4x 0x1fff7000 0 0 0 stm32l4x.cpu
    Debug: 65 24 command.c:289 register_command(): command ‘stm32l4x’ is already registered
    Debug: 66 24 command.c:289 register_command(): command ‘stm32l4x lock’ is already registered
    Debug: 67 24 command.c:289 register_command(): command ‘stm32l4x unlock’ is already registered
    Debug: 68 24 command.c:289 register_command(): command ‘stm32l4x mass_erase’ is already registered
    Debug: 69 24 command.c:289 register_command(): command ‘stm32l4x option_read’ is already registered
    Debug: 70 24 command.c:289 register_command(): command ‘stm32l4x option_write’ is already registered
    Debug: 71 24 command.c:289 register_command(): command ‘stm32l4x trustzone’ is already registered
    Debug: 72 25 command.c:289 register_command(): command ‘stm32l4x wrp_info’ is already registered
    Debug: 73 25 command.c:289 register_command(): command ‘stm32l4x option_load’ is already registered
    Debug: 74 25 command.c:289 register_command(): command ‘stm32l4x otp’ is already registered
    Debug: 75 25 tcl.c:1305 handle_flash_bank_command(): ‘stm32l4x’ driver usage field missing
    Debug: 76 25 command.c:155 script_debug(): command - adapter speed 500
    Debug: 77 25 adapter.c:251 adapter_config_khz(): handle adapter khz
    Debug: 78 25 adapter.c:215 adapter_khz_to_speed(): convert khz to adapter specific speed value
    Debug: 79 25 adapter.c:215 adapter_khz_to_speed(): convert khz to adapter specific speed value
    Debug: 80 25 command.c:155 script_debug(): command - adapter srst delay 100
    Debug: 81 25 command.c:155 script_debug(): command - transport select
    Debug: 82 25 command.c:155 script_debug(): command - expr [ string first “jtag” $_TRANSPORT ] != -1
    Debug: 83 25 command.c:155 script_debug(): command - jtag_ntrst_delay 100
    Debug: 84 25 command.c:155 script_debug(): command - reset_config srst_nogate
    Debug: 85 25 command.c:155 script_debug(): command - transport select
    Debug: 86 25 command.c:155 script_debug(): command - expr [ string first “hla” $_TRANSPORT ] != -1
    Debug: 87 25 command.c:155 script_debug(): command - cortex_m reset_config sysresetreq
    Debug: 88 25 command.c:155 script_debug(): command - stm32l4x.cpu configure -event examine-end

Enable debug during low power modes (uses more power)

DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP

mmw 0xE0042004 0x00000007 0

Stop watchdog counters during halt

DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP

mmw 0xE0042008 0x00001800 0

Debug: 89 25 command.c:155 script_debug(): command - tpiu create stm32l4x.tpiu -dap stm32l4x.dap -ap-num 0 -baseaddr 0xE0040000
Debug: 90 25 command.c:155 script_debug(): command - stm32l4x.tpiu configure -event pre-enable _proc_pre_enable_stm32l4x.tpiu stm32l4x
Debug: 91 25 command.c:155 script_debug(): command - stm32l4x.cpu configure -event reset-init

CPU comes out of reset with MSI_ON | MSI_RDY | MSI Range 6 (4 MHz).

Use MSI 24 MHz clock, compliant even with VOS == 2.

3 WS compliant with VOS == 2 and 24 MHz.

mww 0x40022000 0x00000103 ;# FLASH_ACR = PRFTBE | 3(Latency)
mww 0x40021000 0x00000099 ;# RCC_CR = MSI_ON | MSIRGSEL | MSI Range 9

Boost JTAG frequency

adapter speed 4000

Debug: 92 25 command.c:155 script_debug(): command - stm32l4x.cpu configure -event reset-start

Reset clock is MSI (4 MHz)

adapter speed 500

Debug: 93 25 command.c:155 script_debug(): command - init
Debug: 94 25 command.c:155 script_debug(): command - target init
Debug: 95 25 command.c:155 script_debug(): command - target names
Debug: 96 25 command.c:155 script_debug(): command - stm32l4x.cpu cget -event gdb-flash-erase-start
Debug: 97 25 command.c:155 script_debug(): command - stm32l4x.cpu configure -event gdb-flash-erase-start reset init
Debug: 98 25 command.c:155 script_debug(): command - stm32l4x.cpu cget -event gdb-flash-write-end
Debug: 99 25 command.c:155 script_debug(): command - stm32l4x.cpu configure -event gdb-flash-write-end reset halt
Debug: 100 25 command.c:155 script_debug(): command - stm32l4x.cpu cget -event gdb-attach
Debug: 101 25 command.c:155 script_debug(): command - stm32l4x.cpu configure -event gdb-attach halt 1000
Debug: 102 25 target.c:1657 handle_target_init_command(): Initializing targets…
Debug: 103 25 semihosting_common.c:109 semihosting_common_init():
Debug: 104 25 ftdi.c:654 ftdi_initialize(): ftdi interface using shortest path jtag state transitions
Debug: 105 34 mpsse.c:412 mpsse_purge(): -
Debug: 106 34 mpsse.c:693 mpsse_loopback_config(): off
Debug: 107 34 mpsse.c:738 mpsse_set_frequency(): target 500000 Hz
Debug: 108 34 mpsse.c:730 mpsse_rtck_config(): off
Debug: 109 34 mpsse.c:719 mpsse_divide_by_5_config(): off
Debug: 110 34 mpsse.c:699 mpsse_set_divisor(): 59
Debug: 111 34 mpsse.c:762 mpsse_set_frequency(): actually 500000 Hz
Debug: 112 34 adapter.c:215 adapter_khz_to_speed(): convert khz to adapter specific speed value
Debug: 113 34 adapter.c:219 adapter_khz_to_speed(): have adapter set up
Debug: 114 34 mpsse.c:738 mpsse_set_frequency(): target 500000 Hz
Debug: 115 34 mpsse.c:730 mpsse_rtck_config(): off
Debug: 116 34 mpsse.c:719 mpsse_divide_by_5_config(): off
Debug: 117 34 mpsse.c:699 mpsse_set_divisor(): 59
Debug: 118 34 mpsse.c:762 mpsse_set_frequency(): actually 500000 Hz
Debug: 119 34 adapter.c:215 adapter_khz_to_speed(): convert khz to adapter specific speed value
Debug: 120 34 adapter.c:219 adapter_khz_to_speed(): have adapter set up
Info : 121 34 adapter.c:179 adapter_init(): clock speed 500 kHz
Debug: 122 34 openocd.c:134 handle_init_command(): Debug Adapter init complete
Debug: 123 34 command.c:155 script_debug(): command - transport init
Debug: 124 34 transport.c:219 handle_transport_init(): handle_transport_init
Debug: 125 40 core.c:830 jtag_add_reset(): SRST line released
Debug: 126 40 core.c:855 jtag_add_reset(): TRST line released
Debug: 127 40 core.c:328 jtag_call_event_callbacks(): jtag event: TAP reset
Debug: 128 250 command.c:155 script_debug(): command - jtag arp_init
Debug: 129 250 core.c:1509 jtag_init_inner(): Init JTAG chain
Debug: 130 250 core.c:328 jtag_call_event_callbacks(): jtag event: TAP reset
Debug: 131 250 core.c:1234 jtag_examine_chain(): DR scan interrogation for IDCODE/BYPASS
Debug: 132 250 core.c:328 jtag_call_event_callbacks(): jtag event: TAP reset
Error: 133 252 core.c:1122 jtag_examine_chain_check(): JTAG scan chain interrogation failed: all ones
Error: 134 252 core.c:1124 jtag_examine_chain_check(): Check JTAG interface, timings, target power, etc.
Error: 135 252 core.c:1554 jtag_init_inner(): Trying to use configured scan chain anyway…
Debug: 136 252 core.c:1364 jtag_validate_ircapture(): IR capture validation scan
Error: 137 252 core.c:1413 jtag_validate_ircapture(): stm32l4x.cpu: IR capture error; saw 0x0f not 0x01
Debug: 138 252 core.c:328 jtag_call_event_callbacks(): jtag event: TAP reset
Warn : 139 252 core.c:1577 jtag_init_inner(): Bypassing JTAG setup events due to errors
Debug: 140 252 command.c:155 script_debug(): command - dap init
Debug: 141 252 arm_dap.c:97 dap_init_all(): Initializing all DAPs …
Debug: 142 252 arm_dap.c:121 dap_init_all(): DAP stm32l4x.cpu configured by default to use ADIv5 protocol
Debug: 143 252 arm_adi_v5.c:679 dap_dp_init(): stm32l4x.dap
Debug: 144 252 arm_adi_v5.c:711 dap_dp_init(): DAP: wait CDBGPWRUPACK
Debug: 145 252 arm_adi_v5.h:638 dap_dp_poll_register(): DAP: poll 4, mask 0x20000000, value 0x20000000
Error: 146 253 adi_v5_jtag.c:446 jtagdp_overrun_check(): Invalid ACK (7) in DAP response
Debug: 147 253 adi_v5_jtag.c:651 jtagdp_transaction_endcheck(): jtag-dp: CTRL/STAT 0xffffffff
Error: 148 253 adi_v5_jtag.c:662 jtagdp_transaction_endcheck(): JTAG-DP STICKY ERROR
Debug: 149 253 adi_v5_jtag.c:664 jtagdp_transaction_endcheck(): JTAG-DP STICKY OVERRUN
Debug: 150 253 command.c:544 run_command(): Command ‘dap init’ failed with error code -107
User : 151 253 command.c:608 command_run_line(): in procedure ‘program’
Debug: 152 253 command.c:544 run_command(): Command ‘init’ failed with error code -4
Debug: 153 253 command.c:155 script_debug(): command - echo ** OpenOCD init failed **
User : 154 253 command.c:685 handle_echo(): ** OpenOCD init failed **
Debug: 155 253 command.c:155 script_debug(): command - shutdown error
User : 156 253 server.c:758 handle_shutdown_command(): shutdown command invoked
Debug: 157 253 command.c:544 run_command(): Command ‘shutdown’ failed with error code -4
User : 158 253 command.c:608 command_run_line():
Debug: 159 253 target.c:2199 target_free_all_working_areas_restore(): freeing all working areas
*** [upload] Error 1
==================================== [FAILED] Took 4.64 seconds ====================================

If you can only “upload under reset”, then something in your firmware is affecting the JTAG/SWD pins or debug access functionality. Try uploading an empty main as test, then upload your code again. If that works without pressing reset, then something, somewhere in your build is disabling pins needed by JTAG/SWD.

1 Like

I really appreciate the idea, I’ll give that a try!

Yeah, you are definitely on the right track. An empty main uploaded doesn’t have this issue I can upload fine after uploading that. Now I just have to find how I’m causing that.

Thanks, I didn’t think I would have affected those pins but this certainly proves otherwise.

I think this is a first for me. This appears to be a known issue and is in the errata.

From the STM32L431xx Erratta:

2.2.6 Full JTAG configuration without NJTRST pin cannot be used
Description
When using the JTAG debug port in Debug mode, the connection with the debugger is lost if the NJTRST pin
(PB4) is used as a GPIO or for an alternate function other than NJTRST. Only the 4-wire JTAG port configuration
is impacted.
Workaround
Use the SWD debug port instead of the full 4-wire JTAG port.

This is also consistent with what I found when extending the empty main with code from my project. Once PB4 was configured I lost the ability to upload.