当前位置: 首页 > news >正文

驱动开发,stm32mp157a开发板的led灯控制实验

1.实验目的

        编写LED灯的驱动,在应用程序中编写控制LED灯亮灭的代码逻辑实现LED灯功能的控制;

2.LED灯相关寄存器分析

LED1->PE10 LED1亮灭:

RCC寄存器[4]->1 0X50000A28

GPIOE_MODER[21:20]->01 (输出) 0X50006000

GPIOE_ODR[10]->1(输出高电平) 0(输出低电平)0X50006014

LED2->PF10 LED2亮灭:

RCC寄存器[5]->1 0X50000A28

GPIOE_MODER[21:20]->01 (输出) 0X50006000

GPIOE_ODR[10]->1(输出高电平) 0(输出低电平)0X50006014

LED3->PE8 LED3亮灭:

RCC寄存器[4]->1 0X50000A28

GPIOE_MODER[17:16]->01 (输出) 0X50006000

GPIOE_ODR[8]->1(输出高电平) 0(输出低电平)0X50006014

GPIOE_OTYPER默认为00

GPIOE_PUPDR默认为0

GPIOE_OSPEEDR默认为00

3.编写代码

---Makefile---工程管理文件

modname?=demo
arch?=arm
ifeq ($(arch),arm)
KERNELDIR:= /home/ubuntu/FSMP1A/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61 #编译生成ARM架构
else
KERNELDIR:=/lib/modules/$(shell uname -r)/build #编译生成X86架构
endifPWD:=$(shell pwd) #模块化编译文件路径
all:make -C $(KERNELDIR) M=$(PWD) modules
clean:make -C $(KERNELDIR) M=$(PWD) cleanobj-m:=$(modname).o

---head.h---头文件

#ifndef __HEAD_H__
#define __HEAD_H__typedef struct
{unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int ODR;   
}gpio_t;//LED1和LED3寄存器地址
#define LED1_ADDR 0x50006000
#define LED2_ADDR 0x50007000
#define LED3_ADDR 0x50006000
#define RCC_ADDR 0x50000A28#endif

