(二)S5pv210的GPIO使用_part1

本节内容:

        首先我们会给出LED灯闪烁的汇编代码,然后把上节遗留下来的内容(即SD卡启动时对映像文件的要求)进行补充,然后给出映像文件生成的源代码。最后我们会介绍Makefile的基本书写格式以及介绍gcc、objcopy、objdump的基本用法,对于汇编指令我不做详细介绍,如果想学一点汇编的同学们还是买一本arm的书认真学一下汇编指令,会汇编指令也就那么几页的内容(其实挺多的QAQ)。

start.S:

        在start.S代码中主要实现了4个LED灯的闪烁,这只是一个示例的汇编代码,其实用汇编实现一个复杂的功能是一个费力不讨好的事,因为汇编指令不值得过于纠结,什么都用汇编写那还需要C语言干嘛?实在想纠结汇编的可以通过C语言写出对应的代码,然后一个gcc -S选项即可生成汇编代码。我的硬件情况是这样的,我们的4个LED分别接的是GPJ2[3:0],只要给0即可点亮LED,因此我们这里要做的就是把GPJ2CON配置为输出模式,然后设置对应位为0点亮LED,设置对应为为0则关闭LED,我们现在看看start.S的具体代码:

.global _start


_start:
	//GPJ2CON[3:0] set output mode
	ldr r1, =0xE0200280
	ldr r0, =0x00001111
	str r0, [r1]
	
led_blink:
	//set led on => GPJ2DAT[3:0] is low
	ldr r1, =0xE0200284
	mov r0, #0
	str r0, [r1]
	bl delay
	
	//set led off => GPJ2DAT[3:0] is off
	ldr r1, =0xE0200284
	mov r0, #0xF
	str r0, [r1]
	bl delay


	b led_blink


halt:
	b halt


delay:
	mov r0, #0xD00000
delay_loop:
	cmp r0, #0
	sub r0, r0, #1
	bne delay_loop
	mov pc, lr
.end
         上面的代码其实就是做了配置GPIO的工作模式(输出),设置全部灯关闭(GPJ2DAT=0xFF),延时,设置全部灯打开(GPJ2DAT=0x00)。

SD卡启动要求:

         前面讲过,S5pv210上电时候根据OM[5:0]引脚识别是1st boot是哪个设备,然后把设备的前16K代码拷贝到片内iram中,如果代码有效则执行片内代码。那么问题来了,片内代码怎么样才算有效?芯片规定,程序的前16字节用于一些特别的信息(整个代码的字节大小,代码的校验信息),因此我们生成的映像文件要求是:16字节的头部 + 实际代码,然后把映像文件通过dd命令拷贝到SD卡中,S5pv210的BL0通过校验信息知道我们的程序是否是有误(最怕的就是SD卡没程序,却选择SD卡启动,这时通过校验信息知道SD卡内部数据无效就不会执行SD卡内的“代码”了)。首先我给出程序头的格式:

(二)S5pv210的GPIO使用_part1_第1张图片

       映像文件的第一个字(4字节)保存的是整个映像文件的大小(我们设置成16K即可),第3个字是用于设置校验信息,校验信息是有生成规则的,S5pv210规定代码中按照4个字节对齐,设置uint32_t cheksum=0,每次把4个字节取出来(假设保存在tmp中),执行cheksum+=tmp,直到所有字节都取出来计算过为止,这时checksum中的值就是我们程序的校验信息,把它保存在映像文件的第三个字的地方即可,最后把start.S编译生成的代码拷贝到整个映像文件的后面即完成镜像文件的制作,这些工作都是由源文件mkv210_image.c完成的期待吗如下所示:

#include 
#include 
#include 


#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;
	
	if (argc != 3)//使用格式:mkv210_image 编译后的文件名  生成的映像文件的名字
	{
		printf("Usage: mkbl1  \n");
		return -1;
	}

	BufLen = BUFSIZE;
	Buf = (char *)malloc(BufLen);//分配16K的内存,前16字节保存校验信息
	if (!Buf)
	{
		printf("Alloc buffer failed!\n");
		return -1;
	}

	memset(Buf, 0x00, BufLen);//全部字节清零

	fp = fopen(argv[1], "rb");
	if( fp == NULL)
	{
		printf("source file open error\n");
		free(Buf);
		return -1;
	}
        //filelen就是16K,为了代码的通用性写代码的人装逼了→_→
	fseek(fp, 0L, SEEK_END);
	fileLen = ftell(fp);
	fseek(fp, 0L, SEEK_SET);

	count = (fileLen < (IMG_SIZE - SPL_HEADER_SIZE))
		? fileLen : (IMG_SIZE - SPL_HEADER_SIZE);
        //设置头部信息
	memcpy(&Buf[0], SPL_HEADER, SPL_HEADER_SIZE);
        //把程序拷贝到进去
	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);



	a = Buf + SPL_HEADER_SIZE;
	for(i = 0, checksum = 0; i < IMG_SIZE - SPL_HEADER_SIZE; i++)
		checksum += (0x000000FF) & *a++;

	a = Buf + 8;
	*( (unsigned int *)a ) = checksum;


	fp = fopen(argv[2], "wb");
	if (fp == NULL)
	{
		printf("destination file open error\n");
		free(Buf);
		return -1;
	}

	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;
}

Makefile文件:

        gcc 用于编译文件,ld工具用于将多个目标文件连接成一个可执行文件(elf格式),objcoy将elf文件中的可执行代码拿出来保存在一个文件里头(elf格式的文件含有很多调试信息,符号表等,我们要把它干掉),objdump用于将elf文件生成对应的调试文件(其实就是以汇编的形式列出整个文件的代码),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 $@ $< -c

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

clean:
	rm *.o *.elf *.bin *.dis mkmini210 -f
         对于ld工具,-T指定连接的信息,例如  -Tlink.lds表示指定链接文件link.lds,-Ttext 0x0就是说可执行文件的链接地址是0地址处。objcopy的-O表示指定输出文件格式,我们舍值为binary(二进制输出)其中led.elf为输入文件,生成的文件名为led.bin。objdump的-D说的是debug,通过led.elf生成调试文件led_ellf.dis(重定向输出)。



你可能感兴趣的:(arm单片机)