欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

(1)汇编点亮LED

程序员文章站 2022-07-03 14:15:03
...

1、查阅原理图、数据手册
1.1、因为Tiny 210的LED在核心板上,所以通过通过查阅核心板,获得控制LED的GPIO引脚
(1)汇编点亮LED
(1)汇编点亮LED
得知控制LED的主要引脚是GPJ2_(0~3)
1.2、查阅s5pv210数据手册
(1)首先要明白这里控制LED的寄存器主要有两个:
GPJ2CON:设置引脚的状态
GPJ2DAT:该寄存器中的内容与GPJ2引脚高低电平状态同步,换句话说就是可以通过在该寄存器中写入内容来控制GPJ2引脚的高低电平,1为高电平,0为低电平。
(1)汇编点亮LED
(1)汇编点亮LED
(1)汇编点亮LED
(2)主要寄存器地址
GPJ2CON 0xE020_0280
GPJ2DAT 0xE020_0284
2、编程
2.1、start.s

/*
 *		代码:让LED灯闪烁
 *		日期:2020.7.5 
 *		作者:glass love
 *
 */
 
 
//首先通过查阅原理图,得到控制4颗LED灯的引脚
//GPJ2_(0~3)对应LED(1~4)
//通过查阅数据手册与用户手册得到
//与控制LED有关的寄存器为GPJ2CON、GPJ2DAT
//GPJ2CON的地址为0xE020_0280、0xE020_0280的地址为0xE020_0284
//需要将GPJ2CON的bit(0~15)设置为0x1111
//如果要LED亮需要将GPJ2DAT的bit(0~3)设置为0x0
//如果要LED灭需要将GPJ2DAT的bit(0~3)设置为0xf


.global _start

//设置GPJ2CON的bit(0~15),配置GPJ2_0/1/2/3引脚为输出模式
_start:
	ldr r0, =0x1111
	ldr r1, =0xE0200280
	str r0, [r1]
	
//此处赋给r2一个随机数0x1000,目的是为后面的循环是设定一个时间	
	mov r2, #0x1000
led_blink:
	
//LED亮
	ldr r0, =0x0
	ldr r1, =0xE0200284
	str r0, [r1]
	
//延时
	bl delay
	
//LED灭
	ldr r0, =0xf
	ldr r1, =0xE0200284
	str r0, [r1]

//延时
	bl delay
	

//下面为循环函数

	sub r2, r2, #1
	cmp r2, #0
	beq led_blink         

//此时mov r2, #0x1000和后面的循环函数
//两者中间为循环体一般仿佛声明了

//在汇编函数结尾需要一个死循环

half:
	b half


//前面bl delay调用了函数delay
//需要在这里写出delay函数


delay:
	mov r0, #0x100000
delay_loop:
	sub r0, r0, #1
	cmp r0, #0
	beq delay_loop
//调用完函数需要返回,所以mov pc, lr起到返回作用
	mov pc, lr

2.2、Makefile

led.bin: start.o 
	arm-linux-ld -Ttext 0x0 -o led.elf $^                 
	arm-linux-objcopy -O binary led.elf led.bin			  
	arm-linux-objdump -D led.elf > led_elf.dis   		  
	gcc mkv210_image.c -o mkmini210              		  
	./mkmini210 led.bin 210.bin 						  
	
%.o : %.S
	arm-linux-gcc -o aaa@qq.com $< -c

%.o : %.c
	arm-linux-gcc -o aaa@qq.com $< -c 

clean:
	rm *.o *.elf *.bin *.dis mkmini210 -f

arm-linux-ld(链接)、arm-linux-gcc(编译)、arm-linux-objcopy(生成可以烧录的bin文件)、 arm-linux-objdump(反编译工具)均为交叉编译工具 。
mkv210_image.c为将led.bin转换为210.bin的c代码
%.o : %.S、%.o : %.c就是将.c、.s文件编译为.o文件

2.3、mkv210_image.c

