基于ARM_contexA9 led驱动编程
关于友善之臂出的这款contexA9开发板,目前在网络上的资源较少,特别是内核的,非常之少,鉴于这种情况,我将会写一个系列的驱动来做关于tiny4412这款板子开发的总结。
简单介绍一下:
Tiny4412是一款高性能的四核Cortex-A9核心板,由广州友善之臂设计、生产和发行销售。它采用三星Exynos4412作为主处理器,运行主频可高达1.5GHz,Exynos4412内部集成了Mali-400 MP高性能图形引擎,支持3D图形流畅运行,并可播放1080P大尺寸高清视频。三星旗舰智能手机Galaxy S3即是采用此CPU设计。
我用的是普通版.也就是只有一个串口的.但是核心板是一样的。
好了,介绍完毕,前面的文章我们已经说过了如何编写一个字符设备的驱动程序,这里就不再继续扯字符驱动怎么写,非常简单了,看看就懂了。
我们进入整题,今天,我们需要实现一个LED的驱动程序。在友善之臂的核心板上,有4颗LED灯,如何编写一个驱动程序,让它亮起来,首先我们来看看核心板:
LED灯就位于右上角,第一个和第二个都是电源指示灯,我们不需要管它,我们只管后面那4个LED灯。
如何编写?
1、首先找到板子的原理图,找到对应的引脚。
2、接着打开数据手册,找到对应的寄存器。
3、开始编写LED驱动程序
4、编写makefile
5、插入模块insmod xxx.ko
6、查询主设备号 cat /proc/devices
7、创建设备节点 mknod /dev/xxx c x x
8、执行应用程序app
对应的原理图:
从这里我们可以得出一个结论,LED灯是低电平点亮的,也就是往对应的端口里写0,LED灯就亮了。从最下面一幅图可以知道,我们要找的寄存器是GPIO的GPM4开头的这个寄存器,现在我们进入查数据手册的阶段.
查手册:
我们找到手册的第288页GPIO章节的GPMCON这里:
这是我们要配置端口的模式的IO口,端口有以上的一些状态,在这里我们只考虑输出,也就是只要配置Output那一项就可以了。
我们要配的寄存器有GPM4CON[0],GPM4CON[1],GPM4CON[2],GPM4CON[3],这四位,分别配置成output输出模式.
接下来再看一个GPM4DAT,这个是端口的状态寄存器,对状态寄存器就是写0或者写1,那么LED就被驱动了,我们来看看:
好了,寄存器我们已经找到了,接下来,可以进入写代码的阶段了:
首先编写LED驱动程序:
<span style="font-size:18px;">#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/io.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> //这个是设备的名称,也就是对应在/dev/test-dev #define DEV_NAME "test-dev" //LED灯IO口的地址,也就是刚刚我们在上面的芯片手册看到的Address #define GPM4COM 0x110002E0 //定义配置模式的指针变量 volatile unsigned long *led_config = NULL ; //定义配置状态的指针变量 volatile unsigned long *led_dat = NULL ; //open方法,对LED灯进行初始化 int led_open(struct inode *inode, struct file *filp) { printk("led_open\n");//上层程序对LED进行Open操作的时候会执行这个函数 //先对LED的端口进行清0操作 *led_config &= ~(0xffff); //将4个IO口16位都设置为Output输出状态 *led_config |= (0x1111); return 0; } //write方法 int led_write(struct file *filp , const char __user *buf , size_t count , loff_t *f_pos) { int val ; //注意,这里是在内核中进行操作,我们需要使用copy_from_user这个函数将用户态的内容拷贝到内核态 copy_from_user(&val , buf , count); //以下就是当val是哪个值的时候,led就执行相应的操作,这里不多说 switch(val) { case 0 : //对状态寄存器进行赋值,以下雷同 printk(KERN_EMERG"led1_on\n"); *led_dat &= ~0x1 ; break ; case 1 : printk(KERN_EMERG"led2_on\n"); *led_dat &= ~0x2 ; break ; case 2 : printk(KERN_EMERG"led3_on\n"); *led_dat &= ~0x4 ; break ; case 3 : printk(KERN_EMERG"led4_on\n"); *led_dat &= ~0x8 ; break ; case 4 : printk(KERN_EMERG"ledall_on\n"); *led_dat &= ~0xf ; break ; case 5 : printk(KERN_EMERG"ledall_off\n"); *led_dat |= 0xf ; break ; } } //close方法 int led_close(struct inode *inode, struct file *filp) { printk("led_close\n"); *led_dat |= 0xf ; //全灭,因为高电平是灭的,0xf ----> 1111 return 0; } //用ioctl这个方法也可以实现LED的操作的,自己去实现吧 #if 0 long led_ioctl(struct file *filp, unsigned int request, unsigned long arg) { switch(request) { case 0: printk(KERN_EMERG"led1 on\n"); *led_dat &=~0x1 ; break; case 1: printk(KERN_EMERG"led2 on\n"); *led_dat &=~0x2 ; break; case 3: printk(KERN_EMERG"led3 on\n"); *led_dat &=~0xf ; break; case 4: printk(KERN_EMERG"led4 on\n"); *led_dat &=~0x8 ; break ; default : *led_dat |= 0xf ; } } #endif //对方法进行初始化 struct file_operations fops = { .owner = THIS_MODULE , .open = led_open, .release = led_close, // .unlocked_ioctl = led_ioctl, .write = led_write, }; //主设备号 int major ; //启动函数 static __init int test_init(void) { printk("led_init\n"); major = register_chrdev(major, DEV_NAME, &fops); led_config = (volatile unsigned long *)ioremap(GPM4COM , 16); led_dat = led_config + 1 ; return 0; } //注销函数 static __exit void test_exit(void) { printk("led_exit\n"); unregister_chrdev(major, DEV_NAME); iounmap(led_config); } module_init(test_init); module_exit(test_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Y.X.YANG"); MODULE_VERSION("2016.1.15");</span>
以上就是led这个设备驱动的编写框架。看不懂的可以去学学linux内核设备驱动再来看就很简单了。其实跟单片机的编程差不了多少的,只不过内核驱动是按照框架来编写的,有所驱动就在这里。
驱动程序编写完了,接下来我们编写上层应用层的程序:
<span style="font-size:18px;">#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(int argc, char **argv) { int fd; int val = 0 ; //打开对应的设备 fd = open("/dev/test-dev",O_RDWR) ; if(-1 == fd) { printf("open fair!\n"); return -1 ; } while(1){ val = 0 ; //写write方法就会调用到驱动程序的led_write //最后我们能看到的结果是led灯做流水灯的实现,然后全灭,再周而复始 write(fd , &val , 4); sleep(1); val = 1 ; write(fd , &val , 4); sleep(1); val = 2 ; write(fd , &val , 4); sleep(1); val = 3 ; write(fd , &val , 4); sleep(1); val = 5 ; write(fd , &val , 4); sleep(1); } return 0; }</span>
好了,程序已经写完了,我们来看看makefile怎么写.
<span style="font-size:18px;">#将你所写的驱动程序编译成模块形式 obj-m += leds.o #你需要的文件系统 ROOTFS = /disk/A9/filesystem #你需要的内核 KERNEL = /disk/A9/linux-3.5/ #模块编译 all: make -C $(KERNEL) M=`pwd` modules #模块清除 clean: make -C $(KERNEL) M=`pwd` clean rm -rf my_led #模块更新 install: make -C $(KERNEL) M=`pwd` modules_install INSTALL_MOD_PATH=$(ROOTFS) #编译上层app应用程序 my_led: arm-linux-gcc my_led.c -o my_led</span>
好了,所有的一切都编写完成,我们来看看接下来的操作:
1、先编译整个工程:执行make命令
2、编译app
3、启动minicom,打开开发板的电源,开发板bootload开始启动
4、开发板内核启动
5、进入文件系统,执行insmod插入模块和显示插入后的模块的操作
6、看看主设备号
从这里可以看到,我们的设备test-dev的主设备号是250
所以我们创建设备节点 : mknod /dev/test-dev c 250 0 ,创建完成后
7、执行app应用程序
在这里,我们可以看到程序开始跑起来了,我们来看看开发板上的led是怎么变化的:
好,写了好多,也整理了不少东西出来了,有点累了,以后还要慢慢写.....今天就到这里...
基于ARM_contexA9 led驱动编程的更多相关文章
- 全志A33 linux led驱动编程(附实测参考代码)
开发平台 * 芯灵思SinlinxA33开发板 淘宝店铺: https://sinlinx.taobao.com/ 嵌入式linux 开发板交流 QQ:641395230 开发平台 * 芯灵思Sinl ...
- 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)
这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...
- 驱动编程思想之初体验 --------------- 嵌入式linux驱动开发之点亮LED
这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...
- 基于sys文件系统的LED驱动的移植【原创】
基于RK3188平台LED驱动程序的移植的移植.如有不正确之处,欢迎大家指点. 本文的LED驱动程序不是通过打开设备节点来访问和控制LED的,是通过sys文件系统来控制LED. 板子上有四盏灯以及对应 ...
- 基于S3C2440的linux-3.6.6移植——LED驱动【转】
本文转载自:http://www.voidcn.com/blog/lqxandroid2012/article/p-625005.html 目前的linux版本的许多驱动都是基于设备模型,LED也不例 ...
- at91sam9x5 linux 4.1.0下dts驱动编程模型
测试环境: CPU: AT91SAM9X35 Linux: Atmel提供的linux-at91-linux4sam_5.3 (Linux-4.1.0) 转载请注明: 凌云物网智科嵌入式实 ...
- 简单的led驱动程序设计
基于ok6410: led驱动程序: vim led.c #include<linux/kernel.h>#include<linux/module.h>#include< ...
- Java网络编程和NIO详解9:基于NIO的网络编程框架Netty
Java网络编程和NIO详解9:基于NIO的网络编程框架Netty 转自https://sylvanassun.github.io/2017/11/30/2017-11-30-netty_introd ...
- SPI_FLASH时序描述及驱动编程
推荐 分享一个朋友的人工智能教程,零基础!通俗易懂!希望你也加入到人工智能的队伍中来! http://www.captainbed.net/strongerhuang Ⅰ.写在前面 前面文章讲述过关于 ...
随机推荐
- PHP Ajax JavaScript Json 实现天气信息获取
使用第三方服务 间接方式 思路 使用到的服务 实现代码 前端完整代码 总结 要在自己的网站上添加一个天气预报功能,是一个很普通的需求,实现起来也不是很难.今天来介绍几个简单的方法. 使用第三方服务 有 ...
- JAVA通过继承Thread来创建线程
创建一个线程的第二种方法是创建一个新的类,该类继承Thread类,然后创建一个该类的实例. 继承类必须重写run()方法,该方法是新线程的入口点.它也必须调用start()方法才能执行. 实例 // ...
- Leetcode解题-链表(2.2.6)RotateList
1 题目:Rotate List Given a list, rotate the list to the right by k places, where k is non-negative. Fo ...
- TextView的升级版———AutoCompleteTextView
TextView的升级版---AutoCompleteTextView AutoCompleteTextView顾名知义,可以自动提示的TextView,还可以提示错误信息. 这里介绍基本的使用,能够 ...
- 即时通讯软件openfire+spark+smack
所以我基本上分为三篇文章来介绍此类软件的开发: 第一篇是关于XMPP 协议是啥,IM 是啥以及一个比较有名的开源实现,该开源实现包括三个部分(Spark.Smack和Openfire): 第二篇讲如何 ...
- SpringMVC实现用户登录实例
今天分享一下SpringMVC的一个登陆小案例 准备工作 创建一个Dynamic Web Project(本人是Eclipse) 添加相关的jar包,构建路径 创建springMVC-servlet. ...
- 解决Xshell显示中文乱码的问题
执行echo $LANG命令输出的是当前的编码方式,执行locale命令得到系统中所有可用的编码方式.要让Xshell不显示乱码,则要将编码方式改为UTF-8. 在Xshell中[file]-> ...
- android RecycleView Adapter简单封装
早些时候我们使用系统提供个的BaseAdapter的时候为了满足大家的需要,我们总会对BaseAdapter做一层上层的封装,然后对于实际业务我们只需要关心getView里面的View即可,是代码可读 ...
- linux常用的压缩与解压缩命令
1.gzip 压缩 gzip 是压缩文件,压缩之后文件后缀为.gz 用法:gzip 选项 [文件] 2.gunzip 解压 这个命令与gzip的功能刚好相反,这个是解压. 用法 gunzip 选项 [ ...
- BFS与DFS总结
最近一直在看DFS和BFS,感觉要晕的GJ. DFS思想: 一直往深处走,直到找到解或者走不下去为止 DFS框架: DFS(dep,-) //dep代表目前DFS的深度 { if (找到 ...