How to start code in different FLASH and TCM regions of Teensy 4.1

Status
Not open for further replies.

Jian

Member
I can compile the following code ("main.cpp") with the original linker script provided by pjrc and run it on Teensy 4.1 module without any issue.
-----------------------
[ mail.cpp file ]
#include <Arduino.h>
extern "C" int main(void)
{

// To use Teensy 4.0 without Arduino, simply put your code here.
// For example:

pinMode(13, OUTPUT);
while (1) {
digitalWriteFast(13, HIGH);
delay(500);
digitalWriteFast(13, LOW);
delay(500);
}
}
-------------------

I want to change the original linker script in imxrt1062_t41.ld to the following, in order to to use the different regions of FLASH and TCM. Any of those changes will cause the Teensy 4.1 module to not booting up. The code compiles OK and the map file reflects the changes as well.
Question: What else do I need to change in the code in order to have the ResetHandler() (in startup.c and my guess this is where everything starts) prepare the system correctly in order to run the main()?

--------------------
[ only part of the modified region of the file imxrt1062_t41.ld ]
MEMORY
{
ITCM (rwx): ORIGIN = 0x00040000, LENGTH = 256K
DTCM (rwx): ORIGIN = 0x20040000, LENGTH = 256K
RAM (rwx): ORIGIN = 0x20240000, LENGTH = 256K /* RAM change alone will not cause problem */
FLASH (rwx): ORIGIN = 0x60064000, LENGTH = 6000K
ERAM (rwx): ORIGIN = 0x70000000, LENGTH = 16384K

}
...
[reset of the linker script not changed]
---------------------

Thanks,
Jian
 
bootdata.c, ImageVectorTable

Eh no, misunderstood your question, sorry :)

I guess part of the problem is, that the linker file calculates the amount ITCM 32KB blocks. This might not work anymore.
Shot into the blue :)
Code:
    _itcm_block_count = (SIZEOF(.text.itcm) + SIZEOF(.ARM.exidx) + 0x7FFF) >> 15;
    _flexram_bank_config = 0xAAAAAAAA | ((1 << (_itcm_block_count * 2)) - 1);
    _estack = ORIGIN(DTCM) + ((16 - _itcm_block_count) << 15);
So, I'd try first not to change "MEMORY".
Add a start address to ".text.code : " instead.

". = "
 
Last edited:
Thanks Frank for a quick response. I have looked at the ImageVectorTable. The vector_table contains a pointer to the ResetHandler(). I don't have to change that. The first element of BootData is hard coded to 0x60000000. I don't know what does it mean and I tried to change that to 0x60064000, but did not help. What else in ImageVectorTable should be changed and to what?
Thanks!!!
 
The 32 byte IVT must always be at location 6000,1000. The 512 byte flashconfig (FlexSPI_NOR_Config array) must always be at 6000,0000. These locations are fixed by NXP's ROM and can never be changed. The chip simply will not boot if those data structures are not found at those exact locations. You can place other items in memory where you like and put their addresses into the IVT and BootData, but you have to put the IVT in the location where NXP's boot process uses... if you want the chip to boot up automatically.

Teensy's linker script automatically configures ITCM to the minimum size needed for code you have written which goes into ITCM space. The remainder of RAM1 is automatically configured for DTCM. I do not understand why you would want to waste FlexRAM on ITCM allocation larger than necessary for the code you have written. But if you want to do that anyway, the key is writing the desired configuration to IOMUXC_GPR_GPR17 in startup.c. As you can see in the code, configuration computed by the linker script for the minimum amount of FlexRAM needed to implement ITCM is automatically written to IOMUXC_GPR_GPR17. If you want to do something different, look for the IOMUXC_GPR_GPR17 documentation on page 367 of the reference manual.
 
Thanks Paul and Frank. I'm trying to port an in-house bootloader in to Teensy. I was thinking just give application a linker script so it will use totally different areas of FLASH and TCM. Now I understand what's going on. I need to change my plan a little.
 
