嵌入式系统开发之驱动篇001——LED驱动

https://zhuanlan.zhihu.com/p/27242098

图解嵌入式系统开发之驱动篇:LED驱动

LED驱动可以说是驱动界的 “Hello world”,学习嵌入式开发的人无一例外都会先尝试该实验,虽然看上去非常简单,但是可以帮助你熟悉驱动开发的基本流程。本节就从点亮LED来带领大家进入嵌入式开发的大门。内容以华硕tinker board平台来讲解,好了,废话不多说,接下来就是干干干。
实验平台详见: 有没有国产的类似树莓派这样的廉价linux主机? - 知乎

硬件层面:


(图一 LED 原理图)

led的硬件连接很简单,负极通过一个限流电阻连接到地,正极接到主控的一个GPIO口上(GPIO1_D0),只要IO拉高,LED就被点亮。所以,我们本节课要做的只有一件事情,那就是穷尽各种手段让这个IO口拉高就就好了。

IC层面:


(图二 GPIO口的内部图)

GPIO的内部结构如上图,也是非常的简单,一个方向寄存器控制IO口作为输入还是输出,一个数据寄存器,数据寄存器控制输出电平(数据寄存器写1:IO输出高电平, 相反,写0:输出低电平)。 或保存输入值(gpio作为输入使用时),所以我们软件要做的就是去配置这两个寄存器。

该开发板使用的瑞芯微公司的旗舰级主控RK3288(内部继承了4个A17的ARM内核,最高频率可达1.8G),通过查看芯片的数据手册,我们可以找到上述GPIO1寄存器的基地址地址为0xff780000,数据寄存器偏移为0(所以,其完整地址0xff780000),方向寄存器的偏移为4(完整地址为0xff780004)。这样我们可以在系统中通过io命令直接设置这两个寄存器的值。

(方式一)在文件系统中通过io命令点亮led

io -4 0xff780004  0x1000000 (设置gpio1_d0方向为输出)
io -4 0xff780000  0x1000000 (设置gpio1_d0输出高电平)

然后led等就被点亮了。

(方式二)编写内核驱动,通过操作寄存器,点亮LED。

#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/ioport.h>

//GPIO1 base address according to rk3288 datasheet
#define GPIO1_BASE 0xff780000

// GPIO register map define
struct gpio {
	u32 data; //gpio data register
	u32 direction;//gpio direction register
} *gpio1;

//led module init。
int __init led_init(void)
{
	//remap the gpio1 physic address to virtual address
	gpio1 = (struct gpio *)ioremap(GPIO1_BASE, 8);

	//write 1 at bit24 to set gpio1_b0 direction as output
	writel(1 << 24, &gpio1->direction);
	//write 1 at bit24 to set gpio1_b0 as high
	writel(1 << 24, &gpio1->data);

	return 0;
}
//led module exit. 
void __exit led_exit(void)
{
	//Cancel gpio1 remap
	iounmap(gpio1);
}

module_init(led_init);
module_exit(led_exit);

MODULE_AUTHOR("Eric Gao");
MODULE_LICENSE("GPL");

如上,该代码关键部分就两句。

(1)writel(1 << 24, &gpio1->direction);
设置gpio1_b0方向为输出
(2)writel(1 << 24, &gpio1->data);
设置gpio1_b0输出高电平

其他的部分都是作为一个内核驱动模块的模板式代码,这里不在赘述。

(方式三) 在文件系统中,通过内核提供的接口操作GPIO
进入文件系统,可以在/sys/class/gpio/ 目录下看到如下文件及目录。

以上就是内核提供的gpio接口,通过该接口点亮led的过程非常简单。要注意的一点是gpio的标记方式, 比如我们led接的是GPIO1_d0, 那么这里该gpio的标号就是(1*32 + 3*8 = 56)如下。

(1)echo 56 > export (将标号为56的GPIO导出到文件系统)

执行上述命令会在/sys/class/gpio/会自动生成gpio56文件夹,文件夹内包含了我们可以读写的一些gpio的属性,包括方向,输出电平等。

(2)echo out > gpio56/direction(设置gpio方向为输出)

(3)echo 1 > gpio56/value (使该GPIO输出高电平)

然后,LED就成功被点亮了。

(方式四) 通过用户态程序结合内核GPIO接口实现LED闪烁

led.c:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(void)
{
  system("echo 56 > /sys/class/gpio/unexport");
  system("echo 56 > /sys/class/gpio/export");
  system("echo 'out' > /sys/class/gpio/gpio56/direction");
  while (1) {
    system("echo 0 > /sys/class/gpio/gpio56/value");
    usleep(500000);
    system("echo 1 > /sys/class/gpio/gpio56/value");
    usleep(500000);
  }
  system("echo 56 > /sys/class/gpio/unexport");

  return 0;
}

上述代码通过内核gpio接口实现led等的闪烁控制。编译方式如下。

gcc -o led.o led.c

如果觉得有帮助,请帮忙点个赞或分享给其他人,多谢,你们的赞同将是我最大的动力,希望大家共同进步。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值