正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-6.5--I.MX6U启动方式

 前言:

本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM(MX6U)裸机篇”视频的学习笔记,在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。

引用:

正点原子IMX6U仓库 (GuangzhouXingyi) - Gitee.com

《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf》第 8.1 章

《正点原子资料_A盘/02开发板原理图/IMX6ULL_MINI_V2.2(Mini底板原理图).pdf》

  • 资料盘 开发板资料链接: https://pan.baidu.com/s/1j5Jzbdx9i-g0cWIi3wf2XA 提取码:ag1u


正文:

本文是 “正点原子[第二期]Linux之ARM(MX6U)裸机篇--第6.5讲” 的读书笔记。第6.5讲 I.MX6U 芯片的启动方式。

0. I.MX6U 启动方式详解

I.MX6U 支持多种启动方式以及启动设备,比如可以从 SD/MMC,NAND Flash,QSPIFlash 等启动。用户可以根据实际情况,选择合适的启动设备。不同的启动方式,其启动方式和启动要求也不一样,比如上一张的从 SD 卡启动就需要在 bin 文件前面添加一个数据头,其它的启动设备也是需要这个数据头的。本章我们就来学习一下 I.MX6U 的启动方式,以及不同设备启动的要求。

1. 启动方式的选择

BOOT 的处理过程是发生在 I.MX6U 芯片上电以后,芯片会根据 BOOT_MODE[1:0] 的设备来选择 BOOT 方式。BOOT_MODE[1:0] 的值是可以改变的,有两种方式,一种是改写 eFUSE (熔丝),一种是修改相应的 GPIO 高低电平。第一种修改 eFUSE 的方式只能修改一次,后面就不能再修改了,所以我们不使用。我们用的是通过修改 BOOT_MODE[1:0] GPIO 对应的高低电平来选择启动方式,所有的开发板都使用的这种方式,I.MX6U 有一个 BOOT_MODE1 引脚和 BOOT_MODE0 引脚,这两个引脚对应 BOOT_MODE[1:0] 。I.MX6U -ALPHA/Mini 开发板的这两个引脚的电路原理图如下图所示:

其中 BOOT_MODE1 和 BOOT_MODE0 在芯片内部是有 100KΩ 下拉电阻的,所以默认是0。 BOOT_MODE1 和 BOOT_MODE0 这两个引脚我们也接到了底板上的拨码开关上,这样我们就可以通过拨码开关来控制  BOOT_MODE1 和 BOOT_MODE0 的高低电平。以  BOOT_MODE1 为例,当我们把 BOOT_CFG 的第一个开关拨到 “ON” 位置时,就相当于 BOOT_MODE1 引脚通过 R88 这个 10K 电阻接到了 3.3V 电源,芯片内部的 BOOT_MODE1 又是 100K 下拉电阻接地,因此 BOOT_MODE1 的电压就是 100(10+100)*3.3v=3V,这个就是高电平,因此 BOOT_CFG 的8个开关拨到“ON” 就是高电平,拨到“OFF”就是低电平。

而 I.MX6U 有四个 BOOT 模式,这四个 BOOT 模式由 BOOT_MODE[1:0] 来控制,也就是 BOOT_MODE1 和 BOOT_MODE0 这两个IO,BOOT 模式的配置如下表所示:

BOOT_MODE[1:0]BOOT类型
00从 FUSE 启动
01串行下载
10内部BOOT模式
11保留

在 表 9.1.1 中,我们只用到第二种和第三种BOOT方式。

1.1 串行下载

当 BOOT_MODE1 为0, BOOT_MODE0=1的时候使能此模式,串行下载的意思就是可以通过USB或UART将代码下载到板子上的外置存储设置中,我们可以使用 OTG1 这个 USB 口向开发板上的 SD/EMMC ,NAND 等存储设备下载代码。我们需要将 BOOT_MODE1 拨到 “OFF”,将 BOOT_MODE0 拨到“ON”。这个下载需要用到NXP提供的一个软件,一般用来最终量产的时候将代码烧写到外置的存储设备总的,我们后面讲解如何使用。

1.2 内部BOOT方式

