on 2022-06-22 05:58 AM
int main(void) { /* USER CODE BEGIN 1 */ FLASH_OBProgramInitTypeDef OptionsBytesStruct; uint16_t adc_value; /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ HAL_FLASHEx_EnableDebugger(); /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART2_UART_Init(); MX_ADC1_Init(); /* USER CODE BEGIN 2 */Then, the code will configure the ADC to read the voltage reference and apply a simple check if the voltage is above a certain level, if it is, then it will move forward. This portion of the code is just a pseudo implementation:
/* USER CODE BEGIN 2 */ // ADC enable - to measure Vref. // Vref is internally connected to Vin[13]. Vref is used to calculate the Vpower level // and use that information to disable Option Bytes update. // ADC runs on IN RCC->CCIPR |= 0x80000000; // Select ADC clock = HSI16. RCC->APBENR2 |= 0x00100000; // Enable ADC clock ADC->CCR |= 0x00400000; // Enable Vref - set BEFORE enabling ADC ADC1->CR |= 0x000000001; // Enable ADC while ((ADC1->ISR & 0x00000001) != 0x00000001) { // While ADC is NOT ready = loop..... ; } ADC1->SMPR = 0x00000077; // Sample time (160.5 cycles) ADC1->CHSELR |= 0x00002000; // Select Channel 13 (Vref) ADC1->CR |= 0x00000004; // Start conversion // Here we are about to make a decision whether to update the Option Byte // Based on the Power Supply Voltage while ((ADC1->ISR & 0x00000004) != 0x00000004) { // While ADC conversion is NOT completed loop..... ; } adc_value = ADC1->DR; // Read ADC if (adc_value > 1712) // 1712 for Vss ~2.9V { // Vss too low // Progress indicator: ADC Error: Vss too low. // Skip the update! }Once the basic features are passed, the firmware checks and prints any flags that were previously set and ensures that all reset and clock control flags are cleared.
if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) { printf("IWDG flag\r\n"); } if (__HAL_RCC_GET_FLAG(RCC_FLAG_OBLRST)) { printf("OBL flag\r\n"); } __HAL_RCC_CLEAR_RESET_FLAGS(); printf("clear all RCC flags\r\n");The next step is to verify the RDP level and, in case it is set to level 1, the code waits for the blue button to be pressed and released before progressing to the RDP regression.
HAL_FLASHEx_OBGetConfig(&OptionsBytesStruct); if(OptionsBytesStruct.RDPLevel == OB_RDP_LEVEL_1) { printf("RDP LVL1 \r\n"); printf("wait BT1 to be pressed\r\n"); while(HAL_GPIO_ReadPin(BT1_GPIO_Port, BT1_Pin) == GPIO_PIN_SET) { ; } printf("wait BT1 to be released\r\n"); while(HAL_GPIO_ReadPin(BT1_GPIO_Port, BT1_Pin) == GPIO_PIN_RESET) { ; } while(HAL_FLASH_Unlock() != HAL_OK) { printf("Waiting Flash Unlock\r\n"); } while(HAL_FLASH_OB_Unlock() != HAL_OK) { printf("Waiting OB Unlock\r\n"); } printf("RDP regression LV0 init\r\n"); RDP_Regression(); }In case it is not RDP level 1, the code will also enter in the main loop and wait for the key to be pressed to execute a code that changes a few option bytes, including the RDP to level 1 and the nBOOT selection.
/* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ printf("\033[96mPress BT1 to change Option Bytes\033[0m \r\n"); if(HAL_GPIO_ReadPin(BT1_GPIO_Port, BT1_Pin) == GPIO_PIN_RESET) { printf("BT1 pressed\r\n"); while(HAL_FLASH_Unlock() != HAL_OK) { printf("Waiting Flash Unlock\r\n"); } while(HAL_FLASH_OB_Unlock() != HAL_OK) { printf("Waiting OB Unlock\r\n"); } OptionsBytesStruct.OptionType = OPTIONBYTE_USER | OPTIONBYTE_RDP ; //Configure USER and RDP OptionsBytesStruct.USERType = OB_USER_nBOOT_SEL; OptionsBytesStruct.USERConfig = OB_BOOT0_FROM_PIN;//Set to boot from pin (UART) OptionsBytesStruct.RDPLevel = OB_RDP_LEVEL_1; while(HAL_FLASHEx_OBProgram(&OptionsBytesStruct) != HAL_OK) { printf("Waiting OB Program\r\n"); } printf("OB Boot0 is now Boot From Pin and RDP 1\r\n"); SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT); while((FLASH->SR & FLASH_SR_BSY1) != 0) { ; }To ensure the programming and load of the option bytes the two methods are implemented -- the OBL_LAUNCH and also the IWDG with standby entry, which wakes up due to the IWDG and forces a power reset, so both methods are shown for demonstration purposes.
printf("OBLauch\r\n"); MX_IWDG_Init(); while( HAL_FLASH_OB_Launch()!= HAL_OK) { printf("OBLauch Failed..retry with IWDG and StandBy Mode\r\n"); HAL_PWR_EnterSTANDBYMode(); } }A simple LED and print messages are also present to guide the process if the key is not pressed, executing in the main loop as well
void ToggleLED(void) { if(HAL_GPIO_ReadPin(LED_GREEN_GPIO_Port, LED_GREEN_Pin)) { printf("\033[5;32mLED\033[0m \r\n"); HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_RESET); } else { printf("\033[1;32mLED\033[0m \r\n"); HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_SET); } HAL_Delay(2000); }An additional detail is how the RDP works, so please refer to this image for a quick explanation:
void __attribute__((__section__(".RamFunc"))) RDP_Regression(void) { __disable_irq(); printf("Mass Erase Start\r\n"); FLASH->KEYR = FLASH_KEY1; FLASH->KEYR = FLASH_KEY2; FLASH->OPTKEYR = FLASH_OPTKEY1; FLASH->OPTKEYR = FLASH_OPTKEY2; /* Force readout protection level 0 */ FLASH->OPTR = OPTION_BYTE_TARGET_VALUE; FLASH->CR |= FLASH_CR_OPTSTRT; while((FLASH->SR & FLASH_SR_BSY1) != 0) { ; } /* Force OB Load */ FLASH->CR |= FLASH_CR_OBL_LAUNCH; }Conclusion:
How does one get at option bytes setting via the STM32Cube_Prog CLI ?
�?次选项字节首先在用户存储区域�?�动时;�?�设我�?置的字节高低级�?置字节都改�?了系统引导加载程�?的起始地�?�,�?能回退,怎么办?
�?次选项字节首先在用户内存中�?�动时;�?�设我将�?置字节的选项字节高低电平更改为系统引导加载程�?的起始地�?�,但无法回退,如何处�?�呢?
Hi @JMrow.1 ,
These are the usual steps:
You can find all acronym in the STM32CubeProg user manual> https://www.st.com/resource/en/user_manual/um2237-stm32cubeprogrammer-software-description-stmicroelectronics.pdf