【朝花夕拾】如何在RT4位FDCB中使能QE功能

作者:火山

一, 文档简介

RT1XXX芯片需要接外部memory作为程序存储媒介,如果外部使用QSPI flash,通常会使用quad功能去读写代码,SDK代码也是基于quad去读取代码并启动。外部使用的QSPI flash,需要查看SFDP 是否满足包含JESD216B+以上版本,因为这种版本通常RT ROM会自动使能QE功能,但是对于JESD216B以下版本,需要命令方式去使能QE位,从而使能quad功能,否则FDCB的LUT定义的是quad读,但是新的芯片QE位没有使能,会导致程序启动失败。所以,对于新的芯片,需要使用命令方式先使能QE位,然后才可以使用quad功能去读写flash。然而,对于量产芯片,通常会直接下载好代码到QSPI flash,然后再从RT芯片启动,这个时候,额外使能QE位会导致工作量的增加,那么如何能够实现一次性烧录app代码到QSPI flash,并且能够直接使能QE并在RT4位芯片中boot呢?

下面就QSPI flash在JESD216B+以下版本的情况,在MIMXRT1170-EVK板子上讲解,如何使用FDCB添加QE使能的命令,来实现,即使QE位没有使能,也能利用FDCB使能QE并启动。

二,FDCB 添加QE使能

MIMXRT1170-EVK板子上的QSPI flash是IS25WP128,改芯片的QE位是状态寄存器的第6位,具体情况可以从QSPI芯片数据手册查看:
在这里插入图片描述

图1 QE位置
QE位是非易失性位,也就是对于新的芯片,默认是0,没使能quad模式,但是只要写过1之后,就无需再次置位。

下面给出FDCB使能QE位的相关代码。

2.1 使用kDeviceConfigCmdType_QuadEnable

相关FDCB代码如下:

const flexspi_nor_config_t qspiflash_config = {
    .memConfig =
        {.deviceModeCfgEnable = 1u,
			.deviceModeType		 = kDeviceConfigCmdType_QuadEnable,
			.deviceModeSeq		 = {.seqNum = 1u, .seqId = 4},
			.deviceModeArg		 = 0x40,.lookupTable =
                {//Write QE bit
                    [4 * 4 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x1),}}}

deviceModeCfgEnable 用于使能Device Mode 配置
deviceModeType定义deive mode类型为QE使能
deviceModeSeq定义device mode 配置的序列参数
deviceModeArg定义device mode的数据,0x40代表状态寄存器的第6位
lookupTable中定义写寄存器的LUT序列,主要是写状态寄存器。

2.2 使用kDeviceConfigCmdType_Generic

相关FDCB代码如下:

const flexspi_nor_config_t qspiflash_config = {
    .memConfig =
        {.deviceModeCfgEnable = 1u,
			.deviceModeType		 = kDeviceConfigCmdType_Generic,
			.deviceModeSeq		 = {.seqNum = 1u, .seqId = 4},
			.deviceModeArg		 = 0x40,.lookupTable =
                {//Write QE bit
                    [4 * 4 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x1),}}}

deviceModeCfgEnable 用于使能Device Mode 配置
deviceModeType定义deive mode类型为常规配置
deviceModeSeq定义device mode 配置的序列参数
deviceModeArg定义device mode的数据,0x40代表状态寄存器的第6位
lookupTable中定义写寄存器的LUT序列,主要是写状态寄存器。

这里注意到,其实两种方法,唯一的区别就是deviceModeType,那么这里有个问题就是kDeviceConfigCmdType_Generic和kDeviceConfigCmdType_QuadEnable有什么区别?从代码的注释可以看到:

    kDeviceConfigCmdType_Generic,    //!< Generic command, for example: configure dummy cycles, drive strength, etc
    kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command

从操作方法完全一致,在和内部相关部门确认之后,确实kDeviceConfigCmdType_Generic也能使能QE功能,但是这个常规方式通常还支持一般的配置,比如dummy cycle, 引脚的驱动能力等。而kDeviceConfigCmdType_QuadEnable一般专门用于QE位的时候,所以推荐使用还是kDeviceConfigCmdType_QuadEnable。

三,测试FDCB QE使能结果

对于默认的MIMXRT1170-EVK的QSPI flash是使能了QE位功能,所以我们需要首先关闭QE功能并去测试FDCB使能QE后是否工作。

3.1 QE使能关闭测试

这里测试代码使用的是:SDK_2_13_10_MIMXRT1170-EVK\boards\evkmimxrt1170\driver_examples\flexspi\nor\polling_transfer
添加写状态寄存器第6位为0,并读回确认,相关API添加如下:

