본문 바로가기

Firmware/stm32

STM32 Bootloader 메뉴 FLASH_If_WriteProtectionConfig 문제

cubeMX : 5.6.1
cubeIDE : 1.3.1

Code Lib Version : STM32Cube_FW_F1_V1.8.0

MCU:STM32F103VBTx

 

 

 

Enable the write protection 을 실행 시 Lock 이 이상하게 안 걸리는 문제가 있는데 예제가 잘못되어 있다.

 

우선, 4번을 눌렀을 시 protection 기능이 동작 하는데 예제에 있는 코드를 FlashProtection 함수로 정리 하였다.

void FlashProtection(void)
{
  if (Flash_Protection != FLASHIF_PROTECTION_NONE)
  {
    /* Disable the write protection */
    if (FLASH_If_WriteProtectionConfig(OB_WRPSTATE_DISABLE) == HAL_OK)
    {
      Serial_PutString((uint8_t*) "Write Protection disabled...\r\n");
      Serial_PutString((uint8_t*) "System will now restart...\r\n");
      /* Launch the option byte loading */
      HAL_FLASH_OB_Launch();
      /* Ulock the flash */
      HAL_FLASH_Unlock();
    }
    else
    {
      Serial_PutString((uint8_t*) "Error: Flash write unable-protection failed...\r\n");
    }
  }
  else
  {
    if (FLASH_If_WriteProtectionConfig(OB_WRPSTATE_ENABLE) == HAL_OK)
    {
      Serial_PutString((uint8_t*) "Write Protection enabled...\r\n");
      Serial_PutString((uint8_t*) "System will now restart...\r\n");
      /* Launch the option byte loading */
      HAL_FLASH_OB_Launch();
    }
    else
    {
      Serial_PutString((uint8_t*) "Error: Flash write protection failed...\r\n");
    }
  }

}

 

함수를 살펴 보면 Flash_Protection 변수가 Flash_protection 이 Flashif_protection_none 과 일치 하지 않으면 Flash Lock이 걸려있는 것으로 판단하고 Disable 해주고 그렇지 않으면 Flash Lock 을 걸어 준다.

 

Flash_protection 변수는  Main Menu 출력 하기 전 Flash_If_GetWriteProtectionStatus 함수를 통해 값을 읽어 온다.

 

 

