Failed to verify flash algorithm

Hi,

I'm just getting into Rust and trying to,flash it onto my own custom board where I normally run C++. This is a stable and working board that I haven't had any issues with when working with platformio/openocd.
It's based on the STM32L431RCT6 and I have an FT2232 on the board that I use to flash over USB with JTAG to the MCU.

When trying to run cargo embed it quickly fails when trying to verify RAM which confuses me, but perhaps this is a Rust thing as I wouldn't expect RAM to matter before the program has started.

The output I see:

simon@simon-UX305CA:~/projects/stm32_rust/rustystm32$ cargo embed
Finished dev profile [unoptimized + debuginfo] target(s) in 0.16s
Config default
Target /home/simon/projects/stm32_rust/rustystm32/target/thumbv7em-none-eabihf/debug/rustystm32
ERROR probe_rs::flashing::flasher: Failed to verify flash algorithm. Data mismatch at address 0x20000004
ERROR probe_rs::flashing::flasher: Original instruction: 0x062d780d
ERROR probe_rs::flashing::flasher: Readback instruction: 0xe00abe00
ERROR probe_rs::flashing::flasher: Original: [e00abe00, 62d780d, 24084068, d3000040, 1e644058, 1c49d1fa, 2a001e52, 4770d1f, 8f4ff3bf, 48584770, 49586800, d000500, d0001840, 47702001, 6a004855, fc00280, b5004770, f7ff4602, 2801ffee, f7ffd108, 2801fff3, 484fd104, d3014282, bd002001, bd002000, 4602b500, ffddf7ff, d0022801, d8002d0, 4948bd00, 40080ad0, d5f90391, 300130ff, 4842bd00, 60814944, 60814944, 60012100, 61014943, 3c06a00, 4843d406, 60014941, 60412106, 60814941, 47702000, 49372001, 614807c0, 47702000, 47702001, 49384833, 13c16101, 69416141, 4122201, 61414311, 4a354937, 6011e000, 3db6903, 2100d4fb, 46086141, b5104770, f7ff4604, 4603ffa8, f7ff4620, 4925ffb5, 610c4c29, 2d800c2, 43021c92, 6948614a, 4122201, 61484310, 8f4ff3bf, 4a244826, 6010e000, 3db690b, 2000d4fb, 69086148, d0014020, 2001610c, b5f0bd10, 4d151dc9, 4f1908c9, 612f00c9, 616b2300, e0184c1a, 616b2301, 60036813, 60436853, 8f4ff3bf, e0004b13, 692e601c, d4fb03f6, 616b2300, 423b692b, 612fd002, bdf02001, 39083008, 29003208, 2000d1e4, bdf0, e0042000, fffffbcb, 40022000, 8020000, 3bf, 45670123, cdef89ab, c3fa, 5555, 40003000, fff, aaaa, 0]
ERROR probe_rs::flashing::flasher: Readback: [e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00, e00abe00]
ERROR probe_rs::architecture::arm::core::armv7m: The core is in locked up status as a result of an unrecoverable exception ERROR probe_rs::architecture::arm::core::armv7m: The core is in locked up status as a result of an unrecoverable exception ERROR probe_rs::architecture::arm::core::armv7m: The core is in locked up status as a result of an unrecoverable exception ERROR probe_rs::architecture::arm::core::armv7m: The core is in locked up status as a result of an unrecoverable exception ERROR probe_rs::architecture::arm::core::armv7m: The core is in locked up status as a result of an unrecoverable exception ERROR probe_rs::architecture::arm::core::armv7m: The core is in locked up status as a result of an unrecoverable exception ERROR probe_rs::architecture::arm::core::armv7m: The core is in locked up status as a result of an unrecoverable exception WARN probe_rs::session: Could not clear all hardware breakpoints: An ARM specific error occurred.

Caused by:
Timeout occurred during operation. Error The flashing procedure failed for '/home/simon/projects/stm32_rust/rustystm32/target/thumbv7em-none-eabihf/debug/rustystm32'.

         Caused by:
             The RAM contents did not match the expected contents after loading the flash algorithm.

