2022-10-12 10:43 AM
Hello,
I'm trying to write runtime data in flash without disrupting code execution.
I'm using a STM32G0xx, on a custom PCB with a custom bootloader. STM32 is communicating as I2C slave with another device.
I have no problem erasing and writing the flash as per se (same in-house functions used for the bootloader), but when I try to do it and have DMA I2C communication running simultaneously I encounter problems.
Specifically, when looking at the communication lines with a probe and switching a GPIO pin high during flash operations (see attached images).
I notice that the issue seems to be that ADDR match IRQ can't be serviced, resulting in clock stretching of the I2C_SCK line which resets the µprocessor (the SCK line is used in our design to force a hard reset of the PCB after a being held down for a moment).
I am aware that FLASH should not be accessed by CPU during operations, and that any attempt to read data or execute code from FLASH memory will result in CPU stall. To avoid this, I've ensured that code is located and executed from RAM (which I verified by dissassembling ELF file), including vector table and ISRs.
I understand that this clock stretch happens when the ADDR flag is not clear, but I don't understand what makes it so the ADDR match flag can't be cleared.
IRQ code is executed from RAM, and I see no other access to FLASH being made.
This happens whether I try to transmit data from RAM to I2C or receive data from I2C to RAM.
Do you guys have any other lead as to why it fails ?
Do you think DMA write to flash could solve the problem as DMA arbiter should handle concurrency between FLASH and RAM/Peripheral writes ?
2022-10-12 12:32 PM
Your IRQ code doesn't call any functions that are in FLASH? What about your main code that starts the FLASH write operation. If THAT is running from FLASH it will stall the CPU and no IRQ can run even if the IRQ code is in RAM.
2022-10-13 06:49 AM
The IRQ doesn't call any functions in FLASH. It checks which I2C flag has been raised by the IRQ and then calls a callback function attached at initialization (the callback function is in RAM). By this point, the flag should have already been cleared and clock stretching lifted.
I tried putting all the main function and the functions called in the main loop in RAM but it didn't yield any results. Previously only the functions in the main loop were in RAM because as I understand it, it should not be necessary to put all the main function in RAM.
The hard reset built into the I2C clock line is quite troublesome because it means I lose the context and can't really check flags with a debugger.