树莓派LED驱动编写
编写LED驱动前需要移植树莓派内核,以获得内核源码,内核移植相关方法请参照上一篇《树莓派3B内核移植》。
我们在编写驱动程序的时候,IO空间的起始地址是0x3f000000,加上GPIO的偏移量0x2000000,所以GPIO的物理地址应该是从0x3f200000开始的,然后在这个基础上进行Linux系统的MMU内存虚拟化管理,映射到虚拟地址上。
特别注意,BCM2708 和BCM2709 IO起始地址不同,BCM2708是0x20000000,BCM2709是0x3f000000,这是造成大部分人驱动出现“段错误”的原因。树莓派3B的CPU为BCM2709。
驱动代码:
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/ioport.h> #define PIN 26 //GPIO26 #define BCM2835_GPSET0 0x001c
#define BCM2835_GPFSEL0 0x0000
#define BCM2835_GPCLR0 0x0028
#define BCM2835_GPIO_FSEL_OUTP 1 #define BCM2835_GPIO_BASE 0x3f200000 int open_state = 0; //文件打开状态 int bcm2835_gpio_fsel(uint8_t pin, uint8_t mode)
{ //初始化GPIOB功能选择寄存器的物理地址 volatile uint32_t * bcm2835_gpio = (volatile uint32_t *)ioremap(BCM2835_GPIO_BASE, 16); volatile uint32_t * bcm2835_gpio_fsel = bcm2835_gpio + BCM2835_GPFSEL0/4 + (pin/10); uint8_t shift = (pin % 10) * 3; uint32_t value = mode << shift; *bcm2835_gpio_fsel = *bcm2835_gpio_fsel | value; printk("fsel address: 0x%lx : %x\n", (long unsigned int)bcm2835_gpio_fsel, *bcm2835_gpio_fsel); return 0;
} int bcm2835_gpio_set(uint8_t pin)
{ //GPIO输出功能物理地址 volatile uint32_t * bcm2835_gpio = (volatile uint32_t *)ioremap(BCM2835_GPIO_BASE, 16); volatile uint32_t * bcm2835_gpio_set = bcm2835_gpio + BCM2835_GPSET0/4 + pin/32; uint8_t shift = pin % 32; uint32_t value = 1 << shift; *bcm2835_gpio_set = *bcm2835_gpio_set | value; printk("set address: 0x%lx : %x\n", (long unsigned int)bcm2835_gpio_set, *bcm2835_gpio_set); return 0;
} int bcm2835_gpio_clr(uint8_t pin)
{ //GPIO清除功能物理地址 volatile uint32_t * bcm2835_gpio = (volatile uint32_t *)ioremap(BCM2835_GPIO_BASE, 16); volatile uint32_t * bcm2835_gpio_clr = bcm2835_gpio + BCM2835_GPCLR0/4 + pin/32; uint8_t shift = pin % 32; uint32_t value = 1 << shift; *bcm2835_gpio_clr = *bcm2835_gpio_clr | value; printk("clr address: 0x%lx : %x\n", (long unsigned int)bcm2835_gpio_clr, *bcm2835_gpio_clr); return 0;
} static int leds_open(struct inode *inode, struct file *filp)
{ if(open_state == 0) { open_state = 1; printk("Open file suc!\n"); return 0; } else { printk("The file has opened!\n"); return -1; }
} static long leds_ioctl(struct file*filp, unsigned int cmd, unsigned long arg)
{ switch(cmd) { case 0: bcm2835_gpio_clr(PIN); printk("LED OFF!\n"); break; case 1: bcm2835_gpio_set(PIN); printk("LED ON!\n"); break; default: return-EINVAL; } return 0;
} static int leds_release(struct inode *inode, struct file *filp)
{ if(open_state == 1) { open_state = 0; printk("close file suc!\n"); return 0; } else { printk("The file has closed!\n"); return -1; }
} static const struct file_operations leds_fops = { .owner = THIS_MODULE, .open = leds_open, .unlocked_ioctl = leds_ioctl, .release = leds_release,
}; static struct miscdevice misc = { .minor =MISC_DYNAMIC_MINOR, .name ="my_leds", .fops =&leds_fops,
}; static int __init leds_init(void)
{ int ret; //注册混杂设备 ret =misc_register(&misc); //配置功能选择寄存器为输出 bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_OUTP); //设置输出电平为高电平,LED亮 bcm2835_gpio_set(PIN); printk("ledsinit.\n"); return ret;
} static void leds_exit(void)
{ //LED灭 bcm2835_gpio_clr(PIN); misc_deregister(&misc); printk("leds_exit\n");
} module_init(leds_init);
module_exit(leds_exit); MODULE_AUTHOR("yangwen");
MODULE_LICENSE("GPL");
测试代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h> int main(int argc, char **argv)
{ int on; int fd; if (argc != 2 || sscanf(argv[1],"%d", &on) != 1 ||on < 0 || on > 1 ) { fprintf(stderr, "Usage:%s 0|1\n",argv[0]); exit(1); } fd = open("/dev/my_leds", 0); if (fd < 0) { perror("open device leds"); exit(1); } /*通过ioctl来控制灯的亮、灭*/ if(on){ printf("turn on leds!\n"); ioctl(fd, 1); } else { printf("turn off leds!\n"); ioctl(fd, 0); } close(fd); return 0;
}
测试代码 Makefile:
CROSS= /home/yangwen/Raspberry/tools-master/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-
all: led_testled_test: led_test.c$(CROSS)gcc -o $@ led_test.c -staticclean:@rm -rf led_test *.o
在虚拟机分别编译,将模块、测试程序拷贝至树莓派,插入模块后运行测试程序。
sudo insmod xxx.ko
sudo ./led_test 1 打开LED
sudo ./led_test 0 关闭LED
树莓派LED驱动编写相关推荐
- RK3288 LED驱动编写
开始编写LED驱动程序 我之前学习了rk3288 的led驱动编写的准备 然后也编写了led驱动的框架. 现在只要把框架适当的填充具体的硬件操作,就可以实现led的电灯了. 1.需要用到的函数iore ...
- RK3288 LED驱动编写准备
3288LED驱动编写 1.LED硬件知识 2.GPIO的一般结构 3.普通的GPIO设置方法 4.GPIO寄存器的操作方法 5.3288的GPIO操作方法 5.1 怎么写LED驱动程序? 5.2 3 ...
- 树莓派引脚驱动编写(2)
1.续上篇文章的代码测试过后这节真正来验证是否驱动成功 (1)首先改写驱动代码(在linux源码树目录的/driver/char下) 注意:在编译之前可以先备份以下 #include <linu ...
- 树莓派3B+ 驱动开发之GPIO
1.查看树莓派GPIO地址映射基地址 方法一: cat /proc/iomem 结果 3f200000-3f2000b3 : /soc/gpio@7e200000.3f200000为基地址, 方法二 ...
- Linux驱动_设备树下LED驱动
前言 学习完设备树基础知识后,完成设备树下LED驱动实验 一.修改设备树文件 在设备书根/节点下添加子节点led信息: alphaled {status = "okay";comp ...
- 如何写一个树莓派的驱动来控制GPIO LED
一直以来,物联网开发者面对新的硬件都是一件头痛的事情.有些时候明明有现成的驱动,我们却没法直接利用.公司的PM/领导一句话下来,整套系统就要从新来,说明书一看就是一天,重复的软硬联调,日复一日的造轮子 ...
- 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 ...
最新文章
- 为什么这门技术如此重要?错过这次黄金期,就晚了!
- 仅用几行Python代码就能帮小姐姐复制U盘文件,实用干货
- Trie UVALive 7192 Chip Factory (15长春J)
- Repository模式与UnitOfWorks模式的运用
- JVM 调优实战--常见的垃圾回收算法及垃圾收集器组合
- hibernate之工具类
- C#位图BitArray 小试牛刀
- mysql常用cmd指令_Mysql cmd 常用命令
- 高手追小萝莉的故事(洛谷P1184题题解,Java语言描述)
- 通过git命令将本地代码文件推送至github
- 2022美赛备赛资料大全
- 树莓派基础实验19:光敏传感器实验
- sql注入之时间注入
- C语言switch史上最详细的讲解
- 最近招聘和面试的感想
- Python 云标签——玩点浪漫!
- ArcEngine ISymbol效果预览
- Burpsuite配置抓apk流量代理设置脚本
- 初学C语言:判断输入的数是否能被5整除。
- linux 宝塔镇河妖
热门文章
- 计算机及应用专插本,2020广东财经大学华商学院专插本计算机科学与技术专业《数据库原理与应用》考试大纲...
- mpmath.psi python_Mol Cell Proteomics. |马臻| psims-一个用于编写HUPO-PSI标准下的mzML和mzIdentML的python库...
- vue 生成二维码工具
- BZOJ2209 [Jsoi2011]括号序列
- SpringBoot OSS实战之用户头像上传
- LeetCode 27 移除元素 题解
- 一学年的竞赛总结和回顾【我参加过的那些竞赛】
- django博客项目-文章详情页功能
- C++ 流 文件操作(输入输出流)
- 微营销实战demo coffee