Exynos4412 uboot2013.1 移植A

1. 创建板级支持 
vim boards.cfg 
添加: 
# Target                     ARCH        CPU         Board name          Vendor        SoC         Options
###########################################################################################################
xxdk     arm armv7     xxdk samsung exynos
2. make xxdk
报错:
/opt/4412/ELITE/u-boot-2013.01/include/config.h:10:26: fatal error: configs/xxdk.h: No such file or directory
compilation terminated.
/opt/4412/ELITE/u-boot-2013.01/include/config.h:10:26: fatal error: configs/xxdk.h: No such file or directory
compilation terminated.
解决: 
复制origen.h -> xxdk.h
3. make xxdk
报错: 
make[2]: *** board/samsung/xxdk/: No such file or directory.  Stop.
make[2]: Leaving directory '/opt/4412/ELITE/u-boot-2013.01'
Makefile:584: recipe for target 'board/samsung/xxdk/libxxdk.o' failed
make[1]: *** [board/samsung/xxdk/libxxdk.o] Error 2
make[1]: Leaving directory '/opt/4412/ELITE/u-boot-2013.01'
.boards.depend:243: recipe for target 'xxdk' failed
make: *** [xxdk] Error 2
解决:
   cp board/samsung/origen -r board/samsung/xxdk
4. make xxdk
生成了 uboot.bin 和 spl/xxdk-spl.bin
5. 根据三星的irom手册可以得到
irom中固化的代码启动后在iram中执行, In order to execute iROM(中的固化代码) properly, 
5KB(from 0x0202_0000 to 0x0202_1400) should be reserved at the start of internal memory(iRAM).
The secure context for BL1(E4412_N.bl1.bin三星的固件需要手动烧写大小:8K)code should be located at 0x0202_3000 of internal memory(iRAM).
The size of BL2 code can be user defined and depends on BL1 code. However, in S.LSI‟s reference code of BL1,
the valid size of BL2 code would be less than 14332B 14KB-4B, 4B is the checksum) and if the size of BL2 code is less than
    14332B, the rest area up to 14332B should be filled with zeros.(bl2 大小必须是16k总共,前14k-4B存放用户已定义数据,不够14K-4B,用0填充 
第14-4B存放4个字节的累加和校验)后面的2K存放padding和signature就是签名,因为我们用的是免费版本的,故而这里都用0填充
这里我们编写了一个工具完成上述需求: mkbl2_16k.c 
###################################################################################################
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char **argv)
{
if(3 != argc)
{
printf("Usage: %s <inf> <outf>\n", argv[0]);
return;
}

int fdin = open(argv[1], O_RDONLY);
if(-1 == fdin)
{
perror("open inf");
return -1;
}

int fdout = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0666);
if(-1 == fdout)
{
perror("open outf");
return -1;
}

char buf[16*1024] = {0};
printf("read: %d\n", read(fdin, buf, sizeof buf));

int i = 0;
unsigned int sum = 0;
for(;i<14*1024-4; i++)
sum += (unsigned char)buf[i];
*((unsigned int*)&buf[14*1024-4]) = sum;

printf("write: %d\n", write(fdout, buf, sizeof buf));


