(二)ARM裸机(GPIO)之LED
文章目录
- (二)ARM裸机(GPIO)之LED
- 前言
- 一、安装交叉编译工具链
- 1.环境搭建
- 2.永久配置交叉编译工具链
- 二、Makefile大侠隆重登场
- 三、s5pv210具体启动过程
- 四、.mkv210_image.c文件详解
- 1.为什么需要该程序
- 2.mkv210_image.c源程序
- 五、LED点灯编程
- 1.数据手册查找
- 2.汇编实现led
- 3.编译程序并烧入
- 总结
前言
下面进行使用汇编进行LED灯操作所学内容进行记录,如有错误还望各位大佬指正。
提示:以下是本篇文章正文内容,下面案例可供参考
一、安装交叉编译工具链
1.环境搭建
因为我们要将写好的代码烧入到s5pv210开发板上来运行,所以安装交叉编译是必不可少的一步,在这里我是使用的乌班图18版本,交叉编译工具链是arm-2009q3相应的链接工具我会放在这里有需要的小伙伴自行领取。
链接:https://pan.baidu/s/1TEjyrnOAKPjMm0M37e1Leg
提取码:dia2
–来自百度网盘超级会员V4的分享
//1.首先我们在usr/local 下创建一个文件夹arm 来存放我们交叉编译工具的文件
cd /usr/local
sudo mkdir arm
//2.将我们的arm-2009q3压缩包移动到该目录下进行解压
//3.进入该文件夹的bin文件下
arm-none-linux-gnueabi-gcc -v 查看当前版本
如果能正常显示说明我们交叉编译工具链已经安装成功了
2.永久配置交叉编译工具链
从上面的配置可知如果我们就在arm/bin文件下的话是可以直接使用该工具链但是当我们不在该目录下的时候就需要使用绝对路经就会比较麻烦,所以一般我们推荐的是使用永久配置在.bashrc文件夹加入我们的路径
//1.打开.bashrc文件
sudo vim .bashrc
//2.添加相关配置
注意在添加相关路径的时候大家根据自己安装路径来添加
可以使用pwd来查看当前路径
//3. 退出并更新
source .bashrc就生效了
完成以上步骤就可以在任何一个终端下面正常使用该交叉编译工具了,但是每次使用的使用需要输入的太长我们还是感觉比较麻烦。因此在介绍另外一种工具-----》软链接
ln -s arm-none-linux-gnueabi-gcc arm-linux-gcc
这样下次我们使用的时候输入arm-linux-gcc就可以了
当然后面的链接可以根据自己的喜爱来写,不过一般写的都是具有意义的
/*从下面我们可以看出原有的工具我都进行了软链接 方法同上一样
大家也根据自己的需求来执行就,不过一般向这种比较多的相同执行方式我们
都会写在一个脚本中,来一键实现
*/
在该路径下创立一个shell脚本 命名mk-arm-linux-.sh
source mk-arm-linux-.sh 执行该脚本
到这里我们就把要用到的工具都准备好了就可以进行下一步了
二、Makefile大侠隆重登场
这里不会对Makefile做过多的介绍,只要知道当前写的命令是什么意思就行了,认识Makefile中基本的符号所代表的含义就可以了,在后面还有具体来学习Makefile。
上面图片中所写的代码,都是我们在进行编译的时候所需要用到的,这里就不对每一句的含义做出介绍,只是列出来先了解一下该Makefile所实现的功能,小伙伴想知道一些符号%.o %.s %.c为什么要这样写可以自己先去学习一下Makefile的语法就明白了这里所代表的含义了
三、s5pv210具体启动过程
上面说了这么多,从这里才开始进入我们的主题,下面我们会了解到mkv210_image.c文件所实现的功能,以及我们对s5pv210开发板上所自带的Led灯的操作,更重要的是明白s5pv210从下载程序到启动的具体过程是怎样实现的
同样这里对s5pv210的启动过程就针对该章节所需的进行介绍
后面会专门写一篇对启动的过程的详细介绍,这里所写内容如果有错
欢迎各位伙伴指出
210启动后先执行内部的IROM中的BL0,BL0执行完成后会根据OMPin的配置选择一个外部设备来启动(有很多,实际使用里面的2个USB个sd卡启动)
在USB启动时内部bl0读取到bl1后不做效验,直接从BL0的内部0xd0020010开始执行,因此USB启动的镜像led.bin不需要头信息,因此我们从USB启动时直接将镜像下载到0xd0020010去执行即可,不管头信息;
从sd卡启动时BL0会首先读取sd卡得到完整的镜像(完整指的是Led.bin和16 字节的头)然后BL0会字节根据你的实际镜像(led.bin)来计算一个校验和checksum,然后和你完整镜像头部中的checksum来对比,如果对执行BL1,如果不对则启动失败(会转入执行2st启动)即SD2启动,如果这里已经是sd2启动了,这里校验和不通过,就启动不了了)
四、.mkv210_image.c文件详解
1.为什么需要该程序
我们链接时只得到了led.bin,210.bin这个和交叉编译工具链无关,由led.bin得到210.bin的过程是三星的s5pv210所特有的,因此需要我们自己去完成,为此我们写mkv210_image.c来完成
整个程序的工作流:
整个程序首先申请一个16KB大小的buffer,然后把所以内容按照各自的位置填充进去,最终把填充好的buffer写到一个文件(210.bin)就形成了我们想要的镜像。
2.mkv210_image.c源程序
/*
mkv210_image.c的主要作用就是由usb启动时使用的led.bin制作得到由sd卡启动的镜像210.bin
在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 "
#define SPL_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: %s <source file> <destination file>\n", argv[0]);
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); //从16byte之后开始读取
if ( nbytes != count )
{
printf("source file read error\n");
free(Buf);
fclose(fp);
return -1;
}
fclose(fp);
// 4. 计算校验和
// 4.1 从第16byte开始统计buffer中共有几个1
// 4.1 从第16byte开始计算,把buffer中所有的字节数据加和起来得到的结果
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; // Buf是210.bin的起始地址,+8表示向后位移2个字,也就是说写入到第3个字
*( (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;
}
五、LED点灯编程
1.数据手册查找
gpio概念:
gpio就是芯片引脚,作为gpio这类引脚,它的功能和特点是可以被编程控制它的工作模式,也可以编程控制它的电压高低等
编程操作gpio时首先阅读数据手册,s5pv210_um_rev1
查阅数据手册可知GPJ0寄存器有:
GPJ0CON, GPJ0DAT, GPJ0PUD, GPJ0DRV, GPJ0CONPDN and GPJ0PUDPDN
实际上真正操作的led硬件主要是:GPJ0CON GPJ0DAT
GPJ0CON: gpj0控制寄存器用来配置各引脚的输出模式
注:在驱动LED时候我们要配置gpio为output模式
GPJ0DAT:当引脚配置为input或output模式时,寄存器相应位和引脚的电平高低相对于
GPJ0PUD :控制引脚内部上拉、下拉
GPJ0DRV:配置引脚的驱动
GPxCON GPxDAT寄存器分析:
Gpj0一共有8个引脚gpj0~gpj7
Gpj0con寄存器中设置8个引脚的工作模式(32/8=4)每个引脚分到4位譬如gpj0为bit0bit3,工作方式就是给对于的寄存器写入相应的值(bit12bit15写入0b0001,GPJ03就设置为了输出模式)
Led:gpj0_3 gpjo_4 gpj0_5 低电平亮/高电平灭
Gpj0con寄存器地址(0xe0200240)
2.汇编实现led
从这里我们可以看出其实汇编编写程序和我们用C语言编写有很大的相同之处,只是我们使用汇编的时候更多的是进行寄存器的操作,通过不同的寄存器来操作我们要编程的硬件,牢记老使用的汇编指令(ldr str ….等)
在使用过程中更多的是要学会查看数据手册,根据手册来进行寄存器的配置
每个寄存器都会有一个像对应的地址,每个寄存器中都会分配32位(大多数)然后每四位代表一个引脚,通过不同的二进制序列实现该引脚的不同功能。
方式二:位操作
汇编中实现简单延时函数
3.编译程序并烧入
make 执行脚本
从虚拟机上进行烧入
在当前路径下执行 ./write2sd /dev/sdb
总结
通过上面的学习学会了如何利用相关的数据手册 去查找我们要操作的寄存器,根据功能的需求去对相应寄存器的不同位进行赋值,也对汇编的学习产生了浓厚的兴趣,对脚本功能的强大所震撼。总之还是一步一个脚印慢慢来。
加油鸭
(二)ARM裸机(GPIO)之LED
文章目录
- (二)ARM裸机(GPIO)之LED
- 前言
- 一、安装交叉编译工具链
- 1.环境搭建
- 2.永久配置交叉编译工具链
- 二、Makefile大侠隆重登场
- 三、s5pv210具体启动过程
- 四、.mkv210_image.c文件详解
- 1.为什么需要该程序
- 2.mkv210_image.c源程序
- 五、LED点灯编程
- 1.数据手册查找
- 2.汇编实现led
- 3.编译程序并烧入
- 总结
前言
下面进行使用汇编进行LED灯操作所学内容进行记录,如有错误还望各位大佬指正。
提示:以下是本篇文章正文内容,下面案例可供参考
一、安装交叉编译工具链
1.环境搭建
因为我们要将写好的代码烧入到s5pv210开发板上来运行,所以安装交叉编译是必不可少的一步,在这里我是使用的乌班图18版本,交叉编译工具链是arm-2009q3相应的链接工具我会放在这里有需要的小伙伴自行领取。
链接:https://pan.baidu/s/1TEjyrnOAKPjMm0M37e1Leg
提取码:dia2
–来自百度网盘超级会员V4的分享
//1.首先我们在usr/local 下创建一个文件夹arm 来存放我们交叉编译工具的文件
cd /usr/local
sudo mkdir arm
//2.将我们的arm-2009q3压缩包移动到该目录下进行解压
//3.进入该文件夹的bin文件下
arm-none-linux-gnueabi-gcc -v 查看当前版本
如果能正常显示说明我们交叉编译工具链已经安装成功了
2.永久配置交叉编译工具链
从上面的配置可知如果我们就在arm/bin文件下的话是可以直接使用该工具链但是当我们不在该目录下的时候就需要使用绝对路经就会比较麻烦,所以一般我们推荐的是使用永久配置在.bashrc文件夹加入我们的路径
//1.打开.bashrc文件
sudo vim .bashrc
//2.添加相关配置
注意在添加相关路径的时候大家根据自己安装路径来添加
可以使用pwd来查看当前路径
//3. 退出并更新
source .bashrc就生效了
完成以上步骤就可以在任何一个终端下面正常使用该交叉编译工具了,但是每次使用的使用需要输入的太长我们还是感觉比较麻烦。因此在介绍另外一种工具-----》软链接
ln -s arm-none-linux-gnueabi-gcc arm-linux-gcc
这样下次我们使用的时候输入arm-linux-gcc就可以了
当然后面的链接可以根据自己的喜爱来写,不过一般写的都是具有意义的
/*从下面我们可以看出原有的工具我都进行了软链接 方法同上一样
大家也根据自己的需求来执行就,不过一般向这种比较多的相同执行方式我们
都会写在一个脚本中,来一键实现
*/
在该路径下创立一个shell脚本 命名mk-arm-linux-.sh
source mk-arm-linux-.sh 执行该脚本
到这里我们就把要用到的工具都准备好了就可以进行下一步了
二、Makefile大侠隆重登场
这里不会对Makefile做过多的介绍,只要知道当前写的命令是什么意思就行了,认识Makefile中基本的符号所代表的含义就可以了,在后面还有具体来学习Makefile。
上面图片中所写的代码,都是我们在进行编译的时候所需要用到的,这里就不对每一句的含义做出介绍,只是列出来先了解一下该Makefile所实现的功能,小伙伴想知道一些符号%.o %.s %.c为什么要这样写可以自己先去学习一下Makefile的语法就明白了这里所代表的含义了
三、s5pv210具体启动过程
上面说了这么多,从这里才开始进入我们的主题,下面我们会了解到mkv210_image.c文件所实现的功能,以及我们对s5pv210开发板上所自带的Led灯的操作,更重要的是明白s5pv210从下载程序到启动的具体过程是怎样实现的
同样这里对s5pv210的启动过程就针对该章节所需的进行介绍
后面会专门写一篇对启动的过程的详细介绍,这里所写内容如果有错
欢迎各位伙伴指出
210启动后先执行内部的IROM中的BL0,BL0执行完成后会根据OMPin的配置选择一个外部设备来启动(有很多,实际使用里面的2个USB个sd卡启动)
在USB启动时内部bl0读取到bl1后不做效验,直接从BL0的内部0xd0020010开始执行,因此USB启动的镜像led.bin不需要头信息,因此我们从USB启动时直接将镜像下载到0xd0020010去执行即可,不管头信息;
从sd卡启动时BL0会首先读取sd卡得到完整的镜像(完整指的是Led.bin和16 字节的头)然后BL0会字节根据你的实际镜像(led.bin)来计算一个校验和checksum,然后和你完整镜像头部中的checksum来对比,如果对执行BL1,如果不对则启动失败(会转入执行2st启动)即SD2启动,如果这里已经是sd2启动了,这里校验和不通过,就启动不了了)
四、.mkv210_image.c文件详解
1.为什么需要该程序
我们链接时只得到了led.bin,210.bin这个和交叉编译工具链无关,由led.bin得到210.bin的过程是三星的s5pv210所特有的,因此需要我们自己去完成,为此我们写mkv210_image.c来完成
整个程序的工作流:
整个程序首先申请一个16KB大小的buffer,然后把所以内容按照各自的位置填充进去,最终把填充好的buffer写到一个文件(210.bin)就形成了我们想要的镜像。
2.mkv210_image.c源程序
/*
mkv210_image.c的主要作用就是由usb启动时使用的led.bin制作得到由sd卡启动的镜像210.bin
在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 "
#define SPL_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: %s <source file> <destination file>\n", argv[0]);
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); //从16byte之后开始读取
if ( nbytes != count )
{
printf("source file read error\n");
free(Buf);
fclose(fp);
return -1;
}
fclose(fp);
// 4. 计算校验和
// 4.1 从第16byte开始统计buffer中共有几个1
// 4.1 从第16byte开始计算,把buffer中所有的字节数据加和起来得到的结果
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; // Buf是210.bin的起始地址,+8表示向后位移2个字,也就是说写入到第3个字
*( (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;
}
五、LED点灯编程
1.数据手册查找
gpio概念:
gpio就是芯片引脚,作为gpio这类引脚,它的功能和特点是可以被编程控制它的工作模式,也可以编程控制它的电压高低等
编程操作gpio时首先阅读数据手册,s5pv210_um_rev1
查阅数据手册可知GPJ0寄存器有:
GPJ0CON, GPJ0DAT, GPJ0PUD, GPJ0DRV, GPJ0CONPDN and GPJ0PUDPDN
实际上真正操作的led硬件主要是:GPJ0CON GPJ0DAT
GPJ0CON: gpj0控制寄存器用来配置各引脚的输出模式
注:在驱动LED时候我们要配置gpio为output模式
GPJ0DAT:当引脚配置为input或output模式时,寄存器相应位和引脚的电平高低相对于
GPJ0PUD :控制引脚内部上拉、下拉
GPJ0DRV:配置引脚的驱动
GPxCON GPxDAT寄存器分析:
Gpj0一共有8个引脚gpj0~gpj7
Gpj0con寄存器中设置8个引脚的工作模式(32/8=4)每个引脚分到4位譬如gpj0为bit0bit3,工作方式就是给对于的寄存器写入相应的值(bit12bit15写入0b0001,GPJ03就设置为了输出模式)
Led:gpj0_3 gpjo_4 gpj0_5 低电平亮/高电平灭
Gpj0con寄存器地址(0xe0200240)
2.汇编实现led
从这里我们可以看出其实汇编编写程序和我们用C语言编写有很大的相同之处,只是我们使用汇编的时候更多的是进行寄存器的操作,通过不同的寄存器来操作我们要编程的硬件,牢记老使用的汇编指令(ldr str ….等)
在使用过程中更多的是要学会查看数据手册,根据手册来进行寄存器的配置
每个寄存器都会有一个像对应的地址,每个寄存器中都会分配32位(大多数)然后每四位代表一个引脚,通过不同的二进制序列实现该引脚的不同功能。
方式二:位操作
汇编中实现简单延时函数
3.编译程序并烧入
make 执行脚本
从虚拟机上进行烧入
在当前路径下执行 ./write2sd /dev/sdb
总结
通过上面的学习学会了如何利用相关的数据手册 去查找我们要操作的寄存器,根据功能的需求去对相应寄存器的不同位进行赋值,也对汇编的学习产生了浓厚的兴趣,对脚本功能的强大所震撼。总之还是一步一个脚印慢慢来。
加油鸭