当 BOOT_MODE1 为1, BOOT_MODE0=0的时候使能此模式,在此模式下,芯片会执行内部 bootROM 代码,这段 bootROM 代码会进行硬件初始化(一部分外设),然后从 boot 设备(也就是存放代码的设备,比如 SD/EMMC,NAND)中将代码拷贝复制到RAM中,一般是放在DDR中。

2. BOOT ROM 初始化内容

当我们设置 BOOT 模式为 “内部BOOT模式”以后,I.MX6U 的把内部 boot ROM 代码就是执行,这个 boot ROM 代码会做什么处理呢?首先肯定是初始化时钟,boot ROM 设置的系统是中国如下图所示:

在上图中 BT_FREQ 模式为0,可以看到,boot ROM 会将 I.MX6U 的内核时钟设置为 396MHz,也就是主频为 396MHz。System PLL=528Mhz,USB PLL=480MHz,AHB=132MHz,IPG=66MHz。关于I.MX6U的系统时钟,我们后面会详细讲解。

内部 boot ROM 为了加快执行速度回打开 MMU 和 Cache:

  • 下载镜像的时候 L1 ICache 会打开,
  • 验证镜像的时候 L1 DCache,L2 Cache 和 MMU 都会打开。
  • 一旦镜像验证完成,boot ROM 就会关闭 L1 DCache,L2Cache 和 MMU 

中断向量偏移会被设置到 boot ROM 的起始位置,当 boot ROM 启动了用户代码以后就可以重新设置中断向量偏移了。一般是重新设置到我们用户代码开始的地方,关于中断的内容后面会详细讲解。

3. 启动设备

当 BOO_MODE 设置为内部BOOT模式以后,可以从一下设备中启动:

  1. 接到 EIM 接口的 CS0 上的 16 位 NOR Flash。
  2. 接到 EIM 接口的 CS0 上的 OneNAND Flash。
  3. 接到 GPMI 接口上的 MLC/SLC NAND Flash,NAND Flash 页大小支持 2KByte, 4KByte 和 8Kbyte,8位宽。
  4. Quard SPI Flash
  5. 接到 USDHC 接口上的 SD/MMC/eSD/SDXC/eMMC等设备。
  6. SPI接口的 EEPROM

这些设备启动如何选择呢? I.MX6U 同样提供了 eFUSE 和 GPIO 配置两种,eFUSE 就不讲解了。我们重点看如何通过 GPIO 来选择启动设备,因为所有的 I.MX6U 开发板都是通过 GPIO 来配置启动设备的。正如启动模式由 BOOT_MODE[1:0]来选择一样,启动设备是通过 BOOT_CFG1[7:0] ,BOOT_CFG2[7:0] 和 BOOT_CFG4[7:0] 这 24 个配置IO,这24个配置IO刚好对应着 LCD 的24根数据线 LCD_DATA0 ~ LCD_DATA23,当启动完成以后这个24个IO就可以额作为LCD的数据线使用。这24个数据线和 BOOT_MODE1, BOOT_MODE0 共同组成了 I.MX6U 的启动选择引脚,如图 9.3.1 所示:

通过 图 9.3.1 中的 26 个启动IO即可实现 I.MX6U 从不同设备启动,BOOT_MODE1 和 BOOT_MODE0 已经讲述过了。看到这24个 IO 是不是头大?调整这24个IO的高低电平得多复杂啊?起始不然,虽然有24个IO,但是实际需要调整的只有那几个IO,其它的IO全部下拉接地即可,也就是设置为0.打开 I.MX6U-ALPHA/Mini的开发板核心板电路原理图,这24个IO的默认配置如下图所示:

可以从"正点原子 I.MX6U ALPHA"开发板原理图中看出,"正点原子 I.MX6U ALPHA"开发板的 LCD_DATA0~LCD_DATA23 大部分 IO 都接地了,只有几个 IO 拉高,尤其是 BOOT_CFG4[7:0] 这8个IO都有 10 K 电阻下拉接地,所以我们压根就不需要去关心 BOOT_CFG4[7:0]。我们需要中断关注的只剩下了 BOOT_CFG2[7:0] 和 BOOT_CFG1[7:0] 这16个IO。这16个配置IO的含义在原理图的左侧已经贴出来了,如下图所示。

