RT1176-3(从startup开始)

从startup开始

首先这里先简单叙述下RT1176从上电那一刻起的大致流程吧(正常启动流程,不包含下载模式)。
如下为一般非XIP启动介质的流程,XIP启动介质的流程一般不存在拷贝程序的过程。

非XIP启动介质大致流程:
上电
检测启动介质
初始化启动介质
拷贝程序到指定内存
跳转到用户代码
XIP启动介质大致流程:
上电
检测启动介质
初始化启动介质
跳转到用户代码
1、选择RT1176的启动介质(启动设备)。
启动设备为 XIP 和 非XIP两种方式。
XIP即片上执行,不需拷贝数据到RAM上,一般指在 Nor flash上运行。
非XIP即需要先把代码拷贝到RAM上运行,一般是sd/emmc等启动介质。

关于i.MX.RT1176支持的启动介质详细介绍查询RT1176参考手册的第十章【SystemBoot】的Boot devices章节。

(1)、在MCUXpresso工程中如何配置XIP和非XIP?
	 项目属性->C/C++ Build->Settings->Managed Linker Script页面有个Link application to RAM选项,勾选即是非XIP,不勾选是XIP启动。
	 SDK中的例程默认都是XIP启动。选择XIP启动后,链接脚本也会发生变化,可以试试勾选与不勾选 Debug下的ld脚本的差异。
	 不勾选链接脚本会出现如下:
/* Image Vector Table and Boot Data for booting from external flash */
.boot_hdr : ALIGN(4)
{
    FILL(0xff)
    . = 0x400 ;
    __boot_hdr_start__ = ABSOLUTE(.) ;
    KEEP(*(.boot_hdr.conf))
    . = 0x1000 ;
    __boot_hdr_ivt_loadaddr__  =  ABSOLUTE(.) ;
    KEEP(*(.boot_hdr.ivt))
    . = 0x1020 ;
    __boot_hdr_boot_data_loadaddr__ = ABSOLUTE(.) ;
    KEEP(*(.boot_hdr.boot_data))
    . = 0x1030 ;
    __boot_hdr_dcd_loadaddr__ = ABSOLUTE(.) ;
    KEEP(*(.boot_hdr.dcd_data))
    __boot_hdr_end__ = ABSOLUTE(.) ;
    . = 0x2000 ;
} >BOARD_FLASH

这里是boot header段,在我们的bin文件的头部,是给boot rom使用的,这里包含了nor flash 配置,Image vertor table,boot data,dcd等。boot rom根据这个表去索引程序的第一条指令。

2、分析boot_hdr (Flash Config、Image Vertor Table、boot_data、dcd_data)

参考手册的 【System Boot】的Program image章节,有如下内容:

This section describes the data structures that are required to be included in the user's program image. 
The program image consists of:
• Image vector table—a list of pointers located at a fixed address that the ROM examines to determine 
  where the other components of the program image are located.
• Boot data—a table that indicates the program image location, program image size in bytes, and the plugin flag.
• Device configuration data—IC configuration data.
• User code and data.

由上文可知一个完整能启动的镜像文件包含了 IVT、Boot data、DCD、User code and data。(其中DCD不是必需)。然而结合链接脚本的boot_hdr段的内容,多了一个 .boot_hdr.conf 。

2.1. Flash Config

关于boot_hdr.conf手册中并未提及。根据名称看是配置什么东西的数据。在工程中全局搜索 boot_hdr。内容如下:

#include "evkmimxrt1170_flexspi_nor_config.h"

/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.xip_board"
#endif

/*******************************************************************************
 * Code
 ******************************************************************************/
#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
__attribute__((section(".boot_hdr.conf"), used))
#elif defined(__ICCARM__)
#pragma location = ".boot_hdr.conf"
#endif

const flexspi_nor_config_t qspiflash_config = {
    .memConfig =
        {
            .tag              = FLEXSPI_CFG_BLK_TAG,
            .version          = FLEXSPI_CFG_BLK_VERSION,
            .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
            .csHoldTime       = 3u,
            .csSetupTime      = 3u,
            // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
            .controllerMiscOption = 0x10,
            .deviceType           = kFlexSpiDeviceType_SerialNOR,
            .sflashPadType        = kSerialFlash_4Pads,
            .serialClkFreq        = kFlexSpiSerialClk_133MHz,
            .sflashA1Size         = 16u * 1024u * 1024u,
            .lookupTable =
                {
                    // Read LUTs
                    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
                    FLEXSPI_LUT_SEQ(MODE8_SDR, FLEXSPI_4PAD, 0x00, DUMMY_SDR, FLEXSPI_4PAD, 0x04),
                    FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_4PAD, 0x04, 0, 0, 0),
                },
        },
    .pageSize           = 256u,
    .sectorSize         = 4u * 1024u,
    .ipcmdSerialClkFreq = 0x1,
    .blockSize          = 256u * 1024u,
    .isUniformBlockSize = false,
};
#endif /* XIP_BOOT_HEADER_ENABLE */