close(fdin);
close(fdout);
}
###################################################################################################
生成spl(second program loading 就相当于bl2)的输出信息: 
/opt/4412/ELITE/u-boot-2013.01/tools/mkxxdkspl \
/opt/4412/ELITE/u-boot-2013.01/spl/u-boot-spl.bin /opt/4412/ELITE/u-boot-2013.01/spl/xxdk-spl.bin
这里生成了xxdk-spl.bin(16k), 而xxdk-spl.bin 是由 tools/mkxxdkspl这个工具来生成的。所以转向追溯mkxxdkspl的生成
在spl下的makefile找到:
ifdef CONFIG_SAMSUNG
$(obj)$(BOARD)-spl.bin: $(obj)u-boot-spl.bin
$(OBJTREE)/tools/mk$(BOARD)spl \
$(obj)u-boot-spl.bin $(obj)$(BOARD)-spl.bin
endif
我们检索:grep -n "mk\$(BOARD)spl" ./ -R 
./tools/Makefile:223:$(obj)mk$(BOARD)spl$(SFX): $(obj)mkexynosspl.o
./spl/Makefile:160: $(OBJTREE)/tools/mk$(BOARD)spl \
./board/samsung/origen/Makefile:44:ALL += $(OBJTREE)/tools/mk$(BOARD)spl
./board/samsung/origen/Makefile:53:$(OBJTREE)/tools/mk$(BOARD)spl: tools/mkv310_image.c
./board/samsung/origen/Makefile:54: $(HOSTCC) tools/mkv310_image.c -o $(OBJTREE)/tools/mk$(BOARD)spl
./board/samsung/xxdk/Makefile:44:ALL += $(OBJTREE)/tools/mk$(BOARD)spl
./board/samsung/xxdk/Makefile:53:$(OBJTREE)/tools/mk$(BOARD)spl: tools/mkv310_image.c
./board/samsung/xxdk/Makefile:54: $(HOSTCC) tools/mkv310_image.c -o $(OBJTREE)/tools/mk$(BOARD)spl
./board/samsung/smdkv310/Makefile:43:ALL += $(OBJTREE)/tools/mk$(BOARD)spl
./board/samsung/smdkv310/Makefile:52:$(OBJTREE)/tools/mk$(BOARD)spl: tools/mkv310_image.c
./board/samsung/smdkv310/Makefile:53: $(HOSTCC) tools/mkv310_image.c -o $(OBJTREE)/tools/mk$(BOARD)spl

目标出现:
./board/samsung/xxdk/Makefile:53:$(OBJTREE)/tools/mk$(BOARD)spl: tools/mkv310_image.c
./board/samsung/xxdk/Makefile:54: $(HOSTCC) tools/mkv310_image.c -o $(OBJTREE)/tools/mk$(BOARD)spl
可以看到,$(OBJTREE)/tools/mk$(BOARD)spl 依赖于 tools/mkv310_image.c 也就是 /board/samsung/xxdk/tools/mkv310_image.c
打开 mkv310_image.c 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>

#define BUFSIZE (16*1024)
#define IMG_SIZE (16*1024)
#define SPL_HEADER_SIZE 16
#define FILE_PERM (S_IRUSR | S_IWUSR | S_IRGRP \
| S_IWGRP | S_IROTH | S_IWOTH)
#define SPL_HEADER "S5PC210 HEADER  "
/* 尼玛思路一样
* Requirement:
* IROM code reads first 14K bytes from boot device.
* It then calculates the checksum of 14K-4 bytes and compare with data at
* 14K-4 offset.
*
* This function takes two filenames:
* IN  "u-boot-spl.bin" and
* OUT "$(BOARD)-spl.bin as filenames.
* It reads the "u-boot-spl.bin" in 16K buffer.
* It calculates checksum of 14K-4 Bytes and stores at 14K-4 offset in buffer.
* It writes the buffer to "$(BOARD)-spl.bin" file.
*/

int main(int argc, char **argv)
{
int i, len;
unsigned char buffer[BUFSIZE] = {0};
int ifd, ofd;
unsigned int checksum = 0, count;

if (argc != 3) {
printf(" %d Wrong number of arguments\n", argc);
exit(EXIT_FAILURE);
}

ifd = open(argv[1], O_RDONLY);
if (ifd < 0) {
fprintf(stderr, "%s: Can't open %s: %s\n",
argv[0], argv[1], strerror(errno));
exit(EXIT_FAILURE);
}

ofd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, FILE_PERM);
if (ifd < 0) {
fprintf(stderr, "%s: Can't open %s: %s\n",
argv[0], argv[2], strerror(errno));
if (ifd)
close(ifd);
exit(EXIT_FAILURE);
}

len = lseek(ifd, 0, SEEK_END);  // 获取文件长度
lseek(ifd, 0, SEEK_SET); // 指针回调

memcpy(&buffer[0], SPL_HEADER, SPL_HEADER_SIZE);  // 他这里有头部

count = (len < (IMG_SIZE - SPL_HEADER_SIZE))? len : (IMG_SIZE - SPL_HEADER_SIZE);