图 9.3.3 看着是不是也很头大,BOOT_CFG1[7:0]和BOOT_CFG2[7:0]这16个IO还能不嗯呢再减少哪?可以,打开 I.MX6U ALPHA/Mini 开发板的底板原理图,底板上设备选择拨码开关原理图如下:

在图 9.3.4 中,除了 BOOT_MODE1 和 BOOT_MODE0 必须印出来,LCD_DATA3~LC_DATA7,LCD_DATA11 这 6个IO也被印出来,可以通过拨码开关来设置其对应的高低电平,拨码开关到 “ON” 就是1,拨码开关到 “OFF” 就是0.齐总 LCD_DATA11 就是 BOOT_CFG2[3],LCD_DATA3~LCD_DATA7 就是 BOOT_CFG1[3]~BOOT_CFG1[7],这6个IO的配置的含义如下表:

BOOT_CFG引脚对应LCD引脚含义
BOOT_CFG2[3]LCD_DATA11为0时SDHC1上的SD/EMMC启动,为1时从SDH2上的SD/EMMC启动。
BOOT_CFG1[3]LCD_DATA3当从SD/EMMC启动的时候设置启动速度,当从NAND启动的时候设置ANND数量。
BOOT_CFG1[4]LCD_DATA4

BOOT_CFG1[7:4]: (高位在前,低位在后)
0000 NOR/OneNAND(EIM)启动

0001 QSPI启动

0011 SPI启动

010x SD/eSD/SDXC启动

011x MMC/eMMC启动

1xxx NAND Flash启动

BOOT_CFG1[5]LCD_DATA5
BOOT_CFG1[6]LCD_DATA6
BOOT_CFG1[7]LCD_DATA7

根据表 9.3.1 中 BOOT IO 含义,I.MX6U-ALPHA/Mini 开发板从SD卡,EMMC,NAND 启动的时候拨码开关各个位置配置方式如下表所示

12345678启动设备
01xxxxxx串行下载,可以通过USB烧写镜像文件
10000010SD卡启动
10100110EMMC启动
10001001NAND FLAHS启动

我们再“第八章 汇编LED实验”中,最终的可执行问价 led.bin 烧写到了 SD 卡里面,然后从SD卡启动,其拨码开关就是根据表 9.3.1 来设置的,通过上面的讲解酒味道为什么拨码开关要这么设置了。

4. 镜像烧写

注意!本小节会分析 bin 文件添加的头部信息,但是在笔者写本教程的时候关于I.MX 系列的SOC头部信息的资料很少,基本智能参考NXP的官方资料,而官方资料有些地方讲解的又不是很详细。所以本节有些部分是笔者根据NXP的官方 u-boot.imx 文件的头部信息反推出来的,因此难免有错误的地方,还望大家谅解!如有发现错误之处,欢迎大家在 www.openedv.com 论坛
上留言。

前面我们设置好 BOOT 以后就能从指定的设备启动了,但是你的设备里面得有代码啊,在第八章我们使用 imxdownload 这个软件将 led.bin 烧写到 SD 卡中。imxdownload 会在 led.bin 前面添加一些头信息,重新生成一个叫做 load.imx 的文件,最终烧写的是 load.imx。那么肯能就有人问:imxdownload 是如何将 led.bin 打包成 load.imx的。

学习STM32的时候我们可以直接将编译生成的.bin文件烧写到STM32内部的Flash里面,但是 I.MX6U 不能直接烧写编译生成的 .bin文件,我们需要再.bin文件前面添加一些头信息构成满足 I.MX6U 需求的最终可烧写文件,I.MX6U的最终可烧写文件注册如下:

  1. Image vector rable,简称 IVT,IVT 里面包含了一系列地址信息,这些地址信息在ROM里按照固定的地址存放着。
  2. Boot data,启动数据,包含了镜像要拷贝到哪个地址,拷贝的大小是多少等等。
  3. Device configuration data,简称 DCD ,设别配置信息,重点是 DDR3 的初始化配置。
  4. 用户代码可执行文件,比如 led.bin 

