嵌入式Linux开发-编写自定义uboot命令

描述

1. 前言

U-Boot 是一个主要用于嵌入式系统的引导加载程序,可以支持多种不同的计算机系统结构。

U-Boot的命令为用户提供了交互功能,并且已经实现了几十个常用的命令,前面两篇文章介绍了uboot自带的常用命令使用。

如果开发板需要很特殊的操作,可以添加新的U-Boot命令。U-Boot的每一个命令都是通过U_Boot_CMD宏定义的。

这个宏在头文件中定义。

 #define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
 ​
 cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage}
复制代码

参数介绍:

 name:命令的名字,他不是一个字符串,不能用双引号括起来
 maxargs:最大的参数个数
 command:对应的函数指针
 usage:一个字符串,简短的使用说明
 help:一个字符串,比较详细的使用说明
 UBOOT命令文件命名规则:cmd_xxx.c
复制代码

将写好的命令.c文件放入UBOOT源码顶层的/common目录下,并且修改Makefile文件,将加入的.c文件添加到编译选项中。

在Makefile文件大约50行出进行添加即可:

 格式:COBJS-y += cmd_xxx.o
复制代码

添加完毕,回到uboot顶层目录下,重新生成u-boot.bin文件,再下载到开发板测试。

Linux

2. 自定义UBOOT命令代码

2.1 编写蜂鸣器控制命令

 #include 
 #include 
 #define GPD0CON     (*(volatile unsigned int *)0x114000A0) //定义蜂鸣器IO口的地址
 #define GPD0DAT     (*(volatile unsigned int *)0x114000A4)
 ​
 int do_beep( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
     GPD0CON&=~(0xf<<0);
     GPD0CON|=(0x1<<0);
     
     if(!strcmp(argv[1],"on"))  //strcmp是比较字符串的函数,如果传进来的是on,就打开蜂鸣器
         {
             GPD0DAT|=(1<<0);    
         }
     if(!strcmp(argv[1],"off"))//strcmp是比较字符串的函数,如果传进来的是off,就关闭蜂鸣器
         {
             GPD0DAT&=~(1<<0);   
         }
     else
         printf("Usage:beep !\n"); //如果不是on 也不是off  就输出提示
 }
 ​
 ​
 U_BOOT_CMD( 
     beep,    //在u-boot命令行里显示的命令名称
     2,       //形参最大个数
     1,       //重复次数 (按下回车--自动执行上一次命令)
     do_beep, //命令执行函数(回调函数--)
     "传参格式: beep ",   //用法提示
     "传承示例:beep on 或者 beep off......."  //帮助命令的提示信息
 );
复制代码|off>|off>

2.2 编写LED灯控制命令

 #include 
 #include 
 ​
 /* 1、LED灯接口配置寄存器 */
 #define GPM4CON     (*(volatile unsigned int *)0x110002E0)
 #define GPM4DAT     (*(volatile unsigned int *)0x110002E4)
 ​
 int do_led(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
     // led 1 on
     // led 1 off
     GPM4CON &= ~(0xf << 0 * 4);    //清除寄存器1
   GPM4CON |=  (1   << 0 * 4);    //输出模式
   
   GPM4CON &= ~(0xf << 1 * 4);    //清除寄存器2
   GPM4CON |=  (1   << 1 * 4);    //输出模式
   
   GPM4CON &= ~(0xf << 2 * 4);    //清除寄存器3
   GPM4CON |=  (1   << 2 * 4);    //输出模式
   
   GPM4CON &= ~(0xf << 3 * 4);    //清除寄存器4
   GPM4CON |=  (1   << 3 * 4);    //输出模式
   
   
   /*第一盏灯*/  
     if(!strcmp(argv[1],"1"))  //strcmp是比较字符串的函数,如果传进来的是on,就打开蜂鸣器
         {
             if(!strcmp(argv[2],"on"))
             {
                 GPM4DAT &= ~(1 << 0);      //点亮第一个灯 
             }
             else if(!strcmp(argv[2],"off"))
             {
                 GPM4DAT |=1 << 0;          //关闭第一个灯 
             }
         }
         
         /*第二盏灯*/    
     else if(!strcmp(argv[1],"2"))  //strcmp是比较字符串的函数,如果传进来的是on,就打开蜂鸣器
         {
             if(!strcmp(argv[2],"on"))
             {
                 GPM4DAT &= ~(1 << 1);      //点亮第二个灯 
             }
             else if(!strcmp(argv[2],"off"))
             {
                 GPM4DAT |=1 << 1;          //关闭第二个灯 
             }
         }
     
         /*第三盏灯*/    
     else if(!strcmp(argv[1],"3"))  //strcmp是比较字符串的函数,如果传进来的是on,就打开蜂鸣器
         {
             if(!strcmp(argv[2],"on"))
             {
                 GPM4DAT &= ~(1 << 2);      //点亮第三个灯 
             }
             else if(!strcmp(argv[2],"off"))
             {
                 GPM4DAT |=1 << 2;          //关闭第三个灯 
             }
         }
         
     /*第四盏灯*/    
     else if(!strcmp(argv[1],"4"))  //strcmp是比较字符串的函数,如果传进来的是on,就打开蜂鸣器
         {
             if(!strcmp(argv[2],"on"))
             {
                 GPM4DAT &= ~(1 << 3);      //点亮第四个灯 
             }
             else if(!strcmp(argv[2],"off"))
             {
                 GPM4DAT |=1 << 3;          //关闭第四个灯 
             }
         }
 ​
     else
         printf("Usage:led <1~4> \n"); //如果不是on 也不是off  就输出提示
 }
 ​
 ​
 U_BOOT_CMD( 
     led,     //在u-boot命令行里显示的命令名称
     3,       //形参最大个数
     1,       //重复次数
     do_led,  //命令执行函数
     "user: LED count ",   //用法提示
     "cmd : (1)led  1 on (2)led 1 off...."  //帮助命令的提示信息
 );
