2016-06-20 02:21 PM
Hello Forum,
I've been reading on the forums about custom bootloaders stored in flash and I was wondering if there was another possibility (possibly because I want to avoid messing with stack pointers, reset vectors etc.) In my main app, I have a bootloader function, that copies the new app stored in external flash to processor flash. This bootloader function contains a number of inline functions to read from external flash and copy to processor flash. Checking the .map file, this bootloader function looks to be all located in one place. My thought process is to copy this bootloader function into RAM at say 0x20000100 and then jump to that address as shown below void CopyLoaderToRam(void) { // uint32_t *Ram = (uint32_t *)RAM_ADDR; char *Ram = (char *)RAM_ADDR;///////////// Byte Alignment test typedef void (*pFunction)(void); pFunction RunCode; ptr_bootloader_fn = &bootloader; // Find the address of the bootloader function. // memcpy(Ram, (void *)ptr_bootloader_fn, LOADER_FLASH_SIZE); // Copy bootloader into ram char *boot_byte; boot_byte = (char *)&bootloader; int i; for (i=0; i<= 4*LOADER_FLASH_SIZE; i++) { Ram[i] = *(boot_byte+i); } RunCode = (pFunction)Ram[1]; // ResetHandler (PC in second vector) RunCode(); } Well the first issue is it doesnt seem to work as I get a hard fault.My fears are that I am overwriting some necessary data in Ram or some alignment issue. I'm not sure. However, is it even technically feasible in the first place and if not, why? If it is a non-starter, I would rather know at this stage. Device is a STM32F051. Kind Regards Bob2016-07-04 02:57 AM
2016-07-04 05:46 AM
The linker is usually pretty good at detecting the dependencies and dead code.
You can either add the files it needs or you can make a monolithic file that has all the code you need in it.2016-07-14 02:24 PM
Hi Clive,
I created a standalone project and was able to compile, link and generate a standalone binary. From the binary I generated an array of const char, which was copied into ram in my main app as described earlier in this thread. I can run the bootloader function to just before I initialize the USART. After that it hardfaults. I've linked in all the usart dependencies and there are no errors. ArmLink --entry bootloader app_bootloader.o stm32f0_discovery.o stm32f0xx_flash.o stm32f0xx_misc.o system_stm32f0xx.o stm32f0xx_syscfg.o stm32f0xx_pwr.o stm32f0xx_gpio.o stm32f0xx_spi.o stm32f0xx_rcc.o stm32f0xx_usart.o usarts.o -o app_bootloader.axf Am I missing anything in the link command or can you explain why it hardfaults? Bob int8_t bootloader(void) { RCC_ClocksTypeDef RCC_Clocks; // Switch ON all clocks to the ports RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOF, ENABLE); // SysTick end of count event each 1ms RCC_GetClocksFreq(&RCC_Clocks); // return 22; //Value returned correctly to main app // Enable SYSCFG clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); // return 33; //Value returned correctly to main app // Initialize UART Usart1Init(); // // return 44; //Hard Fault Occurs at this point // SPI configuration ------------------------------------------------------ SPI_Config(); puts(''\rHello From Bootloader''); return 1; }2016-07-14 03:53 PM
Am I missing anything in the link command or can you explain why it hardfaults?
It Hard Faults because you do something, or jump somewhere, which the CPU objects too. Most likely an absolute address. I'm not sure of why it is necessary to guess. Do a disassembly of the generated code, review that, and step through the code with a debugger. Have a handler that outputs clear and specific failure information. FromELF can disassemble AXF or ELF files. The source doesn't really provide enough clarity about what is happening internally.2016-07-16 01:09 PM
Hi Clive,
Tried stepping through the code. However, the constant char array doesn't disassemble into assembly language instructions, so I cannot step through it. The bootloader needs access to spi flash and the usart1. Without access to these modules I am in hot water. Another thought I had was to have a separate loader module as part of my main app and load its object file into ram using the scatter file. I don't know if I will have any better success. Really stuck here, so all ideas greatly appreciated. Regards Bob2016-07-16 03:35 PM
Ok, but you can surely disassemble the stand-alone object you created, and you should be able to step the code and jump code in the disassembly via of the debugger. I have ZERO visibility into what you've created.
And yes, a far more practical approach is to let Keil built the whole loader as a stand-alone app with a vector table, etc, but instead of building it for 0x08000000 you set IROM to 0x20000000[0x4000] and IRAM to 0x20004000[0x1000] or whatever fits you specific M0 part. Then take the .HEX from the linker, create an include file arrayed version of it, and add some code to ''memcpy'' that into RAM and start it, ideally in the Reset_Handler path. Would perhaps take a couple of hours of my time to frame up and demonstrate.2016-07-18 01:05 AM
Hi Clive,
I would appreciate your help here. I've tried two different approaches so far1...I did build a standalone loader consisting of a number of functions to read from SPI flash and write to micro flash. However, I didn't have a vectot table included in the loader as the plan was was for the loader to copy the new app from SPI to address 0x80000000 (completely overwrite the original app). The new app should already contain the vector table so I'm wondering why I need one in the loader.Anyway I used a scatter file to set the partitions to IROM to 0x20000000[0x4000] and IRAM to 0x20004000[0x1000] as you suggested, but I get a linker error. From what I read the linker expects a startup.s file included in the project. Modifying the scatter file gives me a warning so I was able to generate a const char array, but the bottom line is...it is still not working.2...I also integrated the loader within the main app. In the scattr file, I place loader.o in the RAM region. When the main app boots up, I can see the address of the loader function are in RAM. When I call the loader it starts to erase the micro flash as expected. However, it only erase micro flash from 0x80000000 to 0x80003FFF and no more. The micro contains 256K flash so I would have expected all to be erased.I'm wondering id even though I have placed loader.o in RAM, are some of the flash functions I call still in Flash memory and haven't been loaded to RAMBasically Clive, I am learning a lot about bootloaders as I do this but there is still big gaps in my knowledge. so any help appreciated. If you want to move this offline that is OK with me.Bob2016-07-18 03:08 AM
I would use the vector table approach because its orders of magntude simpler than the way you insist on approaching this.
I could copy a monolithic block of code into RAM and execute it, but I would do so with a clear appreciation of what is going into it. At the moment you are fighting against how the processor and linker want to function, and without a sufficient depth of understanding of either. It is a battle you are going to lose.2016-07-18 05:14 AM
Hi Clive,
I'm all ears. Initially, I tried to use an approach I understood in my mind, but the details of implementing this are very difficult...I know I've lost the battle with my current stratagies. Up to now, I've had no dealing with bootloaders to now, so now that I've been through a lot of pain with it, if there is an easier way, I'm all for it.Now, at this stage, I would use the vector table approach if I understood it. Can you give me an indication of how to use it. The main app will be able to determine if an update is available and copy it to external SPI flash. Then the main app should then call the bootloaderMy main criteria with the loader is that I can add puts statements to the console for debugging, and be able to copy from SPI flash to micro flash.I have also a couple of basic questions I need to clear up.1...The original app resides at 0x80000000. Can I copy the new app completely over this address range. If not, why not?2...Based on the above answer, where should the new bootloader be stored (in flash or in Ram)?3...Can you explain the remapping of the vector table to RAM? Why is this required?Clive, I appreciate that these are silly questions, but if the vector table approach is a lot simpler, I'd like to use it.Do you have some basic steps that I can follow to implement this method?Bob2016-07-18 08:08 AM