栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

嵌入式Linux驱动开发笔记(六)

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

嵌入式Linux驱动开发笔记(六)

嵌入式Linux驱动开发笔记(六) I.MX6U 启动方式详解

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]。

(1) BOOT四种 模式

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

【1】串行下载

串行下载的意思就是可以通过 USB 或者 UART 将代码下载到板子上的外置存储设备中,我们可以使用 OTG1 这个 USB口向开发板上的 SD/EMMC、 NAND 等存储设备下载代码 。这个下载是需要用到 NXP 提供的一个软件,一般用来最终量产的时候将代码烧写到外置存储设备中的。

【2】内部 BOOT 模式

在此模式下,芯片会执行内部的 boot ROM 代码,这段 boot ROM 代码会进行硬件初始化(一部分外设),然后从 boot 设备(就是存放代码的设备、比如 SD/EMMC、 NAND)中将代码拷贝出来复制到指定的 RAM 中,一般是DDR。

(2)启动设备

当 BOOT_MODE 设置为内部 BOOT 模式以后,可以从以下设备中启动:
①、接到 EIM 接口的 CS0 上的 16 位 NOR Flash。
②、接到 EIM 接口的 CS0 上的 OneNAND Flash。
③、接到 GPMI 接口上的 MLC/SLC NAND Flash, NAND Flash 页大小支持 2KByte、 4KByte
和 8KByte, 8 位宽。
④、 Quad SPI Flash。
⑤、接到 USDHC 接口上的 SD/MMC/eSD/SDXC/eMMC 等设备。
⑥、 SPI 接口的 EEPROM。

(3)镜像烧写

【1】I.MX6U 的最终可烧写文件组成如下:

①、 Image vector table,简称 IVT, IVT 里面包含了一系列的地址信息,这些地址信息在ROM 中按照固定的地址存放着。

②、 Boot data,启动数据,包含了镜像要拷贝到哪个地址,拷贝的大小是多少等等。
③、 Device configuration data,简称 DCD,设备配置信息,重点是 DDR3 的初始化配置。
④、用户代码可执行文件,比如 led.bin。

可以看出最终烧写到 I.MX6U 中的程序其组成为: IVT+Boot data+DCD+.bin。

【2】IVT 和 Boot Data 数据

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

IVT 和 Boot Data 所示的格式对应起来如表 9.4.1.1 所示:


在表 9.4.1.1 中,我详细的列出了 load.imx 的 IVT+Boot Data 每 32 位数据所代表的意义。这些数据都是由 imxdownload 这个软件添加进去的。

【3】DCD 数据

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

**DCD 里面的初始化配置主要包括三方面: **

①、设置 CCGR0~CCGR6 这 7 个外设时钟使能寄存器,默认打开所有的外设时钟。
②、配置 DDR3 所用的所有 IO。
③、配置 MMDC 控制器,初始化 DDR3。

C语言版LED 灯实验 (1)DDR3 的初始化

【1】启动汇编文件

启动汇编文件中没有初始化 DDR3 的代码,但是却将 SVC 模式下的 SP 指针设置到了 DDR3 的地址范围中 ,是因为DCD 数据包含了 DDR 配置参数, I.MX6U 内部的 Boot ROM 会读取 DCD 数据中的 DDR 配置参数然后完成 DDR 初始化的。

【2】直接操作0x020C4068这个寄存器解析

//下面这行代码的意思是直接操作0x020C4068这个寄存器
//具体寄存器的作用是通过手册得到的
#define CCM_CCGR0 *((volatile unsigned int*)0x020C4068)

//假设寄存器为32位
//要设置0x020C4068寄存器值为0x03,可以直接写成
CCM_CCGR0=0x03

为什么这个宏定义可以直接操作这个地址??

//第一步
//表示将0x020C4068强制转换为unsigned int 类型的指针
//0x020C4068代表一个16进制的数据
(unsigned int*)0x020C4068
//第二步
//使用volatile声明变量值,防止被编译器优化,从而可以提供对特殊地址的稳定访问;
(volatile unsigned int*)0x020C4068
//第三步
//对此变量间接寻址,获取指针指向地址的存储值
*((volatile unsigned int*)0x020C4068)

拓展:

由于内存访问速度远不及CPU处理速度,为提高机器整体性能,在硬件上引入硬件高速缓存Cache,加速对内存的访问。
当要求使用volatile声明变量值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。
精确地说就是,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问;
如果不使用valatile,则编译器将对所声明的语句进行优化。(简洁的说就是:volatile关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错)

用volatile定义的变量会在程序外被改变,每次都必须从内存中读取,而不能重复使用放在cache或寄存器中的备份
注意:频繁地使用volatile很可能会增加代码尺寸和降低性能,因此要合理的使用volatile。

反例:

#define rURXH0 (*(unsigned char *)0x50000024) //UART 0 Receive buffer

这个就是串行的接收buffer,其地址为0x50000024。
如果我们没有将这个地址强行转换成volatile,那么我们在使用rURXH0时,可能直接从cpu的寄存器中取值。
因为之前rURXH0被访问过,也就是说之前就从内存中取出rURXH0的值保存到某个寄存器中。
之所以直接从寄存器中取值,而不去内存中取值,是因为编译器优化代码的结果(访问cpu寄存器比访问ram快的多)。
用volatile关键字对0x50000024进行强制转换,使得每一次被访问rURXH0时,执行部件都会从0x50000024这个内存单元中取出值来赋值给rURXH0。

【3】解析:

GPIO1_DR &= ~(1<<3);	// 将 GPIO1_DR 的 bit3 清零

- 先对1左移3位:0001 -> 1000
- 再按位取反:1000 -> 0111
- 最后“按位”与运算
就相当于把第3位清零了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/963969.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号