驱动开发,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.hqwc.cn/news/111687.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SSL Windows环境诊断修复工具,保持shell连接活跃

SangforHelperToolInstaller.exe 接入内网遇到网络故障&#xff0c;修复网络问题&#xff0c;可以使用这个软件&#xff0c;修复网络问题非常强大。

二叉树的具体原理及实现

文章目录 一.树的专业术语二.二叉树的原理三.常见的二叉树分类1.完全二叉树2.平衡二叉树3.二叉搜索树 四.二叉搜索树算法具体实现五.二叉搜索树具体实现代码 一.树的专业术语 首先先介绍树的专业术语 二.二叉树的原理 二叉搜索树&#xff08;Binary Search Tree&#xff0c…

【rar密码】WinRAR整理密码,如何使用?

之前给大家介绍过WinRAR自动加密的设置方法&#xff0c;今天再介绍一种RAR压缩包加密方法&#xff1a;整理密码。 什么是整理密码&#xff1a; 在加密rar文件的时候&#xff0c;点击下拉框选择密码&#xff0c;不用输入密码 设置方法&#xff1a; 前面的操作步骤和设置自动…

在ExoPlayer中使用协程:构建强大的Android媒体播放器

在ExoPlayer中使用协程&#xff1a;构建强大的Android媒体播放器 现今的移动应用世界中&#xff0c;媒体消费是用户体验的核心部分。无论是流媒体视频、音乐播放还是处理自适应媒体格式&#xff0c;强大的媒体播放器对于提供无缝和愉悦的用户体验至关重要。而在安卓平台上&…

Python(PySpark案例实战)

为什么要学习PySpark&#xff1f; Spark对Python语言的支持&#xff0c;重点体现在&#xff0c;Python第三方库&#xff1a;PySpark之上。 PySpark是由Spark官方开发的Python语言第三方库。 Python开发者可以使用pip程序快速的安装PySpark并像其它三方库那样直接使用。 PySp…

VUE之proxy配置实现跨域

什么是跨域 要了解跨域&#xff0c;首先得知道浏览器的同源策略。 同源策略&#xff1a;是由Netscape提出的一个安全策略&#xff0c;能够阻挡恶意文档&#xff0c;保护本地数据。它能限制一个源的文档或脚本对另一个源的交互&#xff0c;使得其它源的文档或脚本&#xff0c;…

SQL Server 日期范围按每月一行拆分

要将 SQL Server 中的日期范围按每月一行拆分&#xff0c;可以使用一个表值函数&#xff08;Table-Valued Function&#xff09;来生成日期范围内的月份&#xff0c;并将其与其他数据连接&#xff0c;以创建包含每月一行的结果集。 以下是一个示例&#xff0c;说明如何实现这一…

c++ decltype()的两个特殊情况

我们对里面这一行反汇编&#xff1a; 很诡异的左值引用。提供了这么违反感觉的语法&#xff0c;可能是为了语法完备性&#xff0c;但不直观。

【基本数据结构 三】线性数据结构:栈

学习了数组和链表后,再来看看第三种线性表结构,也就是栈,栈和后边讲的队列一样是一种受限的线性表结构,正是因为其使用有限制,所以对于一些特定的需要操作可控的场合,受限的结构就非常有用。 栈的定义 我们平时放盘子的时候,都是从下往上一个一个放;取的时候,我们也…

Java8中判断一个对象不为空存在一个类对象是哪个

Java8中判断一个对象不为空存在一个类对象是哪个&#xff1f; 在Java 8中&#xff0c;你可以使用java.util.Optional类来处理可能为空的对象。Optional类可以帮助你优雅地处理空值情况&#xff0c;而不需要显式地进行空值检查。 这是一个简单的Optional示例&#xff1a; imp…

Matlab中关于 : 的使用

设&#xff0c;mat 这个矩阵的规格是 n*m&#xff0c;temp mat( i , j ) 矩阵的行和列的下标从1开始 在这个矩阵中&#xff0c;a:b 代表的含义是范围是从 a--b 则&#xff0c;当 a 和 b 被省略时&#xff0c;代表的范围就是最大范围&#xff08;1--n&#xff09; or &#…

竞赛选题 基于深度学习的人脸性别年龄识别 - 图像识别 opencv

文章目录 0 前言1 课题描述2 实现效果3 算法实现原理3.1 数据集3.2 深度学习识别算法3.3 特征提取主干网络3.4 总体实现流程 4 具体实现4.1 预训练数据格式4.2 部分实现代码 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 毕业设计…