linux驱动程序开发-第二节:uboot添加自定义控制命令+uboot中运行裸机C语言程序


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烧写(省略)
 

猜你喜欢

转载自blog.csdn.net/wghkemo123/article/details/85796891