DISCO_L072CZ_LRWAN1: EEPROM write failed

20 Feb 2019

EEPROM write snippet

HAL_StatusTypeDef writeEEPROMByte(uint32_t address, uint8_t data)
 {
    HAL_StatusTypeDef  status;
    address = address + 0x08080000;
    HAL_FLASHEx_DATAEEPROM_Unlock();  
    status = HAL_FLASHEx_DATAEEPROM_Program(TYPEPROGRAMDATA_BYTE, address, data);
    HAL_FLASHEx_DATAEEPROM_Lock(); 
    return status;
}

The above snippet leads to hard-fault handler after HAL_FLASHEx_DATAEEPROM_Program api.

Source code: mbed import mbed-os-example-lorawan

I edited main.cpp and add below lines before calling the lorawan initialization function,

EEPROM write call from main.cpp

HAL_StatusTypeDef writeEEPROMByte(uint32_t address, uint8_t data)
 {
    HAL_StatusTypeDef  status;
    address = address + 0x08080000;
    HAL_FLASHEx_DATAEEPROM_Unlock();
    status = HAL_FLASHEx_DATAEEPROM_Program(TYPEPROGRAMDATA_BYTE, address, data);
    HAL_FLASHEx_DATAEEPROM_Lock();  
    return status;
}
int main (void)
{
    writeEEPROMByte(0, 0x05);
    /*followed by lorawan apis*/
}

When I compiled and flashed the binary to the MCU, it entered in hard-fault handler.

hard-fault handler line

*(__IO uint8_t *)Address = (uint8_t) Data;

How do I resolve the hard-fault problem?

Note: EEPROM is working good with I-CUBE-LRWAN firmware (I mean without MBED OS). I don't see any problem with the snippet.

05 Mar 2019

HI Nishanth, we are having a similar issue and our first conclusion is also problem with mbed 5.11. We haven't found the exact cause yet. What is your progress here?

26 Mar 2019

Hi,

Same problem here on DISCO-L072CZ-LRWAN1 and on NUCLEO-L073RZ using the codes from stm32l0xx_hal_flash_ex.c:

Unlocking EEPROM from stm32l0xx_hal_flash_ex.c

/**
  * @brief  Unlocks the data memory and FLASH_PECR register access.
  * @retval HAL_StatusTypeDef HAL Status
  */
HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Unlock(void)
{
  if((FLASH->PECR & FLASH_PECR_PELOCK) != RESET)
  {  
    /* Unlocking the Data memory and FLASH_PECR register access*/
    FLASH->PEKEYR = FLASH_PEKEY1;
    FLASH->PEKEYR = FLASH_PEKEY2;
  }
  else
  {
    return HAL_ERROR;
  }
  return HAL_OK;  
}

and

Writing to EEPROM from stm32l0xx_hal_flash_ex.c

/**
  * @brief  Program word at a specified address
  * @note   To correctly run this function, the @ref HAL_FLASHEx_DATAEEPROM_Unlock() function
  *         must be called before.
  *         Call the @ref HAL_FLASHEx_DATAEEPROM_Unlock() to he data EEPROM access
  *         and Flash program erase control register access(recommended to protect 
  *         the DATA_EEPROM against possible unwanted operation).
  * @note   The function @ref HAL_FLASHEx_DATAEEPROM_EnableFixedTimeProgram() can be called before 
  *         this function to configure the Fixed Time Programming.
  * @param  TypeProgram  Indicate the way to program at a specified address.
  *         This parameter can be a value of @ref FLASHEx_Type_Program_Data
  * @param  Address  specifie the address to be programmed.
  * @param  Data     specifie the data to be programmed
  * 
  * @retval HAL_StatusTypeDef HAL Status
  */

HAL_StatusTypeDef   HAL_FLASHEx_DATAEEPROM_Program(uint32_t TypeProgram, uint32_t Address, uint32_t Data)
{
  HAL_StatusTypeDef status = HAL_ERROR;
  
  /* Process Locked */
  __HAL_LOCK(&pFlash);

  /* Check the parameters */
  assert_param(IS_TYPEPROGRAMDATA(TypeProgram));
  assert_param(IS_FLASH_DATA_ADDRESS(Address));

  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
  
  if(status == HAL_OK)
  {
    /* Clean the error context */
    pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;

    if(TypeProgram == FLASH_TYPEPROGRAMDATA_WORD)
    {
      /* Program word (32-bit) at a specified address.*/
      *(__IO uint32_t *)Address = Data;
    }
    else if(TypeProgram == FLASH_TYPEPROGRAMDATA_HALFWORD)
    {
      /* Program halfword (16-bit) at a specified address.*/
      *(__IO uint16_t *)Address = (uint16_t) Data;
    }
    else if(TypeProgram == FLASH_TYPEPROGRAMDATA_BYTE)
    {
      /* Program byte (8-bit) at a specified address.*/
      *(__IO uint8_t *)Address = (uint8_t) Data;
    }
    else
    {
      status = HAL_ERROR;
    }

    if (status != HAL_OK)
    {
      /* Wait for last operation to be completed */
      status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
    }
  }

  /* Process Unlocked */
  __HAL_UNLOCK(&pFlash);

  return status;
}

as well as the codes from the RM0376 Reference manual:

Unlocking the data EEPROM and FLASH_PECR register code example

/* (1) Wait till no operation is on going */
/* (2) Check if the PELOCK is unlocked */
/* (3) Perform unlock sequence */
while ((FLASH->SR & FLASH_SR_BSY) != 0) /* (1) */
{
  /* For robust implementation, add here time-out management */
}
if ((FLASH->PECR & FLASH_PECR_PELOCK) != 0) /* (2) */
{
  FLASH->PEKEYR = FLASH_PEKEY1; /* (3) */
  FLASH->PEKEYR = FLASH_PEKEY2;
}

and

Write to data EEPROM code example

*(uint8_t *)(DATA_E2_ADDR+i) = DATA_BYTE;
*(uint16_t *)(DATA_E2_ADDR+j) = DATA_16B_WORD;
*(uint32_t *)(DATA_E2_ADDR) = DATA_32B_WORD;

I can read data from EEPROM but impossible to write to it.

I too get HardFault on instruction:

Program byte (8-bit) at a specified address.

*(__IO uint8_t *)Address = (uint8_t) Data;

All aforementioned codes from HAL and from Reference Manual work perfectly in mbed online-compiler (mbed OS 2) but generate HardFault in Mbed Studio (mbed OS 5).

Any help would be welcome. Thank you!

26 Mar 2019

Going through reported issues at https://github.com/ARMmbed/mbed-os/, I found one from yesterday which helped me temporarily solve my issue: https://github.com/ARMmbed/mbed-os/issues/10220.

As mentioned by user wmcelderry, a workaround is to use the ScopedRomWriteLock class (https://os.mbed.com/docs/mbed-os/v5.11/apis/scopedromwritelock.html#a67faf7dbfb06582208cf872122a521f5).

I tested it in MbedStudio and I can now write data to EEPROM on NUCLEO-L073RZ as well as on DISCO-L072CZ-LRWAN1. It seems like an acceptable solution until our problem gets fixed.