可以看出最终烧写到 I.MX6U 中的程序其组成为 IVT+Boot data + DCD + .bin 。所以第8章中的 imxdownload 所生成的 load.imx 就是在 led.bin 前面加上 IVT + Boot data + DCD 。内部 boot ROM 会将 load.imx 拷贝到DDR中,用户代码前面又有 3KByte的 IVT+Boot Data + DCD数据,下面会讲一下为什么是 3KByte,因此 load.imx 在DDR中的起始地址就是 0x8780_0000 - 3072 = 0x877F_F400。

正点原子的教程,我自己理解画的一个SD卡作为启动设备时,SD上烧录镜像的格式,如下图:

4.1 IVT 和 Boot Data 数据

load.imx 最前面就是 IVT 和 Boot Data ,IVT 包含了镜像程序的入口点,指向 DCD指针和一些用作其他用途的指针。内部 boot ROM 要求 IVT 应该放到指定的位置,不同的启动设备位置不同,而 IVT 在整个 load.imx 的最前面,起始就相当于要求 load.imx 在烧写的时候应该烧写到存储设备的指定为止去。整个位置都是相对于存储初设备的起始地址的偏移,如图 9.4.1 所示:

以 SD/EMMC 为例,IVT偏移为 1KByte,IVT+Boot Data+DCD总大小为4KByte - 1KByte = 3KByte。假设 SD/EMMC 每个扇区为 512 字节,那么 load.imx 应该从第三个山城区开始烧写,前两个扇区要流出来。load.imx 从第3KBbyte开始才是真正的 .bin 文件。那么 IVT 里究竟存放着什么东西呢?IVT里存放的内容如下表 9.4.1.2 所示

从 图 9.4.1.2 可以看到,第一个存放的是 head (头),header 的给是如 图 9.4.1.3 所示:

图9.4.3 中,Tag位1字节长度,固定为 0xD1,Length是两个字节,保存着IVT 长度,位大端格式,也就是高字节保存在低内存中。最有的Version是一个字节,为 0x40 或者 0x41。

Boot Data 的数据格式如图 9.4.1.3 所示

实际情况是不是这样的呢?我们用 winhex 打开 load.imx 一看便知,winhex 可以直接查看一个文件的二进制格式数据。用winhex打开 load.imx 如下图所示

图 9.1.4.1 是我们截取的 load.imx 的一部分内容,从地址 0x0000_0000 ~ 0x0000_025F,共608字节的数据。气门将钱44个字节按照4个字节一组组的组合在一起就是,0x402000D1, 0x8780000, 0x00000000, 0x877FF42C,0x877FF420,0x00000000,0x0000000,0x877FF000,0x00200000,0x00000000。这44个字节的内容就是 IVT和Boot Data的数据,按照图 9.4.1.2 和图 9.4.1.4 所示的 IVT 和 Boot Data 所示的格式对应起来如表 9.4.1.1 所示:

4.2 DCD 数据

复位以后,I.MX6U 片内所有寄存器就会复位为默认值,但是这些默认值往往不是我们想要的值,而且有些外设在我们必须在使用之前初始化它。为此 I.MX6U 提出了一个 DCD (device Config Data) 的概念,和 IVT , Boot Data 一样,DCD也是添加到 load.imx 里面的,紧跟在 IVT 和 Boot Data 后面,IVT里面也指定了DCD的位置。DCD起始就是 I.MX6U 寄存器地址和对应配置的集合信息,boot ROM 会使用这些寄存器地址和配置集合来初始化相应的寄存器,比如开启某些外设时钟,初始化DDR等等。DCD去不不能超过 1768 Byte,DCD区域的结构如 9.4.2.1 所示

DCD 的 header 和 IVT 的 header 类似,结构如图 9.4.2.2 所示
中 Tag 是单字节,固定为 0XD2, Length 为两个字节,表示 DCD 区域的大小,包含 header,同样是大端模式, Version 是单字节,固定为 0X40 或者 0X41。

图 9.4.2.1 中的 CMD 就是要初始化的寄存器地址和相应的寄存器值, 结构如图 9.4.2.3 所示:

