Hi,
We have a custom board using an RT1064. Both BOOT_MODE[1:0] are floating, which per the reference manual should result in defaulting to the efuse pins.
We have an issue where I cannot debug a program loaded via J-Link. When I pause the debugger, I get various addresses around 0x21aadc which is in the internal ROM. My best guess is that since we have not yet programmed the efuses and BT_FUSE_SEL = 0, that the device is booting directly to the serial downloader.
This is rather problematic. We are using USB2 and the LPUART1 is being used as ADC pins, so we cannot access the serial config tool.
I have also tried setting the PC via the J link to the start of internal flash, but that (somewhat predictably) didn't work, likely due to the initialization in the ROM code.
I've done a bit of searching, and other members who managed to work around this have been able to get a program running somehow, maybe via internal loader or external jumpers:
https://community.nxp.com/t5/i-MX-RT/How-to-burn-BT-FUSE-SEL-on-RT1050/m-p/809577
And other people have had the same issue of not being able to debug:
Is there no way to debug without these fuses set if BOOT_MODE[1:0] are floating?
Is there any way to burn the fuses via debugger?
Right now, the workarounds I see are as follows:
1. Hack out the ADC pins and temporarily use them as a UART to allow booting MFGTool to program the efuses
2. I've got access to BOOT_MODE1 which should allow me to boot to internal boot, then hopefully run a program.
Neither of those seem very nice to me. Is there really no way to burn via JLink?
Thanks
Solved! Go to Solution.
Hi
If you link code to RAM it will be loaded there and the debugger will set up the stack pointer and start address so that it can run without passing through the ROM Loader.
The flash config is supplied by the startup code (either application when standalone or boot loader when the product supports field and OTA updating) and needs to be in the correct form to be recognised by the ROM loader otherwise it will not start that code.
Debuggers are very sensitive working with the i.MX RT parts and not everything works perfectly, especially when not working with very standard programs that are doing things exactly as the designers foresaw (sometimes breakpoints need to be set only after connection otherwise they will be missed). With trial and error techniques can be worked out that give reasonable results - I have found IAR behavior the most reliable with regards to debugging.
Regards
Mark
As a bit of an update to add some more info, I've continued on with the following:
I now have the following:
I've verified the above with the debuggeR:
Unfortunately, I'm still getting stuck when debugging in the 0x218390 region... This varies, but it still seems like it's in serial loader mode somehow?
This doesn't 100% make sense to me... what else am I missing?
Hi
If you can connect via JTAG you can load a program to RAM that can program eFuses.
Regards
Mark
[uTasker project developer for Kinetis and i.MX RT]
Contact me by personal message or on the uTasker web site to discuss professional training, solutions to problems or rapid product development requirements
For professionals searching for faster, problem-free Kinetis and i.MX RT 10xx developments the uTasker project holds the key: https://www.utasker.com/iMX/RT1064.html
Thanks, would that be done just by linking the program to run from RAM? How do you get the MCU to skip over the ROM code at the start?
In any case, I've made some more progress. I was never able to find where the configuration of the internal flash took place and assumed the tool did it automatically. When I looked closer at the demo projects I noticed that there was a file that looked like it configured the flash:
const flexspi_nor_config_t qspiflash_config = {
.memConfig =
{
.tag = FLEXSPI_CFG_BLK_TAG,
.version = FLEXSPI_CFG_BLK_VERSION,
.readSampleClksrc=kFlexSPIReadSampleClk_LoopbackFromDqsPad,
.csHoldTime = 3u,
.csSetupTime = 3u,
.sflashPadType = kSerialFlash_4Pads,
.serialClkFreq = kFlexSpiSerialClk_100MHz,
.sflashA1Size = 4u * 1024u * 1024u,
.lookupTable =
{
// Read LUTs
FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
},
},
.pageSize = 256u,
.sectorSize = 4u * 1024u,
.blockSize = 64u * 1024u,
.isUniformBlockSize = false,
};
When I included that I can get my hello world to run fine, sometimes.
Now I seem to have an interesting problem where I need to run the debug configuration twice to get an update. The first click erases flash and then ends up in the serial loader ROM region, the second run is able to program flash and executes the hello world, but seems to skip over all the breakpoints I have set in main.
Hi
If you link code to RAM it will be loaded there and the debugger will set up the stack pointer and start address so that it can run without passing through the ROM Loader.
The flash config is supplied by the startup code (either application when standalone or boot loader when the product supports field and OTA updating) and needs to be in the correct form to be recognised by the ROM loader otherwise it will not start that code.
Debuggers are very sensitive working with the i.MX RT parts and not everything works perfectly, especially when not working with very standard programs that are doing things exactly as the designers foresaw (sometimes breakpoints need to be set only after connection otherwise they will be missed). With trial and error techniques can be worked out that give reasonable results - I have found IAR behavior the most reliable with regards to debugging.
Regards
Mark
Thanks,
Using the above and the code from my initially linked post I was able to get the application running in RAM via J-Link and used the following code to set the fuses to internal boot and burn the BT_SEL flags:
void burn_fuses(void)
{
if (!(SRC->SBMR2 & SRC_SBMR2_BT_FUSE_SEL_MASK))
{
// Assumes ipg_clk = 132MHz
// WAIT+1/ipg_clk >= 150ns, 24 = 189ns
// RELAX+1/ipg_clk >= 100ns, 20 = 151.5ns
// STROBE_PROG --> tpgm = ((STROBE_PROG +1) - 2x (RELAX_PROG+1))/ipg_clk = 10000us, 1340 = 10us
// STROBE_READ --> trd = ((STROBE_READ+1) - 2x (RELAX_PROG+1))/ipg_clk > 45ns, STROBE_READ+1/ipg_clk > 75ns =
int timing = OCOTP_TIMING_STROBE_PROG(1340) | OCOTP_TIMING_RELAX(20) | OCOTP_TIMING_STROBE_READ(50) |OCOTP_TIMING_WAIT(24); //ipg_clk=132MHz, Calculation described at Chapter 42.3.3 OTP Read/Write Timing Parameters
OCOTP->TIMING = timing;
while ((OCOTP->CTRL & (1<<OCOTP_CTRL_BUSY_SHIFT)) || (OCOTP->CTRL & (1<<OCOTP_CTRL_ERROR_SHIFT))); //Check that HW_OCOTP_CTRL[BUSY] and HW_OCOTP_CTRL[ERROR]are clear
int ocotp_ctrl = OCOTP->CTRL;
ocotp_ctrl &= ~OCOTP_CTRL_ADDR_MASK;
ocotp_ctrl|= OCOTP_CTRL_ADDR(6);
ocotp_ctrl &= ~OCOTP_CTRL_WR_UNLOCK_MASK ;
ocotp_ctrl|= OCOTP_CTRL_WR_UNLOCK(0x3E77);
OCOTP->CTRL = ocotp_ctrl; //Write ADDR and unlock
OCOTP->DATA = (long)((1<<4)|(1<<16));//burn BT_FUSE_SEL (1<<4) and FORCE_INTERNAL_BOOT (1<<16)
}
}