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

news2024/12/27 12:35:36

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架构
endif

PWD:=$(shell pwd) #模块化编译文件路径
all:
	make -C $(KERNELDIR) M=$(PWD) modules
clean:
	make -C $(KERNELDIR) M=$(PWD) clean

obj-m:=$(modname).o

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

#ifndef __HEAD_H__
#define __HEAD_H__

//LED1和LED3寄存器地址
#define LED1_3_MODER (0xc50006000)
#define LED1_3_ODR (0xc50006014)
#define LED_RCC (0xc50000A28)

//LED2寄存器地址
#define LED2_MODER (0xc50007000)
#define LED2_ODR (0xc50007014)

#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"

char kbuf[128] = {0};
unsigned int major;
unsigned int *vir_moder;
unsigned int *vir_odr;
unsigned int *vir_rcc;
unsigned int *vir_moder2;
unsigned int *vir_odr2;

//封装操作方法
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;
    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)
{
    int ret;
    ret = copy_from_user(kbuf,ubuf,size);
    if(ret)
    {
        printk("copy_from_user err\n"); 
        return -EIO;   
    }
    
    //LED1
    if(kbuf[0] == '1')
    {
        //开灯
        (*vir_odr) |= (0x1 << 10);
    }
    else if(kbuf[0] == '0')
    {
        //关灯逻辑
        (*vir_odr) &= (~(0x1 << 10));
    }

    //LED2
    if(kbuf[1] == '1')
    {
        //开灯
        (*vir_odr2) |= (0x1 << 10);
    }
    else if(kbuf[1] == '0')
    {
        //关灯逻辑
        (*vir_odr2) &= (~(0x1 << 10));
    }

    //LED3
    if(kbuf[2] == '1')
    {
        //开灯
        (*vir_odr) |= (0x1 << 8);
    }
    else if(kbuf[2] == '0')
    {
        //关灯逻辑
        (*vir_odr) &= (~(0x1 << 8));
    }
   
    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,
};