可以看出这块内容是关于Qspi Flash的配置。所以在 .boot_hdr.conf段的内容就是一个flexspi_nor_config_t结构体。BootRom拿到这块数据后配置号Flash, 如果是XIP镜像就可以之家跳转到用户代码了, 如果不是XIP镜像还需要拷贝到指定RAM上跳转。

2.2. Image Vertor Table
	The Image Vector Table (IVT) is the data structure that the ROM reads from the boot device supplying the program image 
containing the required data components to perform a successful boot. The IVT includes the program image entry point, 
a pointer to Device Configuration Data(DCD) and other pointers used by the ROM during the boot process. The ROM locates
the IVT at a fixed address that is determined by the boot device connected to the Chip. The IVT offset from the base address 
for each boot device type is defined in the table below. The location of the IVT is the only fixed requirement by the ROM. 
The remainder or the image memory map is flexible and is determined by the contents of the IVT.

IVT是一个结构体数据,包含了镜像入口地址、指向DCD数据的指针和其他指针。rom从启动设备的固定位置去拿IVT(不同类型的存储设备对应不同的固定地址)。rom只需要IVT的位置是固定的就可以了,镜像的其他部分位置都映射在IVT中。所以只要对rom来说只要找的到IVT就能找到所有关于镜像文件的信息。IVT结构放置在.boot_hdr.ivt段内,可以全局搜素 boot_hdr.ivt 。定义在xip/fsl_flexspi_nor_boot.c中。如下:

#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
__attribute__((section(".boot_hdr.ivt"), used))
#elif defined(__ICCARM__)
#pragma location = ".boot_hdr.ivt"
#endif
/*************************************
 *  IVT Data
 *************************************/
const ivt image_vector_table = {
    IVT_HEADER,                  /* IVT Header */
    IMAGE_ENTRY_ADDRESS,         /* Image Entry Function */
    IVT_RSVD,                    /* Reserved = 0 */
    (uint32_t)DCD_ADDRESS,       /* Address where DCD information is stored */
    (uint32_t)BOOT_DATA_ADDRESS, /* Address where BOOT Data Structure is stored */
    (uint32_t)IVT_ADDRESS,       /* Pointer to IVT Self (absolute address) */
    (uint32_t)CSF_ADDRESS,       /* Address where CSF file is stored */
    IVT_RSVD                     /* Reserved = 0 */
};
#endif

上面ivt结构体的元素赋值都是宏定义,宏的定义以及ivt结构体的定义在xip/fsl_flexspi_nor_boot.h中,摘录如下:

#define IVT_MAJOR_VERSION       0x4
#define IVT_MAJOR_VERSION_SHIFT 0x4
#define IVT_MAJOR_VERSION_MASK  0xF
#define IVT_MINOR_VERSION       0x1
#define IVT_MINOR_VERSION_SHIFT 0x0
#define IVT_MINOR_VERSION_MASK  0xF

#define IVT_VERSION(major, minor)                                    \
    ((((major)&IVT_MAJOR_VERSION_MASK) << IVT_MAJOR_VERSION_SHIFT) | \
     (((minor)&IVT_MINOR_VERSION_MASK) << IVT_MINOR_VERSION_SHIFT))

/* IVT header */
#define IVT_TAG_HEADER 0xD1 /**< Image Vector Table */
#define IVT_SIZE       0x2000
#define IVT_PAR        IVT_VERSION(IVT_MAJOR_VERSION, IVT_MINOR_VERSION)
#define IVT_HEADER     (IVT_TAG_HEADER | (IVT_SIZE << 8) | (IVT_PAR << 24))

#define IMAGE_ENTRY_ADDRESS ((uint32_t)ResetISR)
#define BOOT_DATA_ADDRESS   ((uint32_t)__boot_hdr_boot_data_loadaddr__)
#define DCD_DATA_ADDRESS    ((uint32_t)__boot_hdr_dcd_loadaddr__)
#define IVT_ADDRESS         ((uint32_t)__boot_hdr_ivt_loadaddr__)
#define DCD_ADDRESS DCD_DATA_ADDRESS
#define CSF_ADDRESS 0
#define IVT_RSVD    (uint32_t)(0x00000000)
typedef struct _ivt_
{
    /** @ref hdr with tag #HAB_TAG_IVT, length and HAB version fields
     *  (see @ref data)
     */
    uint32_t hdr;
    /** Absolute address of the first instruction to execute from the
     *  image
     */
    uint32_t entry;
    /** Reserved in this version of HAB: should be NULL. */
    uint32_t reserved1;
    /** Absolute address of the image DCD: may be NULL. */
    uint32_t dcd;
    /** Absolute address of the Boot Data: may be NULL, but not interpreted
     *  any further by HAB
     */
    uint32_t boot_data;
    /** Absolute address of the IVT.*/
    uint32_t self;
    /** Absolute address of the image CSF.*/
    uint32_t csf;
    /** Reserved in this version of HAB: should be zero. */
    uint32_t reserved2;
} ivt;

