AnsweredAssumed Answered

STM32L1xx SPL 1.3.0: Bug - FLASH_OB_RDPConfig clobbers SPRMOD

Question asked by Phil Pemberton on Dec 17, 2014

In stm32l1xx_flash.c, there is a function


which is used to enable program memory read protection. Per RM0038 ( the upper byte of option word 0x1FF80000 is used to store the SPRMOD bit:

Bits [31:25]: reserved must be set to 1

Bit 24: nSPRMOD

Bits [23:16]: nRDP

Bits [15:9]: reserved must be reset to 0

Bit 8: SPRMOD: sector protection mode selection

0: WRPx[i]=1 bit defines sector write protection

1: WRPx[i]=0 bit defines sector write and read (PCROP) protection.

See Section 3.7.4: PCROP for details.

Bits [7:0]: RDP: Read protection option byte (stored in FLASH_OBR[22:16])

The read protection is used to protect the software code stored in Flash memory.

0xAA: Level 0, no protection

0xCC: Level 2, chip protection (debug and boot in SRAM features disabled)

Others: Level 1, read protection of memories (debug features limited)

After executing the above function with OB_RDP_Level_1, the config word is set to 0x004400BB, which is invalid (SPRMOD clear with nSPRMOD also clear).

The function as presented in stm32l1xx_flash.c does not take into account the current setting of the SPRMOD bit, and will always set SPRMOD - this may not be what the user wants.

To correct the function, change it to look like this:

  * @brief  Enables or disables the read out protection.
  * @note   To correctly run this function, the FLASH_OB_Unlock() function
  *         must be called before.
  * @param  FLASH_ReadProtection_Level: specifies the read protection level.
  *   This parameter can be:
  *     @arg OB_RDP_Level_0: No protection
  *     @arg OB_RDP_Level_1: Read protection of the memory
  *     @arg OB_RDP_Level_2: Chip protection
  *  !!!Warning!!! When enabling OB_RDP_Level_2 it's no more possible to go back to level 1 or 0
  * @retval FLASH Status: The returned value can be:
FLASH_Status FLASH_OB_RDPConfig(uint8_t OB_RDP)
  FLASH_Status status = FLASH_COMPLETE;
  uint16_t tmp1 = 0;
  uint32_t tmp2 = 0;
  /* Check the parameters */
  status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
  /* calculate the option byte to write */
  tmp1 = (~((uint32_t)OB_RDP) & 0xFF) | ((~OB->RDP) & 0xFF00);
  tmp2 = (uint32_t)(((uint32_t)((uint32_t)(tmp1) << 16)) | ((uint32_t)OB_RDP));
  if(status == FLASH_COMPLETE)
   /* program read protection level */
    OB->RDP = tmp2;
  /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
  /* Return the Read protection operation Status */
  return status;           

Note that tmp1 is now a uint16_t, and the assignment to it has been changed to take the existing PCROP byte setting into account.