Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible bug when writing to flash using the EEPROM library (F7) #297

Closed
hasenbanck opened this issue Aug 9, 2018 · 9 comments · Fixed by #938
Closed

Possible bug when writing to flash using the EEPROM library (F7) #297

hasenbanck opened this issue Aug 9, 2018 · 9 comments · Fixed by #938
Assignees
Labels
bug 🐛 Something isn't working

Comments

@hasenbanck
Copy link
Contributor

Version used: Current HEAD + PR
Affected variant: RemRam v1

Currently I try to write some configuration values with the help of the EEPROM library to the flash.

Given this simple sketch:

#include <EEPROM.h>

void setup() {
	Serial.begin(115200);
	uint8_t v = EEPROM.read(0);
	if (v == 123) {
		Serial.println("Saved");
	} else {
		Serial.println("Wasn't saved");
		EEPROM.write(0, 123);
	}
}

void loop() {
	delay(15);
}

The flash won't safe the variable content. I tracked down the problem to the set_data_to_flash() function in stm32_eeprom.c.

HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) will return an HAL_ERROR and when debugging the error with HAL_FLASH_GetError(), I will receive a FLASH_ERROR_WRP error (FLASH Write protected error). SectorError contains a 0x17 (23).

Is there anything special I need to do when wanting to write to the flash when using a F7?

@fpistm
Copy link
Member

fpistm commented Aug 9, 2018

Hi @hasenbanck
You could use the STM32CubeProgrammer to check Write flash protection.

@hasenbanck
Copy link
Contributor Author

I will check the state of the write flash protection this evening when I'm back home. I can't remember having set it though. Could it be set by the factory? Maybe a side effect of using a J-Link programmer? Or maybe it just flipped by chance.

@hasenbanck
Copy link
Contributor Author

hasenbanck commented Aug 9, 2018

I just reset the option bytes and checked the write flash protection. They are not write protected.

One thing is curious: The SectorError points to sector 23, which is the last sector in double bank mode. But since the default (and my) configuration is single bank mode, the last sector should be 11.

Could this be a lead?

Edit: For fun I just edited the FLASH_SECTOR_TOTAL definition from 24 to 12 and changed some broken stuff, which enabled me to save top flash just fine. Either I was simply lucky, or we really select the wrong flash sector number.

@fpistm
Copy link
Member

fpistm commented Aug 9, 2018

Probably there is some issue(s) in the generic definition for F7.
Here:
https://github.com/stm32duino/Arduino_Core_STM32/blob/master/cores/arduino/stm32/stm32_eeprom.h#L54
or here:
https://github.com/stm32duino/Arduino_Core_STM32/blob/master/cores/arduino/stm32/stm32_eeprom.c#L81

FLASH_SECTOR_TOTAL is defined by our CMSIS. Hope It was not wrong :)
I think those part need some deep review.

@hasenbanck
Copy link
Contributor Author

I don't think it's a problem in the generic definition for the F7, since the page size and also the memory addresses seem right.

The CMSIS is not wrong about the total sector count, but only when using the double bank mode. Maybe we shouldn't use the FLASH_SECTOR_TOTAL definition in this case, since 24 is definitely wrong in the standard configuration.

@hasenbanck
Copy link
Contributor Author

hasenbanck commented Aug 10, 2018

Okay, let me structure my thoughts a little bit. As it seems to me right now, the HAL doesn't know how to handle SINGLE / DUAL BANK MODE for the flash. As far as I can see inside the stm32f4xx_hal_flash_ex.h and the CMSIS files of the F76xxx and F77xxx, they used the total value of the flash sectors in dual bank mode.

Information about that mode can be found here.

The stm32f4xx_hal_flash_ex.h and the stm32f7xx_hal_flash_ex.h then use those values to define the available sector, that later the HAL will use in his FLASH module. There we currently haven't defined the sectors for the default 12 sectors in single bank mode.

In my case, the HAL will later try to erase the sector 23 of the flash (last), which of course wouldn't work, since offset and size are different from the sector 11 in single bank mode.

So as a work around, people could activate the two bank mode for the flash on the affected systems, but since you lose easy accessible uniform flash memory, that might not be a good option in the long term.