图 9.4.2.3 中 Tag 为一个字节,固定为 0XCC。 Length 是两个字节,包含写入的命令数据长度,包含 header,同样是大端模式。 Parameter 为一个字节,这个字节的每个位含义如图 9.4.2.4 所示

图 9.4.2.4 中的 bytes 表示是目标位置宽度,单位为 byte,可以选择 1、 2、和 4 字节。 flags 是命令控制标志位。

图 9.4.2.3 中的 Address 和 Vlalue/Mask 就是要初始化的寄存器地址和相应的寄存器值,注意采用的是大端模式! DCD 结构就分析到这里,在分析 IVT 的时候我们就已经说过了, DCD 数据是从图 9.4.1.4 的 0X2C 地址开始的。根据我们分析的 DCD 结构可以得到 load.imx 的 DCD 数据如表 9.4.2.1 所示:

从 表 9.4.2.1 中可以看出,DCD 里面初始化配置主要包括三个方面

  1. 设置CCGR0~CCGR6这个7个外设时钟寄存器,默认打开所有外设时钟
  2. 配置DDR3所用的所有IO
  3. 设置MMDC控制器,初始化DDR3

I.MX6U的启动过程我们就讲解到这里,本章我们详细的讲解了 I.MX6U 的启动模式,启动设备类型,和镜像烧写过程。总结一下,我们编译出来的 .bin 文件不能拿直接烧写到SD卡中,需要再.bin文件前面加上 IVT, Boot DATA和DCD这三个数据块。这三个数据块是有指定格式的,播我们必须按照格式填写,然后将其放到.bin文件前面,最终和策划给你的才是我们可以直接烧写到SD卡中的文件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/5885.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VS Code工具将json数据格式化

诉求:json数据格式化应该在工作中用到的地方特别多,为了更方便、更仔细的对json数据查看,将json数据格式化是非常有必要的。 VS Code中如何将json数据快速格式化 1、在VS Code中安装Beautify JSON插件 2、安装完后在需要格式化的文件中按住…

Web APIs 学习归纳6--- BOM浏览器对象

前面几节主要针对DOM进行了学习,现在开始新的内容的学习---DOM浏览器对象。 DOM是更注重页面(document)内容的设计,但是BOM不仅限于页面(document)的设计,而是更加全面包括页面的刷新&#xff0…

【linux学习指南】linux指令与实践文件编写

