Hello, everyone,
in the last few days I have been looking for a way for the ROM bootloader to copy to DTC RAM the binary I was building. In this regard you have probably seen some posts of mine and a colleague of mine. (http://tiny.cc/c8p90y and http://tiny.cc/l8p90y)
We have succeeded in the task, and here I want to explain how we did it. I know that probably there will be better and more direct ways, but this one is definitely a working one.
First of all, I'll start by describing our scenario, which involves having a project independent of MCUXpresso. The binary must be able to be built by makefile with the least possible use of external tools (hopefully none). Our Micro is i.MX RT1051
There are clues in the reference manual, but they are not conclusive.
For example:
Given what is written it might seem that the copy can only be made to OCRAM, but I believe that it can really happen in any destination. In fact here http://tiny.cc/22q90y there is an example to copy in SDRAM.
One of the things that is unclear is the position of the BOOT Header.
If you examine this image you will see that it seems that the entire Boot Header should be copied to the target memory. I haven't done much testing. I just saw that if it is not mapped to the target memory (and therefore not copied) it doesn't work, otherwise it does. Actually I still have several ideas for ways to try. I will do it in the future.
To simplify, we will start from an example provided by the SDK: led_blinky.
I imported the example keeping all the default settings:
Actually, for what we're going to do, it doesn't matter neither the library used, nor, for example, if the SDRAM is present or not (in my board there's no SDRAM), nor if the size of the flash is different.
Once you have imported the project, you need to change a linker setting.
This setting allows MCUXpresso to automatically create a linker script as similar as possible to the one we need.
So just build (Ctrl+B)
Once the building's over, you will find the created linker script in Debug directory:
you will need to edit this script to edit the line as shown in the following figure:
This causes the boot header to be mapped to RAM.
And another line to edit is:
You have to replace LOADADDR(.text) with LOADADDR(.boot_hdr). This is used to calculate the correct size of the image.
Then go back to the linker settings to uncheck Manage linker script
This makes MCUXpresso use the linker script just edited instead of overwriting it with a new one.
The last steps are more tricky: there is the need to edit a file provided by the SDK, which, in my opinion, is wrong.
The file is xip/fsl_flexspi_nor_boot.c
It's contents is:
And here is the IVT format:
if you try to follow the IMAGE_ENTRY_ADDRESS symbol you will see that it is defined as the address of the interrupt vectors. In my opinion this is wrong. According to the description of IVT format it should be the address of the ResetISR function.
Here is the Boot Data format:
In the fsl_flexspi_nor_boot.c Boot Data is populated with the address of the flash and the size of the flash. In my opinion this is wrong. Start field sould be in DTCM and length should be the actual size of the image.
Since I wanted to copy also boot header I modified the file as follows:
That's it.
I repeat that there are probably cleaner ways, where maybe you don't waste 8KB of the target memory for the boot header. However, this is a starting point.
Please let me know your feedback, comments, corrections and improvements.
best regards
Max
Hello world,
If you are using the imxrt1060 you need to set GPR_FLEXRAM_BANK_CFG to 0xaaaaaaaa so it uses the DTCM on the 1050 it is not cleared by the boot-loader. I have tried using the OCRAM on the 1050 and 1060 but cant seem to get it to work as the boot-loader seems to use the DTCM.
To configure ram banking I used the DCD. Although it is weird that the 1050 has the BANK_CFG set to 0x55555555 after the boot-loader exits and the 1060 sets it to 0.
Mabey some one can figure out how to boot into OCRAM and not DTC
Hi i cant seem to get this to work, could some one point me to an example git repo.
here is the ivt...
0001000 00d1 4120 231d 2000 0000 0000 0000 0000
0001010 5040 2000 1000 2000 0000 0000 0000 0000
0001020 ffff ffff ffff ffff ffff ffff ffff ffff
which is obviously wrong
Hello Massimiliano Cialdi,
Thanks for sharing this it is really helpful! Just one thing as heads-up for anyone who's using this approach. The modifications made to the linkerscript didn't take into consideration the initialized global variables, so if you have an initialized global variable you won't see the correct value on it. As a workaround, you can declare global variables but don't initialize them until you are on the main of your application.
I hope it helps!
Victor
Hi @victorjimenez,
yes it's true, you have to add the boot_hdr size as offset as below:
/* MAIN TEXT SECTION */
.text : ALIGN(4)
{
FILL(0xff)
__vectors_start__ = ABSOLUTE(.) ;
KEEP(*(.isr_vector))
/* Global Section Table */
. = ALIGN(4) ;
__section_table_start = .;
__data_section_table = .;
LONG((LOADADDR(.data) - LOADADDR(.text) + 0x2000) + __base_SRAM_ITC);
LONG( ADDR(.data));
LONG( SIZEOF(.data));
LONG((LOADADDR(.data_RAM2) - LOADADDR(.text) + 0x2000) + __base_SRAM_ITC);
LONG( ADDR(.data_RAM2));
LONG( SIZEOF(.data_RAM2));
LONG((LOADADDR(.data_RAM3) - LOADADDR(.text) + 0x2000) + __base_SRAM_ITC);
LONG( ADDR(.data_RAM3));
LONG( SIZEOF(.data_RAM3));
LONG((LOADADDR(.data_RAM4) - LOADADDR(.text) + 0x2000) + __base_SRAM_ITC);
LONG( ADDR(.data_RAM4));
LONG( SIZEOF(.data_RAM4));
__data_section_table_end = .;
__bss_section_table = .;
LONG( ADDR(.bss));
LONG( SIZEOF(.bss));
LONG( ADDR(.bss_RAM2));
LONG( SIZEOF(.bss_RAM2));
LONG( ADDR(.bss_RAM3));
LONG( SIZEOF(.bss_RAM3));
LONG( ADDR(.bss_RAM4));
LONG( SIZEOF(.bss_RAM4));
__bss_section_table_end = .;
__section_table_end = . ;
/* End of Global Section Table */
*(.after_vectors*)
*(.text*)
KEEP(*freertos*/tasks.o(.rodata*)) /* FreeRTOS Debug Config */
*(.rodata .rodata.* .constdata .constdata.*)
. = ALIGN(4);
} > SRAM_ITC AT> PROGRAM_FLASH
What an incredibly helpful post!
An additional thing that I needed to do to get it working was to add some linker flags:
-Wl,--undefined=hyperflash_config
-Wl,--undefined=image_vector_table
-Wl,--undefined=dcd_data
Without these flags, the linker was discarding all the boot info. (This was because the boot info was not referenced from 'main' and also was being compiled into some '.a' archive before being linked together into the binary.)
A good explanation is at cmake - GCC - how to tell linker not to skip unused sections - Stack Overflow .
As a side note, I didn't need to change the IVT's entry point to 'ResetISR' as described by Massimiliano. Booting worked both when I left it pointing at the interrupt vectors or changed it 'ResetISR'.
You can also try this tool, with this tool, You can flash bare image into various boot devices easily and don't need to care about headers (ivt, boot data...)
Great work, Max!
Just one caveat: if you plan to execute from QSPI, you also need to modify the flexspi_nor_config.c file with the correct decoration.
Moreover, the default project adds a DCD block. It is important to ensure that the commands inside are what you need.