Have you tried to just change the start adress?

Add a start address to ".text.code : " instead.

". = "

Also, you can leave everything as it is and just use one of the hooks in the reset handler.
 
Hi Frank,
I did what you suggested. Not changing MEMORY, only changed SECTIONS for flash to the following. The end result is the application code is being located to 0x60064000. I'm happy with that. But, I have another question. Why I cannot move .startup section (for ResetHandler() function) to 0x60064000? If move ". = ORIGIN(FLASH) + 0x64000;" to above "KEEP(*(.startup))" line in the script, it won't boot.

-------------------
SECTIONS
{
.text.progmem : {
KEEP(*(.flashconfig))
FILL(0xFF)
. = ORIGIN(FLASH) + 0x1000;
KEEP(*(.ivt))
KEEP(*(.bootdata))
KEEP(*(.vectors))
KEEP(*(.startup))
. = ORIGIN(FLASH) + 0x64000;
*(.flashmem*)
*(.text*)
...
-----------------------
 
Any thoughts on why I cannot put ResetHandler() (in startup.c) to ORIGIN(FLASH) + 0x64000? I really cannot figure that out. I am able to put my test code to higher FLASH address and execute in higher ITCM and DTCM regions as well. But I really want to move its ResetHandler() to be with the main code in higher FLASH address as well. Please help!

Jian
 
Any thoughts on why I cannot put ResetHandler() (in startup.c) to ORIGIN(FLASH) + 0x64000? I really cannot figure that out. I am able to put my test code to higher FLASH address and execute in higher ITCM and DTCM regions as well. But I really want to move its ResetHandler() to be with the main code in higher FLASH address as well. Please help!

Jian

- you can even write a script which works entirely without ITCM and runs everything from flash.

Butr here's how to put everything in ITCM to 0x4000 ff
Code:
MEMORY
{
    ITCM (rwx):  ORIGIN = 0x00000000, LENGTH = 512K
    DTCM (rwx):  ORIGIN = 0x20000000, LENGTH = 512K
    RAM (rwx):   ORIGIN = 0x20200000, LENGTH = 512K
    FLASH (rwx): ORIGIN = 0x60000000, LENGTH = 7936K
    ERAM (rwx):  ORIGIN = 0x70000000, LENGTH = 16384K
}

ENTRY(ImageVectorTable)

SECTIONS
{
    .text.headers : {
        KEEP(*(.flashconfig))
        FILL(0xFF)
        . = ORIGIN(FLASH) + 0x1000;
        KEEP(*(.ivt))
        KEEP(*(.bootdata))
        . = ALIGN(1024);
    } > FLASH

    
    .text.code : {
        KEEP(*(.startup))
        *(.flashmem*)
        . = ALIGN(4);
        KEEP(*(.init))
        __preinit_array_start = .;
        KEEP (*(.preinit_array))
        __preinit_array_end = .;
        __init_array_start = .;
        KEEP (*(.init_array))
        __init_array_end = .;
        . = ALIGN(4);
    } > FLASH
     
    .text.progmem : {
        *(.progmem*)
        . = ALIGN(4);
    } > FLASH

    .text.itcm : {
        . = . + 32; /* MPU to trap NULL pointer deref */
[U][I][B][COLOR=#ff0000] . = 0x4000;[/COLOR][/B][/I][/U]
        *(.fastrun)
        *(.text*)
        . = ALIGN(16);
    } > ITCM AT> FLASH

    .ARM.exidx : {
        __exidx_start = .;
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
        __exidx_end = .;
    } > ITCM AT> FLASH

  .ARM.extab : {
    __extab_start = .;
    *(.ARM.extab* .gnu.linkonce.armextab.*)
    __extab_end = .;
  }  > ITCM AT> FLASH

    .data : {
        *(.endpoint_queue)   
        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.data*)))
        KEEP(*(.vectorsram))
    } > DTCM  AT> FLASH

    .bss ALIGN(4) : {
        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(COMMON)))
        . = ALIGN(32);
        . = . + 32; /* MPU to trap stack overflow */
    } > DTCM

    .bss.dma (NOLOAD) : {
        *(.hab_log)
        *(.dmabuffers)
        . = ALIGN(32);
    } > RAM

    .bss.extram (NOLOAD) : {
        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.externalram)))
        . = ALIGN(32);
    } > ERAM

    .text.csf : {
        FILL(0xFF)
        . = ALIGN(1024);
        KEEP(*(.csf))
        __text_csf_end = .;
    } > FLASH

    _stext = ADDR(.text.itcm);
    _etext = ADDR(.text.itcm) + SIZEOF(.text.itcm) + SIZEOF(.ARM.exidx) + SIZEOF(.ARM.extab);
    _stextload = LOADADDR(.text.itcm);

    _sdata = ADDR(.data);
    _edata = ADDR(.data) + SIZEOF(.data);
    _sdataload = LOADADDR(.data);

    _sbss = ADDR(.bss);
    _ebss = ADDR(.bss) + SIZEOF(.bss);

    _heap_start = ADDR(.bss.dma) + SIZEOF(.bss.dma);
    _heap_end = ORIGIN(RAM) + LENGTH(RAM);

    _extram_start = ADDR(.bss.extram);
    _extram_end = ADDR(.bss.extram) + SIZEOF(.bss.extram);

    _itcm_block_count = (SIZEOF(.text.itcm) + SIZEOF(.ARM.exidx) + SIZEOF(.ARM.extab) + 0x7FFF) >> 15;
    _flexram_bank_config = 0xAAAAAAAA | ((1 << (_itcm_block_count * 2)) - 1);
    _estack = ORIGIN(DTCM) + ((16 - _itcm_block_count) << 15);

    _flashimagelen = __text_csf_end - ORIGIN(FLASH);
    _teensy_model_identifier = 0x25;

    .debug_info     0 : { *(.debug_info) }
    .debug_abbrev   0 : { *(.debug_abbrev) }
    .debug_line     0 : { *(.debug_line) }
    .debug_frame    0 : { *(.debug_frame) }
    .debug_str      0 : { *(.debug_str) }
    .debug_loc      0 : { *(.debug_loc) }

}

