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
'Firmware > stm32' 카테고리의 다른 글
STM32 SPI Slave 동작 시 데이터 송수신 이상 현상 (0) | 2020.10.14 |
---|---|
STM32 SPI Slave로 Interrupt DMA Transmit/Receive 구현하기 (1) | 2020.07.24 |
STM32 IAP (Ymodem 프로토콜) Bootloader - 2 (0) | 2020.07.02 |
STM32 IAP (Ymodem 프로토콜) Bootloader - 1 (1) | 2020.06.29 |
FSMC HAL_SRAM_Write_16b Bug 문제 (0) | 2020.06.13 |