status_t flexspi_nor_disable_quad_mode(FLEXSPI_Type *base)
{
    flexspi_transfer_t flashXfer;
    status_t status;
    uint32_t writeValue = 0;//

#if defined(CACHE_MAINTAIN) && CACHE_MAINTAIN
    flexspi_cache_status_t cacheStatus;
    flexspi_nor_disable_cache(&cacheStatus);
#endif

    /* Write enable */
    status = flexspi_nor_write_enable(base, 0);

    if (status != kStatus_Success)
    {
        return status;
    }

    /* Enable quad mode. */
    flashXfer.deviceAddress = 0;
    flashXfer.port          = FLASH_PORT;
    flashXfer.cmdType       = kFLEXSPI_Write;
    flashXfer.SeqNumber     = 1;
    flashXfer.seqIndex      = NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG;
    flashXfer.data          = &writeValue;
    flashXfer.dataSize      = 1;

    status = FLEXSPI_TransferBlocking(base, &flashXfer);
    if (status != kStatus_Success)
    {
        return status;
    }

    status = flexspi_nor_wait_bus_busy(base);

    /* Do software reset. */
    FLEXSPI_SoftwareReset(base);

#if defined(CACHE_MAINTAIN) && CACHE_MAINTAIN
    flexspi_nor_enable_cache(cacheStatus);
#endif

    return status;
}
status_t flexspi_nor_QE_register(FLEXSPI_Type *base, uint32_t *QEvalue)
{
    /* Wait status ready. */
    bool isBusy;
    uint32_t readValue;
    status_t status;
    flexspi_transfer_t flashXfer;

    flashXfer.deviceAddress = 0;
    flashXfer.port          = FLASH_PORT;
    flashXfer.cmdType       = kFLEXSPI_Read;
    flashXfer.SeqNumber     = 1;
    flashXfer.seqIndex      = NOR_CMD_LUT_SEQ_IDX_READSTATUSREG;
    flashXfer.data          = &readValue;
    flashXfer.dataSize      = 1;

    do
    {
        status = FLEXSPI_TransferBlocking(base, &flashXfer);

        if (status != kStatus_Success)
        {
            return status;
        }
        if (FLASH_BUSY_STATUS_POL)
        {
            if (readValue & (1U << FLASH_BUSY_STATUS_OFFSET))
            {
                isBusy = true;
            }
            else
            {
                isBusy = false;
            }
        }
        else
        {
            if (readValue & (1U << FLASH_BUSY_STATUS_OFFSET))
            {
                isBusy = false;
            }
            else
            {
                isBusy = true;
            }
        }
        *QEvalue = readValue;

    } while (isBusy);

    return status;
}

在main中,测试流程为:
1)上电初始化后,读取状态寄存器值
2)使能QE位,读取状态寄存器值
3)关于QE位,读取状态寄存器值
代码如下:

PRINTF("Get the QE bit value before QE enable!\r\n");
   uint32_t QEvalue=0;
   status = flexspi_nor_QE_register(EXAMPLE_FLEXSPI, &QEvalue);
   if (status != kStatus_Success)
   {
       return status;
   }
   PRINTF("QE=%X!\r\n",(uint8_t)QEvalue);

    /* Enter quad mode. */
    status = flexspi_nor_enable_quad_mode(EXAMPLE_FLEXSPI);
    if (status != kStatus_Success)
    {
        return status;
    }

    PRINTF("Get the QE bit value after QE enable!\r\n");
   status = flexspi_nor_QE_register(EXAMPLE_FLEXSPI, &QEvalue);
   if (status != kStatus_Success)
   {
       return status;
   }
   PRINTF("QE=%X!\r\n",(uint8_t)QEvalue);

   status = flexspi_nor_disable_quad_mode(EXAMPLE_FLEXSPI);
   if (status != kStatus_Success)
   {
       return status;
   }
   PRINTF("Get the QE bit value after QE disable!\r\n");

  status = flexspi_nor_QE_register(EXAMPLE_FLEXSPI, &QEvalue);
  if (status != kStatus_Success)
  {
      return status;
  }
  PRINTF("QE=%X!\r\n",(uint8_t)QEvalue);

测试结果如下:
在这里插入图片描述
在这里插入图片描述

图2
左图可以看到,刚上电,QE位是使能的,然后最后关闭QE,quad读取也会出错,说明最后quad实际已经关闭。右图是重新上电测试结果,可以发现,上电之后读取的QE也是关闭的。

3.2 下载app FDCB 使能QE并测试