A better fix would be, to let the HAL become aware of the single / double memory bank configuration of those systems and let the user configure, which mode he wants the HAL to use (with single bank mode as the default, since it's the factory default).

So right now we would need:

  • A configuration switch in the stm32f4xx_hal_conf.h and stm32f7xx_hal_conf.h to select either single or dual bank mode.
  • Defining the FLASH_SECTOR_TOTAL based on this configuration switch (in the CMSIS files for the STM32F7 and the stm32f4xx_hal_flash_ex.h for the STM32f4)
  • Define the sectors in case of the FLASH_SECTOR_TOTAL == 12 in the stm32f4xx_hal_flash_ex.h and stm32f7xx_hal_flash_ex.h

@fpistm
Copy link
Member

fpistm commented Aug 10, 2018

Ok looking deeply this and found that it should be possible to know if we are in Single or Dual Bank.
At least for F7:

#if defined (FLASH_OPTCR_nDBANK)
/** @defgroup FLASHEx_Option_Bytes_nDBank FLASH Single Bank or Dual Bank
  * @{
  */
#define OB_NDBANK_SINGLE_BANK      ((uint32_t)0x20000000U) /*!< NDBANK bit is set : Single Bank mode */
#define OB_NDBANK_DUAL_BANK        ((uint32_t)0x00000000U) /*!< NDBANK bit is reset : Dual Bank mode */
/**
  * @}
  */
#endif /* FLASH_OPTCR_nDBANK */

So F7 HAL provide (if FLASH_OPTCR_nDBANK defined):

/**
  * @brief  Return the FLASH User Option Byte value.
  * @retval uint32_t FLASH User Option Bytes values: WWDG_SW(Bit4), IWDG_SW(Bit5), nRST_STOP(Bit6), 
  *         nRST_STDBY(Bit7), IWDG_STDBY(Bit30) and IWDG_STOP(Bit31).
  */
static uint32_t FLASH_OB_GetUser(void)
{
  /* Return the User Option Byte */
  return ((uint32_t)(FLASH->OPTCR & 0xF00000F0U));
}

Then it would be possible to know the correct config, something like that.
if Single:
FLASH_DATA_SECTOR --> ((uint32_t)(FLASH_SECTOR_TOTAL/2 - 1))
else /dual/
FLASH_DATA_SECTOR --> ((uint32_t)(FLASH_SECTOR_TOTAL - 1))

For F4 I didn't find any stuff like for F7. I have to check how to handle or if this is planned to add thoses API.

@hasenbanck
Copy link
Contributor Author

Yeah of course, you could read out the option byte and then set the data sector you want to use based on that information. Didn't thought about doing it that way. That would work and wouldn't require a rework on the HAL/CMSIS level.

@fpistm fpistm self-assigned this Sep 20, 2018
@fpistm fpistm added the bug 🐛 Something isn't working label Sep 20, 2018
@ABOSTM ABOSTM assigned ABOSTM and unassigned fpistm Feb 12, 2020
ABOSTM added a commit to ABOSTM/Arduino_Core_STM32 that referenced this issue Feb 13, 2020
Default configuration for F76xx and F77xx chip is single bank.
But HAL define FLASH_SECTOR_TOTAL doesn't represent the real number of sector,
but the maximum number of sector (for single and dual bank).
So for variants using F76xx and F77xx chip,
we must define FLASH_BASE_ADDRESS and FLASH_DATA_SECTOR according to default sector number.

Variant concerned: NUCLEO_F767ZI and REMRAM

Fixes stm32duino#297
ABOSTM added a commit to ABOSTM/Arduino_Core_STM32 that referenced this issue Feb 13, 2020
Default configuration for F76xx and F77xx chip is single bank.
But HAL define FLASH_SECTOR_TOTAL doesn't represent the real number of sector,
instead, it represents the maximum number of sectors (for single and dual bank).
So for variants using F76xx and F77xx chip,
we must define FLASH_BASE_ADDRESS and FLASH_DATA_SECTOR in order to use the last sector of the flash corresponding to the default single bank configuration.

Variants concerned: NUCLEO_F767ZI and REMRAM

Fixes stm32duino#297
@ABOSTM
Copy link
Contributor

ABOSTM commented Feb 13, 2020

Hi @hasenbanck,
After investigations across all STM32 series it is difficult to found a generic way to handle this single/dual bank configuration:

  • Some chip support only single bank. Ex: STM32F0x1
  • Some chips support only dual bank. Ex: H7
  • Some chip are single bank / dualbank depending on the Flash size (so it is not configurable). Ex F103B 1MB dual bank; F103 512KB single bank
  • Some chip are configurable... but configuration capability depend on Flash size: L4x6 1MB support only dualbank; wheras L4x6 512kB is configurable
  • Most of the chip double sector number switching from singlebank to dual bank,
    but there are exceptions: ex F42x 1Mbytes single bank 12 sectors; dualbank 20 sectors
  • Some can be configured with OptionByte: DUALBANK (or nDBANK)
  • Some can be configured with OptionByte: DB1M
  • Some can be configured with OptionByte: DUALBANK or DB1M depending on flash size (L4R)

In brief this is a nightmare to found a way to management single/dual bank configuration.
As a consequence we propose to keep it simple:

You are right, as per F76xxx and F77xxx Reference Manual: https://www.st.com/content/ccc/resource/technical/document/reference_manual/group0/96/8b/0d/ec/16/22/43/71/DM00224583/files/DM00224583.pdf/jcr:content/translations/en.DM00224583.pdf
default configuration is single bank.
But HAL define FLASH_SECTOR_TOTAL doesn't represent the real number of sector but the maximum number of sector (for single and dual bank).
So for variants using F76xx and F77xx chip, we must define FLASH_BASE_ADDRESS and FLASH_DATA_SECTOR according to default sector number.
PR proposed: #938

fpistm pushed a commit that referenced this issue Feb 14, 2020
Default configuration for F76xx and F77xx chip is single bank.
But HAL define FLASH_SECTOR_TOTAL doesn't represent the real number of sector,
instead, it represents the maximum number of sectors (for single and dual bank).
So for variants using F76xx and F77xx chip,
we must define FLASH_BASE_ADDRESS and FLASH_DATA_SECTOR in order to use the last sector of the flash corresponding to the default single bank configuration.

Variants concerned: NUCLEO_F767ZI and REMRAM

Fixes #297
Bmooij pushed a commit to Bmooij/Arduino_Core_STM32 that referenced this issue Jul 14, 2020
…duino#938)

Default configuration for F76xx and F77xx chip is single bank.
But HAL define FLASH_SECTOR_TOTAL doesn't represent the real number of sector,
instead, it represents the maximum number of sectors (for single and dual bank).
So for variants using F76xx and F77xx chip,
we must define FLASH_BASE_ADDRESS and FLASH_DATA_SECTOR in order to use the last sector of the flash corresponding to the default single bank configuration.

Variants concerned: NUCLEO_F767ZI and REMRAM

Fixes stm32duino#297
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants