例说uboot从命令到驱动

我们知道uboot的最终目标是实现将OS内核由flash中复制到ram中,并跳到操作系统分内核的入口address,将处理器的控制权交给操作系统。U-boot的一个很重要的特点就是使用命令实现对底层的操作,通过执行指令我们就可以实现上述目标。这里以实现一个简单的led_blink硬件操作,解析uboot从命令执行到操作led的过程。依照这个example,我们可以对对包括NAND,USB,串口等驱动的执行过程以及uboot的移植有一个相对清晰的认识。

在common目录下面是常用的命令文件,文件名格式为cmd_xxx.c。如图:



在这个目录下建立我们的命令,以及命令指定的操作函数。操作函数调用drivers目录下的驱动程序,也就是直接操作硬件的代码。drivers目录下包含了各类具体设备的驱动程序,基本上是通用的,它们通过宏从外部引入与平台或者开发板相关的functions。如图:



从单片机的角度,drivers目录下面的驱动文件由该驱动文件同目录的makefile文件指定预处理、编译、汇编生成静态库文件,链接器从库文件取得所需的代码,复制到生成的可执行文件中。所以我们需要将我们自己写的驱动文件和命令文件都要在makefile中指定编译规则。

下面是led_blink具体实现过程。

首先从功能的角度,我们要实现从上层的命令操作到底层的物理操作,需要建立两个文件,一个是在drivers/gpio/sml2440_led_blink.c文件;一个是在
文件。这样我们就可以分别依照uboot的规则,在sml2440_led_blink.c文件中写驱动,在cmd_ledblink.c文件中写命令了。

cmd_ledblink.c具体的内容如下:

//common/cmd_ledblink.c
#include <common.h>
#include <command.h>

int do_led(void)
{
	s3c24x0_led_blink();
	return 0 ;
}

U_BOOT_CMD(
	led, 2, 1,	do_led,
	"ledblink, just for test",
	"测试指令,让led闪烁"
	"学习指令和驱动流程"
);

分析:

U_BOOT_CMD();是建立指令的格式(宏),led是指令名称,2是指令的参数个数,1是指令可重复执行,do_led是指令执行的函数指针。所以我们再写了一个do_led的函数,其内容是调用底层驱动的s3c24x0_led_blink();函数。头文件自行分析。

drivers/gpio/sml2440_led_blink.c文件内容如下:

//drivers/gpio/sml2440_led_blink.c

#include <common.h>
#include <asm/arch/s3c24x0_cpu.h>

static void delay (unsigned long loops)
{
	__asm__ volatile ("1:\n"
			"subs %0, %1, #1\n"
			"bne 1b":"=r" (loops):"0" (loops));
}
int s3c24x0_led_init(void)
{
	struct s3c24x0_led *led = s3c24x0_get_base_led();
	led->GPFCON = 0x55 ;
	led->GPFUP = 0xff ;
	led->GPFDAT = 0 ;
	return 0 ;
}
int s3c24x0_led_blink(void)
{
	int N = 10 ;
	struct s3c24x0_led *led = s3c24x0_get_base_led();
	while(N--){
		led->GPFDAT = 0xff ;
		delay(20000000);
		led->GPFDAT = 0x00 ;
		delay(20000000);
		}
	return 0 ;
	
}

分析:首先我们知道上层的指令led将调用s3c24x0_led_blink()函数,我们在底层续写之。为了实现这个函数,满足对底层操作的要求,我们需要操作控制led的寄存器。相信程led闪烁的方式都看得懂,就是让io引脚延时拉高,延时拉低的结果。  struct s3c24x0_led *led = s3c24x0_get_base_led();在 http://blog.csdn.net/seek_0380/article/details/8764777这篇博文里已有说明,是取出一块首地址固定符合自定义寄存器要求的内存空间。我们在s3c24x0.h中定义一块连续的寄存器空间,具体实现方法请查看链接博文(这里只是一个实现的技巧)。然后对寄存器写数据即可。


紧接着为了生成可执行文件,我们还需要对makefile进行modified,指定规则使source file被编译。对drivers/gpio下的makefile文件内添加:

COBJS-$(CONFIG_SML2440_LED)		+= sml2440_led_blink.o

然后就会被连接生成静态库

LIB 	:= $(obj)libgpio.a


对于common下面的makefile文件,添加如下code即可。

COBJS-y += cmd_ledblink.o


这样我们把编译生成的uboot镜像文件下载到flash中,在terminal输入help,就会看到led驱动及其说明。我们敲入led,就会看到led闪烁了十次后,terminal回到命令接受模式。这样led_blink的uboot下的实现就完成了。


原文地址:https://www.cnblogs.com/javawebsoa/p/3034404.html