RK3288 LED驱动编写
开始编写LED驱动程序
- 我之前学习了rk3288 的led驱动编写的准备
- 然后也编写了led驱动的框架。
- 现在只要把框架适当的填充具体的硬件操作,就可以实现led的电灯了。
1.需要用到的函数ioremap
因为linux内核并不像单片机一样是直接用寄存器地址控制的,操作系统有内存寻址的架构。所以我们需要把物理地址转换成Linux可以操作的地址。这个转换的过程就需要调用ioremap函数,下面的它的函数原型:
#include <asm/io.h> //需要使用时包含头文件
void __iomen *ioremap(resource_size_t res_cookie, size_t size);
void iounmap(volatile void __iomen *cookie);/* virtual_addr = ioremap(physical_addr, size);* 把physical_addr开始的size映射为虚拟地址,返回值时该段虚拟地址的首地址。* physical_addr和size都会按页取整*/
2.firefly3288 led原理图
WORK_LED使用GPIO8_A1,POWER_LED使用GPIO8_A2。
这两个LED引脚在高电平时熄灭,低电平时点亮。
3.Led初始化步骤
- 使能GPIO对应的CRU控制器
CRU_CLKGATE14_CON的b[8]位为0时使能,这里要注意31:16为时掩码位,必须把b[24]位设置为1。才能避免被屏蔽。
/* rk3288 GPIO8_A1 */
/* a. 使能 GPIO8
* set CRU to enable GPIO8
* CRU_CLKGATE14_CON 0xFF760000 + 0x198
* (1<<(8+16)) | (0<<8)
*/
- 设置GPIO可写,并且引脚用作GPIO功能
设置GRF_GPIO8A_IOMUX的b[3:2]和b[4]为0,把GPIO_A1和GPIO_A2作为GPIO。同时b[19:18]和b[21:20]设置为0b11。
/* b. 设置 GPIO8_A1 用于 GPIO
* set PMU/GRF to configure GPIO8_A1 as GPIO
* GRF_GPIO8A_IOMUX 0xFF770000 + 0x0080
* bit[3:2] = 0b00
* (3<<(2+16)) | (0<<2)
*/
- 把对应的GPIO设置为输出
设置 GPIO_SWPORTA_DDR 寄存器 b[1]为 1 b[2]为1,把 GPIO8_A1 和GPIO8_A2设置为输出引脚。
/* c. 设置 GPIO8_A1 作为 output 引脚
* set GPIO_SWPORTA_DDR to configure GPIO8_A1 as output
* GPIO_SWPORTA_DDR 0xFF7F0000 + 0x0004
* bit[1] = 0b1
*/
- 设置GPIO默认的电平为高电平
设置 GPIO_SWPORTA_DR 寄存器 b[1]为 1,让 GPIO8_A1 输出高电平。
/* d. 设置 GPIO8_A1 输出高电平
* set GPIO_SWPORTA_DR to configure GPIO8_A1 output 1
* GPIO_SWPORTA_DR 0xFF7F0000 + 0x0000
* bit[1] = 0b1
*/
/* e. 设置 GPIO8_A1 输出低电平
* set GPIO_SWPORTA_DR to configure GPIO8_A1 output 0
* GPIO_SWPORTA_DR 0xFF7F0000 + 0x0000
* bit[1] = 0b0
*/
Led操作步骤
和上面第四步时一样的。
源码
Makefile
KERN_DIR = /home/book/Documents/100ask_firefly-rk3288/linux-4.4all:make -C $(KERN_DIR) M=`pwd` modules$(CROSS_COMPILE)gcc -o led_app led_app.c -Wno-error=unused-but-set-variableclean:make -C $(KERN_DIR) M=`pwd` modules cleanrm -rf modules.orderrm -f hello_drv_testmyled_drv-y:=led_drv.o board_demoo.o
obj-m += myled_drv.o
led_drv.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/major.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>#include "led_ops.h"static int major = 0;
static struct class *led_class;
struct led_operations *p_led_ops;static int led_drv_open(struct inode *node, struct file *file)
{int minor = iminor(node);printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);p_led_ops->init(minor); return 0;
}static ssize_t led_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{int err;char status;struct inode *inode = file_inode(file);int minor = iminor(inode);printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);err = copy_from_user(&status, buf, 1);printk("write status:%x \n", status);p_led_ops->ctl(minor, status);return 1;
}static int led_drv_close(struct inode *node, struct file *file)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}static struct file_operations led_drv = {.owner = THIS_MODULE,.open = led_drv_open,.read = led_drv_read,.write = led_drv_write,.release = led_drv_close,
};static int __init led_drv_init(void)
{int err;int i = 0;major = register_chrdev(0, "myled", &led_drv);led_class = class_create(THIS_MODULE, "led_class");err = PTR_ERR(led_class);if(IS_ERR(led_class)) {unregister_chrdev(major, "myled"); printk(KERN_WARNING "class creatge failed %d\n", err);return -1;}p_led_ops = get_board_led_ops();for(i=0;i<p_led_ops->num;i++)device_create(led_class, NULL, MKDEV(major, i), NULL, "myled%d", i);printk("%s %sled_drv_init\n", __FILE__, __FUNCTION__);return 0;
}static void __exit led_drv_exit(void)
{int i;printk("%s %sled_drv_exit\n", __FILE__, __FUNCTION__);for(i=0;i<p_led_ops->num;i++)device_destroy(led_class, MKDEV(major, i));class_destroy(led_class); unregister_chrdev(major, "myled");
}module_init(led_drv_init);
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("chen");
board_demoo.c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/io.h>#include "led_ops.h"#define CRU_BASE_PHY_ADDRESS ((unsigned long)(0xff760000))
#define GRF_BASE_PHY_ADDRESS ((unsigned long)(0xff770000))
#define GPIO8_BASE_PHY_ADDRESS ((unsigned long)(0xff7f0000))#define CRU_CLKGATE14_PHY_CON (0x0198)
#define GRF_GPIO8A_PHY_IOMUX (0x0080)
#define GPIO_SWPORTA_PHY_DR (0x0000)
#define GPIO_SWPORTA_PHY_DDR (0x0004)static volatile unsigned int *CRU_CLKGATE14_CON;
static volatile unsigned int *GRF_GPIO8A_IOMUX;
static volatile unsigned int *GPIO8_SWPORTA_DDR;
static volatile unsigned int *GPIO8_SWPORTA_DR;static int board_demoo_led_init(int which)
{printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which);if(!CRU_CLKGATE14_CON) {CRU_CLKGATE14_CON = ioremap(CRU_BASE_PHY_ADDRESS + CRU_CLKGATE14_PHY_CON, 4);GRF_GPIO8A_IOMUX = ioremap(GRF_BASE_PHY_ADDRESS + GRF_GPIO8A_PHY_IOMUX, 4);GPIO8_SWPORTA_DDR = ioremap(GPIO8_BASE_PHY_ADDRESS + GPIO_SWPORTA_PHY_DDR, 4);GPIO8_SWPORTA_DR = ioremap(GPIO8_BASE_PHY_ADDRESS + GPIO_SWPORTA_PHY_DR, 4);}if(which == 0) {*CRU_CLKGATE14_CON = (1<<(8+16)) | (0<<8);*GRF_GPIO8A_IOMUX |= (3<<(2+16)) | (0<<2);*GPIO8_SWPORTA_DDR |= (1<<1);} else if(which == 1) {*CRU_CLKGATE14_CON = (1<<(8+16)) | (0<<8);*GRF_GPIO8A_IOMUX |= (3<<(4+16)) | (0<<4);*GPIO8_SWPORTA_DDR |= (1<<2);}return 0;
}static int board_demoo_led_ctl(int which, char status)
{printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status?"on":"off");if(which == 0) {if(status) { /* on: output 0 */*GPIO8_SWPORTA_DR &= ~(1<<1);} else { /* off: output 1 */*GPIO8_SWPORTA_DR |= (1<<1);}} else if(which == 1) {if(status) {*GPIO8_SWPORTA_DR &= ~(1<<2);} else {*GPIO8_SWPORTA_DR |= (1<<2);}}return 0;
}static struct led_operations board_demoo_led_ops = {.num = 2,.init = board_demoo_led_init,.ctl = board_demoo_led_ctl,
};struct led_operations *get_board_led_ops(void)
{return &board_demoo_led_ops;
}
led_ops.h
#ifndef __LED_OPS_H_
#define __LED_OPS_H_struct led_operations {int num;int (*init)(int which); /* init led, which:led num */int (*ctl)(int which, char status); /* control led, whic:led num,status:0-On 1-Off */
};struct led_operations *get_board_led_ops(void);#endif
led_app.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>void showUsage(void)
{printf("app [dev_path] [on,off]\n");
}int main(int argc, char *argv[])
{char status;if(argc < 3) {showUsage();return -1;}int fd = open(argv[1], O_RDWR);if(fd < 0) {printf("app open device failed path:%s", argv[1]);return -1;}if(0 == strcmp(argv[2], "on")) {status = 1;int ret = write(fd, &status, 1);if(ret <= 0) {printf("app write device fialed %s",argv[2]);return -1;} else {printf("app write device %x", status);}} else if(0 == strcmp(argv[2], "off")) {status = 0;int ret = write(fd, &status, 1);if(ret <= 0) {printf("app write device fialed %s",argv[2]);return -1;} else {printf("app write device %x", status);}}return 0;
}
RK3288 LED驱动编写相关推荐
- RK3288 LED驱动编写准备
3288LED驱动编写 1.LED硬件知识 2.GPIO的一般结构 3.普通的GPIO设置方法 4.GPIO寄存器的操作方法 5.3288的GPIO操作方法 5.1 怎么写LED驱动程序? 5.2 3 ...
- 树莓派LED驱动编写
编写LED驱动前需要移植树莓派内核,以获得内核源码,内核移植相关方法请参照上一篇<树莓派3B内核移植>. 我们在编写驱动程序的时候,IO空间的起始地址是0x3f000000,加上GPIO的 ...
- Linux驱动_设备树下LED驱动
前言 学习完设备树基础知识后,完成设备树下LED驱动实验 一.修改设备树文件 在设备书根/节点下添加子节点led信息: alphaled {status = "okay";comp ...
- linux驱动:二、LED灯驱动编写
一.地址映射 在正式编写驱动前需要先简单了解一下 MMU 这个神器,MMU 全称叫做 Memory Manage Unit,也就是内存管理单元.在老版本的 Linux 中要求处理器必须有 MMU,但是 ...
- Linux驱动——LED驱动的编写与实验
文章目录 1. LED驱动的原理分析 1.1 地址映射 1.1.1 ioremap函数 1.1.2 iounmap函数 1.2 I/O内存访问函数 1.3 读操作函数 1.4写操作函数 2. 硬件原理 ...
- 嵌入式驱动编写-点亮LED驱动程序
在开发板上,有三个LED灯.如何通过应用程序点亮这三个灯如何编写驱动程序 操作硬件的时候,我们需要准备开发板的原理图和开发手册,,根据这两个文档来进行配置 在source insight 编写代码 1 ...
- ARM(IMX6U)裸机汇编LED驱动实验——驱动编写、编译链接起始地址、烧写bin文件到SD卡中并运行
参考:Linux之ARM(IMX6U)裸机汇编LED驱动实验–驱动编写 作者:一只青木呀 发布时间: 2020-08-07 09:13:48 网址:https://blog.csdn.net/weix ...
- linux驱动编写--2--应用程序控制led闪烁
本系列教程的上一篇: linux驱动编写--1--点亮led 目标:编写一个驱动程序,实现上一篇没写的 "接口".并编写一个测试程序,透过驱动来控制led闪烁. 硬件:micro ...
- firefly-rk3288开发板Linux驱动——LED驱动
本文主要介绍三个部分的内容:一.准备SDK源码 二.如何操作GPIO 三.LED设备驱动的实现.由于firefly官方一直在对源码进行更新,所以本文只以我正在用的版本介绍.此外,官方提供的下载工具版本 ...
最新文章
- 科技日报头版显要位置报道国内多家企业投融资给力永中软件
- 为什么焊锡老是粘在烙铁头上_自动焊锡机常见问题及解决方案「由力自动化」...
- 阿里云mysql 日志_mysql日志-阿里云开发者社区
- osx php7 imagick,[PHP] MacOS 自带php环境安装imagick扩展踩坑记录 | 码农部落
- Oracle 常用的一些函数
- ajax+lazyload时lazyload失效问题及解决
- python人像精细分割_人像抠图 - 发丝级人像分割 - 照片人物特效 - 极链科技
- Leetcod每日一题:151.reverse-words-in-a-string(翻转字符串里的单词)
- 加密芯片在汽车无钥匙启动行业的应用
- 协同过滤工具源码下载
- Faster R-CNN理论
- nodejs 下载url文件
- 阿里云域名注册及域名解析
- python实践周总结_Python 一周总结
- 后门防御阅读笔记,Black-box Detection of Backdoor Attacks with Limited Information and Data
- matlab trapz二重积分函数_「matlab 积分」使用Matlab求解定积分/不定积分 - seo实验室...
- matlab含未知数矩阵方程组,solve函数求解含有未知数的矩阵方程问题
- java自动生成word,java动态生成word解决方案
- 数据采集的方法有哪些
- 计算机考研【干货满满】:2021武汉理工计算机考研经验分享