复制代码|off>|off>

2.3 设计自己的movi命令

 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 ​
 int do_mymovi(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 {
     int r_cnt,w_cnt;
    /*1. 查找设备0-SD卡*/
     struct mmc *mmc0 = find_mmc_device(0);
     if(mmc0==NULL)
     {
         printf("设备0查找失败!\n");
         return 0;
     }
     /*2. 查找设备1--MMC*/
     struct mmc *mmc1 = find_mmc_device(1);
     if(mmc1==NULL)
     {
         printf("设备1查找失败!\n");
         return 0;
     }
     /*3. 初始化SD卡*/
     mmc_init(mmc0); /*设备0初始化--SD卡*/
   
   /*4. 初始化EMMC*/
     mmc_init(mmc1); /*设备1初始化--EMMC卡*/ 
     emmc_boot_open(mmc1); /*设备1打开---EMMC*/
     
     /*5. 烧写数据*/
         /*5.1 BL1*/
         r_cnt=movi_read(0,1,16,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
         w_cnt=movi_write(1,0,16,(void*)0x40008000);//将读出的数据写入到EMMC
         printf("BL1_r_cnt=%d\n",r_cnt);
         printf("BL1_w_cnt=%d\n",w_cnt);
     
     /*5.2 BL2*/
         r_cnt=movi_read(0,17,32,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
         w_cnt=movi_write(1,16,32,(void*)0x40008000);//将读出的数据写入到EMMC
         printf("BL2_r_cnt=%d\n",r_cnt);
         printf("BL2_w_cnt=%d\n",w_cnt);
 ​
       /*5.3 UBOOT\这里最好使用malloc申请空间,太大的地址可能会被其他数据覆盖掉*/
         r_cnt=movi_read(0,49,656,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
         w_cnt=movi_write(1,48,656,(void*)0x40008000);//将读出的数据写入到EMMC
         printf("UBOOT_r_cnt=%d\n",r_cnt);
         printf("UBOOT_w_cnt=%d\n",w_cnt);
         
         /*5.4 TZSW*/
         r_cnt=movi_read(0,705,320,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
         w_cnt=movi_write(1,704,320,(void*)0x40008000);//将读出的数据写入到EMMC
         printf("TZSW_r_cnt=%d\n",r_cnt);
         printf("TZSW_w_cnt=%d\n",w_cnt);
         
         /*5.5 Linux内核*/
         r_cnt=movi_read(0,1057,12288,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
         w_cnt=movi_write(1,1057,12288,(void*)0x40008000);//将读出的数据写入到EMMC
         printf("Linux内核_r_cnt=%d\n",r_cnt);
         printf("Linux内核_w_cnt=%d\n",w_cnt);
     emmc_boot_close(mmc1); //关闭EMMC
     
     /*5.5 环境变量*/
     r_cnt=movi_read(0,1025,32,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
     w_cnt=movi_write(1,1025,32,(void*)0x40008000);//将读出的数据写入到EMMC
     printf("环境变量_r_cnt=%d\n",r_cnt);
     printf("环境变量_w_cnt=%d\n",w_cnt);
     printf("环境变量拷贝成功!\n");
     return 0;
 }
 ​
 U_BOOT_CMD(
     mymovi,    /*命令的名称*/
     1,          /*形参的最大个数*/
     0,          /*命令执行重复次数*/
     do_mymovi,/*命令处理函数*/
     "将SD卡的BL1/BL2/uboot/签名文件/内核拷贝到EMMC", /*简短提示*/
     "\n"
     "将SD卡的BL1/BL2/uboot/签名文件/内核拷贝到EMMC\n" /*完整提示*/
     "注意: 该命令在开发板以SD卡启动方式时运用\n"
 );
复制代码

2.4 设计环境变量拷贝命令

 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 ​
 /*
 //以MMC方式启动,运行下面命令即可完成环境变量拷贝(SD-->EMMC)
 mmc read 1 40000000 401 20
 mmc write 0 40000000 401 20
 ​
 //以SD方式启动,运行下面命令即可完成环境变量拷贝 (SD--->EMMC)
 mmc read 0 40000000 401 20
 mmc write 1 40000000 401 20
 */
 int do_copyenv(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 {
     int r_cnt,w_cnt;
     mmc_init(find_mmc_device(0)); /*设备0初始化--SD卡*/
     mmc_init(find_mmc_device(1)); /*设备1初始化--EMMC卡*/ 
 ​
     /*5.5 环境变量*/
     r_cnt=movi_read(0,1025,32,(void*)0x40000000); //读出SD卡里存放到所有数据到DDR指定地址
     w_cnt=movi_write(1,1025,32,(void*)0x40000000);//将读出的数据写入到EMMC
     printf("环境变量_r_cnt=%d\n",r_cnt);
     printf("环境变量_w_cnt=%d\n",w_cnt);
     printf("环境变量拷贝成功!\n");
     return 0;
 }
 ​
 ​
 U_BOOT_CMD(
     copyenv,    /*命令的名称*/
     1,          /*形参的最大个数*/
     0,          /*命令执行重复次数*/
     do_copyenv,/*命令处理函数*/
     "将SD卡的环境变量拷贝到EMMC", /*简短提示*/
     "\n"
     "将SD卡的环境变量拷贝到EMMC\n" /*完整提示*/
     "注意: 该命令在开发板以SD卡启动方式时运用\n"
 );

  审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分