Teensy 4 compatible hex files using MCUXpresso IDE?

cgz

Member
Hi,

I also have T3.6 and configuring an MCUXpresso IDE project to produce compatible hex files worked out with relative ease. Stuff works, and particularly USBHS which I'm interested in. I got the Teensy 4 for the fact that it has two USBHS ports, while T3.6 has only one.

With T4 I'm having difficulty figuring out how to build a compatible hex file. I suspect it must be related to the fact that IMXRT1062 has no built-in flash, which makes booting the system necessarily board-specific. And of course, MCUXpresso IDE doesn't ship with a Teensy 4 board kit, you need to come up with your own solution.

If someone has done it already, could you help me get going as well? Perhaps direct me to a working example?

Or, could someone with an idea help me understand which specifics might be in question that I should double- or triple-check?

I understand that I could be doing any simple mistakes that isn't specific to Teensy and not realizing it, since pretty much the only feedback I can get out of it right now is, A) it works or B) it doesn't work. But is wonder if there's any specific knowledge I should know of, and which might not be otherwise apparent?

If there's no-one with an already working solution, I'll try to come up with an example code attachment.

Thanks!
 
Hi cgz,

I'm trying to do the samething, but I am new to MCUxpresso so i have no idea how to set it up. Can you instruct me on how to set up MCUxpresso for T4 and which libraries to use if any ?

Thanks !!
 
I took the hard path and finally got it working. My current approach could still be somewhat on the quick-and-dirty side. Even so, I'll try to provide all the relevant clues below. Expect running into issues. When that happens, the ".map" file will help tracking down linking problems, as well as the ".dis" file. (And perhaps the multi-thousand-page IMXRT and ARM manuals :D)

OK, so here we go.

Not all the files we need are generated by the IDE by default:

You enable the ".dis" file generation by adding this to the "Post-build steps" in the project config:

Code:
arm-none-eabi-objdump -x -d "${ BuildArtifactFileName }" > "${BuildArtifactFileBaseName}.dis"

The ".hex" file we're after, isn't generated by default either, which you simiarly enable with the following post-build step:

Code:
arm-none-eabi-objcopy -v -O ihex -R .eeprom "${BuildArtifactFileName}" "${BuildArtifactFileBaseName}.hex"



Besides that, there's further adjustments you need in the MCUXpresso project's settings:
1) MCU:
- Choose the correct MCU. If it doesn't show up, get yourself the correct SDK first (from NXP website)
- Adjust the RAM sizes, and add a Flash memory to the list as well

2) C++ Linker:
- Enable "Manage linker script"
- Enable "Plain load image", target the ITCM RAM of the IMXRT (default name probably "SRAM_ITC")
- "Heap and Stack placement": I used "MCUXpresso Style", haven't tried anything else
- Heap and Stack locations both to the DTCM RAM region, location "Post Data", size "Default"
- "Global data placement" to the DTCM RAM area

You should end up with these figures in the "<project name>_Debug_memory.ld" linker script file:

Code:
MEMORY
{
  /* Define each memory region */
  SRAM_ITC (rwx) : ORIGIN = 0x0, LENGTH = 0x80000 /* 512K bytes (alias RAM) */  
  SRAM_DTC (rwx) : ORIGIN = 0x20000000, LENGTH = 0x80000 /* 512K bytes (alias RAM2) */  
  SRAM_OC (rwx) : ORIGIN = 0x20200000, LENGTH = 0x80000 /* 512K bytes (alias RAM3) */  
  Flash_00 (rx) : ORIGIN = 0x60000000, LENGTH = 0x1f0000 /* 1984K bytes (alias Flash) */  
}


When it comes to MCUXpresso linker script customization, you have .ldt-suffixed script templates you can modify. The base templates are located at "<IDE install dir>\ide\Wizards\linker". You customize them by copying each base template you want to change, into the project's root, under a "linkscripts" dir.

I adjusted the "<project name>_Debug.ld" linker script as follows, I mention each base template in the comments that I utilized for each change:

Code:
/* The entry point is outright wrong, must point to the vector, not the ISR. Thanks to T4 linker script for
 * pointing it out up front (it's documented wrong in the NXP material). I used "linkscript_common.ldt"
 * for this one. */
/*ENTRY(ResetISR)*/
ENTRY(ImageVectorTable)
Code:
    /* Goes right after the .boot_hdr. I used "main_text_section.ldt" for this. I use 
     * this to let IDE-generated stuff remain intact, while still be able to do some 
     * initialization before entering the default ResetISR. */
    .teensy_boot : ALIGN(4)
    {
    	FILL(0xff)
    	__teensy_vectors_start__ = ABSOLUTE(.) ;
    	KEEP(*(.teensy_boot.vectors))
    	KEEP(*(.teensy_boot.isr))
    	*(.teensy_boot.*)
    } > Flash_00
