精华内容
下载资源
问答
  • 现象描述: 单片机低功耗唤醒后,SPI读写外部FLASH出错 使用单片机型号: stm32L431 库函数版本: HAL库2017版 查找问题方案: 进入低功耗前打印出SPI的相关寄存器,低功耗唤醒后,再配置完SPI后,再次打印出SPI...

    STM32L4退出低功耗后SPI读写出错

    现象描述: 单片机低功耗唤醒后,SPI读写外部FLASH出错
    使用单片机型号: stm32L431
    库函数版本: HAL库2017版

    查找问题方案:
    进入低功耗前打印出SPI的相关寄存器,低功耗唤醒后,再配置完SPI后,再次打印出SPI对应的寄存器,比较寄存器配置,发现SPI相关寄存器在进低出功耗前后并无变化,然后打印了SPI相关管脚配置的寄存器GPIOB->MODER,发现数据异常,进低功耗前GPIOB->MODER=a9ffad7d,退出低功耗后GPIOB->MODER=ffffad7d,问题找到,通过寄存器可以看到SPI对应管脚GPIOB13,GPIOB14,GPIOB15,在推出低功耗后,管脚还处于模拟输入模式,并未在SPI初始化后进入复用推挽模式
    既然查出时SPI管脚配置问题,但 在唤醒后,立即配置SPI初始化了呀,为什么没有成功呢?呢只可能是没有进去初始化函数,在初始化函数里面通过串口打印“初始化”,发现推出低功耗后确实没有进入初始化函数,在往前查,发现了一个条件编译,只有在SPI 的hspi->State=HAL_SPI_STATE_RESET状态,才会进行管脚初始化函数HAL_SPI_MspInit(hspi);在hspi->State=HAL_SPI_STATE_RESET 之前串口打印hspi->State的值 发现hspi>State=HAL_SPI_STATE_READY ,到此真正的问题找到了,在进低功耗前调用 HAL_SPI_MspDeInit(&hspi2)后,hspi->State寄存器并未恢复HAL_SPI_STATE_RESET。
    解决方案:
    在 void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)函数中将spiHandle->State 清零
    新添加代码:spiHandle->State = HAL_SPI_STATE_RESET; //恢复为reset状态,不然退出低功耗后,无法进行管脚初始化配

    测试验证: 再次在退出低功耗后读取SPI管脚配置寄存器,管脚配置成功,读取外部flash数据成功

    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • QCC300x是使用外部Flash片子,使用外部flash的好处就是成本下来了,大家都知道,CSR的片子一直是很贵的,这样的片子就只能对成本要求不高的项目优先,在使用外部Flash时,我们一般默认使用32M(因为官方配置就是这个...

    哈喽大家好,这是该系列博文的第五篇~ 篇~


    <<【系列博文索引】快速通道 >

    1.    QCC300X 外部Flash的读写
            QCC300x是使用外部Flash片子,使用外部flash的好处就是成本下来了,大家都知道,CSR的片子一直是很贵的,这样的片子就只能对成本要求不高的项目优先,在使用外部Flash时,我们一般默认使用32M(因为官方配置就是这个参数,会让使用方便的多),然而我们在使用过程往往使用不了这么大的空间,现在我们就利用起来,一起来学习对外部Flash的应用。

            1.1.    为外部flash分区
                要对外部Flash使用,必先是对外部Flash进行分区,上一节做Upgrade时有对分区文件说明,即XXX.ptn文件。
              需要注意的是外部的Flash可以作为两种用途使用,一种是只读的文件系统,另一种是未处理的连续数据分区(Raw Serial),只读的文件系统是对于代码,语音文件,用户文件等保存于Flash中,但是这个需要以文件的形式打包写入,在代码中不可以被修改,仅仅可以读取。
            未处理的连续数据分区,就是纯粹的Flash数据,在程序中可以写入和读取。

            使用文件系统时我们需要挂载分区,使用Raw Serial分区时 不需要挂载分区。

            我们想实现一个在Flash中的数据写入和读取,所以Flash在原来的分区下添加一个Raw Serial分区:

            0, 8K, PS, (none) # For PS Store
            1, 32K, RO, i1107e_patch_bundle.xuv # Logical #0 : For DSP & firmware patches #0,1
            2, 32K, RO, (erase) # Logical #0 : For DSP & firmware patches #0,2
            3, 612K, RO, (erase) # Logical #1 Audio prompts #1,1
            4, 612K, RO, (erase) # Logical #1 Audio prompts #1,2
            5, 300K, RO, i1107e.xuv # Logical #2 Main application image and other files. #2,1
            6, 300K, RO, (erase) # Logical #2 Main application image and other files. #2,2
            7, 8K, RO, system_i1107e.xuv # Logical #3 PSFS  #3,1
            8, 8K, RO, (erase) # Logical #3 PSFS #3,2
            9, 8K, RS, (erase) 
            10, 8K, RS, (erase) 
            11, *, RS, (erase)
            即添加分区9和10,大小为8K,分区类型是RS(Raw Serial),(erase)每次下载重新擦除。

            需要说明一下,这个分区文件涉及下载软件Xide.exe的下载流程,新添加的分区尽量填写每次下载擦除,否则会影响下载,
            我之前有调试过使用(none)会导致下载有很久的卡顿,导致下载时间超长。

            1.2.    Flash写入数据
            Flash在分好区后就可以读写了,Flash的读写也是一个流的概论,写入需要获取一个Sink,读取需要获取一个Source ,需要注意的是Flash在没有数据时是读取不到数据的,直接读取未写入数据的Flash会是空。

            1.2.1.    获取Flash的Sink
            获取Sink的方法,ADK提供了两个函数,可以获取Flash的Sink,分别是
            Sink StreamPartitionOverwriteSink(partition_filesystem_devices device,
            uint16 partition) 
            Sink StreamPartitionResumeSink(partition_filesystem_devices device,
            uint16 partition,uint16 first_word); 

            可以在Partition 和Stream的代码文件中找到。

            第一个函数重新写入Flash,获取的Sink写入后会覆盖之前写入的数据。

            第二个函数是再次写入Flash。第三个参数是需要写入的起始地址,如果Sink中已经存在数据,可以使用
            uint32 PartitionSinkPosition(Sink sink)函数来获取已经存在的Flash数据大小

            partition_filesystem_devices :是选择分区文件的类型,我们需要选择Flash
            Partition:这个参数就是我们分区时分的分区号,就是XXX.ptn文件中添加的9或10分区号。

            1.2.2.    设置Flash的写入配置
            Flash在写入是需要设置其写入配置,配置需要如下函数设置:
            bool PartitionSetMessageDigest(Sink sink, partition_message_digest_type md_ty, uint16 *data, uint16 len) 
            这个函数可以设置Flash的配置,
            sink: The sink that is writing to the partition
            md_type: The type of message digest:
                PARTITION_MESSAGE_DIGEST_APP_SIGNATURE: Signed with the application DFU key (see note)
                PARTITION_MESSAGE_DIGEST_CRC: Filesystem CRC
                PARTITION_MESSAGE_DIGEST_SKIP: Do not perform verification
            data: pointer to the message digest
            len: length of message digest. 2 for CRC verification, 66 for signature verification 

            1.2.3.    获取Flash的状态
            这一步不是必要的,我们在操作Flash,如果需要查看看状态可使用:
            bool PartitionGetInfo(partition_filesystem_devices device, uint16 partition,partition_info_key key, uint32 *value) 

            参数说明:
            device: The device to query. Set to PARTITION_SERIAL_FLASH to query the serial flash device.
            partition: The number of the partition to query.
            key: The type of information requested:
                PARTITION_INFO_IS_MOUNTED: Whether a partition is mounted or not (1 = mounted, 0 = unmounted).
                PARTITION_INFO_SIZE: The size of the partition in words.
                PARTITION_INFO_TYPE: The type of the partition (0 = unused, 1 = filesystem, 2 = PS Store).
            value: The pointer to return the query result to 

            1.2.4.    写入Flash数据
            写入数据是最后的一步,但是没有前面的铺垫,是不能写入成功的,我们得到的分区Sink,就是我们写入数据入口。

            拿到Sink后,我们不能盲目写入,可以使用SinkSlack(Sink sink),查看一下Sink可以写入的最大数据量,我测试过程中获取到的是48,说明Flash每次最大只能写入48个字符,如果我们需要大量写入,可以分批写入数据。

            数据写入:
            第一步:使用SinkMap(Sink sink) 获取一个指针;SinkClaim(Sink sink ,uint16 extra) 声明一下写入的大小,为了检查能否写入,如果返回0xFFFF,说明不能写入。

            第二步:使用memcpy() 把需要写入的数据搬运到SinkMap()指针指向的地址上,

            第三步:使用SinkFlush(Sink sink uint6 amount)实现Flash的真正写入。

            第四步:使用SinkClose(Sink sink)关闭Sink
            需要注意的是:
            1,Sink写入数据后,如果需要读取,必先使用第四步关闭Sink才能读取,但是使用SinkClose()关闭Sink后,不能再次对Flash写入,需要使用重启写入函数对Flash重启写入。
            2,如果需要多次分批写入Flash,不要SinkClose()关闭Sink,完全写入完成后,再关闭Sink,关闭后,再次写入Flash失效,需要重新覆盖写入,

            3,Sink再次写入时,需要重新获取Sink,获取的Sink偏移需要PartitionSinkGetPosition函数获取即可。

            如果上面的步骤没有出错,恭喜你,你的Flash数据写入成功。

            1.2.5.    Flash写入程序附录
            示例代码只是初步演示:

            Flash的写入:        

    完整代码请联系版主               ‘

    展开全文
  • 外部 flash 挂载 littlefs 文件系统 打开 fal 软件包 打开 littlefs 软件包 打开文件系统 打开 MTD fal_cfg.h /* * Copyright (c) 2006-2018, RT-Thread Development Team * * SPDX-License-Identifier: Apache-...

    外部 flash 挂载 littlefs 文件系统

    打开 fal 软件包

    打开 littlefs 软件包

    打开文件系统

    打开 MTD

    fal_cfg.h

    /*
     * Copyright (c) 2006-2018, RT-Thread Development Team
     *
     * SPDX-License-Identifier: Apache-2.0
     *
     * Change Logs:
     * Date           Author       Notes
     * 2020-04-28     tyustli     first version
     */
    
    #ifndef _FAL_CFG_H_
    #define _FAL_CFG_H_
    
    #include <rtthread.h>
    #include <board.h>
    
    extern const struct fal_flash_dev nor_flash0;
    
    /* flash device table */
    #define FAL_FLASH_DEV_TABLE                                          \
    {                                                                    \
        &nor_flash0,                                         \
    }
    /* ====================== Partition Configuration ========================== */
    #ifdef FAL_PART_HAS_TABLE_CFG
    
    /* partition table */
    #define FAL_PART_TABLE                                                                                                     \
    {                                                                                                                          \
        {FAL_PART_MAGIC_WROD, "filesystem", "nor_flash",  0 , 16 * 1024 * 1024 , 0}, \
    }
    
    #endif /* FAL_PART_HAS_TABLE_CFG */
    #endif /* _FAL_CFG_H_ */
    

    main.c

    /*
     * Copyright (c) 2006-2018, RT-Thread Development Team
     *
     * SPDX-License-Identifier: Apache-2.0
     *
     * Change Logs:
     * Date           Author       Notes
     * 2020-04-28     tyustli      first version
     */
    
    #include <rtthread.h>
    #include <rtdevice.h>
    #include <board.h>
    #include "spi_flash.h"
    #include "spi_flash_sfud.h"
    #include "drv_spi.h"
    
    #define FS_PARTITION_NAME  "filesystem"
    
    #include "fal.h"
    #include "dfs_file.h"
    
    int main(int argc, char *argv[])
    {
        __HAL_RCC_GPIOB_CLK_ENABLE();
        rt_hw_spi_device_attach("spi1", "spi10", GPIOB, GPIO_PIN_14);
    
        if (RT_NULL == rt_sfud_flash_probe("W25Q128", "spi10"))
        {
            return -RT_ERROR;
        };
    
        fal_init();
    
        struct rt_device *flash_dev = fal_mtd_nor_device_create(FS_PARTITION_NAME);
    
        if (flash_dev == NULL)
        {
            rt_kprintf("Can't create a mtd device on '%s' partition.\n", FS_PARTITION_NAME);
        }
        else
        {
            rt_kprintf("Create a mtd device on the %s partition of flash successful.\n", FS_PARTITION_NAME);
        }
    
        if(rt_device_find(FS_PARTITION_NAME) != RT_NULL)
        {
            dfs_mkfs("lfs", FS_PARTITION_NAME);
    
            if (dfs_mount(FS_PARTITION_NAME, "/", "lfs", 0, 0) == RT_EOK)
            {
                rt_kprintf("onchip lfs filesystem mount to '/'\n");
            }
            else
            {
                rt_kprintf("onchip lfs filesystem mount to '/' failed!\n");
            }
        }
        else
        {
            rt_kprintf("find filesystem portion failed\r\n");
        }
    
        return RT_EOK;
    }
    

    spi_flash_port.c

    
    #include <fal.h>
    #include <sfud.h>
    #include <spi_flash_sfud.h>
    
    sfud_flash sfud_norflash0;
    
    static int fal_sfud_init(void);
    static int read(long offset, uint8_t *buf, size_t size);
    static int write(long offset, const uint8_t *buf, size_t size);
    static int erase(long offset, size_t size);
    const struct fal_flash_dev nor_flash0 = { "nor_flash", 0, (16 * 1024 * 1024), 4096, {fal_sfud_init, read, write, erase} };
    
    
    static int fal_sfud_init(void)
    {
        sfud_flash_t sfud_flash0 = NULL;
        sfud_flash0 = (sfud_flash_t)rt_sfud_flash_find("spi10");
        if (NULL == sfud_flash0)
        {
            return -1;
        }
    
        sfud_norflash0 = *sfud_flash0;
        return 0;
    }
    
    static int read(long offset, uint8_t *buf, size_t size)
    {
        sfud_read(&sfud_norflash0, nor_flash0.addr + offset, size, buf);
    
        return size;
    }
    
    static int write(long offset, const uint8_t *buf, size_t size)
    {
        if (sfud_write(&sfud_norflash0, nor_flash0.addr + offset, size, buf) != SFUD_SUCCESS)
        {
            return -1;
        }
    
        return size;
    }
    
    static int erase(long offset, size_t size)
    {
        if (sfud_erase(&sfud_norflash0, nor_flash0.addr + offset, size) != SFUD_SUCCESS)
        {
            return -1;
        }
    
        return size;
    }
    
    展开全文
  • i.MXRT1050 从外部QSPI Nor Flash的启动

    千次阅读 2019-05-07 17:06:00
    最近在研究imxrt1050,首先要让它从外部flash启动,网上查了很多资料,这里整理了几个比较好的教程。 帖子原文: http://blog.chinaaet.com/jihceng0622/p/5100053101 关于外部Flash的代码安全问题和...
    	最近在研究imxrt1050,首先要让它从外部flash启动,网上查了很多资料,这里整理了几个比较好的教程。
    	帖子原文: http://blog.chinaaet.com/jihceng0622/p/5100053101          
    
       关于外部Flash的代码安全问题和代码在外部执行对整个系统性能的影响,RT105x的加密启动(HAB)功能和32KB的L1 ICache/DCache是可以解决的,只是本文先从RT105x的启动配置问题着手,毕竟系统如果都Boot不起来,其他的问题都是空谈了,呵呵。另外,如上面所说,RT105x支持的启动方式有不少,不过个人觉着外部串行SPI Flash启动会是大多数人的折中选择。由于RT105x的官方EVK板上是带有两块串行SPI Nor Flash(一个是Cypress高性能8线高速的Hyper Flash S26KS512SDPBHI02,一个是ISSI物美价廉的4线QSPI Flash IS25WP064AJBLE),所以咱就手上有啥来啥,以板载的Hyper Flash和QSPI Flash为例详细说明下串行SPI Nor Flash的启动流程和具体使用方法。
    
    1. 串行SPI Nor Flash启动流程
      当RT105x EVK板载的Boot模式选择开关SW7设定为如下Table1-1所示的前两者时(其他BOOT_CFG 管脚默认被下拉到地,即OFF状态),系统会通过片上的FlexSPI接口执行外部串行SPI Nor Flash的启动,其启动地址为Table1-2所示的0x6000_0000(如果是从并行的Nor Flash启动则启动地址为0x8000_0000),关于其他Boot pin对启动模式的配置影响,见RT105x的RM手册8.6章节,这里就不细说了。
      Table1-1 典型的启动模式设定
      SW7-1
      SW7-2
      SW7-3
      SW7-4
      启动模式
      OFF
      ON
      ON
      OFF
      Hyper Flash启动
      OFF
      OFF
      ON
      OFF
      QSPI Flash启动
      ON
      OFF
      ON
      OFF
      SD卡启动

    Table1-2 启动相关地址
    Start Address
    End Address
    Size
    Description
    0x80000000
    0xDFFFFFFF
    1.5GB
    SEMC 外部存储器接口 (SDRAM, 并行NOR Flash, PSRAM,
    并行NAND Flash)
    0x60000000
    0x7F7FFFFF
    504MB
    FlexSPI
    0x20200000
    0x2027FFFF
    512KB
    OCRAM
    0x20000000
    0x2007FFFF
    512KB
    DTCM
    0x00000000
    0x0007FFFF
    512KB
    ITCM

       如图1所示为完整的SPI Nor Flash启动流程图,当RT105x的片上ROM在检测到启动模式为FlexSPI接口后,会根据Boot Pin的配置信息配置该模式下需要使用的FlexSPI接口管脚的复用模式并将FlexSPI的时钟配置成默认的低速30MHz,然后会以0x6000_0000为首地址读取前512个字节作为外部Flash的配置信息(即Flash Configuration Parameters,包括几线制的SPI Flash,SPI的时钟频率,LUT查找表,DDR/SDR模式以及片选CS管脚的Hold/Setup Time等信息,见RM8.6.3章节)并以此来配置FlexSPI模块以满足外部Flash的特性,待配置完毕后,RT105x CPU以后即会以AHB总线读取数据和指令的方式(虽然从外部来看仍然是FlexSPI接口,但是由于LUT查找表读取数据的指令已经配置好,CPU只是通过AHB总线发送读取指令即可触发LUT以操作外部Flash,也就是说在内部对CPU来讲已经屏蔽掉了FlexSPI的底层)来读取接下来的跟用户Image相关的几个关键信息,即IVT(Image Vector Table),Boot Data和DCD(Device configuration data)如图2,其中IVT需要放在外部Flash的固定偏移地址(如图3,对Nor Flash来说其需要存储在基地址 + 4KB的偏移地址,比如0x60000000+4*1024)供ROM读取以便让系统知道用户Image的第一条可执行指令放在了哪里以及BootData和DCD的存放地址,BootData则保存了完整Image的首地址和整个image所占的空间大小,而DCD则包含了一些配置命令以便在跳到用户程序入口之前供ROM调用配置内部外设以更好的匹配外部IC,一般如果系统外挂了SDRAM的情况则需要配置好DCD(因为有时需要主程序在跑起来之前,外部SDRAM就得处在ready状态,以供CPU把data或者code copy到SDRAM里时不会出错)。
    

    图1 SPI Nor Flash启动流程

    图2 完整Image组成元素

    图3 IVT针对不同存储介质的存放地址
    综上所述,我们实际上就可以得出结论来,如果要让系统能正常Boot起来,则烧写到外部串行SPI Flash里面的完整image必须要包括五个重要元素,即Flash Configuration Parameters,IVT,Boot Data,DCD和用户image,而其中Flash Configuration Parameters和IVT是存放在固定的地址的,而后三者则由IVT的内容来决定,无论是直接编译生成或者通过辅助工具手动添加,只要我们最后形成的image里面包含了这几个元素,CPU就会认可这个image并执行(先不谈安全加密的事)。所以我们只要搞清楚这个基本原理了,无论是什么方法,最后都是殊途同归,下面就可以放心大胆地去解决RT105x的FlesSPI启动问题了。
    2. SPI Nor Flash启动配置方法
    前面提到如果想要RT105x能正常从外部串行SPI Nor Flash启动的话,待烧写的image是必须要集成五个元素的(Flash Configuration Parameters, IVT, Boot Data, DCD and User Image, 重要事情要多说几遍 呵呵),那具体的实现方法我目前想到的无非两种,一种是在编译链接过程中直接把这几个元素和应用代码链接到一块,并将这几个元素指定好链接地址,最后通过IDE的Flashloader下载到SPI Flash里,第二种则是通过辅助工具在编译链接好的裸应用代码前面手动的添加一个信息头(头里面包含这几个元素),然后通过单独的下载工具或者MCU内部的ROM Bootloader ISP下载进去。这两种各有优劣势,前者比较适合在前期调试的时候使用,这样在IDE里面编辑修改应用代码后做印证测试的时候可以直接在线download和debug(比如单步,断点,查看寄存器和Memory等等),我相信这也是目前大家比较迫切需要的,但是缺点的话则是前期配置过程稍微复杂些且需要对Boot过程和外部SPI Flash的Spec有一定了解(当然这些配置是一劳永逸的,配置一次即可),而后者则是客户不需要关心其他几个元素的配置只专注用户应用的开发,待开发完毕后通过辅助工具生成最终的Image用于小批测试或者量产,缺点是前期调试的话会比较麻烦,每次修改完重新编译生成用户image还需要用辅助工具手动添加信息头然后再通过Bootloader下载进去验证(我想想都有点累的慌。。。这种情况workaround只能是前期先在RAM里调试,待成熟了之后再走这个流程)。
    第二种使用辅助工具的方法,官方已经提供了一整套工具链(可以从RT105x官方主页的”Flashloader i.MX-RT1050”软件包里找到)且有了相应的AN应用笔记介绍其具体操作步骤,这里就不再赘述了。本次我们重点介绍第一种方法,即在IDE环境里通过对工程的配置达到生成并下载调试完整image的目的,说到这里我再啰嗦几句,实际上这种方法做下来不只方便了在线download和debug,好处也不少,一是所有的这几个元素配置信息都以C语言的常量形式体现在应用工程文件里面,会加深我们对Boot的理解程度不说,这样的话如果更换外部SPI Flash也可以很方便的更改适配信息,第二呢则是这种方式形成的image文件会是通用的image格式(比如.bin, .hex和.S19),也会兼容市面上大多数可以直接烧写SPI Flash的量产工具的批量烧写。好了,不再多说了,再说就有点话痨了,呵呵,因为板载有Hyper Flash和QSPI Flash两种,下面就分别详细说明下这两种Flash在IDE环境下的配置方法(我使用的IAR,Keil的可以参考第四章节自行配置,需要添加的几个文件是IAR,Keil和GCC三个环境兼容的)。
    开发测试环境:
    Hardware Platform: MIMRT1050-EVK (SCH-29538 REV A1)
    Software Package: SDK_2.3.0_EVK-MIMXRT1050(mcuxpresso.nxp.com)
    IDE: IAR_v8.20.1
    Debugger: On-Board CMSIS-DAP
    2.1 Cypress 1.8v Hyper Flash启动
    RT105x的EVK板子默认是使用Hyper Flash启动的,所以硬件不需要改动,只需要将SW7启动模式修改成Table1-1第一行配置使能Hyper Flash启动即可,如下图4,然后我们以SDK2.3中的hello world为例介绍具体配置方法。实际上在最新的SDK2.3里面Keil和MCUXpresso版本已经有针对Hyper Flash启动的hello_world_xip的样例了,只是IAR反倒是没有,不过这下正好我们来走一遍完整的配置过程,这样也可以为下一小节的QSPI启动打下基础(官方例程里是没有QSPI XIP例程的),毕竟大多数客户估计还是会倾向于选择QSPI的。

    图4 Hyper Flash启动模式
    (1)打开SDK2.3的hello world例程\boards\evkmimxrt1050\demo_apps\hello_world\iar,在Workspace下可以看到默认是有8种配置的,包括在SDRAM调试,OCRAM调试和spi nor Flash调试,原始的flexspi_nor_debug配置是没有其他几种元素的,所以这种配置下当把代码下进去外部Hyper Flash上的时候可以在线debug但是当重新上电或者外部复位后系统是Boot不起来的,因为没有其他元素信息RT1050启动的时候识别不了它的。接下来我们在此配置基础上新建一个配置出来然后在新的工程配置上添加文件和修改配置,点击IAR菜单栏Project->Edit Configurations,然后在打开的窗口下选择New,在新的工程配置下起一个新的名字“HyperFlash_bootok”,Base on Configuration则选择原有的flexspi_nor_debug以最大限度的保留原有的配置,改好之后点击Ok即当前工程会进入新添加的HyperFlash_bootok配置状态;

    (2)在此工程配置下,新添加一个Group(右键工程->Add->Add Group)并命名为“xip”,然后右键该Group->Add->Add Files,找到根目录\devices\MIMXRT1052\xip路径下的四个文件,将该四个文件都添加到当前工程上来,如下所示,我们可以打开这两个.c文件即可看到除了User Image之外的其他四个元素信息都以常量的方式被定义在指定的段地址内,以便在编译链接之后将这几个元素配置信息分配到指定的地址上以保存在最终的Image上,且这四个文件是可以兼容IAR,Keil和GCC三大编译器的所以可以随意Porting,当然不要忘了在工程配置中头文件搜索路径上添加那两个头文件的路径,另外如果没有XIP_EXTERNAL_FLASH这个宏的话也要加上;
    在这里插入图片描述

    (3)由于四个元素被分别定义到指定的段内,但是默认的原始工程里面的链接文件是没有这几个段的定义的(Keil和MCUXpresso由于有xip的样例,它们是定义好的了),所以还需要在原始的链接文件基础上添加这几个段的定义并分配好地址,我们将原来的链接文件MIMXRT1052xxxxx_flexspi_nor.icf复制一份重命名为MIMXRT1052xxxxx_hyperflash_nor_bootok.icf(名字倒是无所谓),然后打开该文件,添加这几个段的定义和地址分配如下(修改好的源文件见随本文档附带的压缩包),然后在工程配置Options->Linker里选择新修改的链接文件,最后点击确认;

    在这里插入图片描述

    (4)不要以为这样就结束了,呵呵,我们这两步说到几个重要的元素信息是以常量的形式通过链接文件保存在指定的地址段内,不过我们的应用工程却没有调用它们,在编译的时候编译器会默认把他们又给优化掉了搞的最后没有体现在Image里面,前面的工作白搭了,所以还需要额外一步告诉编译器把这几个常量给Keep住,具体配置如下图,然后点击确认;
    在这里插入图片描述
    (5)这样工程配置就结束了,我们重新编译整个工程,然后在生成的.map文件里即可看到如下这四个元素信息都已经正确的分配到指定地址了,这样就万事俱备,就差IDE IAR的Flashloader这个“东风”了;
    在这里插入图片描述
    [url=](6)在IAR v8.20.1以上的版本已经有HyperFlash的Flashloader了,我们在Options->Debugger选项下选择CMSIS-DAP(RT1050EVK板载默认的调试器),然后接下来特别需要注意两个问题:第一是要在Options->Debugger->Extra Options里添加如下图1所示的“–drv_default_breakpoint=1”,即强制IAR的默认断点方式为硬件断点,因为虽然IAR默认断点是Auto模式,但是它会优先使用软件断点(Keil下会优先使用硬件断点),而不巧的是CMSIS-DAP调试器不支持软件断点(Jlink很NB,它同时支持软件和硬件断点,不需要这一步),所以我们只能通过这种方式解决这个尴尬的问题;第二是在Options->CMSIS-DAP选项下,Reset类型需要选择Core Reset(否则在下载的时候会因为复位时序的问题导致出现下载错误)。这两步都配置完毕之后点击Ok保持该配置,最后点击Debug即可完美的把带有几个重要元素信息的配置数据都下载到外部Hyper Flash里面并进入调试模式,正常单步或者断点(注意ARM Cortex-M7最多支持8个硬件断点),并且按键复位或者重新给板子上电都可以让RT105x正常Boot起来,最后有图有真相,发个串口打印的结果“hello world”, Enjoy it…[/url]

    在这里插入图片描述

    2.2 ISSI 1.8v QSPI启动
    上面说完Hyper Flash的启动方法,接下来继续说说QSPI启动。由于板子上的Hyper Flash和QSPI时钟、片选和部分数据线是共用的,所以在测试QSPI启动的时候需要把Hyper Flash焊掉(跟板子硬件设计有关系,不焊掉会影响时序,稍微有点心疼,毕竟Hyper Flash比较贵而且又是BGA的焊下来就焊不上去了,当然,如果是客户自己设计的板子只会有一种SPI Nor Flash,那就没这个问题了),然后将下图中DNP的0欧姆电阻焊上,最后特别注意的是需要在QSPI Flash的第7脚和3脚即Reset和WP管脚上拉4.7k的电阻到电源Flash_VCC。因为我发现有个别型号的QSPI Flash,比如板子用的ISSI这个,在系统启动的时候Reset和WP这两个脚是悬空态,而QSPI Flash默认上电都是单线方式,这样的话Reset和WP如果是低电平则QSPI一直处于复位和写保护状态,从而造成系统RT1050读取QSPI信息失败进而导致启动失败,所以需要在这两个脚上加个上拉电阻给它有效的高电平,后来我测试的QD和Winbond的QSPI这两个脚里面是有上拉电阻的,系统启动后是固定的高电平就没有问题了,不过我的建议是最好外部再加一个保证可靠,也不会影响后续的4线通信。另外,别忘了SW7启动模式需要修改成Table1-1第二行配置使能QSPI Flash启动,如下图5:

    图5 QSPI Flash启动模式
    (1)我们仍然以上面的hello world工程为例,有前面章节打基础,本章说起来就轻松不少了,在当前工程下,点击IAR菜单栏Project->Edit Configurations继续新建一个工程配置并以HyperFlash_bootok为蓝本将新的配置命名为“Qspi_nor_bootok”如下图,然后点击Ok进入该配置模式下;

    (2)此时xip的Group文件组仍然有效,不过由于Boot的Flash类型发生了变化,所以需要修改外部SPI Flash的前512字节的Flash Configuration Parameters元素信息(其他几个元素无需修改)。打开fsl_flexspi_nor_flash.c文件,然后在hyperflash_config常量前面添加如下图Qspiflash_config的常量(修改后的源文件见随本文档附带的压缩包),实际上只是修改了外部SPI Flash的Pads类型、SPI时钟频率、Flash的大小(包括总大小以及page和sector的大小)和最重要的LUT查找表指令,这里我使用了外部QSPI Flash的四线Quad I/O Read模式(即0xEB),此模式下SPI的时钟频率可以跑到133MHz,总带宽可以达到532Mbps即66.5MByte/s(实际上很多MCU片内的Flash时钟也差不多这个频率甚至比这个低,不过内部的Flash线宽会大些),这个速度虽然相比于CPU 600MHz的主频慢很多,但是实际上RT1050的一级缓存ICache和DCache各有32KB且在程序里默认是打开的,实测下来对大部分代码来说外部SPI Flash的带宽几乎不会拖累CPU性能,针对特定应用的复杂代码留待大家自行测试(实测Opus音频编解码,跑在外部QSPI Flash上的性能大概为跑在内部SRAM上的70%~80%);

    (3)上一步通过预编译QSPI_BOOT宏来使能QspiFlash的配置信息主要是为方便跟前面HyperFlash启动兼容,只需在当前工程配置下添加QSPI_BOOT宏即可,如下图所示,这样即使再跳回HyperFlash_bootok工程时也不必麻烦地来回修改Flash Configuration Parameters元素信息了,同时该工程配置下的链接文件由于各个段地址没有变化则不用修改,只是需要Keep的常量记得替换成Qspiflash_config,然后点击确认保存;

    (4)此时整个工程的配置工作就完成了,点击Build完成对整个工程的编译和链接,查看.map文件也可以看到其他4个主要元素配置信息也都链接到整个image里了。不过接下来需要解决的是QSPI Flash的Flashloader问题了。在IAR For ARM v8.20.2以上的版本的Flashloader里已经加入了对QSPI Flash的支持了,但是该Flashloader只支持ISSI的QSPI Flash,我在此基础上做了修改和优化加入了对GD和Winbond QSPI Flash的支持,该新的Flashloader见随本文档附带的压缩包文件,将压缩包路径Firmware\IAR_8.20_Flashloader下的四个文件copy到IAR安装目录下C:\Program Files (x86)\IAR Systems\Embedded Workbench 8.0\arm\config\flashloader\NXP并覆盖源文件。此外,该修改后的Flashloader同时支持HyperFlash和QSPI Flash的download和debug(通过查询外部Boot模式来切换这两种烧写算法);

    (5)一切准备就绪,在点击debug之前记得确认options->debugger下选择好CMSIS-DAP并且确保Reset类型必须要选择Core Reset,然后点击确认保存,最后debug将代码下载到外部QSPI Flash里并调试或者重新上电测试,hello world仍然让人激动不已,不容易啊不容易。

       上述两种外部SPI Nor Flash的启动配置方式仅仅是以hello world工程为例了,实际上大家可以参照如上几个步骤任意porting到SDK的其他工程实例里面去,而且由于SDK_2.3.0_EVK-MIMXRT1050\devices\MIMXRT1052\xip目录是共享的文件(包括Flashloader也是共享的),所以添加的那四个文件内容不需要再修改了,只需要手动添加文件到工程和配置IAR相关选项即可,操作起来还是比较快的。
    
    1. 代码跑在SPI Flash数据跑在SDRAM的使用方法
      前面比较详细的讲了HyperFlash和QSPI Flash的启动方式,趁着兴致尚在我们再加点餐。我相信在很多客户开发RT105x过程中,将code跑在外部SPI Flash里,而数据存放在外部SDRAM里面会是比较常用的一种选择(比如一些会用到高分辨率的GUI显示方面,内部RAM不够用了)。虽然前面提到的xip那四个文件(两个.c和两个.h)里面的fsl_flexspi_nor_boot.c文件有定义dcd_sdram这个常量,不过很快就会发现这个常量数组里面的数据很大且看不出什么意义来(看不出意义就意味着不知道怎么修改),这是因为这个常量数组里面是编译后的可执行命令,它是根据不同的SDRAM编译后的结果,也就意味着不同的SDRAM这个数组是不一样的,这就尴尬了,客户如果不是使用EVK板载的SDRAM的话该怎么搞呢?哈哈,这个倒是不用担心,官方很快会推出一个辅助工具来生成不同SDRAM的DCD常量数组,不过在此之前我们也不能干等着吧,所以本章节的“加餐”就是提出一种workaround先提前解决下这个问题。
      我们要知道,在系统上电前无论代码还是数据都是存在SPI Flash这些非易失存储介质里面的,待上电后程序会有一个Copy过程将数据或者想要在RAM里执行的代码copy到RAM里面去,对内部RAM来讲无所谓(因为一上电内部的SRAM就已经初始化完成了)而对外部SDRAM来说是需要事先初始化RT105x的SDRAM控制器才能往该SDRAM可寻址的空间copy内容的。幸运的是在Copy之前我们是有段缓冲时间的,恰恰就是这段缓冲时间给了我们有可以不使用DCD配置的机会(实际上DCD也是ROM在跳到应用代码之前读取其内容对SDRAM进行初始化)。以IAR的启动代码为例,打开startup_MIMXRT1052.s文件找到CPU的起始入口Reset_Handler如下图,执行的Copy过程实际上是在__iar_program_start这个函数里面实现的(具体内容使用的是IAR自己的库, Keil是在__main里实现的),而在该函数之前(即在SystemInit函数里面)我们只需要将SDRAM初始化好让其Ready了就不会影响后续数据的copy和使用,所以下面我就简单介绍下具体操作方法。

    (1)仍然是在当前hello world工程下,点击IAR菜单栏Project->Edit Configurations继续新建一个工程配置并以上面的HyperFlash_bootok为蓝本将新的配置命名为“flexspi_code_sdram_data”如下图,然后点击Ok进入该配置模式下;

    (2)打开system_MIMXRT1052.c系统配置文件,也就是SystemInit函数所在的文件里面添加如下图所示SDRAM初始化相关的函数并在SystemInit的最后调用就可以在使用SDRAM之前将其初始化(具体修改后的源文件见随文档附带的压缩包),而且初始化函数均是以C语言形式读写配置SDRAM相关寄存器,这样的话即使SDRAM更换了也可以随时修改初始化寄存器配置以适配不同的SDRAM了,俗话说未知是最可怕的,而一旦都是开放的话就没那么难了。至于SDRAM这块的初始化是怎么找到的呢,实际上就是将SDRAM的预处理文件(当前目录下的evkmimxrt1050_sdram_init.mac)里面的命令用C语言实现了而已;

    (3)由于仍然是为了兼容性问题,上面使用了预编译命令判断HYBERFLASH_SDRAM宏来决定是否初始化SDRAM,所以在当前工程配置下需要添加HYBERFLASH_SDRAM宏声明以使在当前工程配置下SDRAM初始化生效;

    (4)然后需要修改下链接文件,将数据都分配到SDRAM地址范围内,将MIMXRT1052xxxxx_hyperflash_nor_bootok.icf复制后重命名为MIMXRT1052xxxxx_flexspi_code_sdram_data.icf,打开该文件,添加data3相关信息之后保存该链接文件,并在Options->Linker文件里选择新的链接文件(源文件见随文档附带的压缩包),点击确定保存配置;

    (5)一切都修改完毕之后,点击编译链接,再打开.map文件即可看到所有的数据变量已经被分配到外部SDRAM的寻址空间里面了,最后再点击debug将代码下载到外部SPI Flash里面(注意SW7启动模式记得修改成HyperFlash启动,因为本例子演示的是code跑在HyperFlash里,数据跑在SDRAM里),这样就完美实现代码在SPI Flash里执行而数据跑在SDRAM里。当然,hello world本身没多少数据,大家可以把该功能照本宣科的poring到复杂一点的应用里面或者在当前工程里面自己memory alloc一段足够大的数据区,然后读修改写的去操作以测试该方法的可靠性,我这里就不多说了。

    1. GD和Winbond 3.3v QSPI Flash启动
      在第2.2章节里我已经介绍了RT1050 EVK板载1.8v ISSI的QSPI Flash的启动方法,不过经过一段时间客户的反馈,实际上市面上常用的QSPI Flash目前以GD和Winbond的3.3v产品居多,物美价廉且采购渠道丰富,所以我特意增加了第4章用来专门介绍下GD和Winbond 3.3v QSPI Flash启动方法并修改优化了Keil下对这两家QSPI Flash的烧写算法供客户在keil下擦写和debug。
      硬件上仍然是以我们官方RT1050的EVK板子为调试平台,在2.2章节的硬件改动基础上焊掉ISSI的QSPI Flash,换成GD的GD25Q32CSIG 3.3v QSPI Flash(3脚和7脚仍然上拉电阻到VDD),然后将下图中EVK板子R49的0欧姆电阻去掉,R301用0欧姆电阻短接,即将Flash电源由之前的1.8v改成3.3v,其他部分硬件与2.2章节保持一致,接下来我介绍Keil环境下的配置方法(前面的示例用的IAR,这次用keil让大家对IAR和keil下的开发配置都熟悉一遍):

    (1)首先打开Keil下SDK开发包的hello_world_xip工程(路径demo_apps\hello_world_xip\mdk,Keil自带xip的工程),默认只有hello_world_xip Flexspi_nor_debug和hello_world_xip Flexspi_nor_release两个跑在板载HyperFlash的工程配置,点击Keil菜单栏Project->Manage->Project Items,我们新添加一个工程配置hello_world_xip Qspi_nor_debug如下图,然后选择该工程配置为当前工程,最后点击OK确认:

    (2)在新建的工程配置里,右键工程Options->C/C++,添加QSPI_BOOT和XIP_EXTERNAL_FLASH这两个宏如下图1,然后打开工程目录下xip->fsl_flexspi_nor_flash.c文件,参考2.2章节中(2)点,手动添加QSPI的Flash Configuration Parameters元素信息如下图2,有一点不同的是我们官方板子的ISSI QSPI Flash的最高时钟可以到133MHz,而Winbond的QSPI最高到80MHz,GD QSPI最高到120MHz,我板子上自己焊了一块GD的GD32Q32CSIG QSPI Flash,所以将serialClkFreq设定为kFlexSpiSerialClk_100MHz,然后sflashA1Size改成4M Bytes;

    (3)由于keil下自带了xip的工程,所以我们就直接复用其现成的.scf链接文件即可不用做修改,如下图Options->Linker。而且keil下也已经添加了Keep变量以防止xip这几个元素信息因为程序里没有调用而自动被编译器优化掉(注意:下图显示窗口有限,实际上要keep的信息段包括.boot_hdr.ivt,.boot_hdr.boot_data,.boot_hdr.dcd_data和.boot_hdr.conf,格式参考下图);

    (4)至此我们编译整个工程,最后打开生成的.map文件如下图可以看到我们想要的几个QSPI启动必须的元素信息头都已经正确的分配到image文件里了;

    (5)支持QSPI启动的完整image文件通过以上几步我们已经解决了,接下来要解决keil下download、Erase和debug需要的QSPI Flash烧写算法问题,本文档附带的压缩包文件里路径Firmware\Keil_Algorithm下MIMXRT_QSPIFLASH.FLM文件为我已经优化修改好的可以支持ISSI,GD和Winbond烧写的Flash算法,将其copy到keil安装路径下C:\Keil_v5\ARM\Flash即可,然后右键工程options->Debug-> CMSIS-DAP debugger,进入settings->Flash Download,点击Add找到如下图所示的MIMXRT_QSPIFLASH(4KB Sec),另外建议给Flash算法预留的RAM空间大一些否则可能会导致算法运行失败,因为这个flash算法比较占空间,我这里修改成了0x4000大小是没有问题的;

    (6)设置完毕之后,我们再次重新编译整个工程,然后点击F8或者keil菜单栏Flash->Download即可完成对外部QSPI的擦除和写入,待烧写完毕之后我们点击debug即可正常调试(建议:如果程序做了修改,在编译之后进入debug之前先Download一次,再点debug),重新断电之后程序也可以。

    无论是阿莫论坛还是AET,由于图片有点多,排版都比较麻烦而且整体视觉效果不太好,所以我也把PDF的文档加到随本文附带的压缩包里,另外本文提到的代码和源文件均见如下压缩包

    展开全文
  • flash中调用外部程序的另一种方法 之前在fscommand中调用外部程序,今天有网友针对fscommand的安全性问题提出质疑,另外fscommand调用批处理会出现一个大大的黑框。我们目的是在本机运行程序时调用外部程序,可以...
  • STM32采用Jlink烧写外部Nor Flash

    千次阅读 2017-05-16 16:15:04
    1. 开始 -> 所有程序 -> SEGGER,打开安装Jlink的驱动SEGGER下的J-Flash 2. File ->Open Project… -> 打开STM32F103ZE_ST_MB672_CFI_1x16.jflash(根据自己的CPU型 号选择) STM32F103ZE_ST_MB672_CFI_1...
  • SPI作为基本的外设接口,在FLASH,EPPROM和一些数字通讯中,具有广泛的应用。SPI总线由四个接口构成: CS :片选端,由主设备控制 MISO:主设备输入,从设备输出 MOSI:主设备输出,从设备输入 SCK :时钟信号 ...
  • flash builder4使用外部SWC库

    千次阅读 2017-07-03 20:32:19
    flash builder(下面简称FB)使用SWC文件的方法有三种,一种是合并到代码,一种是外部,一种是运行时共享库(RSL) (图1) 1)合并到代码就不用说了,显而易见 2)外部 (可实现主程调用库时有代码提示,而库又...
  • http://blog.sina.com.cn/s/blog_5e83fce60100r663.html<object id="bcastr" data="camnpr.swf?xml=xml/camnpr.xml" type="application/x-shockwave-flash" width="650" height="285"> <param name="mo
  • //加载出错! }//end if } //end onLoadError my_mcl.addListener(myListener);//注册一个新的监听对象 my_mcl.loadClip(loadfile,loadmc);//加载文件loadfile到loadmc stop(); //MovieClipLoader....
  • 文章主要介绍了一下,TMS320C6678 DSP的SPI FLASH的硬件设计需要注意的问题以及相应的软件调试的问题。
  • Flash处理外部XML文档数据详细教程

    千次阅读 2008-08-20 10:03:00
    其次是要装上Windows系统和Flash8.XML基础:既然是处理XML文档.就要先来了解下XML文档.下面是我所了解的,有些是在Flash中用不到的.XML扩展标记语言(Extensible Markup Language)是SGML(Structured Generalized Markup...
  • 每天学一点flash(5) actionscript 3 0 外部加载mp3音乐
  • flash as3,使用 URLLoader 加载外部文件

    千次阅读 2010-08-11 15:03:00
    最近在给一个朋友帮忙,做了一个 flash 整站,站内的文章都采用 web service 方式获得,也就是用 URLLoader 进行加载,但是在加载的过程中总会出现各种异常,造成加载失败,在网上搜索了很多内容,却没找到...
  • 使用破解版的JLink实现对开发板上的外部Nor Flash的烧写+ JLink V4.08k 下载地址 1.拿到JLink 硬件。这个是不到100 RMB的破解版的,无需license。 2.下载并安装JLink的软件: Software and documentation ...
  • 之前系统microblaze使用的是本地存储BRAM,空间有限,因此添加外部存储系统DDR3 QSPI Flash将程序固化到开发板上,使开发板每次重启时自动烧写程序, 新建工程—选择arty a7开发板—创建BD设计—添加系统时钟 系统...
  • 然后会以0x6000_0000为首地址读取前512个字节作为外部Flash的配置信息(即Flash Configuration Parameters,包括几线制的SPI Flash,SPI的时钟频率,LUT查找表,DDR/SDR模式以及片选CS管脚的Hold/Setup Time等信息,...
  • 刚刚初学actionscript 3.0每天总结一点东西那么慢慢积累起来,这些笔记就会成为你一个很厉害的“法宝” 今天我刚刚测试一下外部加载mp3, 与as2.0有着很大的区别,但道理其实也是大同小异。初学者水平有限,望能见谅...
  • (注:本篇文章讨论的是as 3.0,以CS3为环境举例的)对于“如何用Flash来调用和执行可执行程序”这个话题,目前网上的讨论的结果是五花八门,而且大多数不是没有结果,就是说的含糊不清,要不然就是过时了,总之,很...
  • 简单来说,flash按照内部访问接口不同,分为两种:nor flash和nand flash。 nor flash:像访问SDRAM一样,按照数据/地址总线直接访问;...   其中的Nor Flash,根据外部接口分,又有普通
  • Nand与Nor区别: Flash按照内部访问接口不同,分为两种:nor flash和nand flash nor flash:像访问SDRAM一样,按照数据/地址总线直接访问 ...其中的Nor Flash,根据外部接口分,又有普通的接口和SPI接口 而.
  • 出错一:Link - Cortex-MError Could not stop Cortex-Mdevice! Please check the JTAG cable. 解决步骤: 1、点击菜单栏中的魔法棒 2、在Options窗口中,选择C/C++,再勾选 Optimize for time和One ELF Section ...
  • flash详解

    千次阅读 多人点赞 2019-06-04 16:52:26
    Flash全名叫做Flash Memory,从名字就能看出,是种数据存储设备,存储设备有很多类,Flash属于非易失性存储设备(Non-volatile Memory Device),与此相对应的是易失性存储设备(Volatile Memory Device)。关于什么是非...
  • flash按照内部访问接口(技术)不同,flash分为两种:nor flash和nand flash。 nor flash:像访问SDRAM一样,按照数据/地址总线直接访问;...Nand和Nor的使用寿命,块擦除的速度,数据存储的出错...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,721
精华内容 3,488
关键字:

外部flash出错