【ARM从裸机到uboot 2】

点灯

  • 了解寄存器
  • 对寄存器基本操作
  • 编译链接及自动化操作
  • 头部添加及烧录SD卡
  • 测试
寄存器

#。GPIO的控制流程 : 开启GPIO时钟 -> 配置GPIO模式(输入,输出,复用)->向GPIO写数据。
#。A20的GPIO时钟控制器地址为0x01c20068、GPIO的控制寄存器
(以引脚PH15,16为例,其余端口参考数据手册)
(A20的数据手册GitHub地址,我会附在文章末尾
0x01c20904,0x01c20900、数据寄存器(引脚PH)0x01c2090c,

对寄存器的操作

#。由于ARM不能直接对外部寄存器进行操作要借助R0,R1来对外设寄存器读写操作
Eg: 对寄存器0x01c20068写如0xffffffff

	    ldr r0, = 0x01c20060
	    ldr r1, = 0xffffffff
	    str r1, [r0] 

首先通过 lde指令 将数据写入寄存器R0、R1,再通过 str指令 将R1中的内容写入R0地址所在的寄存器中,这样就完成了对外设寄存器的操作。
#。现在开始点灯,下面是点灯代码 文件名为 LED.s

.global _start
_start               ;ARM的汇编开始格式

ldr r0, = 0x01c20068 ;时钟地址
ldr r1, = 0xffffffff ;开启所有外设时钟
str r1, [r0]

ldr r0, = 0x01c20900 ;PH引脚功能寄存器
ldr r1, = 0x11111111 ;输出
str r1, [r0]

ldr r0, = 0x01c20904 ;PH引脚功能寄存器
ldr r1, = 0x11111111 ;输出
str r1, [r0] 

ldr r0, = 0x01c2090c ;PH端口全部输出低电平
ldr r1, = 0x00000000
str r1, [r0]

loop:                ;死循环,仿真程序跑飞
    b loop

GPIO寄存器
配置为输出模式写1在这里插入图片描述直接向数据寄存器写入想要的值就可以控制PH所有引脚的输出电平。在这里插入图片描述

编译链接及自动化操作

#。手动编译

  • 编译LED.s为.o文件
    arm-linux-gnueabihf-gcc -g -c LED.s -o LED.o
  • 链接为.elf文件(链接的起始地址为0x00000000)
    arm-linux-gnueabihf-ld -Ttext 0x00000000 LED.o -o LED.elf
  • 转化为.bin文件
    arm-linux-gnueabihf-objcopy -O binary -S -g LED.elf LED.bin
  • 加头部
    加头部的源码(将源码用gcc编译,注意gcc,不是arm-gcc)
    gcc mksunxiboot.c -o mksunxiboot
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

typedef unsigned char u8;
typedef unsigned int u32;

/* boot head definition from sun4i boot code */
typedef struct boot_file_head
{
	u32  jump_instruction;   // one intruction jumping to real code
	u8   magic[8];           // ="eGON.BT0" or "eGON.BT1",  not C-style string.
	u32  check_sum;          // generated by PC
	u32  length;             // generated by PC
	u32  pub_head_size;      // the size of boot_file_head_t
	u8   pub_head_vsn[4];    // the version of boot_file_head_t
	u8   file_head_vsn[4];   // the version of boot0_file_head_t or boot1_file_head_t
	u8   Boot_vsn[4];        // Boot version
	u8   eGON_vsn[4];        // eGON version
	u8   platform[8];        // platform information
}boot_file_head_t;

#define BOOT0_MAGIC                     "eGON.BT0"
#define STAMP_VALUE                     0x5F0A6C39
/* check sum functon from sun4i boot code */
int gen_check_sum( void *boot_buf )
{
	boot_file_head_t  *head_p;
	u32 length;
	u32 *buf;
	u32 loop;
	u32 i;
	u32 sum;

	head_p = (boot_file_head_t *)boot_buf;
	length = head_p->length;
	if( ( length & 0x3 ) != 0 )                   // must 4-byte-aligned
		return -1;
	buf = (u32 *)boot_buf;
	head_p->check_sum = STAMP_VALUE;              // fill stamp
	loop = length >> 2;
	/* calculate the sum */
	for( i = 0, sum = 0;  i < loop;  i++ )
		sum += buf[i];

	/* write back check sum */
	head_p->check_sum = sum;

	return 0;
}

#define ALIGN(x,a)      __ALIGN_MASK((x),(typeof(x))(a)-1)
#define __ALIGN_MASK(x,mask)    (((x)+(mask))&~(mask))

#define SUN4I_SRAM_SIZE (24 * 1024)
#define SRAM_LOAD_MAX_SIZE (SUN4I_SRAM_SIZE - sizeof(boot_file_head_t))
#define BLOCK_SIZE 512
struct boot_img {
	boot_file_head_t header;
	char code[SRAM_LOAD_MAX_SIZE];
	char pad[BLOCK_SIZE];
};

int main(int argc, char * argv[])
{
	int fd_in, fd_out;
	struct boot_img img;
	unsigned file_size, load_size;
	int count;

	if(argc < 2) {
		printf("\tThis program makes an input bin file to sun4i bootable image.\n"
				"\tUsage: %s input_file out_putfile\n", argv[0]);
		return EXIT_FAILURE;
	}

	fd_in = open(argv[1], O_RDONLY);
	if(fd_in < 0) {
		perror("Open input file:");
		return EXIT_FAILURE;
	}

	fd_out = open(argv[2], O_WRONLY|O_CREAT, 0666);
	if(fd_out < 0) {
		perror("Open output file:");
		return EXIT_FAILURE;
	}

	memset((void *)img.pad, 0, BLOCK_SIZE);

	/* get input file size */
	file_size = lseek(fd_in, 0, SEEK_END);
	printf("File size: 0x%x \n", file_size);

	if(file_size > SRAM_LOAD_MAX_SIZE) {
		load_size = SRAM_LOAD_MAX_SIZE;
	} else {
		load_size = ALIGN(file_size, sizeof(int));
	}
	printf("Load size: 0x%x \n", load_size);

	/* read file to buffer to calculate checksum */
	lseek(fd_in, 0, SEEK_SET);
	count = read(fd_in, img.code, load_size);
	printf("Read 0x%x bytes\n", count);

	/* fill the header */
	img.header.jump_instruction =    /* b instruction */
			0xEA000000 |             /* jump to the first instruction after the header */
			(
				(sizeof(boot_file_head_t) / sizeof(int) - 2)
				& 0x00FFFFFF
			);
	memcpy(img.header.magic, BOOT0_MAGIC, 8);    /* no '0' termination */
	img.header.length = ALIGN(load_size + sizeof(boot_file_head_t), BLOCK_SIZE);
	gen_check_sum((void *)&img);

	count = write(fd_out, (void *)&img, img.header.length);
	printf("Write 0x%x bytes\n", count);

	close(fd_in);
	close(fd_out);

	return EXIT_SUCCESS;
}

编译后sdsunxiboot后使用它加头部
./sdsunxiboot LED.bin led.bin

自动化可以通过编写Makefile来实现

#。感兴趣可以去多了解Makefile的编写格式,下一次使用c语言进行裸机开发时会展示。

  • 烧录到sd卡
    #。 A20将sd卡插入检测会跳过前8k的内容将8k后24k以内的代码放入内存中执行
//if=文件名 of=sd卡挂载目录 bs=写入块大小 seek=开始偏移块

sudo dd if=led.bin of=/dev/sdb bs=1k seek=8
在这里插入图片描述

A20数据手册,用户手册下载地址

https://github.com/chen-jiu-eie/A20_-

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值