if (read(ifd, buffer + SPL_HEADER_SIZE, count) != count) {
fprintf(stderr, "%s: Can't read %s: %s\n",
argv[0], argv[1], strerror(errno));

if (ifd)
close(ifd);
if (ofd)
close(ofd);

exit(EXIT_FAILURE);
}

for (i = 0; i < IMG_SIZE - SPL_HEADER_SIZE; i++)
checksum += buffer[i+16];

*(ulong *)buffer ^= 0x1f;
*(ulong *)(buffer+4) ^= checksum;

for (i = 1; i < SPL_HEADER_SIZE; i++)
buffer[i] ^= buffer[i-1];

if (write(ofd, buffer, BUFSIZE) != BUFSIZE) {
fprintf(stderr, "%s: Can't write %s: %s\n",
argv[0], argv[2], strerror(errno));

if (ifd)
close(ifd);
if (ofd)
close(ofd);

exit(EXIT_FAILURE);
}

if (ifd)
close(ifd);
if (ofd)
close(ofd);

return EXIT_SUCCESS;
}
这里直接用我们写的 mkbl2_16k.c  替换 mkv310_image.c
或者修改 board/samsung/xxdk/Makefile 
ifdef CONFIG_SPL_BUILD
$(OBJTREE)/tools/mk$(BOARD)spl: tools/mkv310_image.c
#$(HOSTCC) tools/mkv310_image.c -o $(OBJTREE)/tools/mk$(BOARD)spl
$(HOSTCC) /opt/4412/ELITE/u-boot-2013.01-xxdk/tools/mkbl2_16k.c -o $(OBJTREE)/tools/mk$(BOARD)spl
endif
mv mkv310_image.c mkv310_image_backup.c
cp mkb12_16k.c mkv310_image.c
make clean 
make xxdk

