RT1170 Octal闪存启用 RT1170 Octal闪存启用
1.摘要
MIMXRT1170-EVK 硬件可直接支持两种类型的闪存:QSPI 闪存 IS25WP128 和八位闪存 MX25UM51345GXDI00。默认使用 QSPI 闪存,因此相关 SDK 的闪存配置块 (FCB) 以及一些 IDE 调试器下载的闪存驱动程序也默认针对 QSPI 闪存。在实际使用中,一些客户需要在 RT1170 上使用八位闪存,但在将 EVK 硬件修改为八位闪存 MX25UM51345GXDI00 后,他们可能会遇到各种问题,如下载问题、启动问题、调试问题,以及当闪存为空或闪存中有有效的启动代码时,下载结果不同等等。
本文将基于NXP官方的MIMXRT1170-EVK REV C1,修改板载闪存硬件,将QSPI闪存更换为八位闪存MX25UM51345GXDI00,并修改SDK项目FCB,进行ROM API测试,下载相关工具,修改调试器相关的闪存加载程序,并使用不同的IDE进行测试,以便需要的客户可以参考。本文不仅适用于EVK,还适用于RT1170+Octal闪存MX25UM51345GXDI00与客户定制电路板的组合。
图片 1
2. 硬件修改
要将 MIMXRT1170-EVK 板卡的闪存修改为八位闪存,需要断开 QSP I闪存引脚,并连接八位闪存引脚,相关修改点如下:
OPTION2:使用八位闪存(安装 R381/R378/R382/R389/R402/R377/R388/R391,不安装 R380/R399/R386/R390/R392/R385)
图片2
八位闪存的 BOOT_CFG 引脚配置如下:
图片3
图片4
在修改硬件相关电阻以选择八位闪存后,应将 SW1、SW2 配置为内部启动,并从八位闪存启动,然后由软件部分进行控制。
3. 八进制闪存 APP FCB
3.1 测试从 RAM 运行的 SDK ROM API
为了验证板卡硬件能否从八位闪存运行,我们可以测试 SDK 附带的 fsl_romapi 项目:
\SDK_2_12_0_MIMXRT1170-EVK\boards\evkmimxrt1170\driver_examples\fsl_romapi\cm7
请注意,不能直接测试默认项目,因为该项目配置是针对 QSPI 闪存的,而不是八位闪存。如果需要使用八位闪存,客户需要先修改代码,并添加 GPIO 来控制 Flash_RST 引脚,该引脚用于重置八位闪存。option0,1 的值需要修改为八位闪存的值。
3.1.1 八位闪存选项值
图片 5
我们可以使用以下 option0 进行测试,无需配置option1,因为八位闪存连接到主引脚。
option0= 0Xc0400007, option1 = 0 //query_pad =1, cmd_pad=1,133MHz
option0= 0Xc0433007,option1 = 0 //query_pad =8,cmd_pad=8,133MHz
option0= 0Xc0403007,option1 = 0 //query_pad =1,cmd_pad=8,133MHz
3.1.2 fsl_romapi 项目测试
ROM API 项目的修改代码如下,在调用 ROM_FLEXSPI_NorFlash_GetConfig API 之前,需要先使用 GPIO 重置外部八位闪存,因此,这里添加了 Flash_RST=GPIO_AD_03=GPIO09_IO02 引脚的 GPIO 配置。
Pinmux.c 相关代码:
gpio_pin_config_t gpio9_pinP15_config = {
.direction = kGPIO_DigitalOutput,
.outputLogic = 1U,
.interruptMode = kGPIO_NoIntmode
};
GPIO_PinInit(GPIO9, 02U, &gpio9_pinP15_config);
IOMUXC_SetPinMux(
IOMUXC_GPIO_AD_03_GPIO9_IO02,
0U);
IOMUXC_SetPinConfig(
IOMUXC_GPIO_AD_03_GPIO9_IO02,//OD,it is a workaround for EVK HW bug
0X12);
Flexspi_romapi.c 添加了代码:
static serial_nor_config_option_t option_1bit = {
.option0.U = 0xc0400007U,
.option1.U = 0U,
};
static serial_nor_config_option_t option_8bit = {
.option0.U = 0xc0433007,
.option1.U = 0U,
};
static serial_nor_config_option_t option_1_8bit = {
.option0.U = 0xC0403007,
.option1.U = 0U,
};
GPIO_PinWrite(GPIO9, 02U, 0U);
// Delay some time to reset external flash with Flash_RST pin
for (uint32_t i = 0; i < 60000; i++)
__asm volatile ("nop");
GPIO_PinWrite(GPIO9, 02U, 1U);
status = ROM_FLEXSPI_NorFlash_GetConfig(FlexSpiInstance, &norConfig, &option_8bit);
if (status == kStatus_Success)
{
PRINTF("\r\n Successfully get FLEXSPI NOR configuration block with option_8bit\r\n ");
}
else
{
status = ROM_FLEXSPI_NorFlash_GetConfig(FlexSpiInstance, &norConfig, &option_1_8bit);
if (status == kStatus_Success)
{
PRINTF("\r\n Successfully get FLEXSPI NOR configuration block with option_1_8bit\r\n ");
}
else
{
status = ROM_FLEXSPI_NorFlash_GetConfig(FlexSpiInstance, &norConfig, &option_1bit);
if (status == kStatus_Success)
{
PRINTF("\r\n Successfully get FLEXSPI NOR configuration block with option_1bit\r\n ");
}
else
{
PRINTF("\r\n Get FLEXSPI NOR configuration block failure!\r\n");
error_trap();
}
}
}
测试结果为:
图片6
图7
从测试结果中我们可以看到,使用 GPIO 重置外部 flash 后,实际使用的选项值为:
option0= 0xc0403007,option1 = 0 //query_pad =1,cmd_pad=8,133MHz
它可以成功读取SFDP,将闪存配置数据获取到norConfig中,然后使用这些值配置flexSPI模块,最后实现八位闪存相关地址区域的擦除-写入-读取-擦除操作。
从上述测试结果可以看出,修改后的硬件完全正常工作。请注意,由于我们无法确认外部闪存硬件是否正常工作,因此该项目的FCB仍然是QSPI闪存的默认设置,而不是八位闪存。因此,在测试此fsl_romapi项目时,建议从RAM而不是外部闪存运行它。
下图展示了如何从内部 RAM 运行项目,而不是直接下载到闪存:
图片8
在这里,对于配置,我们还有一个需要注意的点,为什么要将 GPIO 引脚 Flash_RST:GPIO_AD_03 配置为 OD(开漏)?
这是由于当前的 MIMXRT1170-EVK 硬件存在一个缺陷,因此采用这种 OD 配置作为临时解决方案。八位闪存 MX25UM51345GXDI00 的电源电压为 1.8V,但 GPIO_AD_03 的组电压为 3.3V,这两个模块之间没有电压转换硬件,因此会出现以下情况:
a) 默认情况下,GPIO_AD_03 为输入模式,该引脚具有内部下拉 (PD) 35K 电阻,并通过外部上拉 (PU) 10K 电阻连接到 1.8V,因此 Flash_RST=1.8V*35K/(10K+35K)=1.4V,该电压也可用作使能信号。
对于正常启动,由于 ROM 未控制八位闪存的 Flash_RST 引脚,因此在实际使用中,该引脚可由任意引脚自由选择。因此,复位引脚默认为输入,电压为 1.4V,可启用八位闪存,无影响。
b) 当需要控制八位闪存复位时,需要使用 GPIO 控制 GPIO_AD_03 引脚。若要输出 0,则正常。但若要输出高电平,使用内部上拉电阻时,将向 Flash_RST 引脚输出 3.3V 电压。该电压已高于八位闪存的 1.8V,且八位闪存数据手册规定最大电压为 2V。尽管闪存芯片具有电压缓冲器,短时间内输入 3.3V 不会损坏芯片,但长时间工作后,无法保证芯片正常工作,这将带来风险。因此,为解决此问题,我们可在闪存加载器、ROM API 中采取临时解决方案:当向 Flash_RST 引脚输出高电平时,可使用 OD 模式,此时引脚电压完全由外部上拉电路决定,且 EVK 还具有外部 10K 上拉至 1.8V 的电路,因此可输出 1.8V 而非 3.3V。
图片9
在 NXP 新的 MIMXRT1170-EVKB 板卡中,硬件增加了电压转换芯片以解决这些问题,可实现 3.3V 和 1.8V 之间的转换:
图片10
3.2 使用 MCUBootUtility 对八位闪存进行编程
我们可以使用 MCUBootUtility 在串行下载模式下测试 MIMXRT1170-EVK+ 八位闪存,通常用于芯片连接、内存擦除、读取和编程。此方法还可使用该工具为八位闪存生成正确的 FCB 头,然后在内部启动模式下测试启动情况。
串口下载-> SW1:1-关,2-关,3-关,4-开
内部启动-> SW1:1-关闭,2-关闭,3-开启,4-关闭
MCUBootUtility 配置如下:
图片11
此配置为:option0=0Xc0403007,query 1wire, cmd 8 wire。
然后,应用程序镜像可使用 MCUBootUtility 附带的代码:
NXP-MCUBootUtility-3.5.0\apps\NXP_MIMXRT1170-EVK_Rev.A\cm7\led_blinky_0x3000a000.srec
图片12
我们可以看到,代码下载已完成。接下来,重置设备,将开发板配置为内部启动模式,然后执行POR或硬件复位。此时,板载LED D34会闪烁,这表明硬件也可以从八位闪存启动。
3.3 SDK APP FDCB modification
如果需要从八位闪存调试 SDK 应用程序演示,必须确保提供正确的应用程序 FDCB。那么,如何将应用程序 FDCB 修改为八位闪存呢?您可以参考 MCUBootUtility 工具烧录的 FDCB 以及八位闪存的数据手册。以下是经过多次测试的 FDCB。关键在于提供正确的查找表 (LUT)。以 RT1170 SDK 的 led_blinky 项目为例,项目 xip 文件中的 evkmimxrt1170_flexspi_nor_config.c 文件修改如下:
const flexspi_nor_config_t octalflash_config = {
.memConfig =
{
.tag = FLEXSPI_CFG_BLK_TAG,
.version = FLEXSPI_CFG_BLK_VERSION,
.readSampleClksrc=kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
.csHoldTime = 3,
.csSetupTime = 3,
.deviceModeCfgEnable = 1,
.deviceModeType = kDeviceConfigCmdType_Spi2Xpi,
.waitTimeCfgCommands = 1,
.deviceModeSeq =
{
.seqNum = 1,
.seqId = 6, /* See Lookup table for more details */
.reserved = 0,
},
.deviceModeArg = 2, /* Enable OPI DDR mode */
.controllerMiscOption =
(1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DdrModeEnable),
.deviceType = kFlexSpiDeviceType_SerialNOR,
.sflashPadType = kSerialFlash_8Pads,
.serialClkFreq = kFlexSpiSerialClk_133MHz,
.sflashA1Size = 64ul * 1024u * 1024u,
.dataValidTime =
{
[0] = {.time_100ps = 16},
},
.busyOffset = 0u,
.busyBitPolarity = 0u,
.lookupTable =
{
/* Read */// EEH+11H+32bit addr+20dummy cycles+ 4Bytes read data //133Mhz 20 dummy=10+10
[0 + 0] = FLEXSPI_LUT_SEQ(CMD_DDR , FLEXSPI_8PAD, 0xEE, CMD_DDR, FLEXSPI_8PAD, 0x11),//0x871187ee,
[0 + 1] = FLEXSPI_LUT_SEQ(RADDR_DDR, FLEXSPI_8PAD, 0x20, DUMMY_DDR, FLEXSPI_8PAD, 0x0A),//0xb30a8b20,
[0 + 2] = FLEXSPI_LUT_SEQ(DUMMY_DDR, FLEXSPI_8PAD, 0x0A, READ_DDR, FLEXSPI_8PAD, 0x04),//0xa704b30a,
/* Read Status SPI */// SPI 05h+ status data 0X24 maybe 0X04
[4*1 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR , FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x24),//0x24040405,
/* Read Status OPI *///05H+FAH+ 4byte 00H(addr)+4Byte read
[4*2 + 0] = FLEXSPI_LUT_SEQ(CMD_DDR , FLEXSPI_8PAD, 0x05, CMD_DDR, FLEXSPI_8PAD, 0xFA),//0x87fa8705,
[4*2 + 1] = FLEXSPI_LUT_SEQ(CMD_DDR , FLEXSPI_8PAD, 0x00, CMD_DDR, FLEXSPI_8PAD, 0x00),//0x87008700,
[4*2 + 2] = FLEXSPI_LUT_SEQ(CMD_DDR , FLEXSPI_8PAD, 0x00, CMD_DDR, FLEXSPI_8PAD, 0x00),//0x87008700,
[4*2 + 3] = FLEXSPI_LUT_SEQ(READ_DDR , FLEXSPI_8PAD, 0x04, STOP_EXE, FLEXSPI_1PAD, 0x00),//0x0000a704,
/* Write enable SPI *///06h
[4*3 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR , FLEXSPI_1PAD, 0x06, STOP_EXE, FLEXSPI_1PAD, 0x00),//0x00000406,
/* Write enable OPI *///06h+F9H
[4*4 + 0] = FLEXSPI_LUT_SEQ(CMD_DDR , FLEXSPI_8PAD, 0x06, CMD_DDR, FLEXSPI_8PAD, 0xF9),//0x87f98706,
/* Erase sector */ //21H+DEH + 32bit address
[4*5 + 0] = FLEXSPI_LUT_SEQ(CMD_DDR , FLEXSPI_8PAD, 0x21, CMD_DDR, FLEXSPI_8PAD, 0xDE),//0x87de8721,
[4*5 + 1] = FLEXSPI_LUT_SEQ(RADDR_DDR , FLEXSPI_8PAD, 0x20, STOP_EXE, FLEXSPI_1PAD, 0x00),//0x00008b20,
/*Write Configuration Register 2 =01, Enable OPI DDR mode*/ //72H +32bit address + CR20x00000000 = 0x01
[4*6 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR , FLEXSPI_1PAD, 0x72, CMD_SDR, FLEXSPI_1PAD, 0x00),//0x04000472,
[4*6 + 1] = FLEXSPI_LUT_SEQ(CMD_SDR , FLEXSPI_1PAD, 0x00, CMD_SDR, FLEXSPI_1PAD, 0x00),//0x04000400,
[4*6 + 2] = FLEXSPI_LUT_SEQ(CMD_SDR , FLEXSPI_1PAD, 0x00, WRITE_SDR, FLEXSPI_1PAD, 0x01),//0x20010400,
/*block erase*/ //DCH+23H+32bit address
[4*8 + 0] = FLEXSPI_LUT_SEQ(CMD_DDR , FLEXSPI_8PAD, 0xDC, CMD_DDR, FLEXSPI_8PAD, 0x23),//0x872387dc,
[4*8 + 1] = FLEXSPI_LUT_SEQ(RADDR_DDR, FLEXSPI_8PAD, 0x20, STOP_EXE, FLEXSPI_1PAD, 0x00),//0x00008b20,
/*page program*/ //12H+EDH+32bit address+ write data 4bytes
[4*9 + 0] = FLEXSPI_LUT_SEQ(CMD_DDR , FLEXSPI_8PAD, 0x12, CMD_DDR, FLEXSPI_8PAD, 0xED),//0x87ed8712,
[4*9 + 1] = FLEXSPI_LUT_SEQ(RADDR_DDR, FLEXSPI_8PAD, 0x20, WRITE_DDR, FLEXSPI_8PAD, 0x04),//0xa3048b20,
/* Chip Erase (CE) Sequence *///60H+9FH
[4*11 + 0] = FLEXSPI_LUT_SEQ(CMD_DDR , FLEXSPI_8PAD, 0x60, CMD_DDR, FLEXSPI_8PAD, 0x9F),//0x879f8760,
},
},
.pageSize = 256u,
.sectorSize = 4u * 1024u,
.blockSize = 64u * 1024u,
.isUniformBlockSize = false,
};
此处的 LUT 为全功能查找表,它包括:8 线读取、1/8 线状态读取、1/8 线写使能、8 线扇区擦除、1 线配置写使能(用于开放外设接口双倍数据速率 (OPI DDR) 模式)、8 线块擦除、8 线页编程、8 线芯片擦除。具体命令与 MX25UM51345GXDI00 数据手册以及 MCUBootUtility 工具生成的 FCB 相同。
4. CMSIS DAP Flashloader
MIMXRT1170-EVK 默认使用 CMSIS DAP 调试器,以 MCUXPresso IDE 为例,它会调用名为 .cfx 文件的闪存加载器,闪存加载器源代码可从以下路径找到:
C:\nxp\MCUXpressoIDE_11.6.0_8187\ide\Examples\Flashdrivers\NXP\iMXRT\ iMXRT117x_FlexSPI_SFDP.zip
可直接使用的现有 .cfx 文件路径为:
C:\nxp\MCUXpressoIDE_11.6.0_8187\ide\binaries\Flash\
MIMXRT1170_SFDP_QSPI.cfx: QSPI flash
MIMXRT1170_SFDP_MXIC_OPI.cfx: octal flash
图片 13
使用闪存加载器 + CMSIS DAP + MCUXPresso 调试结果如下:
图片14
有一点需要注意,即 mcuxpresso IDE 闪存加载器源代码 iMXRT117x_FlexSPI_SFDP.zip,该项目已配置为八位闪存,需修改相关 Flash_RST 控制代码,否则,当输出高电平时,电压将为 3.3V。
图片15
在上图中,
添加代码:
MEM_WriteU32(0x400E835CU, 0x12);
即将 SW_PAD_CTL_PAD_GPIO_AD_03 寄存器设置为 0x12,OD 模式,然后重新生成 mxic MX25UM51345GXDI00 八位闪存 .cfx 文件,用于 mcuxpresso+CMSIS DAP 调试器。
5. 带有 RT-UFL 的 JLINK Flashloader
在实际使用中,许多客户不仅使用板载 CMSIS-DAP 调试器,还喜欢使用外部 JLINK/JLINK plus,或使用板载 JLINK 固件(使用 LPCScrypt 修改固件,注意根据网页说明更新 JINK 固件),或使用外部 JLINK 固件(需要断开板载调试器跳线)。但如果直接调用 JLINK 闪存驱动器,则将是 QSPI 闪存。以下是在 JLINK 中使用八位闪存驱动器的方法。现在,JLINK 驱动器使用 JLinkARM.dll 来定义不同芯片使用的闪存,这与旧的 JLINK 驱动器不同。闪存固件由 JLinkDevices.xml 调用。.dll 文件不允许用户直接修改设备的相应闪存,因此需要提供一个支持 RT1170 八位闪存的闪存驱动器文件,并在 JLinkDevices.xml 中添加调用命令,以覆盖 JLinkARM.dll 中的默认 QSPI 定义。
NXP AE 开发了一款非常有用的全功能闪存驱动程序,称为 RT-UFL,可支持通用 QSPI、HyperFlash、OctaFlash 等。用户可以使用 JLINK 调用 RT-UFL 闪存驱动程序,然后使用 JFLASH、JLINK 指挥官或 IDE(如 MCUXpresso、IAR、MDK)来实现 RT 芯片与不同闪存的调试和下载。
RT-UFL下载链接:
https://github.com/JayHeng/RT-UFL
有关 RT-UFL 的详细使用说明,请查看此博客链接:
https://www.cnblogs.com/henjay724/
下载后,将 RT-UFL 安装到 JLINK 驱动器中,复制以下文件夹文件:
RT-UFL-1.0\algo\SEGGER\JLink_Vxxx
至 JLINK 驱动器安装路径:
C:\Program Files\SEGGER\JLINKV768B
JLINK驱动链接是:
https://www.segger.com/downloads/jlink/JLink_Windows_x86_64.exe
现在,使用原始 RT-UFL 固件结合 JFLASH 直接测试 RT1170 中的八位闪存,调试器为 JLINK plus,仅检查是否可以运行,设备选择:MIMXRT1170_UFL_L0。
_L0 后缀算法适用于 QSPI Flash 和 Octal Flash(页大小为 256 字节,扇区大小为 4KB),_L1/2 后缀算法适用于 Hyper Flash(页大小为 512 字节,扇区大小为 4KB/64KB)。
5.1 RT-UFL JFlash Test
为之前已修改为八位闪存的 led_blinky 项目生成一个 .srec 文件,该文件将稍后由 JFLASH 或 JLINK 指挥器使用。
使用 JFLASH 结合 JLINK plus 创建一个新的 JFLASH 项目。选择支持八位闪存的 MIMXRT1170_UFL_L0 芯片。
测试情况如下,可以看到连接成功,可以找到 ARM Cortex-M7 内核,但编程、读取和擦除功能将失败。可以说,与外部八位闪存的连接根本不成功:
Pic 16
如果使用的 JLINK 不是 JLINK plus,由于许可证不支持 JFLASH,那么客户可以使用 JLINK commander 进行测试,但在此情况下,使用原装 RT-UFL 的测试结果与 JFLASH 完全相同:
图片17
即便使用 mem32 读取地址数据,仍然会遇到 “Failed to initialize RAMCode” 的问题,有时读取的数据不正确,并非真实的闪存数据,客户可以将从 MCUBootUtility 读取的数据与内存中的数据进行比较。
因此,需要对 RT-UFL 闪存驱动器代码进行修改,以使其支持八位闪存,让八位闪存正常工作。
5.2 RT-UFL Flashloader 源代码修改
通过对原始 RT-UFL 代码结合八位闪存测试的分析,经过多次修改和测试,现将修改点逐一列出。使用经修改的 RT-UFL 生成的新闪存加载器文件,可通过 JFlash、JLINK commander、IDE 等进行测试。JLINK 工具分为外部 JLINK plus 和板载 JLINK 固件(不支持 JFLASH)两类。
5.2.1 Flashloader 修改点
1) RAMCode错误
在 JLinkDevices.xml 文件中,将 RAM 位置定义为 OCRAM 地址:
2) 新增擦除扇区 ROM API
JLINK 会调用扇区擦除功能,因此需添加相关的扇区擦除 API:
ufl_main.c
static void ufl_fill_flash_api(void)
{
...
case kChipId_RT117x:
uflTargetDesc->flashDriver.init = g_bootloaderTree_imxrt117x->flexspiNorDriver->init;
uflTargetDesc->flashDriver.page_program= g_bootloaderTree_imxrt117x->flexspiNorDriver->page_program;
uflTargetDesc->isFlashPageProgram = true;
uflTargetDesc->flashDriver.erase_all = g_bootloaderTree_imxrt117x->flexspiNorDriver->erase_all;
uflTargetDesc->flashDriver.erase = g_bootloaderTree_imxrt117x->flexspiNorDriver->erase;
uflTargetDesc->flashDriver.erase_sector= g_bootloaderTree_imxrt117x->flexspiNorDriver->erase_sector;//kerry add
uflTargetDesc->flashDriver.read = g_bootloaderTree_imxrt117x->flexspiNorDriver->read;
uflTargetDesc->flashDriver.set_clock_source = NULL;
uflTargetDesc->flashDriver.get_config= g_bootloaderTree_imxrt117x->flexspiNorDriver->get_config;
uflTargetDesc->iarCfg.enablePageSizeOverride = true;
break;
…
}
ufl_flexspi_nor_flash_imxrt117x.h
typedef struct _flexspi_nor_flash_driver_imxrt117x
{
uint32_t version;
status_t (*init)(uint32_t instance, flexspi_nor_config_t *config);
status_t (*page_program)(uint32_t instance, flexspi_nor_config_t *config, uint32_t dst_addr, const uint32_t *src);
status_t (*erase_all)(uint32_t instance, flexspi_nor_config_t *config);
status_t (*erase)(uint32_t instance, flexspi_nor_config_t *config, uint32_t start, uint32_t lengthInBytes);
status_t (*read)(uint32_t instance, flexspi_nor_config_t *config, uint32_t *dst, uint32_t addr, uint32_t lengthInBytes);
void (*clear_cache)(uint32_t instance);
status_t (*xfer)(uint32_t instance, flexspi_xfer_t *xfer);
status_t (*update_lut)(uint32_t instance, uint32_t seqIndex, const uint32_t *lutBase, uint32_t seqNumber);
status_t (*get_config)(uint32_t instance, flexspi_nor_config_t *config, serial_nor_config_option_t *option);
status_t (*erase_sector)(uint32_t instance, flexspi_nor_config_t *config, uint32_t address);//kerry add
status_t (*erase_block)(uint32_t instance, flexspi_nor_config_t *config, uint32_t address);
const uint32_t reserved0;
status_t (*wait_busy)(uint32_t instance, flexspi_nor_config_t *config, bool isParallelMode, uint32_t address);
const uint32_t reserved1[2];
} flexspi_nor_flash_driver_imxrt117x_t;
3) 提高擦除和编程速度
FlashDev.c
struct FlashDevice const FlashDevice = {
FLASH_DRV_VERS, // Driver Version, do not modify!
"MIMXRT_FLEXSPI_RT1170", // Device Name
EXTSPI, // Device Type
0x30000000, // Device Start Address
0x01000000, // Device Size in Bytes (16mB)
256*4, // Programming Page Size
0, // Reserved, must be 0
0xFF, // Initial Content of Erased Memory
100, // Program Page Timeout 100 mSec
15000, // Erase Sector Timeout 15000 mSec
// Specify Size and Address of Sectors
4096*8, 0x00000000, // Sector Size 4kB (256 Sectors)
SECTOR_END
};
FlashPrg.c:
int EraseSector (unsigned long adr) {
uint32_t instance = g_uflTargetDesc.flexspiInstance;
uint32_t baseAddr = g_uflTargetDesc.flashBaseAddr;
/*Erase Sector*/
status_t status = flexspi_nor_flash_erase(instance, (void *)&flashConfig, adr - baseAddr, FLASH_DRV_SECTOR_SIZE*8);//kerry *8, 4096
if (status != kStatus_Success)
{
return (1);
}
else
{
return (0);
}
}
int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {
status_t status = kStatus_Success;
uint32_t instance = g_uflTargetDesc.flexspiInstance;
uint32_t baseAddr = g_uflTargetDesc.flashBaseAddr;
uint32_t loadaddr = adr - baseAddr;
unsigned char *buffer;
buffer = buf;
int i;
for(i = 0; i < 4; i ++) // kerry add 256*4
{
status = flexspi_nor_flash_page_program(instance, (void *)&flashConfig, loadaddr, (uint32_t *)buffer);
if (status != kStatus_Success)
{
return (1);
}
buffer+=256;
loadaddr+=256;
}
return (0);
}
其原理是减少 PC 向 JLINK 发送命令,再由 JLINK 向开发板发送命令的次数。现在,一条命令可直接擦除并编程多个块。
4) 八进制闪存选项值轮询
需要注意的是,在闪存复位后或首次编程时,必须以单线模式读取串行闪存发现参数 (SFDP)。如果未复位且闪存中存在有效的 FCB,则闪存会初始化为 OPT 模式,需要以 8 线模式读取。此时,无法以单线模式读取闪存芯片的有效 SFDP 表。
RT-UFL是一款支持多芯片的闪存加载器,它不使用特定的 GPIO 作为芯片的 flash_RST。对于 RT-UFL 而言,未添加 GPIO 来控制 flash_RST 引脚,保留了高度的灵活性。否则,一旦客户使用的 RST 引脚与 EVK 不同,仍会出现问题,甚至需要客户花费时间修改闪存加载器源代码,增加开发时间。
因此,鉴于上述考虑,在此处修改代码,不添加 RESET 信号控制,不固定单线或 8 线的选项值,而是通过单线和 8 线轮询来读取 SPDF。
ufl_main.c
static void ufl_set_target_property(void)
case kChipId_RT117x:
uflTargetDesc->flexspiInstance = MIMXRT117X_1st_FLEXSPI_INSTANCE;
uflTargetDesc->flexspiBaseAddr = MIMXRT117X_1st_FLEXSPI_BASE;
uflTargetDesc->flashBaseAddr = MIMXRT117X_1st_FLEXSPI_AMBA_BASE;
// uflTargetDesc->configOption.option0.U = 0xc0433007;
// uflTargetDesc->configOption.option1.U = 0x0;
break;
确保未配置上述选项,否则选项配置将被固定,且轮询选项功能将不再启用。
ufl_auto_probe_flash.c
static const serial_nor_config_option_t s_flashConfigOpt[] = {
// 1st Pinmux, PortA for octal 1 bit SFDP for no FCB in flash eg. MX25UM51345G
{.option0.U = 0xc0403007, .option1.U = 0x00000000},
// 1st Pinmux, PortA for octal 8 bit SFDP for FCB in flash eg. MX25UM51345G
{.option0.U = 0xc0433007, .option1.U = 0x00000000},
// 1st Pinmux, PortA for octal 1 bit SFDP &1 bit CMD for no FCB in flash eg. MX25UM51345G
{.option0.U = 0xc0400007, .option1.U = 0x00000000},
..}
在完成上述修改后,编译 RT-UFL 的源代码项目:
RT-UFL-1.0\build\mdk\MIMXRT_FLEXSPI_UV5.uvprojx,
生成一个新的 MIMXRT_FLEXSPI_UV5_UFL.FLM 编程算法,并将其复制到以下路径:
C:\Program Files\SEGGER\JLINKV768B\Devices\NXP\iMXRT_UFL
JLinkDevices.xml中定义的设备名称是:MIMXRT1170_UFL_octalFlash。
JLinkDevices.xml路径:
C:\Program Files\SEGGER\JLINKV768B
修改 .xml 文件,并添加上述提到的 “RAMCode error” 部分。
修改完成后,请刷新JLinkDLLUpdater.exe文件,以便多个IDE能够同步由更新的XML文件定义的固件。
5.2.2 JFlash Test
从以下 Jflash 的测试结果可以看出,其能够成功擦除,并且应用程序镜像可下载至八位闪存中。下载成功后,进行复位操作,即可看到板载 LED 灯在闪烁。这表明修改后的 RT-UFL 闪存加载器已正常工作。此处需注意,使用 JFLASH 需要借助外部 Segger JLINK Plus。若部分客户使用的是普通 JLINK 或 RT EVK 板载 JLINK 固件,则可尝试采用 JLINK commander 方法。
图片18
5.2.3 JLINK命令测试
使用与 JLINK commander 配套的 JLINK plus 进行测试的结果是:
图片19
可以看到固件能够成功下载。
现在使用 EVK 板载的 JLINK 固件进行如下测试,可以看出编程操作正常。因此,如果用户没有外部 JLINK,也可以直接使用 RT EVK 板载的 JLINK 固件。需要注意的一点是,当使用板载 JLINK 固件时,该固件会导致调试器端口 USB 无法直接为 RT 芯片供电,因此需要配置 J38 跳线连接至 3-4 引脚,然后另找一根 USB 线连接 J20 接口为开发板供电。
图片20
5.3 MCUXpresso + JLINK + 修改后的 RT-UFL 测试
首先,选择MCUXPresso IDE的JLINK调试路径,添加已包含RT-UFL固件的JLINK驱动程序路径,依次进入Windows->首选项,然后路径应如下所示:
图片21
下载时,仍需配置RUN->调试器配置,JLINK配置应为:
Pic 22
请注意,请勿在调试配置中勾选“运行前重置”选项,因为该选项在默认情况下已勾选。
Pic 23
如果勾选了 “Reset before running” 选项,在调试时,代码在下载完成后会被阻塞,无法跳转到主函数。如果客户点击暂停按钮,会遇到代码停在 0x223104 地址处的问题,但在退出调试模式并再次执行上电复位 (POR) 后,会发现应用程序已成功下载到闪存中。
图片24
该问题与 RT1170 安全策略对 JLINK 的影响有关。详情请参考以下链接:
https://www.cnblogs.com/henjay724/p/15725966.html
当 JLink 连接到芯片时,只要执行复位命令,它将直接进入安全调试模式(PC 停在 0x223104)。
因此,请确保未勾选“运行前复位”选项,以便能够正常进入调试模式和主函数,测试结果如下:
图片25
5.4 MDK+JLINK+改进型RT-UFL测试
接下来,使用 MCUXPresso 配置工具结合 SDK 包导出一个 MDK 工程,同样基于 led_blinky 项目,并修改八位闪存的 FCB 代码,然后调用修改后的 RT-UFL 闪存加载器,设备名称为:MIMXRT1170_UFL_octalFlash。
注意,务必刷新以下文件:
C:\Program Files\SEGGER\JLINKV768B\JLinkDLLUpdater.exe
确保 IDE 使用的是最新的固件链接。
以下是具体的 MDK 工程相关配置图片:
图片26
项目选择为 flexspi_nor_debug,编译完成后,将调试工具配置为 JLINK,可找到 JLINK 仿真序列,且在“utilities”中,调试前不应勾选 “updated target before debugging” 选项:
Pic 27
图28
图片29
修改 JlinkSettings.ini,配置 override = 1,将设备设置为 RT-UFL 修改后的固件设备名称:MIMXRT1170_UFL_octalFlash。
图片30
图片31
从上图可以看出,修改后的RT-UFL Octal flash已经成功用于运行MDK项目。
需要注意的是,不要使用下载按钮,因为该按钮无法使用经过覆盖和修改的 RT-UFL 编程算法,它仍会调用接口中已删除区域的编程算法,若找不到该算法则会报错。
5.5 IAR + JLINK + 修改后的 RT-UFL 测试
以下是使用 IAR 结合 JLINK 调试 RT1170 八位闪存,并采用修改后的 RT-UFL 编程算法。具体配置如下:
图片32
不要勾选 “ use flash loaders”,这意味着不要使用 IAR 附带的 .out 文件下载算法,而是使用 JLINK 驱动中经过修改的 RT-UFL 八位闪存驱动器。
图片33
复位时可选择内核,若情况正常,调试时会遇到与勾选复位项的 MCUXPresso 相同的问题,PC 将停在 0x223104 地址处。
图片34
在此处,修改项目设置文件夹中的 ->.jlink 文件,使用 RT-UFL 设备名称:MIMXRT1170_UFL_octalFlash,
并设置 override =1,这样就会调用修改后的 RT-UFL 闪存加载器。如果在新创建的项目中找不到 .jlink 文件,只需先选择 JLINK 调试器,点击下载,此时会生成 .jlink 文件,然后修改该文件并再次进行调试。
图片35
将RT-UFL编程算法修改为适用于八位闪存后,点击 “download and debug” 按钮,将进入调试模式,如下图所示,代码已成功运行:
Pic 36
6. 结论
在完成上述细节操作后,可实现 MIMXRT1170-EVK 开发板上八位闪存的代码下载,并使用 fsl_romspi 项目在 RAM 中运行,以此验证硬件八位闪存的正常读写功能,同时使用 MCUBootutility 验证编程和启动状态。APP FCB 修改需与八位闪存相匹配。调试器可使用 JLINK 或 CMSIS DAP,且需采用正确的闪存驱动编程算法。特别地,JLINK 需使用 RT-UFL 作为闪存加载器,但需修改其源代码。最终可见,RT-UFL 下载算法与 JLINK 的组合,成功在 MCUXpresso、IAR、MDK 三种集成开发环境中实现了八位闪存代码的下载与运行。本文内容不仅限于 MIMXRT1170-EVK 开发板,同样适用于采用 RT1170+ MX25UM51345GXDI00 八位闪存的客户设计板。
附件添加了修改后的 RT-UFL 编程算法以及三大 IDE 的八位闪存项目。
查看全文