Linux驱动编程篇(三)——LED驱动(一)简单LED驱动

Linux驱动编程篇(三)——LED驱动(⼀)简单LED驱动⼀、LED驱动程序的实现⽬标及流程图
1、打开LED
2、关闭LED
⼆、LED驱动程序的实现部分
1、内核层LED驱动程序
2、应⽤层LED测试程序
85式高射机三、内核层LED驱动程序的编程步骤
1、添加头⽂件
2、确定主设备号,也可以让内核分配
3、定义⾃⼰的 file_operations 结构体
4、实现对应的 drv_open/drv_read/drv_write 等函数,填⼊ file_operations 结构体
4.1 led_drv_open函数
  4.1.1使能时钟
  4.1.2使能GPIO
  4.1.3配置IO引脚
  4.1.4配置IO引脚⽅向
4.2 led_drv_write函数
  4.2.1获取应⽤层的数据
  4.2.3GPIO输出
4.3 把 file_operations 结构体告诉内核:register_chrdev.
4.4 创建类class_create
4.5 创建设备device_create.
5、实现⼊⼝函数:安装驱动程序时,就会去调⽤这个⼊⼝函数,执⾏⼯作:
5.1 ioremap虚拟地址映射物理地址
5.2 把 file_operations 结构体告诉内核:register_chrdev.
5.3 创建类class_create.
5.4 创建设备device_create.
6、实现出⼝函数:卸载驱动程序时,就会去调⽤这个⼊⼝函数,执⾏⼯作:6.1 iounmap释放虚拟地址
6.2 把 file_operations 结构体从内核注销:unregister_chrdev.
6.3 销毁类class_create.
6.4 销毁设备结点class_destroy.
7、其他完善:GPL协议、驱动作者、驱动名称
四、具体实现
1、内核层LED驱动程序
//1、添加头⽂件
#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<asm/io.h>
/
/函数声明
static ssize_t led_drv_read(struct file *file,char __user *buf, size_t nbytes, loff_t *ppos);
static ssize_t led_drv_write(struct file *file,const char __user *buffer,size_t count, loff_t *ppos); static int led_drv_open(struct inode *inode,struct file *filp);
static int __init led_init(void);
static void __exit led_exit(void);
/*registers*/
// RCC_PLL4CR地址:0x50000000 + 0x894
mf8
static volatile unsigned int*RCC_PLL4CR;
// RCC_MP_AHB4ENSETR 地址:0x50000000 + 0xA28
static volatile unsigned int*RCC_MP_AHB4ENSETR;
// GPIOA_MODER 地址:0x50002000 + 0x00
static volatile unsigned int*GPIOA_MODER;
// GPIOA_BSRR 地址: 0x50002000 + 0x18
static volatile unsigned int*GPIOA_BSRR;
// led类
static struct class *led_class;
//2、确定主设备号,也可以让内核分配令牌网
static int major =0;
//3、定义⾃⼰的 file_operations 结构体
static const struct file_operations my_fops ={
.read  = led_drv_read,
.write  = led_drv_write,
.
open  = led_drv_open,
.owner = THIS_MODULE,
};
//4、实现对应的 drv_open/drv_read/drv_write 等函数,填⼊ file_operations 结构体
static ssize_t led_drv_read(struct file *file,char __user *buf, size_t nbytes, loff_t *ppos)
{
{
return0;
}
static ssize_t led_drv_write(struct file *file,const char __user *buffer,size_t count, loff_t *ppos) {
char val;
/
*1、get data from app*/
/*copy_from_user(void * to, const void __user * from, unsigned long n):get form app*/
copy_from_user(&val,buffer,1);
/*2、set register out 1/0*/
if(val){
/*set gpio to let led on*/
*GPIOA_BSRR =(1<<26);
}else{
/*set gpio to let led off*/
*GPIOA_BSRR =(1<<10);
}
return1;
}
static int led_drv_open(struct inode *inode,struct file *filp)
{
/*1、enalbe PLL4,it is clock source for all gpio*/
*RCC_PLL4CR|=(1<<0);
while((*RCC_PLL4CR &(1<<1))==0)
/*2、enable gpio*/
*RCC_MP_AHB4ENSETR |=(1<<0);
/*3、configure gpA10 as gpio*/
*GPIOA_MODER &=~(3<<20);
/
* 4、configure gpio as output*/
*GPIOA_MODER |=(1<<20);
return0;
}
//5、实现⼊⼝函数:安装驱动程序时,就会去调⽤这个⼊⼝函数,执⾏⼯作:
//  (1)把 file_operations 结构体告诉内核:register_chrdev.
//  (2)创建类class_create.
//  (3)创建设备device_create.
static int __init led_init(void)
{
printk("%s %s line %d\n",__FILE__, __FUNCTION__,__LINE__);
major =register_chrdev(0,"my_led",&my_fops);
/*虚拟地址映射物理地址*/
//ioremap(phys_addr_t phys_addr, size_t size)
// RCC_PLL4CR地址:0x50000000 + 0x894
RCC_PLL4CR =ioremap(0x50000000+0x894,4);
// RCC_MP_AHB4ENSETR地址:0x50000000 + 0xA28
RCC_MP_AHB4ENSETR =ioremap(0x50000000+0xA28,4);
// GPIOA_MODER地址:0x50000000 + 0x00
GPIOA_MODER =ioremap(0x50000000+0x00,4);
// GPIOA_BSRR地址:0x50000000 + 0x18
GPIOA_BSRR =ioremap(0x50000000+0x18,4);
led_class =class_create(THIS_MODULE,"myled");
/*创建/dev/myled*/
device_create(led_class,NULL,MKDEV(major,0),NULL,"myled");
return0;
}
//6、实现出⼝函数:卸载驱动程序时,就会去调⽤这个⼊⼝函数,执⾏⼯作:
//  (1)把 file_operations 结构体从内核注销:unregister_chrdev.
//  (2)销毁类class_create.
戴玉庆
//  (3)销毁设备结点class_destroy.
static void __exit led_exit(void)
{
/
/ RCC_PLL4CR地址:0x50000000 + 0x894
iounmap(RCC_PLL4CR);
iounmap(RCC_PLL4CR);
// RCC_MP_AHB4ENSETR地址:0x50000000 + 0xA28 iounmap(RCC_MP_AHB4ENSETR);
// GPIOA_MODER地址:0x50000000 + 0x00 iounmap(GPIOA_MODER);
// GPIOA_BSRR地址:0x50000000 + 0x18
iounmap(GPIOA_BSRR);
//销毁类
class_destroy(led_class);
//销毁设备
device_destroy(led_class,MKDEV(major,0));
/
/注销驱动
unregister_chrdev(major,"my_led");
}
//修饰⼊⼝、出⼝函数
module_init(led_init);
module_exit(led_exit);
//7、其他完善:GPL协议、驱动作者、驱动名称MODULE_AUTHOR("aipolo <369480046@qq>"); MODULE_DESCRIPTION("led Driver");
MODULE_LICENSE("GPL");
东台市安丰镇中学2、应⽤层LED测试程序
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
#include<unistd.h>
//ledtest /dev/myled on
int main(int argc,char**argv)
{
int fd;
char status =0;
if(argc !=3){
printf("Usage: %s <dev> <on|off>\n",argv[0]);
printf("eg:%s /dev/myled on\n",argv[0]);
printf("eg:%s /dev/myled off\n",argv[0]);
return-1;
}
//open
fd =open(argv[1],O_RDWR);
if(fd <0){
printf("open %s error\n",argv[0]);
return-1;
}
//write  if是on,status = 1;if是off,status = 0;
if(strcmp(argv[2],"on")==0){
printf("open led\n");
status =1;
}
write(fd,&status,1);
}
3、Makefile
# 1.使⽤不同的开发板内核时,⼀定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译,为了能编译内核,要先设置下列环境变量:
# 2.1 ARCH,⽐如: export ARCH=arm64
# 2.2 CROSS_COMPILE,⽐如: export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
# 2.3 PATH,⽐如: export PATH=$PATH:/home/book/100ask_stm32mp157_pro-sdk/ToolChain/armbuildroot-linux-gnueabihf_sdk-buildroot/bin # 注意:不同的开发板不同的编译器上述3个环境变量不⼀定相同,
#      请参考各开发板的⾼级⽤户使⽤⼿册
/*内核存放地址*/
KERN_DIR =/home/book/100ask_stm32mp157_pro-sdk/Linux-5.4
all:
make -C $(KERN_DIR) M=`pwd` modules
$(CROSS_COMPILE)gcc -o ledtest ledtest.c
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -der
rm -f ledtest
obj-m  += led_my.o
五、实验结果
1、配置环境变量
噪声预测export ARCH=arm64
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
export PATH=$PATH:/home/book/100ask_stm32mp157_pro-sdk/ToolChain/armbuildroot-linux-gnueabihf_sdk-buildroot/bin
2、装载驱动
insmod /mnt/my_led.ko
3、查看设备

本文发布于:2024-09-21 20:43:20,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/570785.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:内核   驱动程序   设备   驱动   函数   实现
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议