/opt/u-boot-2013.01/arch/arm/lib/crt0.S:108 _main
/opt/u-boot-2013.01/board/samsung/xxdk/mmc_boot.c:47 board_init_f
/opt/u-boot-2013.01/board/samsung/xxdk/lowlevel_init.S:44 lowlevel_init
ls ./spl/
arch  board  Makefile  spl  u-boot.lst  u-boot-spl  u-boot-spl.bin  u-boot-spl.lds  u-boot-spl.map  xxdk-spl.bin
用addr2line工具 从elf中查找标号地址对应的文件位置
【xxdk☆ 20:03:08】spl > grep mem_ctrl_asm_init u-boot-spl.map 
0x000001c0                mem_ctrl_asm_init
【xxdk☆ 20:04:42】spl > addr2line 0x000001c0 -e u-boot-spl
/opt/4412/ELITE/u-boot-2013.01-xxdk/board/samsung/xxdk/mem_setup.S:36
修改: board/samsung/xxdk/lowlevel_init.S 中的 
bl system_clock_init(时钟配置)
bl mem_ctrl_init(内存配置)
bl uart_asm_init(串口配置)
1. 注释掉有关:bl tzpc_init 函数
2. 拷贝我们的mem.S clk.S uart.S 到该文件夹下
3. 修改Makefile
SOBJS += clk.o
SOBJS += uart.o
SOBJS += mem.o
修改:mmc_boot.c 
void copy_uboot_to_ram(void)
{
// COPY_BL2_FNPTR_ADDR: 0x02020030
// SDMMC_ReadBlocks This function copies the data of SD and MMC type device to
// destination : Return type (True=1/False=0), Arguments (u32 SrcBlock,
// u32 NumofSrcBlock, void * DstByte)
u32 (*copy_bl2)(u32, u32, u32)  = (void *) *(u32 *)COPY_BL2_FNPTR_ADDR;
// sd 卡第0块预留,剩下48块 每一块大小512byte。
// 49 - 1 = 48, 48 / 2 = 24K
// 也就是的这 24K = E4412_N.bl1.bin(8K) + xxdk-spl.bin(mkxxdkspl加工成了16K) 
//copy_bl2(BL2_START_OFFSET, BL2_SIZE_BLOC_COUNT, CONFIG_SYS_TEXT_BASE);
// sd卡分区表
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------
// (1 block)reserved | BL1: E4412_N.bl1.bin(8K = 16blocks) | BL2: xxdk-spl.bin(16K = 32blocks) | BL3: uboot.bin 预留512K
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------
//      第0块                  ^          第1 - 第16块                                    ^       第17 - 第48块                                ^     第49块 - 第1072块                
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------
// ./include/configs/xxdk.h

#ifndef __CONFIG_H
#define __CONFIG_H

/* High Level Configuration Options */
#define CONFIG_SAMSUNG 1 /* SAMSUNG core */
#define CONFIG_S5P 1 /* S5P Family */
#define CONFIG_EXYNOS4210 1 /* which is a EXYNOS4210 SoC */
#define CONFIG_ORIGEN 1 /* working with ORIGEN*/

#include <asm/arch/cpu.h> /* get chip and board defs */

#define CONFIG_ARCH_CPU_INIT
#define CONFIG_DISPLAY_CPUINFO
#define CONFIG_DISPLAY_BOARDINFO

/* Keep L2 Cache Disabled */
#define CONFIG_L2_OFF 1
#define CONFIG_SYS_DCACHE_OFF 1

#define CONFIG_SYS_SDRAM_BASE 0x40000000
#define CONFIG_SYS_TEXT_BASE 0x43E00000

/* input clock of PLL: ORIGEN has 24MHz input clock */
#define CONFIG_SYS_CLK_FREQ 24000000

#define CONFIG_SETUP_MEMORY_TAGS
#define CONFIG_CMDLINE_TAG
#define CONFIG_INITRD_TAG
#define CONFIG_CMDLINE_EDITING

#define CONFIG_MACH_TYPE MACH_TYPE_ORIGEN

/* Power Down Modes */
#define S5P_CHECK_SLEEP 0x00000BAD
#define S5P_CHECK_DIDLE 0xBAD00000
#define S5P_CHECK_LPA 0xABAD0000

/* Size of malloc() pool */
#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + (1 << 20))

/* select serial console configuration */
#define CONFIG_SERIAL2 1 /* use SERIAL 2 */
#define CONFIG_BAUDRATE 115200
#define EXYNOS4_DEFAULT_UART_OFFSET 0x020000

/* SD/MMC configuration */
#define CONFIG_GENERIC_MMC
#define CONFIG_MMC
#define CONFIG_SDHCI
#define CONFIG_S5P_SDHCI

/* PWM */
#define CONFIG_PWM 1

/* allow to overwrite serial and ethaddr */
#define CONFIG_ENV_OVERWRITE

/* Command definition*/
#include <config_cmd_default.h>

#undef CONFIG_CMD_PING
#define CONFIG_CMD_ELF
#define CONFIG_CMD_DHCP
#define CONFIG_CMD_MMC
#define CONFIG_CMD_FAT
#undef CONFIG_CMD_NET
#undef CONFIG_CMD_NFS

#define CONFIG_BOOTDELAY 3
#define CONFIG_ZERO_BOOTDELAY_CHECK
/* MMC SPL */
#define CONFIG_SPL
#define COPY_BL2_FNPTR_ADDR 0x02020030

#define CONFIG_BOOTCOMMAND "fatload mmc 0 40007000 uImage; bootm 40007000"

/* Miscellaneous configurable options */
#define CONFIG_SYS_LONGHELP /* undef to save memory */
#define CONFIG_SYS_HUSH_PARSER /* use "hush" command parser */
#define CONFIG_SYS_PROMPT "XXDK # "
#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size*/
#define CONFIG_SYS_PBSIZE 384 /* Print Buffer Size */
#define CONFIG_SYS_MAXARGS 16 /* max number of command args */
#define CONFIG_DEFAULT_CONSOLE "console=ttySAC2,115200n8\0"
/* Boot Argument Buffer Size */
#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE
/* memtest works on */
#define CONFIG_SYS_MEMTEST_START CONFIG_SYS_SDRAM_BASE
#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_SDRAM_BASE + 0x6000000)
#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + 0x3E00000)

#define CONFIG_SYS_HZ 1000

/* ORIGEN has 4 bank of DRAM */
#define CONFIG_NR_DRAM_BANKS 4
#define SDRAM_BANK_SIZE (256UL << 20UL) /* 256 MB */
#define PHYS_SDRAM_1 CONFIG_SYS_SDRAM_BASE
#define PHYS_SDRAM_1_SIZE SDRAM_BANK_SIZE
#define PHYS_SDRAM_2 (CONFIG_SYS_SDRAM_BASE + SDRAM_BANK_SIZE)
#define PHYS_SDRAM_2_SIZE SDRAM_BANK_SIZE
#define PHYS_SDRAM_3 (CONFIG_SYS_SDRAM_BASE + (2 * SDRAM_BANK_SIZE))
#define PHYS_SDRAM_3_SIZE SDRAM_BANK_SIZE
#define PHYS_SDRAM_4 (CONFIG_SYS_SDRAM_BASE + (3 * SDRAM_BANK_SIZE))
#define PHYS_SDRAM_4_SIZE SDRAM_BANK_SIZE

/* FLASH and environment organization */
#define CONFIG_SYS_NO_FLASH 1
#undef CONFIG_CMD_IMLS
#define CONFIG_IDENT_STRING " for ORIGEN"

#define CONFIG_CLK_1000_400_200

/* MIU (Memory Interleaving Unit) */
#define CONFIG_MIU_2BIT_21_7_INTERLEAVED

#define CONFIG_ENV_IS_IN_MMC 1
#define CONFIG_SYS_MMC_ENV_DEV 0
#define CONFIG_ENV_SIZE (16 << 10) /* 16 KB */
#define RESERVE_BLOCK_SIZE (512)
#define BL1_SIZE (16 << 10) /*16 K reserved for BL1*/
#define CONFIG_ENV_OFFSET 512<<10
#define CONFIG_DOS_PARTITION 1

#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_LOAD_ADDR - GENERATED_GBL_DATA_SIZE)

/* U-boot copy size from boot Media to DRAM.*/
#define COPY_BL2_SIZE 0x80000
#define BL2_START_OFFSET ((CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE)/512)
#define BL2_SIZE_BLOC_COUNT (COPY_BL2_SIZE/512)

/* Enable devicetree support */
#define CONFIG_OF_LIBFDT
#endif /* __CONFIG_H */
// 从上面文件得到
// CONFIG_SYS_TEXT_BASE = 0x43E00000
// 从mmc第49块开始拷贝,拷贝512K(uboot)到内存的0x43E00000处
// BL2_SIZE_BLOC_COUNT 0x80000/512 = 1024 blocks = 512KBytes
copy_bl2(49, BL2_SIZE_BLOC_COUNT, CONFIG_SYS_TEXT_BASE);

}
// 该函数执行完后spl的使命终结
void board_init_f(unsigned long bootflag)
{
__attribute__((noreturn)) void (*uboot)(void);
copy_uboot_to_ram();

/* Jump to U-Boot image */
// CONFIG_SYS_TEXT_BASE = 0x43E00000
// 跳到 0x43E00000处执行,该地址也是我们编译uboot时的链接地址,等价于运行地址和entrypoint
uboot = (void *)CONFIG_SYS_TEXT_BASE;
(*uboot)();
/* Never returns Here */
}
另外我们还要注意Uboot的环境变量存放位置配置,避免与uboot 镜像有交集而,写入时覆盖uboot区。
生成xxdk-spl.bin 和 uboot.bin
1. 将 BL1, BL2, BL3 合成为一个文件
cat E4412_N.bl1.bin spl/xxdk-spl.bin u-boot.bin > xxdk-boot.bin
2. 烧写到sd卡
dd iflag=dsync oflag=dsync if=/dev/sdd of=xxdk-boot.bin seek=1
添加一个命令 led
struct cmd_tbl_s {
char *name; /* Command Name */
int maxargs; /* maximum number of arguments */
int repeatable; /* autorepeat allowed? */
/* Implementation function */
int (*cmd)(struct cmd_tbl_s *, int, int, char * const []);
char *usage; /* Usage message (short) */
#ifdef CONFIG_SYS_LONGHELP
char *help; /* Help  message (long) */
#endif
#ifdef CONFIG_AUTO_COMPLETE
/* do auto completion on the arguments */
int (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
#endif
};

#define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \
_usage, _help, _comp) \
{ #_name, _maxargs, _rep, _cmd, _usage, \
_CMD_HELP(_help) _CMD_COMPLETE(_comp) }