宏定义展开带入:

const ivt image_vector_table = {
	0x412000d1,
	((uint32_t)ResetISR),
	(uint32_t)(0x00000000),
	((uint32_t)__boot_hdr_dcd_loadaddr__),
	((uint32_t)__boot_hdr_boot_data_loadaddr__),
	((uint32_t)__boot_hdr_ivt_loadaddr__),
	0,
	(uint32_t)(0x00000000)
};
/* ResetISR的定义做过ARM开发的应该都熟悉,这是程序的入口地址定义在startup/startup_mimxrt1176_cm7.c中。
 * __boot_hdr_dcd_loadaddr__、__boot_hdr_boot_data_loadaddr__和__boot_hdr_ivt_loadaddr__的定义在boot_hdr段中。
 */
2.3. boot_data

参考手册中关于boot data structure的描述:

	The boot data must follow the format defined in the table found here, each entry is a 32 bit word.
startAbsolute address of the image
lengthSize of the program image
pluginPlugin flag (must be 0, not supported in this device, this field is ignored by the ROM)

代码中boot_data 放置在.boot_hdr.boot_data段内,boot_data的定义在xip/fsl_flexspi_nor_boot.c中。

#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
__attribute__((section(".boot_hdr.boot_data"), used))
#elif defined(__ICCARM__)
#pragma location = ".boot_hdr.boot_data"
#endif
/*************************************
 *  Boot Data
 *************************************/
const BOOT_DATA_T g_boot_data = {
    BOOT_IMAGE_BASE, /* boot start location */
    BOOT_IMAGE_SIZE, /* size */
    PLUGIN_FLAG,     /* Plugin flag*/
    0xFFFFFFFFU      /* empty - extra data word */
};

BOOT_DATA_T 结构体的定义以及BOOT_IMAGE_BASE、BOOT_IMAGE_SIZE和PLUGIN_FLAG定义也都在xip/fsl_flexspi_nor_boot.h中,如下:

#define BOOT_IMAGE_BASE     ((uint32_t)_boot_loadaddr)
#define BOOT_IMAGE_SIZE     ((uint32_t)_boot_size)
#define PLUGIN_FLAG (uint32_t)0
typedef struct _boot_data_
{
    uint32_t start;       /* boot start location */
    uint32_t size;        /* size */
    uint32_t plugin;      /* plugin flag - 1 if downloaded application is plugin */
    uint32_t placeholder; /* placehoder to make even 0x10 size */
} BOOT_DATA_T;

宏定义展开带入:

const BOOT_DATA_T g_boot_data = {
	((uint32_t)_boot_loadaddr),
	((uint32_t)_boot_size),
	(uint32_t)0,
	0xFFFFFFFFU
};
/*   _boot_loadaddr和_boot_size 定义在链接脚本的末尾。
 *   _boot_loadaddr = ORIGIN(BOARD_FLASH);
 *   _boot_size = LENGTH(BOARD_FLASH);
 * 关于_boot_size的大小我个人觉得是有点问题的。
 */
2.4. dcd_data

参考手册关于DCD的描述如下:

Upon reset, the chip uses the default register values for all peripherals in the system.
However, these settings typically are not ideal for achieving the optimal system
performance and there are even some peripherals that must be configured before they can be used.
The DCD is a configuration information contained in the program image (external to the ROM) 
that the ROM interprets to configure various peripherals on the chip.
For example, some components (such as SDRAM) require some sequence of register
programming as a part of the configuration before it is ready to be used. The DCD feature
can be used to program the SEMC register to the optimal settings.
The ROM determines the location of the DCD table based on the information located in
the Image Vector Table (IVT). See Image Vector Table and Boot Data for more details.
The DCD table shown below is a big-endian byte array of the allowable DCD commands.
The maximum size of the DCD is limited to 1768 B.

简答叙述就是一上电后芯片对外设的控制都是用寄存器的默认值,而这些默认值不一定能把外设驱动到完美状态,甚至有些外设必须先初始化才能使用。其实这些DCD值就是寄存器和值(类似 key-value)。这些DCD表最大限制在1768字节。通俗点讲就是来初始化外设的,这个初始化的动作有rom来完成。所以这个是可选的,如果不是用SDRAM的话,可以不适用DCD。因为我们可以在代码中初始化外设也没有问题。而如果程序链接地址是在SDRAM上的话,就需要先初始化SDRAM后rom才能把代码拷贝、跳转,这个时候DCD是需要的。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值