Code:
        /* in the main .text section, "Plain load image" choice gets the data section table wrong,
         * and needs adjustment for T4 purposes. I used "global_section_table.ldt" for this. */
        __section_table_start = .;
        __data_section_table = .;
        /* LONG((LOADADDR(.data_RAM) - __base_Flash_00) + __base_SRAM_ITC); */
        LONG(LOADADDR(.data_RAM));
        LONG(    ADDR(.data_RAM));
        LONG(  SIZEOF(.data_RAM));
        /* LONG((LOADADDR(.data) - __base_Flash_00) + __base_SRAM_ITC); */
        LONG(LOADADDR(.data));
        LONG(    ADDR(.data));
        LONG(  SIZEOF(.data));
        /* LONG((LOADADDR(.data_RAM3) - __base_Flash_00) + __base_SRAM_ITC); */
        LONG(LOADADDR(.data_RAM3));
        LONG(    ADDR(.data_RAM3));
        LONG(  SIZEOF(.data_RAM3));
        __data_section_table_end = .;
Code:
        /* Here we lend and adapt some of the T4's linking logic for our purposes. Use "image_size.ldt" for
         * this. */
	/* WARNING: requires heap and stack:
	 *    1) configured 'post-data'
	 *    2) configured small enough to fit into the DTCM what is left over after ITCM bank reservation
	 */
	_itcm_size = SIZEOF(.text) + SIZEOF(.ARM.extab) + SIZEOF(.ARM.exidx) + SIZEOF(.data_RAM) + SIZEOF(.bss_RAM) + SIZEOF(.noinit_RAM); 
	_itcm_start = ORIGIN(SRAM_ITC);
	_itcm_end = _itcm_start + _itcm_size;
	_itcm_loadstart = LOADADDR(.text);
	/* T4: _itcm_block_count = (SIZEOF(.text.itcm) + 0x7FFE) >> 15; */
        _itcm_block_count = (_itcm_size + 0x7FFF) >> 15;
        _flexram_bank_config = 0xAAAAAAAA | ((1 << (_itcm_block_count * 2)) - 1);

Btw, I think T4's linker script has a bug:

"_itcm_block_count = (SIZEOF(.text.itcm) + 0x7FFE) >> 15;"

should be:

"_itcm_block_count = (SIZEOF(.text.itcm) + 0x7FFF) >> 15;"

Otherwise, in a corner case, you could end up missing a one byte of code and running into a seriously mysterious behavior.


Finally, there's a "boot.c" and "teensy4.h" files for our intermediate ISR function, Flash and FlexRAM configuration. "boot.c" is the T4's "startup.c" with some changes:

Code:
#include <stdint.h>
#include "teensy4.h"

// one of the sources: https://community.nxp.com/thread/489178

// ld-script customization:
//    https://community.nxp.com/thread/477413
//    https://mcuoneclipse.com/2017/08/29/tutorial-porting-blenrf-kinetis-design-studio-project-to-mcuxpresso-ide/


// defined in the ld-script
extern unsigned long __teensy_vectors_start__;
extern unsigned long _vStackTop;
extern unsigned long _image_size, _itcm_size;
extern unsigned long _itcm_start, _itcm_loadstart, _itcm_end;
extern unsigned long _flexram_bank_config;

extern void ResetISR(void);





__attribute__((section(".teensy_boot.util"), optimize("no-tree-loop-distribute-patterns")))
static void memory_copy(uint32_t *dest, const uint32_t *src, uint32_t *dest_end)
{
	if (dest == src)
		return;
	while (dest < dest_end) {
		*dest++ = *src++;
	}
}

__attribute__ ((section(".teensy_boot.isr"), optimize("no-tree-loop-distribute-patterns"), naked))
void ResetISR_pre(void)
{
	IOMUXC_GPR_GPR17 = (uint32_t)&_flexram_bank_config;
	IOMUXC_GPR_GPR16 = 0x00000007; // enable DTCM and ITCM, use GPR17 for bank config
	IOMUXC_GPR_GPR14 = 0x00AA0000; // configure 512KB maximums for DTCM and ITCM (combined total is 512KB max, too)

	// copy code content from Flash to SRAM. data content will be copied/initialized in the ResetISR()
	memory_copy(&_itcm_start, &_itcm_loadstart, &_itcm_end);

	ResetISR();

	// block any accidental exit
	volatile static int i = 0 ;
	while(1) {
		i++ ;
		__asm volatile ("nop");
	}
}

__attribute__ ((section(".teensy_boot.vectors"), used))
const uint32_t vector_table[2] = {
	(uint32_t)&_vStackTop,
	(uint32_t)&ResetISR_pre
};

