2-搭建linux内核编译环境+uboot操作设备+烧写编译好的linux内核
3-在uboot中添加自己的命令语句调用
4-基于uboot添加命令控制外围设备-led+bmp
5-基于uboot模式下内存运行裸机程序
6-修改开发板logo通过制作新的kernel
视频教程及资料链接:
链接:https://pan.baidu.com/s/1qXZ1Fyg2HJwvkrZgc-zFvQ
提取码:t5od
2-搭建linux内核编译环境+uboot操作设备+烧写编译好的linux内核
==================================uboot开发重要文件===========================================
裸机开发核心文件(使用uboot初始化设备实现操作外设)
GEC6818uboot/arch/arm/cpu/slsiap/s5p6818/start.S
GEC6818uboot/board/s5p6818/GEC6818/board.c
GEC6818uboot/include/configs/GEC6818.h
GEC6818uboot/common/board_f.c
===================================裸机操作外围设备===========================================
一 开发流程:修改linux内核特定文件---->编译修改后内核------>烧写到开发板中。
二 思路:修改start.S --->修改board.c--->修改GEC6818.h---->修改board_f.c
三 步骤:
1.在汇编中添加:GEC6818uboot/arch/arm/cpu/slsiap/s5p6818/start.S
在reset后添加:
led_test:
/* led1 output */
ldr r0, =0xC001E004 // 将立即数 0xC001E004 赋值给 r0
ldr r1, =0x2000
str r1, [r0] // r1的值 赋值给 r0对应的地址的变量
/* led1 on */
ldr r0, =0xC001E000
mov r1, #0 // 将立即数 0 赋值给 r1
// bic r0, r0, #0x1f 对相应位进行清零操作
// orr r0, r0, #0xd3 对相应位进行或操作,一般用于置一
str r1, [r0]
2.注释掉C语言对GPIO的再次初始化,避免系统对GPIO默认初始化影响自己对GPIO的设置
修改路径:GEC6818uboot/board/s5p6818/GEC6818/board.c
/* call from u-boot */
int board_early_init_f(void)
{
//bd_gpio_init(); 注释该行
bd_alive_init();
return 0;
}
3. 可通过修改GEC6818.h实现对目标板的一些参数修改
修改路径:GEC6818uboot/include/configs/GEC6818.h
修改例子:改变板子用户显示
/*
* Miscellaneous configurable options
*/
#define CONFIG_SYS_PROMPT "GEC6818# "//可以更改为:"WGH#"
4. 在C语言中添加C语言操作函数,以C语言操作地址间接操作外围设备。
修改路径:GEC6818uboot/common/board_f.c
修改例子:添加启动后点亮某个led灯
(1)
//定义LED3控制函数
int led3_on(void)
{
// 配置寄存器
#define GPIOCALTFN0 (*(volatile unsigned int *)0xC001C020)
#define GPIOCOUTENB (*(volatile unsigned int *)0xC001C004)
#define GPIOCOUT (*(volatile unsigned int *)0xC001C000)
//设置GPIOC8普通IO, 输出,低电平
GPIOCALTFN0 = GPIOCALTFN0 & ~(0x3 << 16) | (0x1 << 16);
GPIOCOUTENB |= (0x1 << 8);
GPIOCOUT &= ~(0x1 << 8) ;
}
(2)
static init_fnc_t init_sequence_f[] =
{
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
jump_to_copy,
#endif
led3_on, //添加LED3控制代码
NULL,
};
5.编译linux内核
(1)编译环境搭建:
1、确认安装好vmware 14 或 更高版本
2、安装Ubuntu16.04或更高版本
3、将BSP开发包拷贝到 ubuntu系统的用户工作目录下:
cd ~
cp /mnt/hgfs/xxxxx/6818GEC.tar.gz .
tar zxf 6818GEC.tar.gz (检查是否解压得到 6818GEC 目录,才表示解压成功)
(2)编译步骤
进入 6818GEC 目录执行:
./mk -u (编译uboot,检查生成文件: 6818GEC/out/release/GECuboot.bin)
(3)把编译出来的6818GEC/out/release/GECuboot.bin拷贝到window某个目录下,方便后期烧写。
6、烧写镜像
1、接好电源,串口线,microUSB线,上电
2、开发板Uboot倒计时3S之内,回车,进入uboot的烧写与交互状态
输入:fastboot
在该状态下可以进行
(
a.查阅uboot的信息
b.设置uboot的信息与参数
c.下载数据与固化
d.配置与控制开发板(uboot模式)
)
3、烧写系统镜像步骤:
(1)文件分析:
在 嵌入式系统驱动\GEC6818系统恢复\GEC6818-fastboot恢复\镜像文件\linux-qt目录中分别有:
烧写脚本: auto.bat
烧写工具: fastboot.exe
烧写文件:
Uboot ----> ubootpak.bin
kernel ----> boot.img
filesystem ----> qt-rootfs.img
(2)实际操作:
1.修改脚本(右键选择编辑:auto.bat)
2.脚本原始内容为:
-----------------------------------------------------------------
命令 烧写设备 数据分区 文件
----------------------------------------------------------------
#fastboot flash GECuboot ubootpak.bin(实际文件名)
#fastboot flash boot boot.img
#fastboot flash system qt-rootfs.img
fastboot reboot
3.脚本修改后内容为:
-----------------------------------------------------------------
命令 烧写设备 数据分区 文件
----------------------------------------------------------------
fastboot flash GECuboot ubootpak.bin(实际文件名)
#fastboot flash boot boot.img
#fastboot flash system qt-rootfs.img
fastboot reboot
4.保存关闭,双击执行,正在烧写,结束自动启动
3-在uboot中添加自己的命令语句调用
============================uboot添加自定义功能===================
1.思路:
a.在命令原型实现目录common中,添加一个cmd_xxx.c文件
b.在cmd_xxx.c文件中,实现自定义命令的设计
c.在当前命令文件所在的目录中,修改或添加Makefile
2.操作:
(1)添加功能cmd_xxx.c
------------------------------------------------------------------
模版
------------------------------------------------------------------
U_BOOT_CMD(
help, CONFIG_SYS_MAXARGS, 1, do_help,
"print command description/usage",
"\n"
" - print brief description of all commands\n"
"help command ...\n"
" - print detailed usage of 'command'"
);
-------------------------------------------------------------------
解析
-------------------------------------------------------------------
U_BOOT_CMD(
命令名,命令可接受的最大参数数量,回车是否重复执行,执行函数,
"xxxxxxx", // ----> 命令声明
"..帮助字符串....", // -----> help 命令名 获取该帮助
"........."
"........."
);
--------------------------------------------------------------------
命令函数格式:
--------------------------------------------------------------------
命令结构 传参标志 参数个数 参数内容指针
static int do_xxxxx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
..... //添加功能
return XXXX; //CMD_RET_SUCCESS
}
enum command_ret_t
{
CMD_RET_SUCCESS, /* 0 = Success */ 执行成功
CMD_RET_FAILURE, /* 1 = Failure */ 执行失败
CMD_RET_USAGE = -1, /* Failure, please report 'usage' error */ 执行成功,并打印帮助信息
};
(2)例子
#include <common.h>
#include <command.h>
static int do_wgh(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
printf("hello wgh\n");
return CMD_RET_SUCCESS;
}
U_BOOT_CMD(
wgh, CONFIG_SYS_MAXARGS, 1, do_wgh,
"command wgh",
"wgh test\n"
);
(3)修改目录common中Makefile使得编译通过,但是注意添加的位置,需要在内核编译后添加:
obj-y += cmd_xxxx.o //增加该行
(4)
重新编译Uboot,烧写测试
4-基于uboot添加命令控制外围设备-led+bmp
-------------------------------demo2--------------------------------
#include <common.h>
#include <command.h>
static int do_ctl(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
printf("contrl command \n");
if(argc < 3 || argc > 4 )
return CMD_RET_USAGE; // age err
if (strcmp(argv[1], "led") == 0)
{
/* goto contrl LED */
printf("goto contrl LED \n");
return CMD_RET_SUCCESS;
}
else if (strcmp(argv[1], "beep") == 0) {
/* goto contrl BEEP */
printf("goto contrl BEEP \n");
return CMD_RET_SUCCESS;
}
return CMD_RET_SUCCESS; //CMD_RET_SUCCESS
}
U_BOOT_CMD(
ctl, CONFIG_SYS_MAXARGS, 1, do_ctl,
"command ctl",
" device contrl command \n"
" contrl led ----- ex. ctl led ledx on/off \n"
" ledx ----- ex. led1 led2 led3 led4 \n"
" contrl beep ----- ex. ctl beep on/off \n"
);
----------------------------------demo3----------------------------------
#include <common.h>
#include <command.h>
#define GPIOEALTFN0 (*(volatile unsigned int *)0xC001E020)
#define GPIOEOUTENB (*(volatile unsigned int *)0xC001E004)
#define GPIOEOUT (*(volatile unsigned int *)0xC001E000)
#define GPIOCALTFN0 (*(volatile unsigned int *)0xC001C020)
#define GPIOCALTFN1 (*(volatile unsigned int *)0xC001C024)
#define GPIOCOUTENB (*(volatile unsigned int *)0xC001C004)
#define GPIOCOUT (*(volatile unsigned int *)0xC001C000)
void gpio_init(void)
{
//1.将GPIOE13设置成普通的GPIO功能
GPIOEALTFN0 &= ~(0x3<<26);//function 0
//2.将GPIOC17/14/8/7设置成普通的GPIO功能
GPIOCALTFN1 = GPIOCALTFN1 & ~(0x3 << 2) | (0x1 << 2); // GPIOC17
GPIOCALTFN0 = GPIOCALTFN0 & ~(0x3 << 28) | (0x1 << 28);// GPIOC14
GPIOCALTFN0 = GPIOCALTFN0 & ~(0x3 << 16) | (0x1 << 16);// GPIOC8
GPIOCALTFN0 = GPIOCALTFN0 & ~(0x3 << 14) | (0x1 << 14);// GPIOC7
//3.将GPIOE13/GPIOC17/8/7设置成输出引脚
GPIOEOUTENB |= (0x1<<13);
GPIOCOUTENB |= (0x1 << 17) | (0x1 << 14) | (0x1 << 8)| (0x1 << 7);
//4.设置GPIO电平
GPIOEOUT |= (0x1 << 13) ;
GPIOCOUT |= (0x1 << 17) |(0x1 << 8)| (0x1 << 7);
GPIOCOUT &= ~(0x1 << 14);
}
static int do_ctl(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int state = -1;
printf("contrl command \n");
if(argc < 3 || argc > 4 )
return CMD_RET_USAGE; // age err
gpio_init();
if(argc == 4)
{
if (strcmp(argv[3], "on") == 0)
state = 0;
else if (strcmp(argv[3], "off") == 0)
state = 1;
}
else if(argc == 3)
{
if (strcmp(argv[2], "on") == 0)
state = 1;
else if (strcmp(argv[2], "off") == 0)
state = 0;
}
if(state == -1)
return CMD_RET_USAGE;
if (strcmp(argv[1], "led") == 0) {
/* goto contrl LED */
printf("goto contrl LED \n");
if (strcmp(argv[2], "led1") == 0) {
GPIOEOUT = (GPIOEOUT & ~(0x1 << 13)) | state << 13 ;
}else if (strcmp(argv[2], "led2") == 0) {
GPIOCOUT = (GPIOCOUT & ~(0x1 << 17)) | state << 17 ;
}else if (strcmp(argv[2], "led3") == 0) {
GPIOCOUT = (GPIOCOUT & ~(0x1 << 8)) | state << 8 ;
}else if (strcmp(argv[2], "led4") == 0) {
GPIOCOUT = (GPIOCOUT & ~(0x1 << 7)) | state << 7 ;
}
}
else if (strcmp(argv[1], "beep") == 0) {
/* goto contrl BEEP */
printf("goto contrl BEEP \n");
GPIOCOUT = (GPIOCOUT & ~(0x1 << 14)) | state << 14 ;
return CMD_RET_SUCCESS;
}
return CMD_RET_SUCCESS; //CMD_RET_SUCCESS
}
U_BOOT_CMD(
ctl, CONFIG_SYS_MAXARGS, 1, do_ctl,
"command ctl",
" device contrl command \n"
" contrl led ----- ex. ctl led ledx on/off \n"
" ledx ----- ex. led1 led2 led3 led4 \n"
" contrl beep ----- ex. ctl beep on/off \n"
);
------------------------------------------------------------------------------------
5-基于uboot模式下内存运行裸机程序
========================uboot的内存运行裸机代码======================
一 流程:(1)编写C文件和Makefile文件,产生裸机代码
(2)编译产生bin文件
(3)uboot模式 tftp网络方式 下载bin文件
二 操作:
------------------ 制作可执行镜像 -----------------
1、 编辑一个裸机的控制程序 led.c
//编写的是裸机程序直接在硬件上运行的,不是在操作系统上运行的.
//逻辑程序不能直接使用C的库.不能直接使用<stdio.h>
//0.定义寄存器
#define GPIOEALTFN0 (*(volatile unsigned int *)0xC001E020)
#define GPIOEOUTENB (*(volatile unsigned int *)0xC001E004)
#define GPIOEOUT (*(volatile unsigned int *)0xC001E000)
void delay(int val);//没有使用C库,没有main函数,入口函数就要放在程序的最开始位置.
void _start(void) //入口函数
{
//1.将GPIOE13设置成普通的GPIO功能
GPIOEALTFN0 &= ~(3<<26);//function 0
//2.将GPIOE13设置成输出引脚
GPIOEOUTENB |= (1<<13);
while(1)
{
//3.设置GPIOE13输出高电平,D7灭
GPIOEOUT |= (1<<13);
delay(0x3000000);
//4.设置GPIOE13输出低电平,D7亮
GPIOEOUT &= ~(1<<13);
delay(0x3000000);
}
}
void delay(int val)
{
while(val--);
}
2、 在同一目录,编写 Makefile
all:
arm-linux-gcc -o led.o led.c -c -nostdlib #将裸机代码编译成非标准库的镜像
arm-linux-ld -Ttext 0x40000000 -o led.elf led.o #将镜像的执行地址设置为内存的起始地址 0x40000000
arm-linux-objcopy -O binary led.elf led.bin #将镜像转换为标准二进制格式
-----------------------------------------------------------
标准Makefile 可以参考这个
$@--目标文件,$^--所有的依赖文件,$<--第一个依赖文件。
-----------------------------------------------------------
led.bin: led7.o
arm-none-linux-gnueabi-ld -Ttext 0x40000000 -o led.elf $^
arm-none-linux-gnueabi-objcopy -O binary led.elf led.bin
arm-none-linux-gnueabi-objdump -D led.elf > led.dis
%.o : %.S
arm-none-linux-gnueabi-gcc -o $@ $< -c -nostdlib
%.o : %.c
arm-none-linux-gnueabi-gcc -o $@ $< -c -nostdlib
clean:
rm *.o *.elf *.bin *.dis -f
3、编译
make (观察,是否得到一个 led.bin)
------------------ uboot 网络下载执行镜像 ------------------
1. 启动开发板,倒计时,回车进入uboot模式下,设置uboot的IP,在uboot模式下 下载执行镜像
setenv gatewayip 192.168.28.1
setenv ipaddr 192.168.28.x
saveenv
2、测试uboot的网络连通性
ping 192.168.28.1 第一次激活会提示异常,重试一次即可
提示: 如果发现Uboot的网卡工作异常,需要检查uboot的网卡初始化是否正确
解决办法步骤:
(1)如果在GEC6818uboot/board/s5p6818/GEC6818/board.c
注释掉bd_gpio_init(); 请去掉注释,否则后面操作都无效。(如果该步骤无效应该是mac地址在局域网内冲突,可以修改mac地址)
/* call from u-boot */
int board_early_init_f(void)
{
bd_gpio_init(); //恢复原来注释的GPIO初始化函数调用
....
}
(2)修改 6818GEC/GECuboot/net/eth.c
修改如下:
//在文件头增加函数声明包含
#include <netdev.h>
//在 254行修改函数调用
int eth_initialize(bd_t *bis)
{
....
/*
* If board-specific initialization exists, call it.
* If not, call a CPU-specific one
*/
if (board_eth_init != __def_eth_init) { //将 board_eth_init 函数改为 GEC6818_board_eth_init
if (board_eth_init(bis) < 0) //将 board_eth_init 函数改为 GEC6818_board_eth_init
printf("Board Net Initialization Failed\n");
} else if (cpu_eth_init != __def_eth_init) {
if (cpu_eth_init(bis) < 0)
printf("CPU Net Initialization Failed\n");
} else
printf("Net Initialization Skipped\n");
......
}
(3)重新编译uboot,并烧写到开发板,烧写完后重复:步骤1、2
3、下载
(1)开启tftpd32服务器
(2)在uboot模式下执行:tftp 下载地址(内存) 服务器IP:文件名
例如:tftp 0x40000000 192.168.28.2:led.bin --> 将服务器192.168.28.2上的led.bin,下载到开发板内存的0x40000000 地址上
4、 运行程序
go 0x40000000 --> 跳到0x40000000地址去执行程序
6-修改开发板logo通过制作新的kernel
------------------------------------制作启动logo--------------------------------------
一 目标:开发板启动后显示自己制作的logo
二 思路:烧写新制作的kernel镜像
三 扩展:启动后显示自己的UI界面
四 流程:
1. 设计新logo并替换:6818GEC/out/target/product/GEC6818/boot/update.bmp
2. logo 要求:
像素: 300*300
色深: 24bit
格式: BMP
3. 编译系统镜像:
cd /home/xxx/6818GEC
./mk -k (-k :编译kernel)
4. 得到系统镜像:boot.img
提示:如果提示 make_ext4fs 异常或者命令未识别,请先安装 make_ext4fs
成功提示:
Created filesystem with 18/4096 inodes and 4212/16384 blocks
'/home/gec/6818GEC/out/target/product/GEC6818//boot.img' -> '/home/gec/6818GEC/out/release/boot.img'
5. 把/home/gec/6818GEC/out/release/下文件 :boot.img 拷贝到 fastboot工具目录
6. 修改auto.bat
#fastboot flash GECuboot GECuboot.bin
fastboot flash boot boot.img
#fastboot flash system qt-rootfs.img
fastboot reboot
7. fastboot烧写(省略)