准备app FDCB使能QE的代码,这里使用SDK中的led_blinky代码,FDCB修改为上述使能QE的情况,并予以下载测试。
准备的app有两种:分别为2.1, 2.2两种方法,生产的app为:
evkmimxrt1170_iled_blinky_cm7_FCB_QE.bin
evkmimxrt1170_iled_blinky_cm7_FCB_QEGEN.bin
为了保证下载的flashloader不使能QE从而影响测试结果,这里使用MCUBootUtility, FDCB使用单线方式下载代码,配置如下:
在这里插入图片描述

图3

下载evkmimxrt1170_iled_blinky_cm7_FCB_QE.bin或者evkmimxrt1170_iled_blinky_cm7_FCB_QEGEN.bin
到QSPI flash中:

在这里插入图片描述

图4
下载evkmimxrt1170_iled_blinky_cm7_FCB_QE.bin或者evkmimxrt1170_iled_blinky_cm7_FCB_QEGEN.bin成功后,返回到internal boot模式,启动,可以发现led已经闪烁,说明QE已经被使能并且工作。 下面再次跑QE位验证工程下载到RAM测试,结果如下:

在这里插入图片描述

图5
可以发现,上电后,QE位是使能的! 所以,本文的方式最终可以实现使用FDCB添加QE位使能的功能

四,附件

  • 附件A
    附上blhost的批量.bat文件内容
blhost -t 5242000 -u 0x1FC9,0x013D -j -- get-property 1 0
sleep 10
blhost -t 5242000 -u 0x1FC9,0x013D -j -- load-image ivt_flashloader_user.bin
sleep 100
blhost -t 50000 -u 0x15A2,0x0073 -j -- get-property 1 0
sleep 10
blhost -t 5242000 -u 0x15A2,0x0073 -j -- fill-memory 0x20202000 4 0xcf900001 word
sleep 100
blhost -t 50000 -u 0x15A2,0x0073 -j -- configure-memory 9 0x20202000
sleep 100
blhost -t 5242000 -u 0x15A2,0x0073 -j -- write-memory 0x20202000 cfg_fdcb_RTxxx_1bit_sdr_flashA.bin
sleep 200
blhost -t 50000 -u 0x15A2,0x0073 -j -- configure-memory 9 0x20202000
sleep 100
blhost -t 5242000 -u 0x15A2,0x0073 -j -- read-memory 0x30000000 0x1000 flexspiNorCfg.dat 9
sleep 200
blhost -t 2048000 -u 0x15A2,0x0073 -j -- flash-erase-region 0x30000000 0x9000 9
sleep 200
blhost -t 5242000 -u 0x15A2,0x0073 -j -- read-memory 0x30000000 0x1000 flexspiNorCfg.dat 9
sleep 200
blhost -t 5242000 -u 0x15A2,0x0073 -j -- write-memory 0x30000000 evkmimxrt1170_iled_blinky_cm7_FCB_QE.bin 9
sleep 200
blhost -t 5242000 -u 0x15A2,0x0073 -j -- read-memory 0x30000000 0x9000 flexspiNorCfg.dat 9
sleep 200

pause
  • 附件B
    .bat文件烧录log
C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>blhost -t 5242000 -u 0x1FC9,0x013D -j -- get-property 1 0

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>sleep 10

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>blhost -t 5242000 -u 0x1FC9,0x013D -j -- load-image ivt_flashloader_user.bin

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>sleep 100

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>blhost -t 50000 -u 0x15A2,0x0073 -j -- get-property 1 0
{
   "command" : "get-property",
   "response" : [ 1258424064 ],
   "status" : {
      "description" : "0 (0x0) Success.",
      "value" : 0
   }
}

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>sleep 10

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>blhost -t 5242000 -u 0x15A2,0x0073 -j -- fill-memory 0x20202000 4 0xcf900001 word
{
   "command" : "fill-memory",
   "response" : [],
   "status" : {
      "description" : "0 (0x0) Success.",
      "value" : 0
   }
}

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>sleep 100

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>blhost -t 50000 -u 0x15A2,0x0073 -j -- configure-memory 9 0x20202000
{
   "command" : "configure-memory",
   "response" : [],
   "status" : {
      "description" : "0 (0x0) Success.",
      "value" : 0
   }
}

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>sleep 100

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>blhost -t 5242000 -u 0x15A2,0x0073 -j -- write-memory 0x20202000 cfg_fdcb_RTxxx_1bit_sdr_flashA.bin
{
   "command" : "write-memory",
   "response" : [],
   "status" : {
      "description" : "0 (0x0) Success.",
      "value" : 0
   }
}

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>sleep 200

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>blhost -t 50000 -u 0x15A2,0x0073 -j -- configure-memory 9 0x20202000
{
   "command" : "configure-memory",
   "response" : [],
   "status" : {
      "description" : "0 (0x0) Success.",
      "value" : 0
   }
}

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>sleep 100

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>blhost -t 5242000 -u 0x15A2,0x0073 -j -- read-memory 0x30000000 0x1000 flexspiNorCfg.dat 9
{
   "command" : "read-memory",
   "response" : [ 4096 ],
   "status" : {
      "description" : "0 (0x0) Success.",
      "value" : 0
   }
}