__attribute__ ((section(".boot_hdr.boot_data"), used))
const uint32_t BootData[3] = {
	0x60000000, // 6000_0000 ... 6FFF_FFFF : 256MB FlexSPI/ FlexSPI ciphertext, refman p. 35

	// _flashimagelen = SIZEOF(.text.progmem) + SIZEOF(.text.itcm) + SIZEOF(.data);
	(uint32_t)&_image_size, // NOTE for this to work, requires linkscripts/image_size.ldt override

	0
};

__attribute__ ((section(".boot_hdr.ivt"), used))
const uint32_t ImageVectorTable[8] = {
	0x402000D1,		// header

	//(uint32_t)vector_table, // docs are wrong, needs to be vec table, not start addr
	(uint32_t)&__teensy_vectors_start__,

	0,			// reserved
	0,			// dcd

	(uint32_t)BootData,	// abs address of boot data
	(uint32_t)ImageVectorTable, // self
	0,			// command sequence file
	0			// reserved
};

__attribute__ ((section(".boot_hdr.conf"), used))
uint32_t FlexSPI_NOR_Config[128] = {
	// 448 byte common FlexSPI configuration block, 8.6.3.1 page 223 (RT1060 rev 0)
	// MCU_Flashloader_Reference_Manual.pdf, 8.2.1, Table 8-2, page 72-75
	0x42464346,		// Tag				0x00
	0x56010000,		// Version
	0,			// reserved
	0x00020101,		// columnAdressWidth,dataSetupTime,dataHoldTime,readSampleClkSrc

	0x00000000,		// waitTimeCfgCommands,-,deviceModeCfgEnable
	0,			// deviceModeSeq
	0, 			// deviceModeArg
	0x00000000,		// -,-,-,configCmdEnable

	0,			// configCmdSeqs		0x20
	0,
	0,
	0,

	0,			// cfgCmdArgs			0x30
	0,
	0,
	0,

	0x00000000,		// controllerMiscOption		0x40
	0x00030401,		// lutCustomSeqEnable,serialClkFreq,sflashPadType,deviceType
	0,			// reserved
	0,			// reserved

	0x00200000,		// sflashA1Size			0x50
	0,			// sflashA2Size
	0,			// sflashB1Size
	0,			// sflashB2Size

	0,			// csPadSettingOverride		0x60
	0,			// sclkPadSettingOverride
	0,			// dataPadSettingOverride
	0,			// dqsPadSettingOverride

	0,			// timeoutInMs			0x70
	0,			// commandInterval
	0,			// dataValidTime
	0x00000000,		// busyBitPolarity,busyOffset

	0x0A1804EB,		// lookupTable[0]		0x80
	0x26043206,		// lookupTable[1]
	0,			// lookupTable[2]
	0,			// lookupTable[3]

	0x24040405,		// lookupTable[4]		0x90
	0,			// lookupTable[5]
	0,			// lookupTable[6]
	0,			// lookupTable[7]

	0,			// lookupTable[8]		0xA0
	0,			// lookupTable[9]
	0,			// lookupTable[10]
	0,			// lookupTable[11]

	0x00000406,		// lookupTable[12]		0xB0
	0,			// lookupTable[13]
	0,			// lookupTable[14]
	0,			// lookupTable[15]

	0,			// lookupTable[16]		0xC0
	0,			// lookupTable[17]
	0,			// lookupTable[18]
	0,			// lookupTable[19]

	0x08180420,		// lookupTable[20]		0xD0
	0,			// lookupTable[21]
	0,			// lookupTable[22]
	0,			// lookupTable[23]

	0,			// lookupTable[24]		0xE0
	0,			// lookupTable[25]
	0,			// lookupTable[26]
	0,			// lookupTable[27]

	0,			// lookupTable[28]		0xF0
	0,			// lookupTable[29]
	0,			// lookupTable[30]
	0,			// lookupTable[31]

	0x081804D8,		// lookupTable[32]		0x100
	0,			// lookupTable[33]
	0,			// lookupTable[34]
	0,			// lookupTable[35]

	0x08180402,		// lookupTable[36]		0x110
	0x00002004,		// lookupTable[37]
	0,			// lookupTable[38]
	0,			// lookupTable[39]

	0,			// lookupTable[40]		0x120
	0,			// lookupTable[41]
	0,			// lookupTable[42]
	0,			// lookupTable[43]

	0x00000460,		// lookupTable[44]		0x130
	0,			// lookupTable[45]
	0,			// lookupTable[46]
	0,			// lookupTable[47]

	0,			// lookupTable[48]		0x140
	0,			// lookupTable[49]
	0,			// lookupTable[50]
	0,			// lookupTable[51]

	0,			// lookupTable[52]		0x150
	0,			// lookupTable[53]
	0,			// lookupTable[54]
	0,			// lookupTable[55]

	0,			// lookupTable[56]		0x160
	0,			// lookupTable[57]
	0,			// lookupTable[58]
	0,			// lookupTable[59]

	0,			// lookupTable[60]		0x170
	0,			// lookupTable[61]
	0,			// lookupTable[62]
	0,			// lookupTable[63]

	0,			// LUT 0: Read			0x180
	0,			// LUT 1: ReadStatus
	0,			// LUT 3: WriteEnable
	0,			// LUT 5: EraseSector

	0,			// LUT 9: PageProgram		0x190
	0,			// LUT 11: ChipErase
	0,			// LUT 15: Dummy
	0,			// LUT unused?

	0,			// LUT unused?			0x1A0
	0,			// LUT unused?
	0,			// LUT unused?
	0,			// LUT unused?

	0,			// reserved			0x1B0
	0,			// reserved
	0,			// reserved
	0,			// reserved

	// 64 byte Serial NOR configuration block, 8.6.3.2, page 346

	256,			// pageSize			0x1C0
	4096,			// sectorSize
	1,			// ipCmdSerialClkFreq
	0,			// reserved

	0x00010000,		// block size			0x1D0
	0,			// reserved
	0,			// reserved
	0,			// reserved

	0,			// reserved			0x1E0
	0,			// reserved
	0,			// reserved
	0,			// reserved

	0,			// reserved			0x1F0
	0,			// reserved
	0,			// reserved
	0			// reserved
};


