CubieBoard中文论坛

 找回密码
 立即注册
搜索
热搜: unable
查看: 12659|回复: 6

cubieboard上通过U-boot点亮板载LED

[复制链接]
发表于 2013-5-25 22:09:12 | 显示全部楼层 |阅读模式
原文http://blog.csdn.net/andy_wsj/article/details/8973818
软件环境: 笔记本一台,安装WindowsXP sp3

                     XP下软件:Source Insight 3.5;SecureCRT;VMware Workstation7.0

                    虚拟机中安装ubuntu10.04

                    ubuntu中软件:Vim;编译工具链 arm-none-eabi- 版本4.7.2

硬件环境:cubieboard,淘宝自带的串口线和电源线

                    microSD卡一只,读卡器一个

准备工作:U-boot实现SD卡启动,请参考另一篇文章 http://blog.csdn.net/andy_wsj/article/details/8515197

                   CB的原理图

                   A10用户手册



        在XP下用Source Insight 3.5建立u-boot代码查阅工程。

        SecureCRT就是超级终端,XP还需要USB转串口的驱动,网上很多例子。

       直接就在u-boot代码查阅工程中搜索"LED",出来一大片结果,最后可以定位通用的LED控制代码在文件:

        /u-boot-sunxi-sunxi/drivers/misc/status_led.c
        调用的函数有__led_init,__led_toggle,__led_set,搜索这几个函数,定位在文件:
        /u-boot-sunxi-sunxi/drivers/misc/gpio_led.c
        如果需要实现LED控制,则将这两个文件修改成适合cubieboard即可。
1、编译细节处理

以上两个文件需要编译到u-boot里面去,看一下目录/u-boot-sunxi-sunxi/drivers/misc/的Makefile文件内容:

.......
COBJS-$(CONFIG_GPIO_LED) += gpio_led.o
COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
COBJS-$(CONFIG_NS87308) += ns87308.o
COBJS-$(CONFIG_PDSP188x) += pdsp188x.o
COBJS-$(CONFIG_STATUS_LED) += status_led.o

.......

可以看出,编译这两个文件需要定义两个宏

CONFIG_GPIO_LED

CONFIG_STATUS_LED


2、函数调用细节

阅读gpio_led.c代码,调用了gpio_direction_output,gpio_set_value,gpio_get_value三个函数,在工程内搜索一下,找到相关文件就是/u-boot-sunxi-sunxi/arch/arm/cpu/armv7/sunxi/gpio.c

再来看看status_led.c内函数的调用情况,要实现LED闪烁,只要调用status_led_tick函数

搜索status_led_tick函数,可以看见其他平台的实现,都是在定时器中断中调用

如果不使用中断,最好的莫过于使用命令来控制了。到目录/u-boot-sunxi-sunxi/common看一下,

发现已经存在一个文件cmd_led.c,打开看看头文件和宏定义,如果想直接使用这个文件,再看看目录下的Makefile,那么需要定义

CONFIG_CMD_LED

CONFIG_BOARD_SPECIFIC_LED

如此一来,在/u-boot-sunxi-sunxi/include/configs/sunxi-common.h最后加上下面这几行:

/*LED*/

#define CONFIG_CMD_LED                                       //使用LED命令,即编译cmd_led.c
#define CONFIG_BOARD_SPECIFIC_LED                //板载特别LED
#define CONFIG_GPIO_LED                                      //LED的IO操作,即编译../driver/misc/gpio_led.c
#define CONFIG_STATUS_LED                                //LED的状态控制操作,即编译../driver/misc/status_led.c,

实际上./driver/misc/status_led.c这个文件没有使用到。


这样编译会报错,因为还有一些LED相关的宏没有定义,定义在何处呢?

经过观察,我发现其他开发板都定义在status_led.h内,因此我也打算这样做

进入status_led.h,发现正好使用了CONFIG_BOARD_SPECIFIC_LED这个宏做条件编译

偷一下懒,status_led.h文件内如下定义之:

#elif defined(CONFIG_BOARD_SPECIFIC_LED)

#define STATUS_LED_BIT               ((7 << 5) + 20)    /*PH20, gpio group 7*/

#define STATUS_LED_PERIOD      (CONFIG_SYS_HZ / 10)

#define STATUS_LED_STATE        STATUS_LED_BLINKING


#define STATUS_LED_BIT1              ((7 << 5) + 21)   /*PH21*/

#define STATUS_LED_PERIOD1     (CONFIG_SYS_HZ / 10)

#define STATUS_LED_STATE1       STATUS_LED_BLINKING


解释一下这个宏:

#define STATUS_LED_BIT               ((7 << 5) + 20)    /*PH20, gpio group 7*/      7左移5表示:7乘以32

