RT1170 CMSIS DAP+IDE debug based on ECC enabled
1. Abstract
This article aims to solve the problem that after enabling the ECC function, RT1170 cannot be debugged using CMSIS DAP in the three major IDEs (MCUXpresso, IAR, MDK). ECC is enabled by burning the relevant fuses and enabling ROM preloading, which means that the ROM will help initialize the RAM. However, in actual use, it is found that different debuggers have different appearances on the IDE. For example, Segger JLINK can directly implement debugging, but when CMSIS DAP is combined with the three major IDEs, there will be a problem that the code cannot be debugged after being downloaded to RAM. Here, taking MCUXpresso IDE as an example, after burning the ECC-related fuses on the MIMXRT1170-EVK board, if the project is burned to RAM, it can be debugged directly. However, if the project is burned to flash, there will be problems with flashloader:
Fig 1
So is this problem caused by the mismatch of flashloader, or does it require additional operations? This article will give a specific solution!
2. RT1170 ECC basic enable and solution
2.1 RT1170 ECC basic
ECC stands for Error Correcting Code, which can detect and correct memory errors. So what ECC does RT1170 have? They are: MECC64, XECC, FlexRAM ECC.
MECC64
MECC64 supports 1-bit error correction and 2-bit error detection,to 2bit, it cannot correct errors, just detect the error. MECC64 is mainly protects OCRAM1 and 2 in the chip. MECC1 protects OCRAM1, and MECC2 protects OCRAM2. OCRAM1 ECC and OCRAM2 ECC are used to store ECC check values. If ECC64 is not enabled, it can be used as a normal OCRAM. An 8-bit ECC check value (8 bits) is calculated for every 64 bits of data. The ECC algorithm is Hsiao Hamming.
XECC
XECC is External ECC controller, which is used to provide ECC function for external storage space. XECC supports 1-bit error correction and 2-bit error detection. External memory includes XECC_FLEXSPI1, XECC_FLEXSPI2, and XECC+SEMC. XECC can calculate a 4-bit ECC check value for every 4 bits. The XECC check value is immediately following the original value. For example, for a 32-bit data, a 4-bit ECC check value is generated for every 4 bits. 32-bit original data needs to generate 32-bit ECC check data, which requires a total of 64 bits of space. Algorithm: Hsiao Hamming algorithm
FlexRAM ECC
FlexRAM ECC is used to protect the ITCM, DTCM and OCRAM of FlexRAM. It supports 1-bit error correction and 2-bit error detection. A 7/8-bit ECC check value is calculated for every 4 bytes of DTCM or 8 bytes of ITCM/OCRAM, and the ECC check value is placed in the ECC RAM.
2.2 RT1170 ECC enable
The method used in this article to enable ECC is to directly enable the relevant fuse bit.
- MECC_ENABLE (0x840[2]) = 1
- XECC_ENABLE (0x840[3]) = 1
- ROM preloading (0x950[0]) = 1
- FLEXRAMECC_ENABLE (0x840[15]) = 1
For more software configuration information, please refer to the official application note AN13204:
https://www.nxp.com/docs/en/application-note/AN13204.pdf
The following is the situation after burning the relevant fuses. Burning the fuses can enter the serial download mode and use MCUbootutility to burn:
Fig 2
2.3 ECC debug issue solution methods
After testing in many ways, such as initializing RAM in the script, because of the characteristics of ECC, RAM needs to be flashed once, but it is found that the general code speed of flashing RAM directly is too slow, resulting in download timeout problems, and then it is changed to use DMA to move data to RAM to ensure that RAM is flashed once, but the result is still not good, so flashing RAM is not the fundamental way to solve the debug problem. Finally, by chance, ECC is turned off in the connection script first, especially FlexRAM ECC, and it is found that the burning algorithm can be called to perform external flash operations at this time. In this way, the code can be successfully downloaded, and then reset to let the ROM turn on the ECC function by itself.
The reason why the RAM project can work is that the process of downloading RAM is a process of flashing RAM, so the RAM code can work directly.
For the debugger burning and simulation of Flash code, it is still necessary to turn off the ECC module first, mainly the FlexRAM ECC module. Of course, for the sake of insurance, we can directly turn off all MECC and FlexRAM ECC register enable bits, let the flashloader work first, and directly control the register address:
0x40014100=0;0x40018100=0;0x40028108=0;
0x40014100 PIPE_ECC_EN[ECC_EN], control MECC1
0x40018100 PIPE_ECC_EN[ECC_EN], control MECC2
Fig 3
0x40028108 FLEXRAM_CTRL ECC_EN, control FlexRAM ECC
Fig 4
According to the actual test situation, disabling FlexRAM ECC is effective. The problem should be that the area where the flashloader used is stored is the DTCM of FlexRAM. Check the area of the Flashloader of the burning algorithm as follows:
Fig 5
3 Three major IDEs script and testing
Here, share the three IDE(MCUXPresso, IAR, MDK)+CMSIS DAP+ECC related modified script file.
3.1 MCUXpresso IDE
Script path in the IDE:
C:\nxp\MCUXpressoIDE_11.9.0_2144\ide\LinkServer\binaries\Scripts
Prepare one script file T1170_connect_M7_wake_M4_ecc.scp,copy it to the above path, and the content is:
1 REM ======================================
2 REM Copyright 2020-2024 NXP
3 REM All rights reserved.
4 REM SPDX-License-Identifier: BSD-3-Clause
5 REM ======================================
100 REM =======================================================================
110 REM RT1170_connect_M7_wake_M4.scp
150 REM =======================================================================
160 PRINT "RT1170 Connect M7 and Wake M4 Script"
170 REM =======================================================================
180 REM Uncomment ProbeList for standalone script use (outside the stub)
190 REM =======================================================================
200 REM ProbeList
210 p% = ProbeFirstFound
220 REM ProbeOpenByIndex p%
230 WireSwdConnect p%
240 SelectProbeCore p% 0
250 CMInitApDp this
252 REM =======================================================================
254 REM Disable ECC
256 GOSUB 1500
260 REM =======================================================================
270 REM The M4 AP is not visible while the core is held in reset
280 REM Prepare a spin code in RAM and wake up / reset the M4 to it
290 REM This serves two purposes:
300 REM - enables the M4 AP, required for debug visibility
310 REM - prevents M4 code from interfering with flash programming on M7
320 REM =======================================================================
330 REM Prepare spin code
340 GOSUB 1000
350 REM =======================================================================
360 PRINT "Setting M4 clock"
370 REM Set m4_clk_root to OSC_RC_400M / 2: CLOCK_ROOT1 = mux(2), div(1)
380 Poke32 this 0x40CC0080 0x201
390 PRINT "Resetting M4 core"
400 REM Save current reset SRMR and prevent M4 SW reset affecting the system
410 s% = Peek32 this 0x40C04004
420 Poke32 this 0x40C04004 0x00000C00
430 Poke32 this 0x40C04284 0x1
440 Poke32 this 0x40C04004 s%
450 REM =======================================================================
460 REM Release M4 if needed
500 s% = Peek32 this 0x40c04000
510 IF s% & 1 == 1 THEN GOTO 560
520 PRINT "Releasing M4"
530 s% = s% | 1
540 Poke32 this 0x40c04000 s%
550 REM =======================================================================
560 PRINT "View cores on the DAP AP"
570 WireSwdConnect p%
580 CoreList p%
590 SelectProbeCore p% 0
600 REM =======================================================================
610 REM Potentially FlexRAM might need to be set to ensure TCMs are available
620 REM Uncomment next line if needed
630 REM GOSUB 800
640 REM =======================================================================
650 REM Finished - 0 to select the M7, 1 to select M4
660 d% = 0
670 REM =======================================================================
680 REM Setup VTOR in preparation for VECTRESET
690 GOSUB 1300
700 REM =======================================================================
710 END
800 REM ====================== SUB: Configure FlexRAM ========================
810 PRINT "Configuring FlexRAM for 256KB I-TCM, 256KB D-TCM, 0KB OCRAM"
820 REM FlexRAM TCM_CTRL - force RAM clocking ON and set fast mode = b100
830 Poke32 this 0x40028000 0x4
840 REM IOMUXC_GPR17/18 FlexRAM 32KB banks allocation - I(b11), D(b10), OC(b01)
850 Poke32 this 0x400E4044 0x0000AAFF
860 Poke32 this 0x400E4048 0x0000AAFF
870 REM IOMUXC_GPR16 Enable FLEXRAM_BANK_CFG in GPR16/17
880 s% = Peek32 this 0x400E4040
890 s% = s% | 4
900 Poke32 this 0x400E4040 s%
910 RETURN
1000 REM ==================== SUB: Set up M4 spin code ========================
1010 REM Setup some spin code into an area of D-TCM (0x2021FF00)
1020 REM Condensed vector table format taking up 2 words of memory:
1030 REM - x00: SP (dummy), two back-to-back branch-to-self opcodes (b 0)
1040 REM - x04: PC - points to address x00 (+1 Thumb)
1050 PRINT "Setting M4 spin code"
1060 Poke32 this 0x2021FF00 0xE7FEE7FE
1070 Poke32 this 0x2021FF04 0x2021FF01
1080 REM Set top/bottom 16 bits of RAM address into CM4 VTOR iomuxc_lpsr_GPR0/1
1090 Poke32 this 0x40C0C000 0xFF00
1100 Poke32 this 0x40C0C004 0x2021
1110 RETURN
1300 REM ==================== SUB: Setup CM7 VTOR =============================
1310 REM Upon VECTRESET, VTOR is loaded with the value from this register.
1320 REM If the address is invalid, a hard fault occurs after VECTRESET.
1330 REM These registers are set in preparation for a pre-flash driver VECTRESET
1340 REM requested by the stub.
1350 REM BootROM VTOR
1360 s% = 0x210000
1370 REM Set addr >> 7 into CM7 VTOR iomuxc_lpsr_GPR26 (RevB) or 0x400e404c (Rev A)
1380 v% = Peek32 this 0x40C84800
1390 IF v% & 0x00FFFFF0 == 0x1170A0 Then GOTO 1420
1400 Poke32 this 0x40C0C068 s% >> 7
1410 GOTO 1430
1420 Poke32 this 0x400E404C s% >> 7
1430 RETURN
1440 REM =======================================================================
1500 REM ====================== SUB: Disable M7 TCM ECC and OCRAM ECC ==========
1510 REM FlexRAM_CTRL - disable TCM ECC and OCRAM ECC
1520 Poke32 this 0x40028108 0x00000000
1530 REM MECC1/2 PIPE_ECC_EN - disable ECC
1540 Poke32 this 0x40014100 0x00000000
1550 Poke32 this 0x40018100 0x00000000
1560 RETURN
MCUXpresso debug configuration,in the “connect script” item, select the above prepared .scp file:
Fig 6
The result after Debug is:
Fig 7
We can see, the code downloading and debugging all works now.
3.2 IAR IDE ECC script and testing
IAR project script path:
\MIMXRT1170-EVK-hello_world_demo_cm7\hello_world_demo_cm7\evkmimxrt1170
Prepare the file: evkmimxrt1170_connect_cm7_disableECC.mac
The content is:
/*
* Copyright 2019-2021 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
__var rev;
initSysPll2()
{
__var t;
// ANADIG_PLL_PLL_528_CTRL
t = __readMemory32(0x40C84240, "Memory");
if (t & 0x800000)
{
// SysPll2 has been initialized
t &= ~0x40000000;
__writeMemory32(t, 0x40C84240, "Memory");
return;
}
t = __readMemory32(0x40C84270, "Memory");
t |= 0x80808080;
__writeMemory32(t, 0x40C84270, "Memory");
t = __readMemory32(0x40C84240, "Memory");
t &= ~(0x802000);
t |= 0x40000000;
__writeMemory32(t, 0x40C84240, "Memory");
// ANADIG_PLL_PLL_528_MFN
__writeMemory32(0, 0x40C84280, "Memory");
// ANADIG_PLL_PLL_528_MFI
__writeMemory32(22, 0x40C84290, "Memory");
// ANADIG_PLL_PLL_528_MFD
__writeMemory32(0x0FFFFFFF, 0x40C842A0, "Memory");
// ANADIG_PLL_PLL_528_CTRL
__writeMemory32(0x40000008, 0x40C84240, "Memory");
__delay(30);
// ANADIG_PLL_PLL_528_CTRL
t = __readMemory32(0x40C84240, "Memory");
t |= 0x800000 | 0x800;
__writeMemory32(t, 0x40C84240, "Memory");
__delay(250);
t = __readMemory32(0x40C84240, "Memory");
t &= ~0x800;
__writeMemory32(t, 0x40C84240, "Memory");
do
{
t = __readMemory32(0x40C84240, "Memory");
} while ((t & 0x20000000) == 0);
t |= 0x2000;
__writeMemory32(t, 0x40C84240, "Memory");
t &= ~0x40000000;
__writeMemory32(t, 0x40C84240, "Memory");
}
initSysPll2Pfd1()
{
__var t, stable;
t = __readMemory32(0x40C84270, "Memory");
if (((t & 0x8000) != 0) || (((t & 0x3F00) >> 😎 != 16))
{
stable = t & 0x4000;
t |= 0x8000;
__writeMemory32(t, 0x40C84270, "Memory");
t = __readMemory32(0x40C84270, "Memory");
t &= ~0x3F00;
t |= 16 << 8;
__writeMemory32(t, 0x40C84270, "Memory");
t = __readMemory32(0x40C84250, "Memory");
t ^= 0x4;
__writeMemory32(t, 0x40C84250, "Memory");
t = __readMemory32(0x40C84270, "Memory");
t &= ~0x8000;
__writeMemory32(t, 0x40C84270, "Memory");
do
{
t = __readMemory32(0x40C84270, "Memory") & 0x4000;
} while (t == stable);
}
else
{
t &= ~0x8000;
__writeMemory32(t, 0x40C84270, "Memory");
}
}
SDRAM_WaitIpCmdDone()
{
__var reg;
do
{
reg = __readMemory32(0x400D403C, "Memory");
__delay(10);
}while((reg & 0x3) == 0);
__writeMemory32(0x00000003, 0x400D403C, "Memory"); // clear IPCMDERR and IPCMDDONE bits
}
setSemcClock()
{
initSysPll2();
initSysPll2Pfd1();
// Set SEMC root clock to use sys pll2 pfd1 divided by 3: 198Mhz
__writeMemory32(0x602, 0x40cc0200, "Memory");
}
initSDRAM()
{
// Config IOMUX
__writeMemory32(0x00000000, 0x400E8010, "Memory");
__writeMemory32(0x00000000, 0x400E8014, "Memory");
__writeMemory32(0x00000000, 0x400E8018, "Memory");
__writeMemory32(0x00000000, 0x400E801C, "Memory");
__writeMemory32(0x00000000, 0x400E8020, "Memory");
__writeMemory32(0x00000000, 0x400E8024, "Memory");
__writeMemory32(0x00000000, 0x400E8028, "Memory");
__writeMemory32(0x00000000, 0x400E802C, "Memory");
__writeMemory32(0x00000000, 0x400E8030, "Memory");
__writeMemory32(0x00000000, 0x400E8034, "Memory");
__writeMemory32(0x00000000, 0x400E8038, "Memory");
__writeMemory32(0x00000000, 0x400E803C, "Memory");
__writeMemory32(0x00000000, 0x400E8040, "Memory");
__writeMemory32(0x00000000, 0x400E8044, "Memory");
__writeMemory32(0x00000000, 0x400E8048, "Memory");
__writeMemory32(0x00000000, 0x400E804C, "Memory");
__writeMemory32(0x00000000, 0x400E8050, "Memory");
__writeMemory32(0x00000000, 0x400E8054, "Memory");
__writeMemory32(0x00000000, 0x400E8058, "Memory");
__writeMemory32(0x00000000, 0x400E805C, "Memory");
__writeMemory32(0x00000000, 0x400E8060, "Memory");
__writeMemory32(0x00000000, 0x400E8064, "Memory");
__writeMemory32(0x00000000, 0x400E8068, "Memory");
__writeMemory32(0x00000000, 0x400E806C, "Memory");
__writeMemory32(0x00000000, 0x400E8070, "Memory");
__writeMemory32(0x00000000, 0x400E8074, "Memory");
__writeMemory32(0x00000000, 0x400E8078, "Memory");
__writeMemory32(0x00000000, 0x400E807C, "Memory");
__writeMemory32(0x00000000, 0x400E8080, "Memory");
__writeMemory32(0x00000000, 0x400E8084, "Memory");
__writeMemory32(0x00000000, 0x400E8088, "Memory");
__writeMemory32(0x00000000, 0x400E808C, "Memory");
__writeMemory32(0x00000000, 0x400E8090, "Memory");
__writeMemory32(0x00000000, 0x400E8094, "Memory");
__writeMemory32(0x00000000, 0x400E8098, "Memory");
__writeMemory32(0x00000000, 0x400E809C, "Memory");
__writeMemory32(0x00000000, 0x400E80A0, "Memory");
__writeMemory32(0x00000000, 0x400E80A4, "Memory");
__writeMemory32(0x00000000, 0x400E80A8, "Memory");
__writeMemory32(0x00000010, 0x400E80AC, "Memory"); // EMC_39, DQS PIN, enable SION
__writeMemory32(0x00000000, 0x400E80B8, "Memory");
__writeMemory32(0x00000000, 0x400E80BC, "Memory");
__writeMemory32(0x00000000, 0x400E80C0, "Memory");
__writeMemory32(0x00000000, 0x400E80C4, "Memory");
__writeMemory32(0x00000000, 0x400E80C8, "Memory");
__writeMemory32(0x00000000, 0x400E80CC, "Memory");
__writeMemory32(0x00000000, 0x400E80D0, "Memory");
__writeMemory32(0x00000000, 0x400E80D4, "Memory");
__writeMemory32(0x00000000, 0x400E80D8, "Memory");
__writeMemory32(0x00000000, 0x400E80DC, "Memory");
__writeMemory32(0x00000000, 0x400E80E0, "Memory");
__writeMemory32(0x00000000, 0x400E80E4, "Memory");
__writeMemory32(0x00000000, 0x400E80E8, "Memory");
__writeMemory32(0x00000000, 0x400E80EC, "Memory");
__writeMemory32(0x00000000, 0x400E80F0, "Memory");
__writeMemory32(0x00000000, 0x400E80F4, "Memory");
__writeMemory32(0x00000000, 0x400E80F8, "Memory");
__writeMemory32(0x00000000, 0x400E80FC, "Memory");
// PAD ctrl
// PDRV = 1b (normal); PULL = 10b (PD)
__writeMemory32(0x00000008, 0x400E8254, "Memory");
__writeMemory32(0x00000008, 0x400E8258, "Memory");
__writeMemory32(0x00000008, 0x400E825C, "Memory");
__writeMemory32(0x00000008, 0x400E8260, "Memory");
__writeMemory32(0x00000008, 0x400E8264, "Memory");
__writeMemory32(0x00000008, 0x400E8268, "Memory");
__writeMemory32(0x00000008, 0x400E826C, "Memory");
__writeMemory32(0x00000008, 0x400E8270, "Memory");
__writeMemory32(0x00000008, 0x400E8274, "Memory");
__writeMemory32(0x00000008, 0x400E8278, "Memory");
__writeMemory32(0x00000008, 0x400E827C, "Memory");
__writeMemory32(0x00000008, 0x400E8280, "Memory");
__writeMemory32(0x00000008, 0x400E8284, "Memory");
__writeMemory32(0x00000008, 0x400E8288, "Memory");
__writeMemory32(0x00000008, 0x400E828C, "Memory");
__writeMemory32(0x00000008, 0x400E8290, "Memory");
__writeMemory32(0x00000008, 0x400E8294, "Memory");
__writeMemory32(0x00000008, 0x400E8298, "Memory");
__writeMemory32(0x00000008, 0x400E829C, "Memory");
__writeMemory32(0x00000008, 0x400E82A0, "Memory");
__writeMemory32(0x00000008, 0x400E82A4, "Memory");
__writeMemory32(0x00000008, 0x400E82A8, "Memory");
__writeMemory32(0x00000008, 0x400E82AC, "Memory");
__writeMemory32(0x00000008, 0x400E82B0, "Memory");
__writeMemory32(0x00000008, 0x400E82B4, "Memory");
__writeMemory32(0x00000008, 0x400E82B8, "Memory");
__writeMemory32(0x00000008, 0x400E82BC, "Memory");
__writeMemory32(0x00000008, 0x400E82C0, "Memory");
__writeMemory32(0x00000008, 0x400E82C4, "Memory");
__writeMemory32(0x00000008, 0x400E82C8, "Memory");
__writeMemory32(0x00000008, 0x400E82CC, "Memory");
__writeMemory32(0x00000008, 0x400E82D0, "Memory");
__writeMemory32(0x00000008, 0x400E82D4, "Memory");
__writeMemory32(0x00000008, 0x400E82D8, "Memory");
__writeMemory32(0x00000008, 0x400E82DC, "Memory");
__writeMemory32(0x00000008, 0x400E82E0, "Memory");
__writeMemory32(0x00000008, 0x400E82E4, "Memory");
__writeMemory32(0x00000008, 0x400E82E8, "Memory");
__writeMemory32(0x00000008, 0x400E82EC, "Memory");
__writeMemory32(0x00000008, 0x400E82F0, "Memory");
__writeMemory32(0x00000008, 0x400E82FC, "Memory");
__writeMemory32(0x00000008, 0x400E8300, "Memory");
__writeMemory32(0x00000008, 0x400E8304, "Memory");
__writeMemory32(0x00000008, 0x400E8308, "Memory");
__writeMemory32(0x00000008, 0x400E830C, "Memory");
__writeMemory32(0x00000008, 0x400E8310, "Memory");
__writeMemory32(0x00000008, 0x400E8314, "Memory");
__writeMemory32(0x00000008, 0x400E8318, "Memory");
__writeMemory32(0x00000008, 0x400E831C, "Memory");
__writeMemory32(0x00000008, 0x400E8320, "Memory");
__writeMemory32(0x00000008, 0x400E8324, "Memory");
__writeMemory32(0x00000008, 0x400E8328, "Memory");
__writeMemory32(0x00000008, 0x400E832C, "Memory");
__writeMemory32(0x00000008, 0x400E8330, "Memory");
__writeMemory32(0x00000008, 0x400E8334, "Memory");
__writeMemory32(0x00000008, 0x400E8338, "Memory");
__writeMemory32(0x00000008, 0x400E833C, "Memory");
__writeMemory32(0x00000008, 0x400E8340, "Memory");
// Config SDR Controller Registers/
__writeMemory32(0x10000004, 0x400d4000, "Memory"); // MCR
__writeMemory32(0x00000081, 0x400d4008, "Memory"); // BMCR0
__writeMemory32(0x00000081, 0x400d400C, "Memory"); // BMCR1
__writeMemory32(0x8000001D, 0x400d4010, "Memory"); // BR0, 64MB
__writeMemory32(0x00000F32, 0x400d4040, "Memory"); // SDRAMCR0, 32bit
__writeMemory32(0x00772A22, 0x400d4044, "Memory"); // SDRAMCR1
__writeMemory32(0x00010A0D, 0x400d4048, "Memory"); // SDRAMCR2
__writeMemory32(0x21210408, 0x400d404C, "Memory"); // SDRAMCR3
__writeMemory32(0x80000000, 0x400d4090, "Memory"); // IPCR0
__writeMemory32(0x00000002, 0x400d4094, "Memory"); // IPCR1
__writeMemory32(0x00000000, 0x400d4098, "Memory"); // IPCR2
__writeMemory32(0xA55A000F, 0x400d409C, "Memory"); // IPCMD, SD_CC_IPREA
SDRAM_WaitIpCmdDone();
__writeMemory32(0xA55A000C, 0x400d409C, "Memory"); // SD_CC_IAF
SDRAM_WaitIpCmdDone();
__writeMemory32(0xA55A000C, 0x400d409C, "Memory"); // SD_CC_IAF
SDRAM_WaitIpCmdDone();
__writeMemory32(0x00000033, 0x400d40A0, "Memory"); // IPTXDAT
__writeMemory32(0xA55A000A, 0x400d409C, "Memory"); // SD_CC_IMS
SDRAM_WaitIpCmdDone();
__writeMemory32(0x00000017, 0x400d4150, "Memory"); // DCCR
__writeMemory32(0x21210409, 0x400d404C, "Memory"); // enable sdram self refresh after initialization done.
__message "SDRAM init done";
}
restoreFlexRAM()
{
__var base;
__var value;
base = 0x400E4000;
value = __readMemory32(base + 0x44, "Memory");
value &= ~(0xFFFF);
value |= 0xFFAA;
__writeMemory32(value, base + 0x44, "Memory");
value = __readMemory32(base + 0x48, "Memory");
value &= ~(0xFFFF);
value |= 0xFFAA;
__writeMemory32(value, base + 0x48, "Memory");
value = __readMemory32(base + 0x40, "Memory");
value &= ~(0xFF << 8);
value |= 0x7 | (0xaa << 8);
__writeMemory32(value, base + 0x40, "Memory");
__message "FlexRAM configuration is restored";
}
clearECC()
{
__writeMemory32(0x00000000, 0x40014100, "Memory");
__writeMemory32(0x00000000, 0x40018100, "Memory");
__writeMemory32(0x00000000, 0x40028108, "Memory");
}
execUserPreload()
{
restoreFlexRAM();
setSemcClock();
initSDRAM();
clearECC();
}
Mainly add the above red code, which is used to clear the MECC and FlexRAM ECC enable bit.
Add the modified mac script:
Fig 8
Debug result is:
Fig 9
We can see, in the IAR also can do the code downloading and debugging, the script also works for the ECC enabled board.
3.3 MDK IDE ECC script and test result
Open the project path:
\MIMXRT1170-EVK-hello_world_demo_cm7\hello_world_demo_cm7\evkmimxrt1170
Prepare the file:evkmimxrt1170_flexspi_nor_sdram.ini, the content is:
/*
* Copyright 2019-2021 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
FUNC void restoreFlexRAM(void)
{
unsigned int value;
value = _RDWORD(0x400E4044);
value &= ~(0xFFFF);
value |= 0xFFAA;
_WDWORD(0x400E4044, value);
value = _RDWORD(0x400E4048);
value &= ~(0xFFFF);
value |= 0xFFAA;
_WDWORD(0x400E4048, value);
value = _RDWORD(0x400E4040);
value &= ~(0xFF << 8);
value |= 0x7 | (0xAA << 8);
_WDWORD(0x400E4040, value);
}
FUNC void SDRAM_WaitIpCmdDone(void)
{
unsigned long reg;
do
{
reg = _RDWORD(0x400D403C);
}while((reg & 0x3) == 0);
_WDWORD(0x400D403C,0x00000003); // clear IPCMDERR and IPCMDDONE bits
}
FUNC void EnableOSC400M(void)
{
unsigned int reg;
// CTRL1: power down
reg = _RDWORD(0x40C84050);
reg &= ~0x1;
_WDWORD(0x40C84050,reg);
// CTRL2: enable clock
reg = _RDWORD(0x40C84060);
reg |= 0x1;
_WDWORD(0x40C84060,reg);
}
FUNC void EnableOSC24M(void)
{
unsigned int reg;
reg = _RDWORD(0x40C84020);
if(0 == (reg & 0x10))
{
reg = 0x14; // OSC_EN and LP_EN
_WDWORD(0x40C84020,reg);
reg = _RDWORD(0x40C84020);
while (0 == (reg & 0x80000000));
}
}
FUNC void EnablePllLdo(void)
{
unsigned int reg;
// CTRL_AI_CTRL
_WDWORD(0x40C84820,0x00000000);
// CTRL_AI_WDATA
_WDWORD(0x40C84830,0x00000105);
// PMU_LDO_PLL
reg = _RDWORD(0x40C84500);
reg |= 0x10000;
_WDWORD(0x40C84500,reg);
_Sleep_(100);
// PMU_POWER_DETECT_CTRL
_WDWORD(0x40C84580,0x00000100);
_Sleep_(1);
// PMU_REF_CTRL
_WDWORD(0x40C84570,0x00000010);
}
FUNC void InitSysPll2Pfd1(void)
{
unsigned int reg;
unsigned int stable;
// ANADIG_PLL_PLL_528_PFD
reg = _RDWORD(0x40C84270);
if (((reg & 0x8000) != 0) || (((reg & 0x3F00) >> 😎 != 16))
{
stable = reg & 0x4000;
reg |= 0x8000;
_WDWORD(0x40C84270,reg);
reg = _RDWORD(0x40C84270);
reg &= ~0x3F00;
reg |= 16 << 8;
_WDWORD(0x40C84270,reg);
reg = _RDWORD(0x40C84250);
reg ^= 0x4;
_WDWORD(0x40C84250,reg);
reg = _RDWORD(0x40C84270);
reg &= ~0x8000;
_WDWORD(0x40C84270,reg);
do
{
reg = _RDWORD(0x40C84270) & 0x4000;
} while (reg == stable);
}
else
{
//syspll2 pfd1 has been initialized already
reg &= ~0x8000;
_WDWORD(0x40C84270,reg);
}
}
FUNC void InitSysPll2(void)
{
unsigned int reg;
// ANADIG_PLL_PLL_528_CTRL
reg = _RDWORD(0x40C84240);
if (reg & 0x800000)
{
// SysPll2 has been initialized
reg &= ~0x40000000;
_WDWORD(0x40C84240, reg);
return;
}
reg = _RDWORD(0x40C84270);
reg |= 0x80808080;
_WDWORD(0x40C84270, reg);
reg = _RDWORD(0x40C84240);
reg &= ~(0x802000);
reg |= 0x40000000;
_WDWORD(0x40C84240, reg);
// ANADIG_PLL_PLL_528_MFN
_WDWORD(0x40C84280, 0);
// ANADIG_PLL_PLL_528_MFI
_WDWORD(0x40C84290, 22);
// ANADIG_PLL_PLL_528_MFD
_WDWORD(0x40C842A0, 0x0FFFFFFF);
// ANADIG_PLL_PLL_528_CTRL
_WDWORD(0x40C84240, 0x8 | 0x40000000);
_Sleep_(30);
// ANADIG_PLL_PLL_528_CTRL
reg = _RDWORD(0x40C84240);
reg |= 0x800000 | 0x800;
_WDWORD(0x40C84240, reg);
_Sleep_(250);
reg = _RDWORD(0x40C84240);
reg &= ~0x800;
_WDWORD(0x40C84240, reg);
do
{
reg = _RDWORD(0x40C84240);
} while ((reg & 0x20000000) == 0);
reg |= 0x2000;
_WDWORD(0x40C84240, reg);
reg &= ~0x40000000;
_WDWORD(0x40C84240, reg);
}
FUNC void SetSemcClock(void)
{
//EnableOSC400M();
EnablePllLdo();
InitSysPll2();
InitSysPll2Pfd1();
// Set SEMC root clock
// Use sys pll2 pfd1 divided by 3: 198Mhz
_WDWORD(0x40CC0200,0x00000602);
}
FUNC void _clock_init(void)
{
SetSemcClock();
}
FUNC void _sdr_Init(void)
{
// Config IOMUX
_WDWORD(0x400E8010, 0x00000000);
_WDWORD(0x400E8014, 0x00000000);
_WDWORD(0x400E8018, 0x00000000);
_WDWORD(0x400E801C, 0x00000000);
_WDWORD(0x400E8020, 0x00000000);
_WDWORD(0x400E8024, 0x00000000);
_WDWORD(0x400E8028, 0x00000000);
_WDWORD(0x400E802C, 0x00000000);
_WDWORD(0x400E8030, 0x00000000);
_WDWORD(0x400E8034, 0x00000000);
_WDWORD(0x400E8038, 0x00000000);
_WDWORD(0x400E803C, 0x00000000);
_WDWORD(0x400E8040, 0x00000000);
_WDWORD(0x400E8044, 0x00000000);
_WDWORD(0x400E8048, 0x00000000);
_WDWORD(0x400E804C, 0x00000000);
_WDWORD(0x400E8050, 0x00000000);
_WDWORD(0x400E8054, 0x00000000);
_WDWORD(0x400E8058, 0x00000000);
_WDWORD(0x400E805C, 0x00000000);
_WDWORD(0x400E8060, 0x00000000);
_WDWORD(0x400E8064, 0x00000000);
_WDWORD(0x400E8068, 0x00000000);
_WDWORD(0x400E806C, 0x00000000);
_WDWORD(0x400E8070, 0x00000000);
_WDWORD(0x400E8074, 0x00000000);
_WDWORD(0x400E8078, 0x00000000);
_WDWORD(0x400E807C, 0x00000000);
_WDWORD(0x400E8080, 0x00000000);
_WDWORD(0x400E8084, 0x00000000);
_WDWORD(0x400E8088, 0x00000000);
_WDWORD(0x400E808C, 0x00000000);
_WDWORD(0x400E8090, 0x00000000);
_WDWORD(0x400E8094, 0x00000000);
_WDWORD(0x400E8098, 0x00000000);
_WDWORD(0x400E809C, 0x00000000);
_WDWORD(0x400E80A0, 0x00000000);
_WDWORD(0x400E80A4, 0x00000000);
_WDWORD(0x400E80A8, 0x00000000);
_WDWORD(0x400E80AC, 0x00000010); // EMC_39, DQS PIN, enable SION
_WDWORD(0x400E80B8, 0x00000000);
_WDWORD(0x400E80BC, 0x00000000);
_WDWORD(0x400E80C0, 0x00000000);
_WDWORD(0x400E80C4, 0x00000000);
_WDWORD(0x400E80C8, 0x00000000);
_WDWORD(0x400E80CC, 0x00000000);
_WDWORD(0x400E80D0, 0x00000000);
_WDWORD(0x400E80D4, 0x00000000);
_WDWORD(0x400E80D8, 0x00000000);
_WDWORD(0x400E80DC, 0x00000000);
_WDWORD(0x400E80E0, 0x00000000);
_WDWORD(0x400E80E4, 0x00000000);
_WDWORD(0x400E80E8, 0x00000000);
_WDWORD(0x400E80EC, 0x00000000);
_WDWORD(0x400E80F0, 0x00000000);
_WDWORD(0x400E80F4, 0x00000000);
_WDWORD(0x400E80F8, 0x00000000);
_WDWORD(0x400E80FC, 0x00000000);
// PAD ctrl
// PDRV = 1b (normal); PULL = 10b (PD)
_WDWORD(0x400E8254, 0x00000008);
_WDWORD(0x400E8258, 0x00000008);
_WDWORD(0x400E825C, 0x00000008);
_WDWORD(0x400E8260, 0x00000008);
_WDWORD(0x400E8264, 0x00000008);
_WDWORD(0x400E8268, 0x00000008);
_WDWORD(0x400E826C, 0x00000008);
_WDWORD(0x400E8270, 0x00000008);
_WDWORD(0x400E8274, 0x00000008);
_WDWORD(0x400E8278, 0x00000008);
_WDWORD(0x400E827C, 0x00000008);
_WDWORD(0x400E8280, 0x00000008);
_WDWORD(0x400E8284, 0x00000008);
_WDWORD(0x400E8288, 0x00000008);
_WDWORD(0x400E828C, 0x00000008);
_WDWORD(0x400E8290, 0x00000008);
_WDWORD(0x400E8294, 0x00000008);
_WDWORD(0x400E8298, 0x00000008);
_WDWORD(0x400E829C, 0x00000008);
_WDWORD(0x400E82A0, 0x00000008);
_WDWORD(0x400E82A4, 0x00000008);
_WDWORD(0x400E82A8, 0x00000008);
_WDWORD(0x400E82AC, 0x00000008);
_WDWORD(0x400E82B0, 0x00000008);
_WDWORD(0x400E82B4, 0x00000008);
_WDWORD(0x400E82B8, 0x00000008);
_WDWORD(0x400E82BC, 0x00000008);
_WDWORD(0x400E82C0, 0x00000008);
_WDWORD(0x400E82C4, 0x00000008);
_WDWORD(0x400E82C8, 0x00000008);
_WDWORD(0x400E82CC, 0x00000008);
_WDWORD(0x400E82D0, 0x00000008);
_WDWORD(0x400E82D4, 0x00000008);
_WDWORD(0x400E82D8, 0x00000008);
_WDWORD(0x400E82DC, 0x00000008);
_WDWORD(0x400E82E0, 0x00000008);
_WDWORD(0x400E82E4, 0x00000008);
_WDWORD(0x400E82E8, 0x00000008);
_WDWORD(0x400E82EC, 0x00000008);
_WDWORD(0x400E82F0, 0x00000008);
_WDWORD(0x400E82FC, 0x00000008);
_WDWORD(0x400E8300, 0x00000008);
_WDWORD(0x400E8304, 0x00000008);
_WDWORD(0x400E8308, 0x00000008);
_WDWORD(0x400E830C, 0x00000008);
_WDWORD(0x400E8310, 0x00000008);
_WDWORD(0x400E8314, 0x00000008);
_WDWORD(0x400E8318, 0x00000008);
_WDWORD(0x400E831C, 0x00000008);
_WDWORD(0x400E8320, 0x00000008);
_WDWORD(0x400E8324, 0x00000008);
_WDWORD(0x400E8328, 0x00000008);
_WDWORD(0x400E832C, 0x00000008);
_WDWORD(0x400E8330, 0x00000008);
_WDWORD(0x400E8334, 0x00000008);
_WDWORD(0x400E8338, 0x00000008);
_WDWORD(0x400E833C, 0x00000008);
_WDWORD(0x400E8340, 0x00000008);
// Config SDR Controller Registers/
_WDWORD(0x400d4000,0x10000004); // MCR
_WDWORD(0x400d4008,0x00000081); // BMCR0
_WDWORD(0x400d400C,0x00000081); // BMCR1
_WDWORD(0x400d4010,0x8000001D); // BR0, 64MB
_WDWORD(0x400d4040,0x00000F32); // SDRAMCR0, 32bit
_WDWORD(0x400d4044,0x00772A22); // SDRAMCR1
_WDWORD(0x400d4048,0x00010A0D); // SDRAMCR2
_WDWORD(0x400d404C,0x21210408); // SDRAMCR3
_WDWORD(0x400d4090,0x80000000); // IPCR0
_WDWORD(0x400d4094,0x00000002); // IPCR1
_WDWORD(0x400d4098,0x00000000); // IPCR2
_WDWORD(0x400d409C,0xA55A000F); // IPCMD, SD_CC_IPREA
SDRAM_WaitIpCmdDone();
_WDWORD(0x400d409C,0xA55A000C); // SD_CC_IAF
SDRAM_WaitIpCmdDone();
_WDWORD(0x400d409C,0xA55A000C); // SD_CC_IAF
SDRAM_WaitIpCmdDone();
_WDWORD(0x400d40A0,0x00000033); // IPTXDAT
_WDWORD(0x400d409C,0xA55A000A); // SD_CC_IMS
SDRAM_WaitIpCmdDone();
_WDWORD(0x400d4150,0x00000017); // DCCR
_WDWORD(0x400d404C,0x21210409 ); // enable sdram self refresh again after initialization done.
}
FUNC void Setup (void) {
SP = _RDWORD(0x30002000); // Setup Stack Pointer
PC = _RDWORD(0x30002004); // Setup Program Counter
_WDWORD(0xE000ED08, 0x30002000); // Setup Vector Table Offset Register
}
FUNC void DisableECC(){
_WDWORD(0x40014100, 0x00000000);
_WDWORD(0x40018100, 0x00000000);
_WDWORD(0x40028108, 0x00000000);
}
FUNC void OnResetExec (void) { // executes upon software RESET
_clock_init();
_sdr_Init();
DisableECC();
Setup(); // Setup for Running
}
restoreFlexRAM();
_clock_init();
_sdr_Init();
DisableECC();
LOAD %L INCREMENTAL // Download
Setup(); // Setup for Running
// g, main
In the project, add the prepared script file:
Fig 10
Debug result is:
Fig 11
We can see, in MDK, debugging can also be successful using CMSIS DAP.
Information sharing: For MCUXPresso IDE, subsequent scripts will automatically add ECC support, the new version is MCUXpresso11.10.0. Scripts for other IDEs need to be added by themselves.
View full article