#define U_BOOT_CMD_MKENT(_name, _maxargs, _rep, _cmd, _usage, _help) \
U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \
_usage, _help, NULL)

#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \
ll_entry_declare(cmd_tbl_t, _name, cmd, cmd) = \
U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \
_usage, _help, _comp);
#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) \
U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)

抄一个比如:
U_BOOT_CMD(
led, // 命令名字
1, // 最大参数个数
1, // 自动重复允许?
do_led, // 命令对应的执行函数
"led", // 用法
"enter led flush mode \n" // 帮助 -help
);
预处理后变成:
cmd_tbl_t _u_boot_list_cmd_led __attribute__(( unused, aligned(4), section(".u_boot_list.""cmd"".""led"))) =
{ "led", 1, 1, do_led, "led", "enter led flush mode \n", NULL, };
所以相当于实例化一个cmd_tbl_t类型的对象 _u_boot_list_cmd_led 编译时存放到.u_boot_list.的代码段。
并对其初始化 主要关注命令对应的执行函数 do_led ,其函数类型,int (*cmd)(struct cmd_tbl_s *, int, int, char * const []);
#include <common.h>
#include <command.h>
#include <linux/time.h>
/* GPX1 */
typedef struct {
unsigned int CON;
unsigned int DAT;
unsigned int PUD;
unsigned int DRV;
}gpx1;
#define GPX1 (* (volatile gpx1 *)0x11000C20 )
/* GPX2 */
typedef struct {
unsigned int CON;
unsigned int DAT;
unsigned int PUD;
unsigned int DRV;
}gpx2;
#define GPX2 (* (volatile gpx2 *)0x11000C40 )
/* GPF3 */
typedef struct {
unsigned int CON;
unsigned int DAT;
unsigned int PUD;
unsigned int DRV;
unsigned int CONPDN;
unsigned int PUDPDN;
}gpf3;
#define GPF3 (* (volatile gpf3 *)0x114001E0)