It looks as if the first value being written is either repeated over and over or it's just reading back the first value many times.

main.rs

#![no_std]
#![no_main]

use cortex_m_rt::entry;
use panic_halt as _;

#[entry]
fn main() -> ! {
    loop {
        
    }
}

memory.x

MEMORY
{
  FLASH : ORIGIN = 0x08000000, LENGTH = 256K
  RAM : ORIGIN = 0x20000000, LENGTH = 64K
}

Embed.toml

[default.probe]
# USB vendor ID
usb_vid = "0403"
# USB product ID
usb_pid = "6010"
# Serial number
serial = "FT8XABI4"
# The protocol to be used for communicating with the target.
protocol = "Jtag"
#protocol = "Swd"
# The speed in kHz of the data link to the target.
# speed = 1337

[default.flashing]
# Whether or not the target should be flashed.
enabled = true
# Whether or not bytes erased but not rewritten with data from the ELF
# should be restored with their contents before erasing.
restore_unwritten_bytes = false
# The path where an SVG of the assembled flash layout should be written to.
# flash_layout_output_path = "out.svg"
# Triggers a full chip erase instead of a page by page erase.
do_chip_erase = false
# Whether to disable double buffering
disable_double_buffering = false
# Whether to verify flash contents before downloading
#preverify = false
# Whether to verify flash contents after downloading
verify = true

[default.reset]
# Whether or not the target should be reset.
# When flashing is enabled as well, the target will be reset after flashing regardless of this setting.
enabled = true
# Whether or not the target should be halted after reset.
halt_afterwards = false

[default.general]
# The chip name of the chip to be debugged.
chip = "STM32L431RCTx"
# A list of chip descriptions to be loaded during runtime.
chip_descriptions = []
# The default log level to be used. Possible values are one of:
#   "OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"
#   If not set, the `RUST_LOG` environment variable will be used.
# log_level = "WARN"
# Use this flag to assert the nreset & ntrst pins during attaching the probe to the chip.
connect_under_reset = false

[default.rtt]
# Whether or not an RTTUI should be opened after flashing.
enabled = false
# The duration in ms for which the logger should retry to attach to RTT.
timeout = 3000
# Whether to save rtt history buffer on exit.
log_enabled = false
# Where to save rtt history buffer relative to manifest path.
log_path = "./logs"
# A list of up (target -> host) channel settings associations to be displayed. If left empty, all channels are displayed.
# object key  - RTT channel identifier number
# mode     (Optional) - RTT operation mode. Describes how the target handles RTT outputs that won't
#                       fit in the buffer. If left unset, the firmware will determine the default
#                       for each RTT up channel.
#              * NoBlockSkip - Skip writing the data completely if it doesn't fit in its
#                            entirety.
#              * NoBlockTrim - Write as much as possible of the data and ignore the rest.
#              * BlockIfFull - Spin until the host reads data.  Can result in app freezing.
# format   (Optional) - How to interpret data from target firmware.  One of:
#              * String - Directly show output from the target (default)
#              * Defmt  - Format output on the host, see https://defmt.ferrous-systems.com/
#              * BinaryLE - Display as raw hex
# show_location (Optional) - Whether to show the location of defmt messages in the UI.
# show_timestamps (Optional) - Whether to show the timestamps of String and Defmt messages in the UI, if available.
# socket   (Optional) - Server socket address (for optional external frontend or endpoint).
# log_format (Optional) - Control the output format for `format = Defmt`.
up_channels = [
    # { channel = 0, mode = "BlockIfFull", format = "Defmt", show_location = true },
    # { channel = 1, mode = "BlockIfFull", format = "String", show_timestamps = false, socket = "127.0.0.1:12345" },
]

# A list of down (host -> target) channel settings. You can select a down channel for each UI tab,
# which will be used to send data to the target.
# object key  - RTT channel identifier number
# mode     (Optional) - RTT operation mode. Describes how the target handles RTT outputs that won't
#                       fit in the buffer. If left unset, the firmware will determine the default
#                       for each RTT down channel.
down_channels = [
    # { channel = 0, mode = "BlockIfFull" }
]

