【朝花夕拾】RT1170 使能ECC后CMSIS DAP+IDE debug
一,文档描述
本文旨在解决RT1170在使能ECC功能后,使用CMSIS DAP在三大IDE( MCUXpresso,IAR,MDK)不能debug的问题。使能ECC是通过烧录相关的fuse,并且使能了ROM preloading,也就是ROM会帮忙做RAM初始化,但是实际使用的时候,发现不同debugger在IDE上的表象也不一样,比如Segger JLINK就能直接实现debug,但是CMSIS DAP在结合三大IDE的时候,均会出现下载代码到RAM不能debug的问题。这里以MCUXpresso IDE为例,在MIMXRT1170-EVK板子上烧录了ECC相关fuse之后,如果工程是烧录到RAM,那么是能够直接debug,没问题。但是如果是烧录到flash的工程,就会出现flashloader的问题:
图 1
那么这个问题是因为flashloader的不匹配,还是需要额外其他操作呢?本文将会具体给出解决方案。
二,RT1170 ECC基础使能以及问题解决
2.1 RT1170 ECC 基础
ECC即Error Correcting Code, 可以实现内存的错误检查和纠正。那么RT1170有哪些ECC呢?分别为:MECC64, XECC, FlexRAM ECC
- MECC64
MECC64支持1位纠错,和2位检错,无法纠错,主要保护片内的OCRAM1,2。 MECC1保护OCRAM1, MECC2 保护OCRAM2。 OCRAM1 ECC, OCRAM2 ECC用于存放ECC校验值。如果ECC64未使能,可用作普通OCRAM。每 64bits 数据计算出一个8bit的 ECC 校验值(8bits),ECC 算法是 Hsiao Hamming。 - XECC
XECC即External ECC controller,用于为外部存储空间提供ECC功能。XECC支持1位纠错,和2位检错。外部内存包含XECC_FLEXSPI1,XECC_FLEXSPI2,XECC+SEMC. XECC每4bit可以计算出一个4bit的ECC校验值,XECC校验值是紧跟在原始值后面,比如一个32位数据,每4位生成一个4位的ECC校验值,32位原始数据需要生成32bit的ECC校验数据,一共需要64bit的空间。算法:Hsiao Hamming algorithm - FlexRAM ECC
FlexRAM ECC用于保护FlexRAM的ITCM,DTCM以及OCRAM。支持1bit纠错,2bit检错。每DTCM 4byte,或者ITCM/OCRAM 8bytes计算出一个7/8bit 的ECC校验值,ECC校验值放到ECC RAM中。
2.2 RT1170 ECC 使能
本文使能ECC的方法是直接使能相关fuse bit。
- MECC_ENABLE (0x840[2]) = 1
- XECC_ENABLE (0x840[3]) = 1
- ROM preloading (0x950[0]) = 1
- FLEXRAMECC_ENABLE (0x840[15]) = 1
更多软件配置情况,可以参考官方的应用笔记AN13204:
https://www.nxp.com/docs/en/application-note/AN13204.pdf
如下是烧过相关fuse之后的情况,烧fuse可以进入serial download模式,使用MCUbootutility烧录:
图 2
2.3 ECC debug问题解决方法
经过多种方法的测试,比如在脚本中初始化RAM,因为通过ECC的特性,需要先刷一次RAM,但是发现通用直接刷RAM的代码速度太慢,导致下载超时问题,然后再改成使用DMA搬运数据到RAM,保证RAM是被刷过一次的情况,但是结果还是不行,所以刷RAM并不是解决debug问题的根本方式。最后机缘巧合,在连接脚本中先关闭ECC,尤其是FlexRAM ECC,发现这个时候就能够调用烧录算法去做外部flash的操作了。这样可以成功下载代码,然后复位,让ROM自行打开ECC功能。
对于RAM工程能够工作的原因,是因为下载RAM的过程就是一个刷RAM的过程,所以RAM代码才能直接工作。
对于Flash代码的debugger烧录和仿真,还是需要先行关闭ECC模块,主要FlexRAM ECC模块,当然,我们这边为了保险起见,可以直接关闭所有的MECC和FlexRAM ECC寄存器使能位,让flashloader先工作起来,直接控制寄存器地址:
0x40014100=0;0x40018100=0;0x40028108=0;
- 0x40014100 PIPE_ECC_EN[ECC_EN],控制MECC1
- 0x40018100 PIPE_ECC_EN[ECC_EN],控制MECC2
图 3
- 0x40028108 FLEXRAM_CTRL ECC_EN,控制FlexRAM ECC
图 4
根据实际测试的情况,关闭FlexRAM ECC有效,问题应该是出在使用的flashloader存放的区域是FlexRAM的DTCM,查看烧录算法Flashloader的区域情况如下:
图5
三,三大IDE相关脚本准备与测试
下面直接开门见山,给出能解决CMSIS DAP结合三大IDE下载问题的修改脚本。
3.1 MCUXpresso IDE
脚本在IDE中的路径:
C:\nxp\MCUXpressoIDE_11.9.0_2144\ide\LinkServer\binaries\Scripts
准备RT1170_connect_M7_wake_M4_ecc.scp,并且拷贝到上面的路径中,内容如下:
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,在connect script中选择刚刚准备好的.scp文件:
图 6
Debug之后的结果如下:
图 7
可以看到,代码以及能够成功下载。
3.2 IAR IDE ECC 脚本
IAR工程的脚本路径:
\MIMXRT1170-EVK-hello_world_demo_cm7\hello_world_demo_cm7\evkmimxrt1170
准备脚本文件:evkmimxrt1170_connect_cm7_disableECC.mac
内容如下:
/*
* 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) >> 8) != 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();
}
主要添加代码如上述的clearECC(),清除ECC使能标志。
加载修改后的mac脚本:
图 8
Debug结果如下:
图 9
可以看到,在IAR中也能成功下载并且debug。
3.3 MDK IDE ECC脚本
打开工程路径:
\MIMXRT1170-EVK-hello_world_demo_cm7\hello_world_demo_cm7\evkmimxrt1170
准备文件:evkmimxrt1170_flexspi_nor_sdram.ini,内容如下:
/*
* 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) >> 8) != 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
在工程中选择准备好的脚本文件:
图 10
Debug结果如下:
图 11
可以看到,在MDK中,使用CMSIS DAP 也可以成功debug。
信息分享:对于MCUXPresso IDE,后续的脚本会自动添加ECC的支持,版本为MCUXpresso111.10.0。其他IDE的脚本需要自行添加。