Main_Menu 함수 중 일부. (while 문에서 Flash_Protection 변수 값을 읽어 온다.)

  while (1)
  {

    /* Test if any sector of Flash memory where user application will be loaded is write protected */
    Flash_Protection = FLASH_If_GetWriteProtectionStatus();
    /* Flash_Protection 값을 읽어와서 Lock or unLock 인지 판단한다  */

    Serial_PutString(
        (uint8_t*) "\r\n=================== Main Menu ============================\r\n\n");
    Serial_PutString((uint8_t*) "  Download image to the internal Flash ----------------- 1\r\n\n");
    Serial_PutString((uint8_t*) "  Upload image from the internal Flash ----------------- 2\r\n\n");
    Serial_PutString((uint8_t*) "  Execute the loaded application ----------------------- 3\r\n\n");
    if (Flash_Protection != FLASHIF_PROTECTION_NONE)
    {
      Serial_PutString(
          (uint8_t*) "  Disable the write protection ------------------------- 4\r\n\n");
    }
    else
    {
      Serial_PutString(
          (uint8_t*) "  Enable the write protection -------------------------- 4\r\n\n");
    }
    /* FLASH_WRITE_ADDRESS 값이 0x08006000이 아니라면 */
    if (FLASH_If_Read_32bit(FLASH_WRITE_ADDRESS) != APPLICATION_ADDRESS0)
    {
      Serial_PutString((uint8_t*) "  application address : 0x08006000 (ver.0) \r\n\n");
      Serial_PutString((uint8_t*) "  Next Download address : 0x0800A000 (ver.1)\r\n\n");
    }
    else
    {
      Serial_PutString((uint8_t*) "  application address : 0x0800A000 (ver.1)\r\n\n");
      Serial_PutString((uint8_t*) "  Next Download address : 0x08006000 (ver.0)\r\n\n");
    }
    Serial_PutString((uint8_t*) "==========================================================\r\n\n");

 

문제는 FLASH_If_WriteProtectionConfig 코드가 잘못 되어있어 제대로 동작하지 않는다.

 

FLASH_If_WriteProtectionConfig 함수를 살펴 보자.

uint32_t FLASH_If_WriteProtectionConfig(uint32_t protectionstate)
{
  uint32_t ProtectedPAGE = 0x0;
  FLASH_OBProgramInitTypeDef config_new, config_old;
  HAL_StatusTypeDef result = HAL_OK;
  

  /* Get pages write protection status ****************************************/
  HAL_FLASHEx_OBGetConfig(&config_old);

  /* The parameter says whether we turn the protection on or off */
  config_new.WRPState = (protectionstate == FLASHIF_WRP_ENABLE ? OB_WRPSTATE_ENABLE : OB_WRPSTATE_DISABLE);

  /* We want to modify only the Write protection */
  config_new.OptionType = OPTIONBYTE_WRP;
  
  /* No read protection, keep BOR and reset settings */
  config_new.RDPLevel = OB_RDP_LEVEL_0;
  config_new.USERConfig = config_old.USERConfig;  
  /* Get pages already write protected ****************************************/
  
  //Lock or unlock 할 Page를 구한다.
  ProtectedPAGE = config_old.WRPPage | FLASH_PAGE_TO_BE_PROTECTED;

  /* Unlock the Flash to enable the flash control register access *************/ 
  HAL_FLASH_Unlock();

  /* Unlock the Options Bytes *************************************************/
  HAL_FLASH_OB_Unlock();
  
  /* Erase all the option Bytes ***********************************************/
  result = HAL_FLASHEx_OBErase();
    
  if (result == HAL_OK)
  {
    config_new.WRPPage    = ProtectedPAGE;    //Lock 걸어야할 PAGE를 저장한다.
    result = HAL_FLASHEx_OBProgram(&config_new);
  }
  
  return (result == HAL_OK ? FLASHIF_OK: FLASHIF_PROTECTION_ERRROR);
}

 

FlashProtection 함수에서 살펴 보았듯이 FLASH_If_WriteProtectionConfig에서 Lock -> unlock 또는 unlock -> lock을

걸어 줘야 하는데  판단해서 작업하는 조건이 잘못 되었다.

 

 config_new.WRPState = (protectionstate == FLASHIF_WRP_ENABLE ? OB_WRPSTATE_ENABLE : OB_WRPSTATE_DISABLE);

 

위 코드를 보면 protectionstate가 FLASHIF_WRP_ENABLE 이면 이제 DISABLE 을 해줘야 하는데 ENABLE을 한다

 

따라서 다음과 같이 수정한다.

 

config_new.WRPState = (protectionstate == FLASHIF_WRP_DISABLE ? OB_WRPSTATE_ENABLE : OB_WRPSTATE_DISABLE);

 

FLASH LOCK이 걸려 있으면 ? -> OB_WRPSTATE_DISABLE;

FLASH LOCK 이 걸려 있지 않으면 ? -> OB_WRPSTATE_ENABLE;

 

 

다음 잘못된 코드는 Page에 lock 연산이 잘못되어있다.

 

ProtectedPAGE = config_old.WRPPage | FLASH_PAGE_TO_BE_PROTECTED;

 

아래 디버깅을 value 사진에도 보이듯이 

 

연산에서 or 연산을 하는데 WRPPage의 초기 값은 항상 0xff 값인데 or 연산을 하는 의미가 없다.

 

따라서 코드를 다음과 같이 수정해준다.

 

ProtectedPAGE = config_old.WRPPage & FLASH_PAGE_TO_BE_PROTECTED;

 

 

FLASH_PAGE_TO_BE_PROTECTED는 다음과 같이 설정 되어있다.

(24 ~ 39 Page)

#define FLASH_PAGE_TO_BE_PROTECTED (OB_WRP_PAGES24TO27  | OB_WRP_PAGES28TO31 | OB_WRP_PAGES32TO35 | OB_WRP_PAGES36TO39)

//#define OB_WRP_PAGES0TO3               0x00000001U /*!< Write protection of page 0 to 3 */
//#define OB_WRP_PAGES4TO7               0x00000002U /*!< Write protection of page 4 to 7 */
//#define OB_WRP_PAGES8TO11              0x00000004U /*!< Write protection of page 8 to 11 */
//#define OB_WRP_PAGES12TO15             0x00000008U /*!< Write protection of page 12 to 15 */
//#define OB_WRP_PAGES16TO19             0x00000010U /*!< Write protection of page 16 to 19 */
//#define OB_WRP_PAGES20TO23             0x00000020U /*!< Write protection of page 20 to 23 */
//#define OB_WRP_PAGES24TO27             0x00000040U /*!< Write protection of page 24 to 27 */
//#define OB_WRP_PAGES28TO31             0x00000080U /*!< Write protection of page 28 to 31 */
//#define OB_WRP_PAGES32TO35             0x00000100U /*!< Write protection of page 32 to 35 */
//#define OB_WRP_PAGES36TO39             0x00000200U /*!< Write protection of page 36 to 39 */

컴파일 후

 

실행해 보면 Lock 이 정상적으로 걸려있는걸 확인 할 수 있다.

 

Page 24 ~ 39 Loc