Excerpt from symbol file:
Code:
0004000 t __do_global_dtors_aux
[COLOR=#ff0000]00004024[/COLOR] t frame_dummy
00004040 0000002c T setup
0000406c 00000002 T loop
00004070 000000ac T delay
0000411c 00000070 T pinMode
0000418c 00000180 T unused_interrupt_vector
0000430c 00000004 T Panic_Temp_isr
00004310 00000064 T tempmonGetTemp
00004374 00000070 t schedule_transfer
000043e4 00000036 t run_callbacks
 
And this does both: flash startup to > 60004000 and itcm > 0x4000

Code:
MEMORY
{
    ITCM (rwx):  ORIGIN = 0x00000000, LENGTH = 512K
    DTCM (rwx):  ORIGIN = 0x20000000, LENGTH = 512K
    RAM (rwx):   ORIGIN = 0x20200000, LENGTH = 512K
    FLASH (rwx): ORIGIN = 0x60000000, LENGTH = 7936K
    ERAM (rwx):  ORIGIN = 0x70000000, LENGTH = 16384K
}

ENTRY(ImageVectorTable)

SECTIONS
{
    .text.headers : {
        KEEP(*(.flashconfig))
        FILL(0xFF)
        . = ORIGIN(FLASH) + 0x1000;
        KEEP(*(.ivt))
        KEEP(*(.bootdata))
        . = ALIGN(1024);
    } > FLASH

    
    .text.code : {
[COLOR=#ff0000]    . = ORIGIN(FLASH) + 0x4000;[/COLOR]
        KEEP(*(.startup))
        *(.flashmem*)
        . = ALIGN(4);
        KEEP(*(.init))
        __preinit_array_start = .;
        KEEP (*(.preinit_array))
        __preinit_array_end = .;
        __init_array_start = .;
        KEEP (*(.init_array))
        __init_array_end = .;
        . = ALIGN(4);
    } > FLASH
     
    .text.progmem : {
        *(.progmem*)
        . = ALIGN(4);
    } > FLASH

    .text.itcm : {
        . = . + 32; /* MPU to trap NULL pointer deref */
[COLOR=#ff0000]    . = 0x4000;[/COLOR]
        *(.fastrun)
        *(.text*)
        . = ALIGN(16);
    } > ITCM AT> FLASH

    .ARM.exidx : {
        __exidx_start = .;
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
        __exidx_end = .;
    } > ITCM AT> FLASH

  .ARM.extab : {
    __extab_start = .;
    *(.ARM.extab* .gnu.linkonce.armextab.*)
    __extab_end = .;
  }  > ITCM AT> FLASH

    .data : {
        *(.endpoint_queue)   
        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.data*)))
        KEEP(*(.vectorsram))
    } > DTCM  AT> FLASH

    .bss ALIGN(4) : {
        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(COMMON)))
        . = ALIGN(32);
        . = . + 32; /* MPU to trap stack overflow */
    } > DTCM

    .bss.dma (NOLOAD) : {
        *(.hab_log)
        *(.dmabuffers)
        . = ALIGN(32);
    } > RAM

    .bss.extram (NOLOAD) : {
        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.externalram)))
        . = ALIGN(32);
    } > ERAM

    .text.csf : {
        FILL(0xFF)
        . = ALIGN(1024);
        KEEP(*(.csf))
        __text_csf_end = .;
    } > FLASH

    _stext = ADDR(.text.itcm);
    _etext = ADDR(.text.itcm) + SIZEOF(.text.itcm) + SIZEOF(.ARM.exidx) + SIZEOF(.ARM.extab);
    _stextload = LOADADDR(.text.itcm);

    _sdata = ADDR(.data);
    _edata = ADDR(.data) + SIZEOF(.data);
    _sdataload = LOADADDR(.data);

    _sbss = ADDR(.bss);
    _ebss = ADDR(.bss) + SIZEOF(.bss);

    _heap_start = ADDR(.bss.dma) + SIZEOF(.bss.dma);
    _heap_end = ORIGIN(RAM) + LENGTH(RAM);

    _extram_start = ADDR(.bss.extram);
    _extram_end = ADDR(.bss.extram) + SIZEOF(.bss.extram);

    _itcm_block_count = (SIZEOF(.text.itcm) + SIZEOF(.ARM.exidx) + SIZEOF(.ARM.extab) + 0x7FFF) >> 15;
    _flexram_bank_config = 0xAAAAAAAA | ((1 << (_itcm_block_count * 2)) - 1);
    _estack = ORIGIN(DTCM) + ((16 - _itcm_block_count) << 15);

    _flashimagelen = __text_csf_end - ORIGIN(FLASH);
    _teensy_model_identifier = 0x25;

    .debug_info     0 : { *(.debug_info) }
    .debug_abbrev   0 : { *(.debug_abbrev) }
    .debug_line     0 : { *(.debug_line) }
    .debug_frame    0 : { *(.debug_frame) }
    .debug_str      0 : { *(.debug_str) }
    .debug_loc      0 : { *(.debug_loc) }

}