---mychrdev.c---驱动程序

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "head.h"
#include<linux/device.h>char kbuf[128] = {0};
unsigned int major;
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
unsigned int *vir_rcc;struct class *cls;
struct device *dev;//封装操作方法
int mycdev_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{int ret;if(size > sizeof(kbuf)){size = sizeof(kbuf);}ret = copy_to_user(ubuf,kbuf,size);if(ret){printk("copy_to_user err\n");return -EIO;}return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{unsigned long ret;if(size > sizeof(kbuf)){size = sizeof(kbuf);}ret = copy_from_user(kbuf,ubuf,size);if(ret){printk("copy_from_user err\n"); return -EIO;   }switch(kbuf[0]){case '1':if(kbuf[1] == '1')  //开灯vir_led1->ODR |= (0x1 << 10);else if(kbuf[1] == '0')  //关灯vir_led1->ODR &= (~(0x1 << 10));break;case '2':if(kbuf[1] == '1')  //开灯vir_led2->ODR |= (0x1 << 10);else if(kbuf[1] == '0') //关灯vir_led2->ODR &= (~(0x1 << 10));break;case '3':if(kbuf[1] == '1')  //开灯vir_led3->ODR |= (0x1 << 8);else if(kbuf[1] == '0') //关灯vir_led3->ODR &= (~(0x1 << 8));break;default:printk("输入错误\n"); }return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}struct file_operations fops={.open=mycdev_open,.read=mycdev_read,.write=mycdev_write,.release=mycdev_close,
};//相关寄存器地址映射及初始化
int all_led_init(void)
{//相关寄存器的内存映射vir_led1=ioremap(LED1_ADDR,sizeof(gpio_t));if(vir_led1 == NULL){printk("物理内存映射失败%d\n",__LINE__);return -ENOMEM;}vir_led2=ioremap(LED2_ADDR,sizeof(gpio_t));if(vir_led2 == NULL){printk("物理内存映射失败%d\n",__LINE__);return -ENOMEM;}vir_led3 = vir_led1;vir_rcc=ioremap(RCC_ADDR,4);if(vir_rcc == NULL){printk("物理内存映射失败%d\n",__LINE__);return -ENOMEM;}printk("寄存器内存映射成功\n");//硬件寄存器的初始化(*vir_rcc) |= (0x3 << 4);//LED1vir_led1->MODER &= (~(0x3 << 20));vir_led1->MODER |= (0x1 << 20);vir_led1->ODR &= (~(0x1 << 10));//LED2vir_led2->MODER &= (~(0x3 << 20));vir_led2->MODER |= (0x1 << 20);vir_led2->ODR &= (~(0x1 << 10));//LED3vir_led3->MODER &= (~(0x3 << 16));vir_led3->MODER |= (0x1 << 16);vir_led3->ODR &= (~(0x1 << 8));printk("寄存器初始化成功\n");return 0;
}//入口函数
static int __init mycdev_init(void)
{major = register_chrdev(0,"mychrdev",&fops);if(major < 0){printk("字符设备驱动注册失败\n");return major;}printk("字符设备驱动注册成功:major=%d\n",major);//寄存器映射及初始化all_led_init();//向上提交目录cls = class_create(THIS_MODULE,"mychrdev");if(IS_ERR(cls)){printk("向上提交目录失败\n");return -PTR_ERR(cls);}printk("向上提交目录成功\n");//向上提交设备节点信息int i;for(i=0; i<3; i++){dev = device_create(cls,NULL,MKDEV(major,i),NULL,"mychrdev%d",i);if(IS_ERR(dev)){printk("向上提交设备节点信息失败\n");return -PTR_ERR(dev);}}printk("向上提交设备节点信息成功\n");return 0;
}//出口函数
static void __exit mycdev_exit(void)
{//销毁设备节点信息int i;for(i=0; i<3; i++){device_destroy(cls,MKDEV(major,i));}//销毁目录信息class_destroy(cls);//取消物理内存的映射iounmap(vir_led1);iounmap(vir_led2);iounmap(vir_rcc);//字符设备驱动注销unregister_chrdev(major,"mychrdev");
}//声明
//入口函数地址
module_init(mycdev_init);
//出口函数地址
module_exit(mycdev_exit);
//遵循的GPL协议
MODULE_LICENSE("GPL");

---test.c---应用程序测试程序

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>int main(int argc,char const *argv[])
{char buf[128]={0};int fd = open("/dev/mychrdev0",O_RDWR);if(fd < 0){printf("设备文件打开失败\n");exit(-1);}while(1){printf("第一个字符:1(LED1) 2(LED2) 3(LED3)\n");printf("第二个字符1(开灯)0(关灯)\n");printf("输入控制灯的两个字符>>> ");fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1] = '\0';//像设备文件中写write(fd,buf,sizeof(buf));}close(fd);return 0;  
}

4.测试

http://www.lryc.cn/news/169571.html

相关文章:

  • 黑客入侵机构,导致2万条信息被卖
  • 循环购:让消费者和商家共赢的新型电商模式
  • 分布式缓冲-Redis
  • C# 流Stream详解(3)——FileStream源码
  • C语言的文件操作(炒详解)
  • 27.基于ADS的不等分威尔金森功分器设计
  • Linux自用命令
  • clickhouse union all之后数据量不一致
  • 力扣刷题19-删除链表的倒数第N个节点
  • Unity中的简单数据存储办法
  • Pytorch-MLP-CIFAR10
  • SQL2 查询多列
  • 算法分享三个方面学习方法(做题经验,代码编写经验,比赛经验)
  • 爬虫 — 验证码反爬
  • 视频图像处理算法opencv模块硬件设计图像颜色识别模块
  • 目标检测网络之Fast-RCNN
  • Golang Gorm 创建HOOK
  • 计算机视觉的应用15-图片旋转验证码的角度计算模型的应用,解决旋转图片矫正问题
  • 【Seata】分布式事务问题和理论基础
  • 文件打包解包的方法
  • npm 清缓存(重新安装node-modules)
  • sqlserver查询表中所有字段信息
  • 二叉树的概念、存储及遍历
  • 【面试题】智力题
  • 【SpringBoot集成Redis + Session持久化存储到Redis】
  • day49:QT day2,信号与槽、对话框
  • Meta分析核心技术
  • Gof23设计模式之责任链模式
  • 数字孪生和元宇宙:打造未来的数字边界
  • 【新版】系统架构设计师 - 软件架构设计<新版>