/**********************************************************************
* @brief mydelay_ms program body
* @param[in] int (ms)
* @return None
**********************************************************************/

int do_led(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{


printf ("## Starting application led flush ...\n");
/*
*Config
*/

GPX2.CON = (GPX2.CON & ~(0xf<<28))| 1<<28;//GPX2_7:output, LED2
GPX1.CON = (GPX1.CON & ~(0xf)) | 1; //GPX1_0:output, LED3
GPF3.CON = (GPF3.CON & ~(0xf<<16 | 0xf<<20)) | (1<<16 | 1<<20);//GPF3_4:output, LED4
  //GPF3_5:output, LED5
volatile int i = 0;
for(i = 0; i < 5; i++) {
//Turn on LED2
GPX2.DAT |= 0x1 << 7;
mdelay(1000);

//Turn on LED3
GPX1.DAT |= 0x1;
//Turn off LED2
GPX2.DAT &= ~(0x1<<7);
mdelay(1000);


//Turn on LED5
GPF3.DAT |= (0x1 << 5);
//Turn off LED3
GPX1.DAT &= ~0x1;
mdelay(1000);


//Turn on LED4
GPF3.DAT |= (0x1 << 4);
//Turn off LED5
GPF3.DAT &= ~(0x1 << 5);
mdelay(1000);
//Turn off LED4
GPF3.DAT &= ~(0x1 << 4);
}

printf ("## Led fulsh application terminated.\n");
return 0;
}

/* -------------------------------------------------------------------- */

U_BOOT_CMD(
led, 1, 1, do_led,
"led",
"Enter to led flush mode. *^_^* \n"

);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值