# UI tab settings. All up channels are displayed, except when hidden here. You can specify how each
# tab is displayed and whether they allow sending data to the target.
# up_channel              - The channel_number of the RTT up channel to display
# hide         (Optional) - Whether to hide the tab. Defaults to false.
# down_channel (Optional) - The channel_number of the RTT down channel to use for this tab.
# name         (Optional) - String to be displayed in the RTTUI tab. Defaults to the channel name.
tabs = [
    # { up_channel = 0, down_channel = 0, name = "My channel" },
    # { up_channel = 1, hide = true },
]

[default.gdb]
# Whether or not a GDB server should be opened after flashing.
enabled = false
# The connection string in host:port format wher the GDB server will open a socket.
gdb_connection_string = "127.0.0.1:1337"

I can't quite figure out what I could be doing wrong and would really appreciate your help. I'm happy to provide any additional information you need. I've tried to provide anything I think is relevant now.

Your computer is not communicating with the target. All the rest is noise.

...is my guess.

Hmm, that's odd. There isn't anything wrong with the connection if I run openocd. So I guess there must be something with the configuration

1 Like

is there any chance your firmware locked up the DAP? try set connect_under_reset to true.

note: this will only work if you have both nRST and nTRST signals of the JTAG connection, it will NOT work if you omitted the nRST signal.

I'm afraid I don't have the reset signals connected. But since I'm able to flash C++ software with platformio I emptied main in one of my applications and loaded so there should be nothing running. But it still gives me the same issue.

I set the log_level to INFO, I'm not sure how to interpret the output but is it recognizing the MCU when it's getting the ARM and STM IDCODE?

Finished dev profile [unoptimized + debuginfo] target(s) in 0.15s
Config default
Target /home/simon/projects/stm32_rust/rustystm32/target/thumbv7em-none-eabihf/debug/rustystm32
INFO probe_rs::config::target: Using sequence Arm(Stm32Armv7)
INFO probe_rs::util::common_options: Protocol speed 1000 kHz
INFO probe_rs::probe::ftdi: Setting speed to 1000 kHz (divisor: 29, actual speed: 1000 kHz)
INFO probe_rs::probe::common: Found IDCODE: 0x4BA00477 (ARM Ltd)
INFO probe_rs::probe::common: Found IDCODE: 0x06435041 (STMicroelectronics)
INFO probe_rs::probe::common: JTAG DR scan complete, found 2 TAPs. [Some(IdCode { .0: 1268778103, version: 4, part_number: 47616, manufacturer: 571, manufacturer_continuation: 4, manufacturer_identity: 59, lsbit: true }), Some(IdCode { .0: 105074753, version: 0, part_number: 25653, manufacturer: 32, manufacturer_continuation: 0, manufacturer_identity: 32, lsbit: true })]
INFO probe_rs::probe::common: IR lengths are unambiguous: [4, 5]
INFO probe_rs::probe::common: Found 2 TAPs on reset scan
INFO probe_rs::probe: JtagChainItem { idcode: Some(IdCode { .0: 1268778103, version: 4, part_number: 47616, manufacturer: 571, manufacturer_continuation: 4, manufacturer_identity: 59, lsbit: true }), irlen: 4 }
INFO probe_rs::probe: JtagChainItem { idcode: Some(IdCode { .0: 105074753, version: 0, part_number: 25653, manufacturer: 32, manufacturer_continuation: 0, manufacturer_identity: 32, lsbit: true }), irlen: 5 }
INFO probe_rs::session: Core status: Running
INFO probe_rs::session: Halting core...
INFO probe_rs::session: Resuming core...
INFO probe_rs::flashing::download: Found loadable segment, physical address: 0x08000000, virtual address: 0x08000000, flags: 0x4
INFO probe_rs::flashing::download: Matching section: ".vector_table"
INFO probe_rs::flashing::download: Found loadable segment, physical address: 0x08000400, virtual address: 0x08000400, flags: 0x5
INFO probe_rs::flashing::download: Matching section: ".text"
INFO probe_rs::flashing::loader: Found 2 loadable sections:
INFO probe_rs::flashing::loader: .vector_table at 0x08000000 (1024 bytes)
INFO probe_rs::flashing::loader: .text at 0x08000400 (140 bytes)
INFO probe_rs::flashing::flasher: Chosen RAM to run the algo: RamRegion { name: Some("SRAM1"), range: 20000000..2000c000, is_boot_memory: false, cores: ["main"] }
INFO probe_rs::flashing::flasher: Data will be loaded to: RamRegion { name: Some("SRAM1"), range: 20000000..2000c000, is_boot_memory: false, cores: ["main"] }
INFO probe_rs::flashing::flash_algorithm: The flash algorithm will be configured with 46628 bytes of stack
INFO probe_rs::flashing::flash_algorithm: Stack top: 0x2000B800
ERROR probe_rs::flashing::flasher: Failed to verify flash algorithm. Data mismatch at address 0x20000004
ERROR probe_rs::flashing::flasher: Original instruction: 0x062d780d
ERROR probe_rs::flashing::flasher: Readback instruction: 0xe00abe00