//入口函数
static int __init mycdev_init(void)
{
	major = register_chrdev(0,"mychrdev",&fops);
    if(major < 0)
    {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功:major=%d\n",major);

    //相关寄存器的内存映射
    vir_odr=ioremap(LED1_3_ODR,4);
    if(vir_odr == NULL)
    {
        printk("物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }

    vir_rcc=ioremap(LED_RCC,4);
    if(vir_rcc == NULL)
    {
        printk("物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }

    vir_moder=ioremap(LED1_3_MODER,4);
    if(vir_moder == NULL)
    {
        printk("物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }

    vir_moder2=ioremap(LED2_MODER,4);
    if(vir_moder2 == NULL)
    {
        printk("物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }

    vir_odr2=ioremap(LED2_ODR,4);
    if(vir_odr2 == NULL)
    {
        printk("物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }
    printk("寄存器内存映射成功\n");

    //硬件寄存器的初始化
    (*vir_rcc) |= (0x3 << 4);
    
    //LED1
    (*vir_moder) &= (~(0x3 << 20));
    (*vir_moder) |= (0x1 << 20);

    (*vir_odr) &= (~(0x1 << 10));

    //LED2
    (*vir_moder2) &= (~(0x3 << 20));
    (*vir_moder2) |= (0x1 << 20);

    (*vir_odr2) &= (~(0x1 << 10));

    //LED3
    (*vir_moder) &= (~(0x3 << 16));
    (*vir_moder) |= (0x1 << 16);
    
    (*vir_odr) &= (~(0x1 << 8));
     
	return 0;
}

//出口函数
static void __exit mycdev_exit(void)
{
    //取消物理内存的映射
    iounmap(vir_moder);
    iounmap(vir_odr);
    iounmap(vir_rcc);
     iounmap(vir_moder2);
    iounmap(vir_odr2);
    
    //字符设备驱动注销
    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/mychrdev",O_RDWR);

    if(fd < 0)
    {
        printf("设备文件打开失败\n");
        exit(-1);
    }
    while(1)
    {
        printf("请输入对LED1的控制命令1(开灯)0(关灯)>>> ");
        fgets(buf,sizeof(buf),stdin);
        buf[strlen(buf)-1] = '\0';
        write(fd,buf,sizeof(buf));

        printf("请输入对LED2的控制命令1(开灯)0(关灯)>>> ");
        fgets(buf+1,sizeof(buf),stdin);
        buf[strlen(buf)-1] = '\0';
        write(fd,buf,sizeof(buf));

        printf("请输入对LED3的控制命令1(开灯)0(关灯)>>> ");
        fgets(buf+2,sizeof(buf),stdin);
        buf[strlen(buf)-1] = '\0';
        write(fd,buf,sizeof(buf));
        memset(buf,0,sizeof(buf));
    }

    close(fd);   
    return 0;  
}

 

4.测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/999944.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5. HBase必知必会之理论进阶篇

HBase必知必会之理论进阶篇 1.1 集群搭建以及规模预测1.1.1 HBase集群搭建1.1.2 HBase集群规划 1.2 HBase重要的概念1.2.1 snapshot1.2.2 region 切分1.2.3 RIT1.2.4 HBase读优化1.2.4.1 客户端优化1.2.4.2 服务端优化1.2.4.3 hdfs 优化 1.2.5 HBase写优化1.2.5.1 客户端优化1.…

Linux centos7 bash编程训练__打印各类形状

利用for循环&#xff0c;打印各种不同的三角形、矩形和菱形。 主要是fort循环嵌套使用&#xff0c;及条件判断等。 因方法简单&#xff0c;不作更多解释&#xff0c;部分注释可以帮助初学者掌握代码。 下面列出代码&#xff0c;供参考。 #! /bin/bash ## 打印输出各种*型形…

中企出海,用火山引擎DataTester开启增长第一步

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 今年 Google 宣布其提供的A/B测试工具 Optimize 将在2023年9月30号停止服务。在全球化浪潮席卷下&#xff0c;越来越多的中国企业正在加速走向全球市场&#xff0c;…

使用 Webpack 从 0 到 1 构建 Vue3 项目 + ts

使用 Webpack 从 0 到 1 构建 Vue3 项目 1.初始化项目结构2.安装 webpack&#xff0c;补充智能提示3.初步编写 webpack.config.js3.1设置入口文件及出口文件3.2 指定 html 模板位置 4.配置 运行/打包 命令&#xff0c;首次打包项目5.添加 Vue 及相关配置5.1安装并引入 vue5.2 补…

一个详细且完整的公司局域网搭建案例,跟着操作!

局域网(Local Area Network&#xff0c;简称LAN)&#xff0c;用于将有限范围内&#xff08;例如一个实验室、一层办公楼或者校园&#xff09;的各种计算机、终端与外部设备互联成网。公司局域网怎么建立&#xff1f;首先来了解下不同规模企业网络组建方式。 10人以下企业网络组…

固定资产管理表怎么填写

在现代企业管理中&#xff0c;固定资产的管理是至关重要的环节。它不仅关系到企业运营的效率&#xff0c;也直接影响到企业的财务状况。因此&#xff0c;正确、有效地填写和管理固定资产管理表显得尤为重要。并提供一些创新的方法来优化这一过程。  让我们理解什么是固定资产…

Win10 cmd默认使用管理员身份运行的修改

一、在开始菜单搜索cmd&#xff0c;打开快捷方式文件位置 二、鼠标右键快捷方式&#xff0c;打开属性 三、选择高级&#xff0c;再勾选用管理员身份运行&#xff0c;点击确定即可

文心一言插件开发全流程,ERNIE-Bot-SDK可以调用文心一言的能力

文心一言插件开发 前言插件插件是什么工作原理申请开发权限 开始第一步&#xff1a;安装python第二步&#xff1a;搭建项目manifest 描述文件&#xff1a;ai-plugin.json插件服务描述文件&#xff1a;openapi.yaml开发自己的plugin-server 第三步&#xff1a;上传插件 SDK相关链…

记录一次开机内存分析的全过程

作者&#xff1a;zzy的学习笔记 记录一次开机内存分析的全过程&#xff0c;尽量详尽的介绍常用内存分析工具和命令行的使用&#xff0c;结合具体问题探讨开机内存分析的实践经验。通过这篇文章我会介绍开机内存的常用测试分析工具的基本使用方法&#xff0c;以及如何通过抓取出…

在UMG中播放图像序列,出现卡帧怎么办?

在虚幻引擎中播放图像序列 前期步骤可以参考上面链接中官方文档的步骤1-13 如果在媒体播放器中播放的时候&#xff0c;出现卡帧现象&#xff0c;说明你的图片序列的帧率与默认的不匹配 需要在lmg Media Source类型文件中&#xff0c;覆写你的帧率 比如&#xff0c;我的图片序…

VSCode错误整理

文章目录 一、zsh: command not found: python二、Python pip安装Django异常Could not find a version that satisfies the requirement pytz (from django)三、WARNING: You are using pip version 21.2.4, however version 23.2.1 is available.四、pip install django下载报…

Sui参会必备|Token 2049活动一览

TOKEN2049是在新加坡举办的一年一度首屈一指地加密货币活动&#xff0c;吸引了顶级的Web3公司和项目的创始人和高管&#xff0c;他们将在这里分享行业观点、聚焦全球发展&#xff0c;同时以独特且广泛的视角审视这个生态系统及其广阔的机会。 自5月份主网上线以来&#xff0c;S…

lv3 嵌入式开发-11 Linux下GDB调试工具

目录 1 GDB简介 2 GDB基本命令 3 GDB调试程序 1 GDB简介 GDB是GNU开源组织发布的一个强大的Linux下的程序调试工具。 一般来说&#xff0c;GDB主要帮助你完成下面四个方面的功能&#xff1a; 1、启动你的程序&#xff0c;可以按照你的自定义的要求随心所欲的运行程序&#…

七、MySql表的内置函数

文章目录 一、日期函数&#xff08;一&#xff09;常用日期函数1.获得年月日&#xff1a;2.获得时分秒&#xff1a;3.获得时间戳&#xff1a;4.在日期的基础上加日期&#xff1a;5.在日期的基础上减去时间&#xff1a;6.计算两个日期之间相差多少天 &#xff08;二&#xff09;…

基于Spring Boot 3.1.0的Dubbo代码实现(以Redis作为注册中心)

目录 基于Spring Boot 3.1.0的Dubbo代码实现&#xff08;以Redis作为注册中心&#xff09;一 简介二 前言三 文档查阅四 依赖项1 注意事项2 版本3 dependencyManagement依赖4 dependency依赖 五 配置文件1 注意事项2 代码 六 yml文件 基于Spring Boot 3.1.0的Dubbo代码实现&…

RRU-Net:The Ringed Residual U-Net for Image Splicing Forgery Detection阅读笔记一

文章目录 1. Introduction2. Related Work3. The Ringed Residual U-Net (RRU-Net)3.1. Residual Propagation3.2. Residual Feedback3.3. Ringed Residual Structure and Network Architectures 4. Evaluation Experiment and Comparative Analysis 1. Introduction 根据现有…

Golang 常用的几种密码加密方式

加密方式 加密有两种方式&#xff0c;一种是直接加密&#xff0c;一种是盐值加密 **直接加密&#xff08;Plain Hashing&#xff09;**指的是将原始密码直接进行加密&#xff0c;而不进行任何额外的操作。这种方式可能存在一些安全风险&#xff0c;因为相同的密码在经过加密后…

STM32F4X DMA

STM32F4X DMA 什么是DMASTM32F4X DMADMA框图DMA通道DMA仲裁器DMA FIFO DMA传输模式DMA传输方向存储器到存储器存储器到外设外设到存储器 DMA循环模式和普通模式循环模式&#xff08;Circular&#xff09;普通模式&#xff08;Normal&#xff09; DMA源、目标寄存器增量模式DMA例…

一文简介,数字时代的数据交易模式

在数字时代&#xff0c;数据作重要的信息和资源&#xff0c;未来获得更高质量的数据资源&#xff0c;数据交易越来越常见&#xff0c;数据也成为企业重要的无形资产。 2022年3月出台的《中共中央、国务院关于加快建设全国统一大市场的意见》强调要加快培育数据要素市场&#xf…

Zabbix登录绕过漏洞复现(CVE-2022-23131)

0x00 前言 最近在复现zabbix的漏洞&#xff08;CVE-2022-23131&#xff09;&#xff0c;偶然间拿到了国外某公司zabbix服务器。Zabbix Sia Zabbix是拉脱维亚Zabbix SIA&#xff08;Zabbix Sia&#xff09;公司的一套开源的监控系统。该系统支持网络监控、服务器监控、云监控和…