您的位置:首页 > 其它

(二)S5pv210的GPIO使用_part1<LED汇编版>

2015-01-29 09:26 246 查看
本节内容:

        首先我们会给出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:
<span style="white-space:pre"> </span>//GPJ2CON[3:0] set output mode
<span style="white-space:pre"> </span>ldr r1, =0xE0200280
<span style="white-space:pre"> </span>ldr r0, =0x00001111
<span style="white-space:pre"> </span>str r0, [r1]
<span style="white-space:pre"> </span>
led_blink:
<span style="white-space:pre"> </span>//set led on => GPJ2DAT[3:0] is low
<span style="white-space:pre"> </span>ldr r1, =0xE0200284
<span style="white-space:pre"> </span>mov r0, #0
<span style="white-space:pre"> </span>str r0, [r1]
<span style="white-space:pre"> </span>bl delay
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//set led off => GPJ2DAT[3:0] is off
<span style="white-space:pre"> </span>ldr r1, =0xE0200284
<span style="white-space:pre"> </span>mov r0, #0xF
<span style="white-space:pre"> </span>str r0, [r1]
<span style="white-space:pre"> </span>bl delay

<span style="white-space:pre"> </span>b led_blink

halt:
<span style="white-space:pre"> </span>b halt

delay:
<span style="white-space:pre"> </span>mov r0, #0xD00000
delay_loop:
<span style="white-space:pre"> </span>cmp r0, #0
<span style="white-space:pre"> </span>sub r0, r0, #1
<span style="white-space:pre"> </span>bne delay_loop
<span style="white-space:pre"> </span>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卡内的“代码”了)。首先我给出程序头的格式:



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

#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[])
{
<span style="white-space:pre"> </span>FILE<span style="white-space:pre"> </span>*fp;
<span style="white-space:pre"> </span>char<span style="white-space:pre"> </span>*Buf, *a;
<span style="white-space:pre"> </span>int<span style="white-space:pre"> </span>BufLen;
<span style="white-space:pre"> </span>int<span style="white-space:pre"> </span>nbytes, fileLen;
<span style="white-space:pre"> </span>unsigned int<span style="white-space:pre"> </span>checksum, count;
<span style="white-space:pre"> </span>int<span style="white-space:pre"> </span>i;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if (argc != 3)//使用格式:mkv210_image 编译后的文件名 生成的映像文件的名字
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("Usage: mkbl1 <source file> <destination file>\n");
<span style="white-space:pre"> </span>return -1;
<span style="white-space:pre"> </span>}

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

<span style="white-space:pre"> </span>memset(Buf, 0x00, BufLen);//全部字节清零

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

<span style="white-space:pre"> </span>count = (fileLen < (IMG_SIZE - SPL_HEADER_SIZE))
<span style="white-space:pre"> </span>? fileLen : (IMG_SIZE - SPL_HEADER_SIZE);
//设置头部信息
<span style="white-space:pre"> </span>memcpy(&Buf[0], SPL_HEADER, SPL_HEADER_SIZE);
//把程序拷贝到进去
<span style="white-space:pre"> </span>nbytes = fread(Buf + SPL_HEADER_SIZE, 1, count, fp);
<span style="white-space:pre"> </span>if ( nbytes != count )
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("source file read error\n");
<span style="white-space:pre"> </span>free(Buf);
<span style="white-space:pre"> </span>fclose(fp);
<span style="white-space:pre"> </span>return -1;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>fclose(fp);

<span style="white-space:pre"> </span>a = Buf + SPL_HEADER_SIZE;
<span style="white-space:pre"> </span>for(i = 0, checksum = 0; i < IMG_SIZE - SPL_HEADER_SIZE; i++)
<span style="white-space:pre"> </span>checksum += (0x000000FF) & *a++;

<span style="white-space:pre"> </span>a = Buf + 8;
<span style="white-space:pre"> </span>*( (unsigned int *)a ) = checksum;

<span style="white-space:pre"> </span>fp = fopen(argv[2], "wb");
<span style="white-space:pre"> </span>if (fp == NULL)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("des
9ef6
tination file open error\n");
<span style="white-space:pre"> </span>free(Buf);
<span style="white-space:pre"> </span>return -1;
<span style="white-space:pre"> </span>}

<span style="white-space:pre"> </span>a = Buf;
<span style="white-space:pre"> </span>nbytes<span style="white-space:pre"> </span>= fwrite( a, 1, BufLen, fp);
<span style="white-space:pre"> </span>if ( nbytes != BufLen )
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>printf("destination file write error\n");
<span style="white-space:pre"> </span>free(Buf);
<span style="white-space:pre"> </span>fclose(fp);
<span style="white-space:pre"> </span>return -1;
<span style="white-space:pre"> </span>}

<span style="white-space:pre"> </span>free(Buf);
<span style="white-space:pre"> </span>fclose(fp);

<span style="white-space:pre"> </span>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 s5pv210