Into the "teensy4.h" file I copied a handful of definitions from T4:

Code:
typedef struct {
	volatile uint32_t offset000;
	volatile uint32_t offset004;
	volatile uint32_t offset008;
	volatile uint32_t offset00C;
	volatile uint32_t offset010;
	volatile uint32_t offset014;
	volatile uint32_t offset018;
	volatile uint32_t offset01C;
	volatile uint32_t offset020;
	volatile uint32_t offset024;
	volatile uint32_t offset028;
	volatile uint32_t offset02C;
	volatile uint32_t offset030;
	volatile uint32_t offset034;
	volatile uint32_t offset038;
	volatile uint32_t offset03C;
	volatile uint32_t offset040;
	volatile uint32_t offset044;
	volatile uint32_t offset048;
	volatile uint32_t offset04C;
	volatile uint32_t offset050;
	volatile uint32_t offset054;
	volatile uint32_t offset058;
	volatile uint32_t offset05C;
	volatile uint32_t offset060;
	volatile uint32_t offset064;
	volatile uint32_t offset068;
	volatile uint32_t offset06C;
	volatile uint32_t offset070;
	volatile uint32_t offset074;
	volatile uint32_t offset078;
	volatile uint32_t offset07C;
	volatile uint32_t offset080;
	volatile uint32_t offset084;
	volatile uint32_t offset088;
	volatile uint32_t offset08C;
	volatile uint32_t offset090;
	volatile uint32_t offset094;
	volatile uint32_t offset098;
	volatile uint32_t offset09C;
	volatile uint32_t offset0A0;
	volatile uint32_t offset0A4;
	volatile uint32_t offset0A8;
	volatile uint32_t offset0AC;
	volatile uint32_t offset0B0;
	volatile uint32_t offset0B4;
	volatile uint32_t offset0B8;
	volatile uint32_t offset0BC;
	volatile uint32_t offset0C0;
	volatile uint32_t offset0C4;
	volatile uint32_t offset0C8;
	volatile uint32_t offset0CC;
	volatile uint32_t offset0D0;
	volatile uint32_t offset0D4;
	volatile uint32_t offset0D8;
	volatile uint32_t offset0DC;
	volatile uint32_t offset0E0;
	volatile uint32_t offset0E4;
	volatile uint32_t offset0E8;
	volatile uint32_t offset0EC;
	volatile uint32_t offset0F0;
	volatile uint32_t offset0F4;
	volatile uint32_t offset0F8;
	volatile uint32_t offset0FC;
	volatile uint32_t offset100;
	volatile uint32_t offset104;
	volatile uint32_t offset108;
	volatile uint32_t offset10C;
	volatile uint32_t offset110;
	volatile uint32_t offset114;
	volatile uint32_t offset118;
	volatile uint32_t offset11C;
	volatile uint32_t offset120;
	volatile uint32_t offset124;
	volatile uint32_t offset128;
	volatile uint32_t offset12C;
	volatile uint32_t offset130;
	volatile uint32_t offset134;
	volatile uint32_t offset138;
	volatile uint32_t offset13C;
	volatile uint32_t offset140;
	volatile uint32_t offset144;
	volatile uint32_t offset148;
	volatile uint32_t offset14C;
	volatile uint32_t offset150;
	volatile uint32_t offset154;
	volatile uint32_t offset158;
	volatile uint32_t offset15C;
	volatile uint32_t offset160;
	volatile uint32_t offset164;
	volatile uint32_t offset168;
	volatile uint32_t offset16C;
	volatile uint32_t offset170;
	volatile uint32_t offset174;
	volatile uint32_t offset178;
	volatile uint32_t offset17C;
	volatile uint32_t offset180;
	volatile uint32_t offset184;
	volatile uint32_t offset188;
	volatile uint32_t offset18C;
	volatile uint32_t offset190;
	volatile uint32_t offset194;
	volatile uint32_t offset198;
	volatile uint32_t offset19C;
	volatile uint32_t offset1A0;
	volatile uint32_t offset1A4;
	volatile uint32_t offset1A8;
	volatile uint32_t offset1AC;
	volatile uint32_t offset1B0;
	volatile uint32_t offset1B4;
	volatile uint32_t offset1B8;
	volatile uint32_t offset1BC;
	volatile uint32_t offset1C0;
	volatile uint32_t offset1C4;
	volatile uint32_t offset1C8;
	volatile uint32_t offset1CC;
	volatile uint32_t offset1D0;
	volatile uint32_t offset1D4;
	volatile uint32_t offset1D8;
	volatile uint32_t offset1DC;
	volatile uint32_t offset1E0;
	volatile uint32_t offset1E4;
	volatile uint32_t offset1E8;
	volatile uint32_t offset1EC;
	volatile uint32_t offset1F0;
	volatile uint32_t offset1F4;
	volatile uint32_t offset1F8;
	volatile uint32_t offset1FC;
	volatile uint32_t offset200;
	volatile uint32_t offset204;
	volatile uint32_t offset208;
	volatile uint32_t offset20C;
	volatile uint32_t offset210;
	volatile uint32_t offset214;
	volatile uint32_t offset218;
	volatile uint32_t offset21C;
	volatile uint32_t offset220;
	volatile uint32_t offset224;
	volatile uint32_t offset228;
	volatile uint32_t offset22C;
	volatile uint32_t offset230;
	volatile uint32_t offset234;
	volatile uint32_t offset238;
	volatile uint32_t offset23C;
	volatile uint32_t offset240;
	volatile uint32_t offset244;
	volatile uint32_t offset248;
	volatile uint32_t offset24C;
	volatile uint32_t offset250;
	volatile uint32_t offset254;
	volatile uint32_t offset258;
	volatile uint32_t offset25C;
	volatile uint32_t offset260;
	volatile uint32_t offset264;
	volatile uint32_t offset268;
	volatile uint32_t offset26C;
	volatile uint32_t offset270;
	volatile uint32_t offset274;
	volatile uint32_t offset278;
	volatile uint32_t offset27C;
	volatile uint32_t offset280;
	volatile uint32_t offset284;
	volatile uint32_t offset288;
	volatile uint32_t offset28C;
	volatile uint32_t offset290;
	volatile uint32_t offset294;
	volatile uint32_t offset298;
	volatile uint32_t offset29C;
	volatile uint32_t offset2A0;
	volatile uint32_t offset2A4;
	volatile uint32_t offset2A8;
	volatile uint32_t offset2AC;
	volatile uint32_t offset2B0;
	volatile uint32_t offset2B4;
	volatile uint32_t offset2B8;
	volatile uint32_t offset2BC;
	volatile uint32_t offset2C0;
	volatile uint32_t offset2C4;
	volatile uint32_t offset2C8;
	volatile uint32_t offset2CC;
	volatile uint32_t offset2D0;
	volatile uint32_t offset2D4;
	volatile uint32_t offset2D8;
	volatile uint32_t offset2DC;
	volatile uint32_t offset2E0;
	volatile uint32_t offset2E4;
	volatile uint32_t offset2E8;
	volatile uint32_t offset2EC;
	volatile uint32_t offset2F0;
	volatile uint32_t offset2F4;
	volatile uint32_t offset2F8;
	volatile uint32_t offset2FC;
	volatile uint32_t offset300;
	volatile uint32_t offset304;
	volatile uint32_t offset308;
	volatile uint32_t offset30C;
	volatile uint32_t offset310;
	volatile uint32_t offset314;
	volatile uint32_t offset318;
	volatile uint32_t offset31C;
	volatile uint32_t offset320;
	volatile uint32_t offset324;
	volatile uint32_t offset328;
	volatile uint32_t offset32C;
	volatile uint32_t offset330;
	volatile uint32_t offset334;
	volatile uint32_t offset338;
	volatile uint32_t offset33C;
	volatile uint32_t offset340;
	volatile uint32_t offset344;
	volatile uint32_t offset348;
	volatile uint32_t offset34C;
	volatile uint32_t offset350;
	volatile uint32_t offset354;
	volatile uint32_t offset358;
	volatile uint32_t offset35C;
	volatile uint32_t offset360;
	volatile uint32_t offset364;
	volatile uint32_t offset368;
	volatile uint32_t offset36C;
	volatile uint32_t offset370;
	volatile uint32_t offset374;
	volatile uint32_t offset378;
	volatile uint32_t offset37C;
	volatile uint32_t offset380;
	volatile uint32_t offset384;
	volatile uint32_t offset388;
	volatile uint32_t offset38C;
	volatile uint32_t offset390;
	volatile uint32_t offset394;
	volatile uint32_t offset398;
	volatile uint32_t offset39C;
	volatile uint32_t offset3A0;
	volatile uint32_t offset3A4;
	volatile uint32_t offset3A8;
	volatile uint32_t offset3AC;
	volatile uint32_t offset3B0;
	volatile uint32_t offset3B4;
	volatile uint32_t offset3B8;
	volatile uint32_t offset3BC;
	volatile uint32_t offset3C0;
	volatile uint32_t offset3C4;
	volatile uint32_t offset3C8;
	volatile uint32_t offset3CC;
	volatile uint32_t offset3D0;
	volatile uint32_t offset3D4;
	volatile uint32_t offset3D8;
	volatile uint32_t offset3DC;
	volatile uint32_t offset3E0;
	volatile uint32_t offset3E4;
	volatile uint32_t offset3E8;
	volatile uint32_t offset3EC;
	volatile uint32_t offset3F0;
	volatile uint32_t offset3F4;
	volatile uint32_t offset3F8;
	volatile uint32_t offset3FC;
} IMXRT_REGISTER32_t;