/* 在BL0阶段,Irom内固化的代码读取nandflash或SD卡前16K的内容,
 * 并比对前16字节中的校验和是否正确,正确则继续,错误则停止。
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define BUFSIZE                 (16*1024)
#define IMG_SIZE                (16*1024)
#define SPL_HEADER_SIZE         16
#define SPL_HEADER              "S5PC110 HEADER  "

int main (int argc, char *argv[])
{
	FILE		*fp;
	char		*Buf, *a;
	int		BufLen;
	int		nbytes, fileLen;
	unsigned int	checksum, count;
	int		i;
	
	// 1. 3个参数
	if (argc != 3)
	{
		printf("Usage: mkbl1 <source file> <destination file>\n");
		return -1;
	}

	// 2. 分配16K的buffer
	BufLen = BUFSIZE;
	Buf = (char *)malloc(BufLen);
	if (!Buf)
	{
		printf("Alloc buffer failed!\n");
		return -1;
	}

	memset(Buf, 0x00, BufLen);

	// 3. 读源bin到buffer
	// 3.1 打开源bin
	fp = fopen(argv[1], "rb");
	if( fp == NULL)
	{
		printf("source file open error\n");
		free(Buf);
		return -1;
	}
	// 3.2 获取源bin长度
	fseek(fp, 0L, SEEK_END);
	fileLen = ftell(fp);
	fseek(fp, 0L, SEEK_SET);
	// 3.3 源bin长度不得超过16K-16byte
	count = (fileLen < (IMG_SIZE - SPL_HEADER_SIZE))
		? fileLen : (IMG_SIZE - SPL_HEADER_SIZE);
	// 3.4 buffer[0~15]存放"S5PC110 HEADER  "
	memcpy(&Buf[0], SPL_HEADER, SPL_HEADER_SIZE);
	// 3.5 读源bin到buffer[16]
	nbytes = fread(Buf + SPL_HEADER_SIZE, 1, count, fp);
	if ( nbytes != count )
	{
		printf("source file read error\n");
		free(Buf);
		fclose(fp);
		return -1;
	}
	fclose(fp);

	// 4. 计算校验和
 	// 4.1 从第16byte开始统计buffer*有几个1
	a = Buf + SPL_HEADER_SIZE;
	for(i = 0, checksum = 0; i < IMG_SIZE - SPL_HEADER_SIZE; i++)
		checksum += (0x000000FF) & *a++;
	// 4.2 将校验和保存在buffer[8~15]
	a = Buf + 8;
	*( (unsigned int *)a ) = checksum;

	// 5. 拷贝buffer中的内容到目的bin
	// 5.1 打开目的bin
	fp = fopen(argv[2], "wb");
	if (fp == NULL)
	{
		printf("destination file open error\n");
		free(Buf);
		return -1;
	}
	// 5.2 将16k的buffer拷贝到目的bin中
	a = Buf;
	nbytes	= fwrite( a, 1, BufLen, fp);
	if ( nbytes != BufLen )
	{
		printf("destination file write error\n");
		free(Buf);
		fclose(fp);
		return -1;
	}

	free(Buf);
	fclose(fp);

	return 0;
}

注:这个代码是我搬砖过来的
代码主要内容:
第一步 分配 16k 的 buffer;
第二步 将 led.bin 读到buffer 的第 16byte 开始的地方;
第三步 计算校验和,并将校验和保存在 buffer 第 8~11byte 中;
第四步 将 16k 的 buffer 拷贝到 210.bin 中

2.4、write2 sd

#!/bin/sh
sudo dd iflag=dsync oflag=dsync if=210.bin of=/dev/sdb seek=1

dd 是一个读写命令, if 是输入, of 是输出, seek 表示从扇区 1 开始读写。sd 启动时, IROM 里的固化代码是从扇区1 开始拷贝代码的。sdb 为本文档编写时 sd 卡的设备节点。

3、生成可烧录镜像文件
3.1、将sd卡插入PC ,在ubuntu(我用的ubuntu,也可以是其他的)终端 执行如下命令 :
首先你要cd 到你放代码的文件夹(例如我放在1.led_s下)
cd 1.led_s
make
chmod 777 write2sd
./write2sd
就可以把生成的led.bin文件烧录到sd卡的1扇区。