C:\KerryPC\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>sleep 200

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>blhost -t 2048000 -u 0x15A2,0x0073 -j -- flash-erase-region 0x30000000 0x9000 9
{
   "command" : "flash-erase-region",
   "response" : [],
   "status" : {
      "description" : "0 (0x0) Success.",
      "value" : 0
   }
}

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>sleep 200

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>blhost -t 5242000 -u 0x15A2,0x0073 -j -- read-memory 0x30000000 0x1000 flexspiNorCfg.dat 9
{
   "command" : "read-memory",
   "response" : [ 4096 ],
   "status" : {
      "description" : "0 (0x0) Success.",
      "value" : 0
   }
}

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>sleep 200

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>blhost -t 5242000 -u 0x15A2,0x0073 -j -- write-memory 0x30000000 evkmimxrt1170_iled_blinky_cm7_FCB_QE.bin 9
{
   "command" : "write-memory",
   "response" : [],
   "status" : {
      "description" : "0 (0x0) Success.",
      "value" : 0
   }
}

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>sleep 200

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>blhost -t 5242000 -u 0x15A2,0x0073 -j -- read-memory 0x30000000 0x9000 flexspiNorCfg.dat 9
{
   "command" : "read-memory",
   "response" : [ 36864 ],
   "status" : {
      "description" : "0 (0x0) Success.",
      "value" : 0
   }
}

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>sleep 200

C:\--\IMXRTCode\Question\RT1170\flash\QSPI flash\FCB QE\kerry\app\cmd>pause
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你的代码中使用了一个自定义的数字验证码输入框,它包含一个原生的 `input` 标签和一个 `view` 标签,后者用于显示每个数字输入框。根据你的代码,我看到你想要实现的功能是:用户输入数字后,自动跳转到下一个数字输入框,且输入框中的数字会自动填充到对应的置上。如果用户输入的数字已经达到最大长度(11),则输入框不再接受新的输入。 我看到你使用了 `v-for` 指令来遍历数字输入框,并使用了一个 `code` 数组来保存用户输入的数字。在用户输入数字时,你监听了 `input` 事件,并在方法中更新了 `code` 数组。同时,你还监听了 `click` 事件,在方法中实现了点击数字输入框自动跳转到对应置的功能。 如果你想要实现在输入数字时,自动跳转到下一个数字输入框的功能,可以在 `input` 事件中判断当前输入框是否已经输入了最大长度的数字,如果是,则自动将焦点转移到下一个数字输入框上。下面是一个示例代码: ``` <template> <div class="code-input-wrapper"> <input class="cinput" type="number" adjust-position="true" auto-blur="true" @blur="blur" @input="codenum" :focus="focus" value="code" v-model="code" maxlength="11" /> <div class="code-input"> <div v-for="(item, index) in 11" :key="index" @click="codefocus(index)" :style="{ borderBottom: index == code.length ? '8rpx solid #fdcb2e' : '8rpx solid' + codecolor }"> {{ code[index] || '' }} </div> </div> </div> </template> <script> export default { data() { return { code: '', codecolor: '#000' } }, methods: { codenum(event) { const value = event.target.value // 判断是否已经输入最大长度的数字 if (value.length === 11) { // 自动跳转到下一个数字输入框 this.codefocus(value.length) } // 更新组件的数据 this.code = value.slice(0, 11) }, codefocus(index) { if (this.code.length < index) { this.codecolor = '#000' return } this.$refs.cinput[index].focus() this.codecolor = '#fdcb2e' }, blur() { this.codecolor = '#000' }, focus() { this.codecolor = '#fdcb2e' } } } </script> <style scoped> .code-input-wrapper { display: flex; align-items: center; justify-content: center; height: 200px; } .cinput { display: none; } .code-input { display: flex; flex-direction: row; justify-content: center; margin-left: 20px; } .code-input > div { width: 140rpx; height: 140rpx; line-height: 140rpx; text-align: center; font-size: 60rpx; font-weight: bold; border: none; margin-right: 20px; cursor: pointer; } </style> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值