// For FlexRAM config
#define IMXRT_IOMUXC_GPR 	   (*(IMXRT_REGISTER32_t *)0x400AC000)
#define IOMUXC_GPR_GPR14		(IMXRT_IOMUXC_GPR.offset038)
#define IOMUXC_GPR_GPR16		(IMXRT_IOMUXC_GPR.offset040)
#define IOMUXC_GPR_GPR17		(IMXRT_IOMUXC_GPR.offset044)

// These all have "T4_" prefix, just in case. I used these for debugging the boot (led blinking).
#define T4_IMXRT_IOMUXC		(*(IMXRT_REGISTER32_t *)0x401F8000)
#define T4_IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_03	(T4_IMXRT_IOMUXC.offset148)
#define T4_IOMUXC_SW_PAD_CTL_PAD_GPIO_B0_03	(T4_IMXRT_IOMUXC.offset338)
#define T4_IMXRT_IOMUXC_GPR	(*(IMXRT_REGISTER32_t *)0x400AC000)
#define T4_IOMUXC_GPR_GPR27		(T4_IMXRT_IOMUXC_GPR.offset06C)
#define T4_IMXRT_GPIO7		(*(IMXRT_REGISTER32_t *)0x42004000)
#define T4_GPIO7_GDIR			(T4_IMXRT_GPIO7.offset004)
#define T4_GPIO7_DR_SET			(T4_IMXRT_GPIO7.offset084)
#define T4_GPIO7_DR_CLEAR			(T4_IMXRT_GPIO7.offset088)
#define T4_IOMUXC_PAD_DSE(n)				((uint32_t)(((n) & 0x07) << 3))