文章目录 📝前言🌠 linux目录结构🌉linux命令介绍 🌠pwd命令🌉mkdir指令(重要) 🌠cd 指令🌉touch指令 🌠rmdir指令 && rm 指令(重要&…

抖音评论区精准获客自动化获客释放双手

挺好用的,评论区自动化快速获客,如果手动点引流涨,那就很耗费时间了,不是吗? 网盘自动获取 链接:https://pan.baidu.com/s/1lpzKPim76qettahxvxtjaQ?pwd0b8x 提取码:0b8x

Dashboard 安装部署

Dashboard 安装部署 Dashboard 安装部署 一:下载 二:部署步骤 1.镜像下载及导入 国内直接拉外网镜像会失败,可在境外下载镜像 查看 deployment 里的镜像版本 Dashboard Deploymentcontainers:- name: kubernetes-dashboardimage: k8s.g…

Unity Audio Filter 入门

概述: 如果你在你项目中需要一些特殊的声音效果,那这部分声音过滤器的部分一定不要错过喔,让我们来学习这部分的内容吧! 这部分理论性比较强,认真看我的注解哈,我尽量解释的易懂一点。 Audio Chorus Filter…

Intelij Idea Push失败,出现git Authentication failed(验证失败)

目录 1、出现问题的原因 2、解决之法 1、出现问题的原因 能出现这种问题,最主要的原因是链接对上了,但用户验证失败了,即登录失败。 因为服务器转移或者换了git项目链接,导致你忘记了用户名密码,随意输入之后&…

持续更新|UNIAPP适配APP遇到的问题以及解决方案

在使用UNIAPP开发APP的时候遇到的一些奇奇怪怪问题记录 组件样式丢失 问题:组件引入界面中,在小程序和H5环境下样式正常,而在APP中却出现高度异常问题 解决:增加view标签将组件包裹起来即可正常显示 解决前: 解决后…

数据结构:实验七:数据查找

一、 实验目的 (1)领会各种查找算法的过程和算法设计。 (2)掌握查找算法解决实际问题。 二、 实验要求 (1)编写一个程序exp8-1.cpp, 按提示输入10个任意的整形数据(无序)&…

Mysql_数据库事务

文章目录 😊 作者:Lion J 💖 主页: https://blog.csdn.net/weixin_69252724 🎉 主题: MySQL__事务) ⏱️ 创作时间:2024年04月26日 ———————————————— 这里写目…

服务端不 listen 可以创建 tcp 连接吗

这个问题有三类答案。 上来就撸 linux kernel 源码,折腾半天,哦,终于在 tcp_rcv_state_process 里找到了 tcp_rcv_synsent_state_process 调用,后者包含: if (th->syn) {/* We see SYN without ACK. It is attemp…

【golang-ent】go-zero框架 整合 ent orm框架实现一对一 一对多 多种姿势查询方式

一、ent的 O2O 问题 官方文档如下: https://entgo.io/zh/docs/schema-edges#o2o-same-type 1、ent O2O问题 官方提供了三种 one2one的方式,可以看到他全部使用了 mysql的 foregionKey 的方式进行关联,虽然举例了单表和双表的不同使用方式,但是我们实际使用mysql中是不创建…

【R语言数据分析】函数

目录 自定义函数 apply函数 分类汇总函数aggregate 自定义函数 R语言中的自定义函数更像是在自定义一种运算规则。 自定义函数的语法是 函数名 函数体 } 比如 表示定义了一个名为BMI_function的函数,这个函数代表了一种运算规则,就是把传入的x和…

目标检测算法YOLOv3简介

YOLOv3由Joseph Redmon等人于2018年提出,论文名为:《YOLOv3: An Incremental Improvement》,论文见:https://arxiv.org/pdf/1804.02767.pdf ,项目网页:https://pjreddie.com/darknet/yolo/ 。YOLOv3是对YOL…

Node.js -- express 框架

文章目录 1. express 使用2. 路由2.1 路由的使用2.2 获取请求报文参数2.3 获取路由参数2.4 路由参数练习 3. express 响应设置4. 中间件4.1 全局中间件4.2 路由中间件4.3 静态资源中间件 5. 获取请求体数据 body-parser6. 防盗链7. 路由模块化8. 模板引擎8.1 了解EJS8.2 列表渲…

【C++】深入理解string类

一、熟悉string类 1.1 string类的由来: C语音中的字符串需要我们自己管理底层空间,容易内存泄露。而C是面向对象语音,所以它把字符串封装成一个string类。 C中对于string的定义为:typedef basic_string string; 也就是说C中的str…

java面试(微服务)

SpringCloud五大组件 Nacos:注册中心Ribbon:负载均衡Feign:远程调用sentinel:服务熔断Gateway:网关 注册中心 Eureka Nacos 负载均衡 Ribbon负载均衡流程 Ribbon的负载均衡策略 RoundRobinRule:简单的…

C++中把Lambda 表达式作为参数传递给模板函数。

例子&#xff1a; template<class fun> void mytest(fun f) {_string s1 "abc";_string s2 "abc";if (f(s1, s2)){std::cout << "相等。\n";}}int main() {mytest([](const _string s1, const _string& s2) { return s1 s2; …

python学习笔记----异常、模块与包(九)

一、异常 1.1 什么是异常 在Python中&#xff0c;异常是程序执行时发生的错误。当Python检测到一个错误时&#xff0c;它会引发一个异常&#xff0c;这可能是由于多种原因&#xff0c;如尝试除以零、访问不存在的文件&#xff0c;或者尝试从列表中获取不存在的索引等。异常处…

数组的拷贝

数组的拷贝 文章目录 数组的拷贝浅拷贝内存分析 深拷贝内存分析 浅拷贝 概念&#xff1a;数组的浅拷贝是指新数组保存的是原数组的内存地址&#xff0c;并没有拷贝真正的值&#xff0c;如果原数组的内容发生改变那么新数组的内容也会发生相应改变。 代码实现&#xff1a; pu…