整体简介
如何在uboot下实现GPIO配置,并在最终Linux启动完成之后的阶段生效
本文编写耗费1小时,阅读本文需要25分钟时间。
环境准备
Linux kernelversion :3.14.43
board: TL-am4379-gp-evm
boot: origin-2017.4._tlv1.4
需求描述
由于为产品新增了充电检测功能,那么经过简单的整理,需要对以下几个GPIO引脚进行配置。
在uboot的启动过程中,我们会在充电的情况下启动boot并显示一张图片在LCD上。主要逻辑如下:
if(power==in)
{
boot_start();
GPIO_INIT();
{
set GPIO0_12 input
set GPIO0_13 input
set GPIO0_14 output
set GPIO0_15 output
}
if(GPIO0_12==ON)
{
goto Init_completed.
set GPIO0_14 HIGH
show_img( Charging completion );
while(button==IN && timer > 3min)
{
boot_kernel;
}
}
if(GPIO0_13==ON)
{
goto Init_completed.
set GPIO0_15 HIGH
show_img( Charging );
while(button==IN && timer > 3min)
{
boot_kernel;
}
}
}
| 序号 | 原引脚 | 新引脚 | 备注 | boot | kernel | app |
|---|---|---|---|---|---|---|
| 1 | 无 | GPIO0_12 | CHG_END_STAT充电完成检测管脚 | √ | — | √ |
| 2 | 无 | GPIO0_13 | CHG_ING_STAT正在充电检测管脚 | √ | — | √ |
| 3 | 无 | GPIO0_14 | CHG_END_LED充电完成指示灯 | √ | — | √ |
| 4 | 无 | GPIO0_15 | CHG_ING_LED正在充电指示灯 | √ | — | √ |
结构分析
U-Boot的GPIO系统设计简洁而高效,它采用三层架构来实现功能:
-
顶层接口层:这一层面向用户提供了一套通用的接口定义,但并不涉及具体的实现细节。实现工作需要根据具体的芯片型号来定制开发。
-
中间接口实现层:在这一层,我们利用特定硬件板的GPIO特性来具体实现顶层定义的接口。
-
底层芯片GPIO实现层:这是最接近硬件的一层,直接负责实现与具体芯片GPIO相关的操作。
在实际工程应用中,我们通常需要直接操作硬件寄存器,并根据需要查找相应的寄存器地址。这样的设计既保证了系统的灵活性,又能满足不同硬件平台的需求。
uboot源码编译
1.1 安装 U-Boot 源代码
1.2 清理 U-Boot
进入 U-Boot 的安装目录"media/tl437x/u-boot"。执行以下命令:
cd /media/tl437x/u-boot/
make CROSS_COMPILE=arm-linux-gnueabihf- distclean
1.3 配置 U-Boot
执行以下命令进行 U-Boot 配置:
make CROSS_COMPILE=arm-linux-gnueabihf- am43xx_evm_config
1.4 编译 U-Boot
执行以下命令进行 U-Boot 编译:
make CROSS_COMPILE=arm-linux-gnueabihf- -j4
1.5 烧写 U-Boot
由于uboot在nand上启动,那么需要我们启动filesystem之后,运行flashboot脚本
之后是拷贝MLO文件和uboot.img文件到烧写的缓存目录下,笔者这里将个人所使用的目录原样给出,在实践时应当注意改成自己的路径。
cp mlo /run/media/mmcblk0p1/
cp u-boot.img /run/media/mmcblk0p1/
接下来通过 dd指令 和 flash_eraseall指令 对MLO和uboot.img进行烧写
flash_eraseall /dev/mtd0
flash_eraseall /dev/mtd1
flash_eraseall /dev/mtd2
flash_eraseall /dev/mtd3
dd if=/run/media/mmcblk0p1/MLO of=/dev/mtdblock0
dd if=/run/media/mmcblk0p1/MLO of=/dev/mtdblock1
dd if=/run/media/mmcblk0p1/MLO of=/dev/mtdblock2
dd if=/run/media/mmcblk0p1/MLO of=/dev/mtdblock3
flash_eraseall /dev/mtd5
dd if=/run/media/mmcblk0p1/u-boot.img of=/dev/mtdblock5
uboot源码分析
uboot的第一阶段做了哪些工作
在U-Boot的第一阶段,初始化过程涵盖了多个关键步骤,为系统的后续启动奠定了基础。首先,构建异常向量表是确保系统能够正确响应中断和异常的基础。接着,将CPU设置为SVC模式,为操作系统的运行提供了必要的执行环境。此外,关闭看门狗计时器是为了防止在启动过程中不必要的系统重置。开发板供电置锁确保了电源的稳定供应,为系统的持续运行提供了保障。时钟初始化为系统提供了精确的时间基准,而DDR初始化则为内存管理提供了必要的硬件支持。
串口初始化并打印"OK"是验证系统基本功能正常运行的一个简单测试。随后,重定位操作确保了代码和数据在正确的内存地址中执行和存储。建立映射表并开启MMU(内存管理单元)为更复杂的内存管理和虚拟内存提供了支持。最终,通过跳转到第二阶段的入口点,即ldr pc, =main指令,完成了第一阶段的初始化工作,为系统引导的下一阶段做好了准备。在lowlevel_init.S中,除了上述步骤,还额外执行了检查复位状态、IO恢复、开发板供电锁存、tzpc初始化,并在完成这些步骤后分别打印了’O’和’K’,作为系统初始化进度的指示。这些步骤共同确保了系统在启动过程中的稳定性和可靠性。
对于Uboot中具体的改动需求,我们可以将IO的业务逻辑部分写在boot的第二阶段,对应的是board.c这个文件,这样的做法是比较符合规范,也更好移植。
其中,start_armboot() 函数的作用是:第二阶段主要初始化剩下的硬件,主要是外部硬件如iNand和网卡,以及uboot中CLI的支持等。
进一步地,我们的目标应该是start_armboot下的 device_init() 函数中,这里的设备指的就是板上的硬件设备。
在/u-boot/arch/arm/include/asm/arch-am33xx/gpio.h中,有
#define AM33XX_GPIO0_BASE 0x44E07000
#define AM33XX_GPIO1_BASE 0x4804C000
#define AM33XX_GPIO2_BASE 0x481AC000
#define AM33XX_GPIO3_BASE 0x481AE000
#define AM33XX_GPIO4_BASE 0x48320000
#define AM33XX_GPIO5_BASE 0x48322000
根据 AM437x_Technical Reference Manual.pdf (TL开发板的参考手册)
GPIO5 0x4832_2000 ~ 0x4832_2FFF size:4KB Description:GPIO5_Registers

A38h CTRL_CONF_GPIO5_8 Section 7.3.1.194
A3Ch CTRL_CONF_GPIO5_9 Section 7.3.1.195
A40h CTRL_CONF_GPIO5_10 Section 7.3.1.196
A44h CTRL_CONF_GPIO5_11 Section 7.3.1.197
A48h CTRL_CONF_GPIO5_12 Section 7.3.1.198
A4Ch CTRL_CONF_GPIO5_13 Section 7.3.1.199
在跳转宏AM33XX_GPIO5_BASE定义处的时候,我们找到了am437x平台的源码。
如下这段代码存放在src/board/ti/am43xx/board.c下
我们将参考这部分代码进行对GPIO的设置
static void enable_vtt_regulator(void)
{
u32 temp;
/* enable module */
//#define writel(v,addr) __readwrite_bug("writel")
writel(GPIO_CTRL_ENABLEMODULE, AM33XX_GPIO5_BASE + OMAP_GPIO_CTRL);
/* enable
469



被折叠的 条评论
为什么被折叠?