Good luck!
 
Finally, there's a "boot.c" and "teensy4.h" files for our intermediate ISR function, Flash and FlexRAM configuration. "boot.c" is the T4's "startup.c" with some changes:

By "startup.c", I meant "bootdata.c".
 
Hi cgz,

I followed your instructions to modify the linker scripts, but it doesn't seem to modify the "Debug.ld" file at all. Is there any setings I need to change or path I need to specify ?

Thanks.
 
Last edited:
UPDATE

So I was able to modify the *_debug.ld" file using the linker scripts using the linkscripts folder but then I faced this error

Code:
_Debug.ld:33 cannot move location counter backwards (from 60001040 to 60001020)
collect2.exe: error: ld returned 1 exit status

I was able to solve this by modifying the linker script using boot_hdr.ldt linker script template:

Code:
/* Image Vector Table and Boot Data for booting from external flash */
    .boot_hdr : ALIGN(${text_align})
    {
        FILL(0xff)
        __boot_hdr_start__ = ABSOLUTE(.) ;
        KEEP(*(.boot_hdr.conf))
        . = 0x1000 ;
        KEEP(*(.boot_hdr.ivt))
        . = 0x1040 ;/*changed the pointer value from 0x1020 to 1040 */
        KEEP(*(.boot_hdr.boot_data))
        . = 0x1060 ;/*changed the pointer value from 0x1040 to 1060 */
        KEEP(*(.boot_hdr.dcd_data))
        __boot_hdr_end__ = ABSOLUTE(.) ;
        . = 0x2000 ;
    } >${CODE}

