#。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所有引脚的输出电平。
#。手动编译
arm-linux-gnueabihf-gcc -g -c LED.s -o LED.o
arm-linux-gnueabihf-ld -Ttext 0x00000000 LED.o -o LED.elf
arm-linux-gnueabihf-objcopy -O binary -S -g LED.elf LED.bin
gcc mksunxiboot.c -o mksunxiboot
#include
#include
#include
#include
#include
#include
#include
#include
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的编写格式,下一次使用c语言进行裸机开发时会展示。
//if=文件名 of=sd卡挂载目录 bs=写入块大小 seek=开始偏移块
sudo dd if=led.bin of=/dev/sdb bs=1k seek=8
https://github.com/chen-jiu-eie/A20_-