TQ210 —— 点亮LED
来源:互联网 发布:vb上视频教程全集 编辑:程序博客网 时间:2024/06/06 10:52
TQ210 —— 点亮LED
1、S5PV210 GPIO硬件简介
1.1、GPIO 【S5PV210有237个多功能IO口,通过设置寄存器确定某个引脚用于输入输出或者其他特殊功能】
2、GPIO寄存器
控制S5PV210的GPIO端口寄存器主要有三类:
控制寄存器——GPxCON——配置GPIO输入输出功能
数据寄存器——GPxDAT——设置高低电平
上拉寄存器——GPxUP——确定是否使用内部上拉电阻
3、LED原理图
这里两个NPN三极管,具有放大电流作用,增大驱动能力,只要给基极一个高电平,三极管就可以导通,产生大电流驱动LED点亮。
4、汇编点亮LED
要点亮LED1,需要配置寄存器GPC0CON的[15:12]为0b0001,使GPC0_3为输出模式,同时配置寄存器GPC0DAT[3]=1,使GPC0_3引脚输出高电平。
要点亮LED2,需要配置寄存器GPC0CON 的[19:16]为0b0001,使 GPC0_4为输出模式,同时配置寄存器GPC0DAT[4]=1,使GPC0_4引脚输出高电平。
三个文件:led_on.S addheader.c Makefile
/* led_on.S */.global _start _start: ldr r0, =0xE0200060 /* GPC0CON寄存器*/ ldr r1, =0x00001000 str r1, [r0] /* 设置GPC0_3为输出,GPC0[15:12]= 0b0001 */ ldr r0, =0xE0200064 /* GPC0DAT寄存器*/ ldr r1, =0x00000008 str r1, [r0] /* 设置GPC0_3为高电平*/ halt: b halt /*死循环*/
为什么需要死循环:CPU 一旦从某个地址运行,它就会从这个地址往后依次取指运行,当运行完我们的代码,它不会停止,还会往后继续取指运行,但是后面的指令是未知的,CPU运行后不知道会是什么结果,可能正常执行,也可能出现异常,所以我们应该让CPU一直在那里死循环。
Makefile:
led_on.bin:led_on.o arm-linux-ld -Ttext 0xD0020010 -oled_on.elf $^ arm-linux-objcopy -O binary led_on.elf $@ arm-linux-objdump -D led_on.elf >led_on.dis led_on.o :led_on.S arm-linux-gcc -c $< -o $@ clean: rm *.o *.elf *.bin *.dis
(1)、arm-linux-gcc将start.S编译成start.o目标文件,-c表示编译不链接,-o跟随输出文件名。
(2)、arm-linux-ld 将start.o目标文件链接成elf文件格式,-Ttext 0xD0020010表示程序运行的地址是0xD0020010,其实程序可以在任何一个地址运行,因为本源代码是位置无关码,后面您会看到可以在内存0x30000000地址运行【TQ210内存:0x20000000~0x40000000】。
(3)、arm-linux-objcopy将ELF格式的可执行文件转换为二进制文件,即可以在开发板上执行的文件,-O表示指定格式来输出文件,这里是binary即二进制文件。
(4)、arm-linux-objdump 将ELF文件反汇编,主要用于编译出错时,对调试很有帮助,-D表示反汇编所有段。
裸机可以使用SD卡烧和使用 u-boot 菜单栏或者u-boot命令行来烧写
// 要将led_on.bin烧写到TQ210中,还需要要添加一个16字节的头信息。#include<stdio.h>#include<string.h>#include<stdlib.h> #defineIMG_SIZE 16 * 1024#defineHEADER_SIZE 16 intmain (int argc, char *argv[]){ FILE *fp; unsigned char*buffer; int bufferLen; int nbytes,fileLen; unsigned int checksum, count; int i; if (argc != 3) { printf("Usage: %s <sourcefile> <destination file>\n", argv[0]); return -1; } /* 分配16KByte的buffer,BL1最大为16KByte,并初始化为0*/ buffer = calloc(1, IMG_SIZE); if (!buffer) { perror("Alloc bufferfailed!"); return -1; } /* 打开源bin文件*/ fp = fopen(argv[1], "rb"); if( fp == NULL) { perror("source file openerror"); free(buffer); return -1; } /* 获取源bin文件的长度*/ fseek(fp, 0L, SEEK_END); fileLen = ftell(fp); fseek(fp, 0L, SEEK_SET); /* 源bin文件不得超过(16K-16)Byte*/ if (fileLen > (IMG_SIZE -HEADER_SIZE)) { fprintf(stderr, "Source fileis too big(> 16KByte)\n"); free(buffer); fclose(fp); } /* 计算校验和*/ i = 0; checksum = 0; while (fread(buffer + HEADER_SIZE + i, 1,1, fp)) { checksum += buffer[HEADER_SIZE +i++]; } fclose(fp); /* 计算BL1的大小(BL1的大小包括BL1的头信息),并保存到buffer[0~3]中*/ fileLen += HEADER_SIZE; memcpy(buffer, &fileLen, 4); // 将校验和保存在buffer[8~15] memcpy(buffer + 8, &checksum, 4); /* 打开目标文件*/ fp = fopen(argv[2], "wb"); if (fp == NULL) { perror("destination file openerror"); free(buffer); return -1; } // 将buffer拷贝到目标bin文件中 nbytes =fwrite(buffer, 1, fileLen, fp); if (nbytes != fileLen) { perror("destination filewrite error"); free(buffer); fclose(fp); return -1; } free(buffer); fclose(fp); return 0;}
首先编译 addheader.c:gcc addheader.c -o addheader
./addheader led_on.bin 210.bin
将生成的210.bin文件通过SD或者tftp方式下载到TQ210开发板中。
5、烧写裸机程序
(1)、使用SD卡烧写
dd iflag=dsync oflag=dsync if=210.bin of=/dev/sdb seek=1 表示输出文件为 210.bin,输出文件到/dev/sdb,设备文件在 linux 下是 在/dev/目录下,此时 SD 卡在 Linux 下仅仅被看成是一个文件, seek=1 表示烧写到扇区 1, Linux 读写磁盘设备最小单位是一个扇区。取出SD卡放入TQ210开发板,拨动拨码开关为SD卡启动。
注意: /dev/sdb 是查阅 SD在 Linux虚拟机上的设备节点而设置的,如果设备节点为/dev/sdc则需要修改为/dev/sdc,插入 SD卡到 PC 后,在 Linux虚拟机命令行执行 ls /dev/sd*命令查看到设备节点的情况。
(2)、使用u-boot菜单栏烧写
ipaddr:开发板的IP;serverip:Linux的IP【设置好,save保存一下】
tftp 3000000210.bin
go30000000
6、用C和汇编混合编程
/* led_on.S*/ .global _start _start: blmain /* 跳转到C函数去执行*/halt: bhalt /* 死循环 */ /* main.c */#define GPC0CON *((volatileunsigned int *)0xE0200060)#define GPC0DAT *((volatileunsigned int *)0xE0200064) void delay(volatile unsigned int t){ volatileunsigned int t2 = 0xFFFF; while(t--) for(; t2; t2--);} int main(){ int toggle = 0; GPC0CON &= ~(0xFF << 12); GPC0CON |= 0x11 << 12; //配置GPC0_3和GPC0_4为输出 while(1) { GPC0DAT &= ~(0x3 << 3); // 熄灭LED1和LED2 if(toggle) GPC0DAT|= 1 << 3; // 点亮LED1 else GPC0DAT|= 1 << 4; // 点亮LED2 toggle= !toggle; delay(0x50000); } return 0;}
运行 C 语言需要栈,为什么在 led_on.S 中没有设置栈:S5PV210 上电运行 iROM 中的代码已经设置好栈,栈顶地址为 0xD0037F80,
- TQ210 —— 点亮LED
- TQ210裸机编程——led
- 点亮LED——汇编
- TQ210的裸机编程(一)点亮一个LED灯
- ARM11——点亮LED灯
- TQ210裸机编程(1)——LED流水灯
- Linux驱动程序学习笔记(3)——点亮LED
- CC2530学习笔记のGPIO配置——点亮LED
- TQ210_裸机编程(一)——点亮LED灯
- Raspberry PI 系列 —— 裸机点亮LED灯
- Linux设备驱动开发——3.点亮LED灯
- 1.2.第一个实验——点亮LED灯
- 1.2.第一个实验——点亮LED灯
- 51单片机之外设——点亮LED
- Unity和Arduino交互系列——点亮LED
- 嵌入式Linux裸机开发(一)——点亮Led
- 单片机开发——点亮你的LED小灯
- Linux驱动学习——使用汇编语言点亮一个LED
- lua数据结构之table的内部实现
- Qt学习之二:创建对话框
- cocos2d-x Label不同文字不同颜色
- androidr图片压缩和保存本地
- gggg
- TQ210 —— 点亮LED
- 中断和异常的处理
- 条件变量为什么要和互斥锁配合使用
- hadoop-2.X 版本HA出现的背景
- 求Fibonacci数量的第N项
- 分页机制
- 回调函数
- PAT(乙级)1007 A除以B (20)
- Qt 子窗口父窗口切换,窗口间传值