Hello,
I want to load multiple applications onto my NUCLEO-F429ZI. This is for a production product.
The program at 0x08000000 will be a bootloader that decides whether to run the application in partition A or B. These are as follows:
Partition A will be the backup application that is field tested and guaranteed to work.
Partition B will be the beta application
The bootloader should run the program in partition B. If it faults, it will switch to partition A (I still have to figure out how to do this - for another day). To be clear, I am trying to figure out how to place the three separate applications (bootloader/A/B) at once. I have looked around for a solution, but these do not directly answer my question:
www.keil.com/.../ stackoverflow.com/.../running-multiple-applications-in-stm32-flash electronics.stackexchange.com/.../stm32f091-jump-to-bootloader-from-application
** I think I just answered my own question. It is unlikely you can place three applications at once, I will just flash the board three times and change the IROM1 value in settings.
Thank you
My suggested strategy of changing the IROM1 location is wrong. It just places the application at the new location and leaves 0x08000000 empty. The search continues...
You should stop and reconsider the way you plan to get this work. In order to get this done, you need a separate project per program type (bootloader, application A and B). Each must have a unique linker script, determining a unique entry point and vector table. Do not fiddle with IROM1 - use a linker script instead! In addition to that, you will need a variable/RAM location, defined in the bootloader, indicating whether application B failed - such a variable must not be initialized to 0 upon startup of the bootloader (look up ZI and UNINIT elements in linker scripts).
Thank you Tamir, very helpful. I do not have much experience with linker scripts, but I will take the time to learn and report back.
Another import point of interest: In the bootloader, before jumping to application, disable the interrupts and clear the pending ones. In the application initialization procedure, remap the vector table - then enable the interrupts.
With respect to using the linker to select where the program goes, I would prefer to use the bootloader application at 0x08000000 to stream the incoming program to partition A/B. I have figured out how to erase/write flash using variables from SRAM, so all I have to do is give a starting address and it writes fine.
My question now is, what exactly do I write to "partition A" to get a working program. This runs along the lines of the question here stackoverflow.com/.../running-multiple-applications-in-stm32-flash. Is it as simple as sequentially writing all of the bytes seen in the hex file, and telling the bootloader application to jump to the starting address? For example, if this is my hex file in Intel Hex format and say my starting address is 0x08020000:
:020000040800F2 :1000000000000320F51E0008B1080008B30800082E :10001000B5080008B7080008B9080008000000008B :10002000000000000000000000000000BB08000805 :10003000BD08000800000000BF080008C108000853 :10004000451F0008451F0008451F0008451F000800 :10005000451F0008451F0008451F0008451F0008F0 :10006000451F0008451F0008451F0008451F0008E0
Should I just write: @0x08020000: 0x08 @0x08020001: 0x00 @0x08020002: 0x00 @0x08020003: 0x00 @0x08020004: 0x03 @0x08020005: 0x20 ... @0x0802xxxx: 0x08
Just having a hard time finding resources on this. I would prefer to learn this myself so if anyone can point me in the right direction it would be much appreciated.
The .hex file reflects where binary data should be placed in memory - any memory. Unless you need to write more than one type of memory, you could make you life much easier by converting the .hex file into a .bin type file and handling this one in the bootloader - which is basically the same program code/data content stripped on addressing data. This is useful if you always need to write your data to a constant address in memory. You can find many free programs to convert a .hex file to a binary. You could of course add parsing a .hex file in your program but that seems rather an overkill for simple cases.
Update: I am able to flash the program into Partition A (@address 0x8060000) and verify it with a CRC check. The program runs anything in while loop fine (LED3 toggling, UART); however, the LED2 toggling based off of a timer interrupt does not work. When I flash the program normally (ie not with my bootloader) it works 100%, including LED2 toggling.
Below I include the jump function/linker file for the bootloader application at 0x8000000 and the main.c/linker file for the application at 0x8060000:
@@@@@@@@@@@@@@@@@@@@ JUMP FUNCTION IN BOOTLOADER PROGRAM AT 0x8000000 @@@@@@@@@@@@@@@@@
void ApplicationManager::RunActivePartition() { JumpToApplication = (void (*)(void)) (*((uint32_t *) (active_partition.address + 4)));
/* Reset RCC clock configuration */ HAL_RCC_DeInit();
/* Disable and reset systick timer */ SysTick->CTRL= 0; SysTick->LOAD = 0; SysTick->VAL = 0;
/* Disable all interrupts */ __disable_irq();
/* Set vector table offset register */ SetVectorTable(MemoryInfo::BTLR_ADDRESS, MemoryInfo::PARTITION_A_OFFSET_FROM_BTLR);
/* STM32 needs the stack pointer to start at the beginning of ** the application in flash. This must happen last */ __set_MSP(*(uint32_t*) active_partition.address);
JumpToApplication();
/*************** Other things I have tried ***************/ /* Remap system memory */ // SYSCFG->MEMRMP = SYSCFG_MEMRMP_MEM_MODE_0; //
// /* Clear pending interrupts */ // uint32_t isrflags = READ_REG(huart->Instance->SR); // Clears some UART interrupt
/* Disable peripheral clocks */ // __HAL_RCC_GPIOA_CLK_DISABLE(); // __HAL_RCC_GPIOB_CLK_DISABLE(); // __HAL_RCC_GPIOC_CLK_DISABLE(); // __HAL_RCC_GPIOD_CLK_DISABLE(); // __HAL_RCC_GPIOG_CLK_DISABLE(); // __HAL_RCC_GPIOH_CLK_DISABLE();
// __HAL_UART_DISABLE(&huart3);
// __HAL_RCC_PWR_CLK_DISABLE();
/*************** What I want to add when more basic implementation works ***************/ // /* Relocate vector interrupt table to RAM */ // CopyVectorInterruptTable();
// /* TODO: Patch VIT with bootloader interrupt handlers (ex: hard fault handler) */ // PatchVectorInterruptTable();
// if (!CopyandPatchOkay()) // { // LOG_DEBUG("Vector interrupt table not probably copied and/or patched \n"); // } // else // { // LOG_DEBUG("Device ready to jump into application \n"); // } }
@@@@@@@@@@@@@@@@@@@@ LINKER FILE FOR APPLICATION (BOOTLOADER) 0x8000000 @@@@@@@@@@@@@@@@@
/* Highest address of the user mode stack */ _estack = 0x20010000; /* end of RAM */ /* Generate a link error if heap and stack don't fit into RAM */ _Min_Heap_Size = 0x200; /* required amount of heap */ _Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K }
@@@@@@@@@@@@@@@@@@@@@@@@ APPLICATION TO JUMP TO AT 0x8060000 @@@@@@@@@@@@@@@@@@@@
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim10) { HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin); } /* USER CODE END 0 */
/** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */
/* 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 */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART3_UART_Init(); MX_TIM10_Init(); /* USER CODE BEGIN 2 */ uint32_t count = 0; HAL_TIM_Base_Start_IT(&htim10); /* USER CODE END 2 */
/* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { for (uint32_t i=0; i < 100000; i++); HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin); _printf("Hi %d \n", count); count++; /* USER CODE END WHILE */
/* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }
@@@@@@@@@@@@@@@@@@@@ LINKER FILE FOR APPLICATION (BLINKY) 0x8060000 @@@@@@@@@@@@@@@@@
/* Specify the memory areas */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K FLASH (rx) : ORIGIN = 0x8060000, LENGTH = 1024K }
I posted on SO because of the poor formatting stackoverflow.com/.../interrupts-not-working-when-i-jump-to-application-stm32. I just realised I could have used "pre" to format the source code better sorry.
I see you are disabling interrupts in the bootloader. Are you ever enabling them again?