看看原理图,LED画在PH20和PH21上,同过IO控制三极管导通,进而控制LED状态

这时候需要看看A10的用户手册,“Port Controller”那一节,若要获得PH的控制寄存器首地址,需要 n*0x24 + 0x00

而PH是第7组IO,0x24就是十进制32,因此需要 7 << 5

加20表示是第PH20,如果是PH21就加21,当使用这个宏的时候,代码是反过来解析使用的,

阅读/u-boot-sunxi-sunxi/arch/arm/cpu/armv7/sunxi/gpio.c,就可以看到这个数据使用的方法了。

最后发现是初始化没有调用,在文件cmd_led.c里面还需要调用一下初始化,在函数 do_led 中加入
        static int led_init_flag = 0;
        if( led_init_flag == 0)
        {
                for(i=0; led_commands.mask; i++){
                        __led_init(led_commands.mask, 0);
                }
                led_init_flag = 1;
        }
3、测试

编译,按SD卡启动方式写入SD卡,上电之后输入命令

led  0  on

led  0  off


led  1  on

led  1  off

led   all   toggle   

就可以控制两个LED了



评分

参与人数 2威望 +10 金钱 +10 贡献 +10 收起 理由
ishz2013 + 5 + 5 + 5 很给力!
soloforce + 5 + 5 + 5 赞一个!

查看全部评分

回复

使用道具 举报

发表于 2013-5-26 08:34:21 | 显示全部楼层
好贴!学习了
回复 支持 反对

使用道具 举报

发表于 2013-7-10 09:05:21 | 显示全部楼层
有没有不用打指令的方法,比如闪灯,把bin烧入sd,插卡后就可以看到灯闪
回复 支持 反对

使用道具 举报

发表于 2013-7-17 15:01:21 | 显示全部楼层
寒寒 发表于 2013-7-10 09:05
有没有不用打指令的方法,比如闪灯,把bin烧入sd,插卡后就可以看到灯闪

读贴不精,再读一次就知道问题怎么解决了
回复 支持 反对

使用道具 举报

发表于 2013-10-6 21:58:06 | 显示全部楼层
本帖最后由 tll 于 2013-10-6 22:00 编辑

这个用gpio的命令去控制led就好了,实在没必要上传程序……
回复 支持 反对

使用道具 举报

发表于 2013-11-13 09:19:11 | 显示全部楼层
不错哦。。
回复 支持 反对

使用道具 举报

发表于 2013-11-15 09:01:37 | 显示全部楼层
LZ你好,我在A20的uboot.lds文件中发现是这样写的:
  1. OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
  2. OUTPUT_ARCH(arm)
  3. ENTRY(_start)
  4. SECTIONS
  5. {
  6.         . = 0x00000000;

  7.         . = ALIGN(4);
  8.         .text        :
  9.         {
  10.                 arch/arm/cpu/armv7/start.o        (.text)
  11.                 *(.text)
  12.         }

  13.         . = ALIGN(4);
  14.         .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }

  15.         . = ALIGN(4);
  16.         .data : {
  17.                 *(.data)
  18.         }

  19.         . = ALIGN(4);

  20.         . = .;
  21.         __u_boot_cmd_start = .;
  22.         .u_boot_cmd : { *(.u_boot_cmd) }
  23.         __u_boot_cmd_end = .;

  24.         . = ALIGN(4);

  25.         __image_copy_end = .;

  26.         .rel.dyn : {
  27.                 __rel_dyn_start = .;
  28.                 *(.rel*)
  29.                 __rel_dyn_end = .;
  30.         }

  31.         .dynsym : {
  32.                 __dynsym_start = .;
  33.                 *(.dynsym)
  34.         }

  35.         _end = .;

  36.         .bss __rel_dyn_start (OVERLAY) : {
  37.                 __bss_start = .;
  38.                 *(.bss)
  39.                  . = ALIGN(4);
  40.                 __bss_end__ = .;
  41.         }

  42.         /DISCARD/ : { *(.dynstr*) }
  43.         /DISCARD/ : { *(.dynamic*) }
  44.         /DISCARD/ : { *(.plt*) }
  45.         /DISCARD/ : { *(.interp*) }
  46.         /DISCARD/ : { *(.gnu*) }
  47. }
复制代码
也就是在它的前4kB中,就只有一个start.S文件,而没有从nand flsh拷贝到ram 的函数,请问这个是怎么回事...?莫非拷贝功能已经在 start.S中已经实现了?还是...?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|粤ICP备13051116号|cubie.cc---深刻的嵌入式技术讨论社区

GMT+8, 2024-4-19 02:30 , Processed in 0.028467 second(s), 16 queries .

Powered by Discuz! X3.4

© 2001-2012 Comsenz Inc. | Style by Coxxs

返回顶部