by the look of things, it seems the probe can talk to the TAP through JTAG without problem, yet, for some reason, when it tries to transfer the flashing algorithm to RAM, the data read back is jumbled: the first word is repeating...

I feel like it's probably a bug in probe-rs in handling TAP protocols for bulk data transfer, but just to do a quick check, try to manually write multiple words then read them back and do a comparison, e.g.:

$ probe-rs write --chip xxxx b32 0x20000000 0x11111111 0x22222222 0x33333333 0x44444444
$ probe-rs read --chip xxxx b32 0x20000000 4

these commands will write 4 32-bit words starting at address 0x20000000, then read them back. the actual data to write doesn't matter, as long you can verify the value being read back is the same.

btw, what's the output if you run the command probe-rs info?

Manually writing and reading gives the exact same behaviour. I read back 4 values of 0x11111111.

$ probe-rs info --protocol jtag
Probing target via JTAG

WARN probe_rs::architecture::arm::memory::romtable: Component at 0xe00ff000: CIDR1 has invalid preamble (expected 0x0, got 0xd)
WARN probe_rs::architecture::arm::memory::romtable: Component at 0xe00ff000: CIDR2 has invalid preamble (expected 0x5, got 0xd)
WARN probe_rs::architecture::arm::memory::romtable: Component at 0xe00ff000: CIDR3 has invalid preamble (expected 0xb1, got 0xd)
ARM Chip with debug port Default:
Debug Port: DPv0, DP Designer:
└── 0 MemoryAP
└── Generic

RISC-V Chip:
IDCODE: 0000000000
Version: 0
Part: 0
Manufacturer: 0 (Unknown Manufacturer Code)
Error showing Xtensa chip information: Invalid instruction register access: 30

Caused by:
Invalid instruction register access: 30

This certainly seems like a clue but hopefully it tells you something more than it does me.

this definitely feels like a BUG in probe-rs's JTAG implementation. I don't have any good idea how to solve the problem at this point, if the basic memory reading and writing operation cannot be relied on.

you should report to probe-rs github page. in the mean while, you chould try out different things, but these are just shots in the absolute dark and may not make any difference at all, but it doesn't hurt to at least try. examples includes:

  • check if there's newer version of probe-rs
  • check if there's a driver update for the probe
  • change the JTAG clock rate, you can try both very high frequency (e.g. 25MHz) and very low frequency (e.g. 100kHz) to see if it makes any difference
  • if your probe support SWD mode, try to reconfigure it as SWD
1 Like

I posted a bug to the probe-rs repository and first answer was that this is hopefully already solved.

1 Like

Can now confirm that I've tried the latest master and this issue is fixed!

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.