excerpt fom sym:
Code:
00000000 T _stext
00000001 A _itcm_block_count
00000025 A _teensy_model_identifier
[COLOR=#ff0000]00004000 t __do_global_dtors_aux[/COLOR]
00004024 t frame_dummy
00004040 0000002c T setup
0000406c 00000002 T loop
00004070 000000ac T delay
[...]
60000000 00000200 D FlexSPI_NOR_Config
60001000 00000020 D ImageVectorTable
60001020 0000000c D BootData
[COLOR=#ff0000]60004000 00000016 t memory_copy[/COLOR]
60004018 00000010 t memory_clear
60004028 00000220 T ResetHandler


@Paul. It took way longer to write and edit this answer than to add the two lines.
That's what I mean. And I completely understand why users start new threads if there is no answer.

@Jian: I have no Idea what this should be good for.. but does this answer your question?
You know that teensy loader erases the whole flash every time?
 
Thanks Paul. I was able to get the memory (TCM and FLASH) configuration working the way I wanted. But my question is why ResetHandler() has to be at the default location? If I try to put it at say 0x60001100, it will fail to boot.

Code:
...
SECTIONS
{
	.text.progmem : {
		KEEP(*(.flashconfig))
		FILL(0xFF)
		. = ORIGIN(FLASH) + 0x1000;   
		KEEP(*(.ivt))
		KEEP(*(.bootdata))
		KEEP(*(.vectors))
     /*	FILL(0xFF) 
		. = ORIGIN(FLASH) + 0x1100;    */     /* put ResetHandler() to 0x60001100 instead of the default 0x60001035.  Will NOT boot. */
		KEEP(*(.startup))   
..
 
Have you read my answers?
As you see in Post #11 it's NOT at the default location.

Edit: What is that .ld file you use? Seems not to be the default?
 
Hi Paul,
This is the exact ld file that works. But if I uncomment the chunk (in red) and re-compile, it will not boot. I can change the offset from 0x1100 to 0x4000 (as the one used in your post #11), it still won't boot.

Code:
MEMORY
{
	ITCM (rwx):  ORIGIN = 0x00000000, LENGTH = 512K 
	DTCM (rwx):  ORIGIN = 0x20000000, LENGTH = 512K
	RAM (rwx):   ORIGIN = 0x20200000, LENGTH = 512K   
/*	ITCM (rwx):  ORIGIN = 0x00020000, LENGTH = 128K
	DTCM (rwx):  ORIGIN = 0x20020000, LENGTH = 128K
	RAM (rwx):   ORIGIN = 0x20240000, LENGTH = 256K  */
	
	FLASH (rwx): ORIGIN = 0x60000000, LENGTH = 6400K
/*	FLASH (rwx): ORIGIN = 0x60064000, LENGTH = 6400K  */  
	ERAM (rwx):  ORIGIN = 0x70000000, LENGTH = 16384K
	MY_F (rx):   ORIGIN = 0x6006E000, LENGTH = 128K
}

ENTRY(ImageVectorTable)

SECTIONS
{
	.text.progmem : {
		KEEP(*(.flashconfig))
		FILL(0xFF)
		. = ORIGIN(FLASH) + 0x1000;   
		KEEP(*(.ivt))
		KEEP(*(.bootdata))
		KEEP(*(.vectors))
	[COLOR="#FF0000"]/*	FILL(0xFF)  
		. = ORIGIN(FLASH) + 0x1100;   */[/COLOR]   /* put ResetHandler() at a relatively fixed location  BUT, It it won't boot*/
		KEEP(*(.startup))   
        /*   . = ORIGIN(FLASH) + 0x64000;  */
		*(.flashmem*)
	/*	*(.text*)   */
		*(.progmem*)
                . = ALIGN(4);
                KEEP(*(.init))
                __preinit_array_start = .;
                KEEP (*(.preinit_array))
                __preinit_array_end = .;
                __init_array_start = .;
                KEEP (*(.init_array))
                __init_array_end = .;
		. = ALIGN(16);
	} > FLASH

	.text.itcm : {
		. = . + 32; /* MPU to trap NULL pointer deref */
		*(.fastrun)  
	    *(.text*)
		. = ALIGN(16);
	} > ITCM  AT> FLASH

	.ARM.exidx : {
		__exidx_start = .;
		*(.ARM.exidx* .gnu.linkonce.armexidx.*)
		__exidx_end = .;
	} > ITCM  AT> FLASH

	.text.itcm.padding (NOLOAD) : {
		. = ALIGN(32768);
	} > ITCM

	.data : {
		*(.rodata*)
		*(.data*)
		. = ALIGN(16);
	} > DTCM  AT> FLASH

	.bss ALIGN(4) : {
		*(.bss*)
		*(COMMON)
		. = ALIGN(32);
		. = . + 32; /* MPU to trap stack overflow */
	} > DTCM

	.bss.dma (NOLOAD) : {
		*(.dmabuffers)
		. = ALIGN(32);
	} > RAM

	.bss.extram (NOLOAD) : {
		*(.externalram)
	} > ERAM

	.mysection : {
		**(.mysection*)
		. = ALIGN(4);
	} > MY_F
	
	_stext = ADDR(.text.itcm);
	_etext = ADDR(.text.itcm) + SIZEOF(.text.itcm) + SIZEOF(.ARM.exidx);
	_stextload = LOADADDR(.text.itcm);

	_sdata = ADDR(.data);
	_edata = ADDR(.data) + SIZEOF(.data);
	_sdataload = LOADADDR(.data);

	_sbss = ADDR(.bss);
	_ebss = ADDR(.bss) + SIZEOF(.bss);

	_heap_start = ADDR(.bss.dma) + SIZEOF(.bss.dma);
	_heap_end = ORIGIN(RAM) + LENGTH(RAM);

	_itcm_block_count = (SIZEOF(.text.itcm) + SIZEOF(.ARM.exidx) + 0x7FFF) >> 15;
	/* _itcm_block_count = 8;   */  /* 8 blocks (256K) of ITCM and DTCM each  */ 
	_flexram_bank_config = 0xAAAAAAAA | ((1 << (_itcm_block_count * 2)) - 1);
	_estack = ORIGIN(DTCM) + ((16 - _itcm_block_count) << 15);
	/* _estack = ORIGIN(DTCM) + (4 << 15); */  /* 4 blocks (128K) in size */

	_flashimagelen = SIZEOF(.text.progmem) + SIZEOF(.text.itcm) + SIZEOF(.ARM.exidx) + SIZEOF(.data);
	_teensy_model_identifier = 0x25;

	.debug_info     0 : { *(.debug_info) }
	.debug_abbrev   0 : { *(.debug_abbrev) }
	.debug_line     0 : { *(.debug_line) }
	.debug_frame    0 : { *(.debug_frame) }
	.debug_str      0 : { *(.debug_str) }
	.debug_loc      0 : { *(.debug_loc) }

}
 
Just so you know I'm not ignoring your question, please let me say I do not know why it isn't booting with this change.

If I were to try to investigate, I would start looking at the generated HEX files. I would also uncomment the LED code early in startup, so I could see the difference between not booting at all versus crashing early (after the LED turned on).

But I need you to understand I have no plans to investigate this. For so many other types of problems, like serial data received wrong, timing issues, etc.. I do often set up the hardware and put time into reproducing the problem. But this sort of issue is pretty far outside of the sort of support I can offer. This code is open source and you're welcome to modify it and discuss the details here. Just know that I can't put more time into direct support for editing linker files. The best I can say for this case is I don't know why it's not working and I'm not going to dig into troubleshooting it.
 
Tried your *.ld.
It even prints a errormessage in nice red:
Code:
[COLOR=#ff0000]a:/hardware/tools/arm10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: C:\temp\arduino_build_852071/core\core.a(startup.c.o): in function `configure_external_ram':
A:\hardware\teensy\avr\cores\teensy4/startup.c:453: undefined reference to `_extram_end'
a:/hardware/tools/arm10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: A:\hardware\teensy\avr\cores\teensy4/startup.c:453: undefined reference to `_extram_start'
collect2.exe: error: ld returned 1 exit status[/COLOR]
You've deleted the extram part.

I'm under the impression you use a pretty old TD version.
However, after re-adding the missing parts, it blinks.

You'll have more fun with a newer TD version.
 
Last edited:
Status
Not open for further replies.
Back
Top