After making these changes it compiled sucessfully but after I uploaded it to the teensy using the teensy loader, the teesny didnt seem to do anything(I'm trying to blink the LED on pin 13 using the led_blink example in the SDK provided by nxp.).

I dont know what I'm doing wrong here and I have no idea how to debug the teensy.

Any help would be appreciated !!

Thanks !!
 
For LED blinking, I think you should start a bit earlier than the main loop - get your led turning on from the reset ISR first, then move on further from there. See what the T4's reset ISR "ResetHandler()" has for that purpose, "pin 13 - if startup crashes...":

Code:
__attribute__((section(".startup"), optimize("no-tree-loop-distribute-patterns"), naked))
void ResetHandler(void)
{
	unsigned int i;

#if defined(__IMXRT1062__)
	//in ld-script: _itcm_block_count = (SIZEOF(.text.itcm) + 0x7FFE) >> 15;
	//in ld-script: _flexram_bank_config = 0xAAAAAAAA | ((1 << (_itcm_block_count * 2)) - 1);
	IOMUXC_GPR_GPR17 = (uint32_t)&_flexram_bank_config;
	IOMUXC_GPR_GPR16 = 0x00000007; // enable DTCM and ITCM, use GPR17 for bank config
	IOMUXC_GPR_GPR14 = 0x00AA0000; // configure 512KB DTCM and ITCM
	// init stack pointer ( ld-script: _estack = ORIGIN(DTCM) + ((16 - _itcm_block_count) << 15); )
	__asm__ volatile("mov sp, %0" : : "r" ((uint32_t)&_estack) : );
#endif
	// pin 13 - if startup crashes, use this to turn on the LED early for troubleshooting
	//IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_03 = 5;
	//IOMUXC_SW_PAD_CTL_PAD_GPIO_B0_03 = IOMUXC_PAD_DSE(7);
	//IOMUXC_GPR_GPR27 = 0xFFFFFFFF;
	//GPIO7_GDIR |= (1<<3);
	//GPIO7_DR_SET = (1<<3); // digitalWrite(13, HIGH);

In my files, the T4 defines were prefixed with "T4_", so you might need to adjust accordingly.

About the "cannot move location counter backwards (from 60001040 to 60001020)" error: I think you would benefit from studying the linker scripting enough to know what's going on. It will help you when another linking problem arises, and it's general low level programming knowledge too, so won't hurt in any case. I learned it for the first time for this as well. :)

One of the sources I used.

For this particular error, another source explains you need to define output section contents in ascending order.
 
I finally got it to work !!

Thanks alot for suggesting to study the linker scripts !! Turns out the linker was taking two seperate .boot_hdr.* scripts... One being the default SDK boot headers and the other being in the changes you provided for the startup.c file.

This was causing the boot header to take double the memory and hence thowing out the "cannot move location counter backwards (from 60001040 to 60001020)" error.

I solved it by just changing the names of the ".boot_hdr.*" attributes to ".boot_hdr.*1" in both the startup.c file and the *_default.ld file.

The .boot_hdr section in the *_default.ld file looks like this.

Code:
     /*I used the boot_hdr_MIMXRT1060.ldt to make these modifications*/
     .boot_hdr : ALIGN(${text_align})
    {
        FILL(0xff)
        __boot_hdr_start__ = ABSOLUTE(.) ;
        /*KEEP(*(.boot_hdr.conf))*/
        KEEP(*(.boot_hdr.conf1))
        . = 0x1000 ;
        /*KEEP(*(.boot_hdr.ivt))*/
        KEEP(*(.boot_hdr.ivt1))
        . = 0x1020 ;
        /*KEEP(*(.boot_hdr.boot_data))*/
        KEEP(*(.boot_hdr.boot_data1))
        . = 0x1030 ;
        KEEP(*(.boot_hdr.dcd_data))
        __boot_hdr_end__ = ABSOLUTE(.) ;
        . = 0x2000 ;
    } >${CODE}

And my startup.c file looks like this

Code:
__attribute__ ((section(".boot_hdr.boot_data1")))// for linker to recognise this as the new boot_hdr codes
const uint32_t BootData[3] = {
    0x60000000, // 6000_0000 ... 6FFF_FFFF : 256MB FlexSPI/ FlexSPI ciphertext, refman p. 35

    // _flashimagelen = SIZEOF(.text.progmem) + SIZEOF(.text.itcm) + SIZEOF(.data);
    (uint32_t)&_image_size, // NOTE for this to work, requires linkscripts/image_size.ldt override

    0
};

__attribute__ ((section(".boot_hdr.ivt1") ))// for linker to recognise this as the new boot_hdr codes
const uint32_t ImageVectorTable[8] = {
    0x402000D1,        // header

    //(uint32_t)vector_table, // docs are wrong, needs to be vec table, not start addr
    (uint32_t)&__teensy_vectors_start__,

    0,            // reserved
    0,            // dcd

    (uint32_t)BootData,    // abs address of boot data
    (uint32_t)ImageVectorTable, // self
    0,            // command sequence file
    0            // reserved
};

__attribute__ ((section(".boot_hdr.conf1")))// for linker to recognise this as the new boot_hdr codes
uint32_t FlexSPI_NOR_Config[128] = {
    // 448 byte common FlexSPI configuration block, 8.6.3.1 page 223 (RT1060 rev 0)
    // MCU_Flashloader_Reference_Manual.pdf, 8.2.1, Table 8-2, page 72-75
    0x42464346,        // Tag                0x00
    0x56010000,        // Version
    0,            // reserved
    0x00020101,        // columnAdressWidth,dataSetupTime,dataHoldTime,readSampleClkSrc

    0x00000000,        // waitTimeCfgCommands,-,deviceModeCfgEnable
    0,            // deviceModeSeq
    0,             // deviceModeArg
    0x00000000,        // -,-,-,configCmdEnable

    0,            // configCmdSeqs        0x20
    0,
    0,
    0,

    0,            // cfgCmdArgs            0x30
    0,
    0,
    0,

    0x00000000,        // controllerMiscOption        0x40
    0x00030401,        // lutCustomSeqEnable,serialClkFreq,sflashPadType,deviceType
    0,            // reserved
    0,            // reserved

    0x00200000,        // sflashA1Size            0x50
    0,            // sflashA2Size
    0,            // sflashB1Size
    0,            // sflashB2Size

    0,            // csPadSettingOverride        0x60
    0,            // sclkPadSettingOverride
    0,            // dataPadSettingOverride
    0,            // dqsPadSettingOverride

    0,            // timeoutInMs            0x70
    0,            // commandInterval
    0,            // dataValidTime
    0x00000000,        // busyBitPolarity,busyOffset

    0x0A1804EB,        // lookupTable[0]        0x80
    0x26043206,        // lookupTable[1]
    0,            // lookupTable[2]
    0,            // lookupTable[3]

    0x24040405,        // lookupTable[4]        0x90
    0,            // lookupTable[5]
    0,            // lookupTable[6]
    0,            // lookupTable[7]

    0,            // lookupTable[8]        0xA0
    0,            // lookupTable[9]
    0,            // lookupTable[10]
    0,            // lookupTable[11]

    0x00000406,        // lookupTable[12]        0xB0
    0,            // lookupTable[13]
    0,            // lookupTable[14]
    0,            // lookupTable[15]

    0,            // lookupTable[16]        0xC0
    0,            // lookupTable[17]
    0,            // lookupTable[18]
    0,            // lookupTable[19]

    0x08180420,        // lookupTable[20]        0xD0
    0,            // lookupTable[21]
    0,            // lookupTable[22]
    0,            // lookupTable[23]

    [...]

};

I think the only reason I faced this issue is because I'm trying to use the examples provided for the Evaluation board rather than making my own project from scratch.:rolleyes:
 
I finally got it to work !!

...

I think the only reason I faced this issue is because I'm trying to use the examples provided for the Evaluation board rather than making my own project from scratch.:rolleyes:

Good job! :)

Just keep in mind you could have some issues waiting in your linker files to surface, because it's likely either me or you didn't completely understand all the implications of these linking adjustments. They could result in hard-to-identify problems.

Getting an idea of how to read and interpret the ".map" and the ".dis" files could prove useful (if not already familiar with them).
 
Just keep in mind you could have some issues waiting in your linker files to surface, because it's likely either me or you didn't completely understand all the implications of these linking adjustments. They could result in hard-to-identify problems.

Thanks, I'll definitly keep that in mind. If I face any issues I'll post it on this thread. That way it can be a guide to anyone who needs it.
 
YES, I got it working, too! Thanks to this thread and your awesome description, cgz!

The .teensy_boot section didn't work for me, though. I had to incorporate the section into the .boot_hdr section:

Code:
    /* Image Vector Table and Boot Data for booting from external flash */
    .boot_hdr : ALIGN(${text_align})
    {
        FILL(0xff)
        __boot_hdr_start__ = ABSOLUTE(.) ;
        KEEP(*(.boot_hdr.conf))
        . = 0x1000 ;
        KEEP(*(.boot_hdr.ivt))
        . = 0x1020 ;
        KEEP(*(.boot_hdr.boot_data))
        . = 0x1030 ;
        KEEP(*(.boot_hdr.dcd_data))
        __boot_hdr_end__ = ABSOLUTE(.) ;
        . = 0x2000 ;
        __teensy_vectors_start__ = ABSOLUTE(.) ;
        KEEP(*(.teensy_boot.vectors))
        KEEP(*(.teensy_boot.isr))
        *(.teensy_boot.*)
    } > ${CODE}

I'm learning so much about linker scripts and memory maps! :)
 
Hi cgz,

a big "Thank you" I just got it to work with Teensy 4.1, follwing your explanation without modifications.
You made my day :)

cheers

rsassman
 
Generating hexfiles for teensy 4.1 with MCUXpression i quite simple and works out of the box without any changes of the linker skript. You will find some ready to use examples here.
 
Back
Top