Programming External QSPI with OpenOCD via STM32H7A3/STM32H7B0
So firstly, I'll explain what I'm trying to achieve. My company is planning to utilize an STM32H7B0 because it's the chip that we were able to find stock of. For testing, I'm using a STM32H7A3 because it was available as a Nucleo board. The primary requirement we have is that updates to the device must have as little downtime as possible. Functionally this means that an update should be downloaded into a second image slot during normal operation, and then switched with as little downtime as possible. This would be simple using the H7B3 or H7A3, but we cannot find available parts.
My current approach is to use MCUBoot to load the image into RAM from a slot contained in a QSPI NOR flash. This also enables us to encrypt the image in the QSPI for IP protection. This is also the primary reason I'm not pursuing XIP. In theory this approach should work just fine, and I've already confirmed that the software runs just fine out of RAM instead of flash.
The problem I'm facing is in setting up a sane development environment. Currently, OpenOCD is configured to load the program into RAM which lets me test the program just fine. But I have to be able to write the program into the QSPI in order to test the bootloader. OpenOCD actually has a flash driver called `stmqspi` which will let me access the QSPI as another flash bank. However, I've only had limited success in getting this to work due to the memory mapped mode returning garbage.
The QSPI Flash I'm using is a Winbond W25Q16DV.
Here is the TCL script I'm using to setup the OCTOSPI. This intended to run immediately following a reset and halt.
proc qspi_init {} {
global _CHIPNAME
mmw 0x58024540 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks)
mmw 0x58024534 0x00284000 0 ;# RCC_AHB3ENR |= IOMNGREN, OSPI2EN, OSPI1EN (enable clocks)
sleep 1 ;# Wait for clock startup
mww 0x5200B404 0x03010111 ;# OCTOSPIM_P1CR: assign Port 1 to OCTOSPI1
mww 0x5200B408 0x00000000 ;# OCTOSPIM_P2CR: disable Port 2
# Port B: PB2:AF09:V
mmw 0x58020400 0x00000020 0x00000030 ;# MODER
mmw 0x58020408 0x00000030 0x00000030 ;# OSPEEDR
mmw 0x5802040C 0x00000000 0x00000030 ;# PUPDR
mmw 0x58020420 0x00000900 0x00000F00 ;# AFRL
# Port D: PD11:AF09:V, PD12:AF09:V, PD13:AF09:V
mmw 0x58020C00 0x0A800000 0x0FC00000 ;# MODER
mmw 0x58020C08 0x0FC00000 0x0FC00000 ;# OSPEEDR
mmw 0x58020C0C 0x00000000 0x0FC00000 ;# PUPDR
mmw 0x58020C24 0x00999000 0x00FFF000 ;# AFRH
# Port E: PE2:AF09:V
mmw 0x58021000 0x00000020 0x00000030 ;# MODER
mmw 0x58021008 0x00000030 0x00000030 ;# OSPEEDR
mmw 0x5802100C 0x00000000 0x00000030 ;# PUPDR
mmw 0x58021020 0x00000900 0x00000F00 ;# AFRL
# Port G: PG6:AF09:V
mmw 0x58021800 0x00002000 0x00003000 ;# MODER
mmw 0x58021808 0x00003000 0x00003000 ;# OSPEEDR
mmw 0x5802180C 0x00000000 0x00003000 ;# PUPDR
mmw 0x58021820 0x0A000000 0x0F000000 ;# AFRL
mmw 0x52005000 0 1
mww 0x52005008 0x00150100 ;# OCTOSPI_DCR1: MTYP=0x0, DEVSIZE=0x15, CSHT=0x1
mww 0x5200500C 0x00000020 ;# OCTOSPI_DCR2: PRESCALER=0x20
mww 0x52005010 0x00000000 ;# OCTOSPI_DCR3
mww 0x52005014 0x00000000 ;# OCTOSPI_DCR4
mww 0x52005108 0x00000004 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x4
mww 0x52005100 0x01002101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x2, ADMODE=0x1, ISIZE=0x0, IMODE=0x1
mww 0x52005110 0x00000003 ;# OCTOSPI_IR: Read Data 03h
mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x11, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1
sleep 1
flash probe $_CHIPNAME.qspi
}You might notice that this is configured for 1-lane for both data and address. This is because for some reason, the stmqspi driver is unable to probably fetch the SFDP parameters, device ID, or run commands in quad spi mode.
But in this mode, I'm able to erase, write, and read the flash via raw commands. But the memory mapped region just returns "garbage". I mean, it's close?
> stmqspi cmd 1 4 0x03 0 0 0
spi: 03 00 00 00 -> ef be ad de
> mrw 0x90000000
0xefddeafb
> mrw 0x90000004
0xffffffff
>Even more confusing, the signals coming back from the memory mapped operation look completely fine:
Am I missing something obvious? Do I need to explicitly disable cache? I'm just really lost here.