STM32MP15-FSMP1A单片机移植Linux系统platform总线驱动
之前在该单片机下移植的Linux驱动是学习过程中,对Linux内核驱动的引导学习,接下来才是比较正常的驱动开发。
在Linux内核中,对于驱动的处理,一般会通过总线进行设备信息和设备驱动的匹配,来达到自动检测外设连接系统以及驱动外设的效果,设备信息由内核设备树写入,内核驱动则对设备树信息进行相关的注册、注销等操作,实现效果:设备信息包含可控制的gpio或i2c,驱动对gpio进行高低电平的控制或进行i2c通信获取从机数据。

上图是Linux内核驱动使用内核自带总线驱动进行处理时的处理方式,其中由I2C、PWM等总线驱动,但是实际使用时很多外设驱动不在自带的总线驱动中,因此引入platform虚拟总线驱动以实现相关功能。

这里可以看出platform虚拟总线和Linux内核总线的处理方式基本一致。
Linux设备树文件-->stm32mp157a-fsmp1a.dts
新增设备信息
/dts-v1/;
#include "stm32mp157.dtsi"
#include "stm32mp15xa.dtsi"
#include "stm32mp15-pinctrl.dtsi"
#include "stm32mp15xxac-pinctrl.dtsi"
#include "stm32mp15xx-fsmp1x.dtsi"
/ {model = "HQYJ STM32MP157 FSMP1A Discovery Board";compatible = "st,stm32mp157a-fsmp1a", "st,stm32mp157";aliases {serial0 = &uart4;serial5 = &usart3;};chosen {stdout-path = "serial0:115200n8";};reserved-memory {gpu_reserved: gpu@d4000000 {reg = <0xd4000000 0x4000000>;no-map;};optee_memory: optee@0xde000000 {reg = <0xde000000 0x02000000>;no-map;};};//测试platform设备驱动myplatform {compatible = "johnson,myplatform_test";led1_gpio = <&gpioe 10 0>;};
};
以上代码为测试使用设备树信息,其中myplatform为设备名,compatible为设备信息,led1_gpio为该设备控制的gpio为PE10
驱动源码
#include <linux/init.h> // 包含内核初始化相关的头文件
#include <linux/module.h> // 包含内核模块相关的头文件
#include <linux/of.h> // 包含设备树操作相关的头文件
#include <linux/gpio.h> // 包含 GPIO 操作相关的头文件
#include <linux/of_gpio.h> // 包含设备树 GPIO 相关的头文件
#include <linux/fs.h> // 包含文件操作相关的头文件
#include <linux/uaccess.h> // 包含用户空间访问内核空间相关的头文件
#include <linux/device.h> // 包含设备相关的头文件
#include <linux/platform_device.h> // 包含 platform 设备相关的头文件
#include "platform_test.h" // 包含自定义头文件//字符设备
static int major; // 定义主设备号
//class类
static struct class *led_class; // 定义类指针
//device节点
static struct device *led_device; // 定义设备指针
//编写gpio_desc设备
struct gpio_desc *gdesc;static int led_open(struct inode *inode, struct file *file)
{printk("led_open\n");return 0;
}static int led_close(struct inode *inode, struct file *file)
{printk("led_close\n");return 0;
}static int led_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{printk("led_read\n");return 0;
}static int led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{printk("led_write\n");return 0;
}static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{switch(cmd){case LED_ON:gpiod_set_value(gdesc, 1);break;case LED_OFF:gpiod_set_value(gdesc, 0);break;default:break;}printk("led_ioctl\n");return 0;
}//定义file_operations结构体
struct file_operations fops = {.owner = THIS_MODULE,.open = led_open,.release = led_close,.read = led_read,.write = led_write,.unlocked_ioctl = led_ioctl,
};//编写platform设备驱动
static int mydriver_probe(struct platform_device *pdev)
{printk("mydriver_probe\n");//注册字符设备major = register_chrdev(0, "leds_control", &fops); if(major < 0){printk("register_chrdev failed\n");return -ENODEV;}//创建类led_class = class_create(THIS_MODULE, "leds_control");if (IS_ERR(led_class)){printk("class_create failed\n");unregister_chrdev(major, "leds_control");return -ENODEV;}//创建设备节点led_device = device_create(led_class, NULL, MKDEV(major, 0), NULL, "leds_control");if (IS_ERR(led_device)){printk("device_create failed\n");class_destroy(led_class);unregister_chrdev(major, "leds_control");return -ENODEV;} gdesc = gpiod_get_from_of_node(pdev->dev.of_node, "led1_gpio", 0, GPIOD_OUT_HIGH, NULL);if (IS_ERR(gdesc)){printk("gpiod_get_from_of_node failed\n");class_destroy(led_class);device_destroy(led_class, MKDEV(major, 0));unregister_chrdev(major, "leds_control");return PTR_ERR(gdesc);}printk("gpiod_get_from_of_node success\n");return 0;
}static int mydriver_remove(struct platform_device *pdev)
{printk("mydriver_remove\n");gpiod_set_value(gdesc, 0);gpiod_put(gdesc);device_destroy(led_class, MKDEV(major, 0));class_destroy(led_class);unregister_chrdev(major, "leds_control");return 0;
}static const struct of_device_id myplatform_test_match_table[] = {{ .compatible = "johnson,myplatform_test", },{ /* sentinel */ }
};struct platform_driver mydriver = {.probe = mydriver_probe,.remove = mydriver_remove,.driver = {.name = "myplatform",.of_match_table = myplatform_test_match_table,},
};/* static __init int mydriver_init(void)
{platform_driver_register(&mydriver);return 0;
}static __exit void mydriver_exit(void)
{platform_driver_unregister(&mydriver);
}module_init(mydriver_init);
module_exit(mydriver_exit); *///一键注册宏定义
module_platform_driver(mydriver);
MODULE_LICENSE("GPL");
驱动头文件
#ifndef __PLATFROM_H__
#define __PLATFROM_H__#define LED_ON _IO('l', 1)
#define LED_OFF _IO('l', 0)#endif
应用程序-->实现1s控制LED灯亮灭
#include<stdlib.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<unistd.h>
#include<string.h>
#include<sys/ioctl.h>
#include "platform_test.h" // 包含自定义头文件int main(int argc,const char * argv[])
{int fd;fd = open("/dev/leds_control", O_RDWR); // 打开设备文件if(fd < 0) // 如果打开设备文件失败{perror("open"); // 打印错误信息return -1; // 返回错误码}printf("open success\n"); // 打印打开设备文件成功的消息while(1){ioctl(fd, LED_ON); // 打开 LED1sleep(1); // 等待 1 秒ioctl(fd, LED_OFF); // 关闭 LED1sleep(1); // 等待 1 秒}return 0;
}
相关文章:
STM32MP15-FSMP1A单片机移植Linux系统platform总线驱动
之前在该单片机下移植的Linux驱动是学习过程中,对Linux内核驱动的引导学习,接下来才是比较正常的驱动开发。 在Linux内核中,对于驱动的处理,一般会通过总线进行设备信息和设备驱动的匹配,来达到自动检测外设连接系统以…...
Java 常见的面试题(设计模式)
一、说一下你熟悉的设计模式? **设计模式:**是一套被反复使用的代码设计经验的总结(情境中一个问题经过证实的一个解决方案)。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式使人们可以更加简…...
机器学习3-聚类
1 聚类解决的问题 知识发现,发现事物之间的潜在关系异常值检测特征提取 数据压缩的例子新闻自动分组、用户分群、图像分割、像素压缩等等 2 与监督学习比较 监督学习是需要给定X、Y,X为特征,Y为标签,选择模型,学习&a…...
html中的css
css (cascading style sheets,串联样式表,也叫层叠样式表) css规范一般约定: 1.存放CSS样式文件的目录一般命名为style或css。 2.在项目初期,会把不同类别的样式放于不同的CSS文件,是为了CSS编…...
36. Spring Boot 2.1.3.RELEASE 中实现监控信息可视化并添加邮件报警功能
1. 创建 Spring Boot Admin Server 项目 1.1 添加依赖 在 pom.xml 中添加 Spring Boot Admin Server 和邮件相关依赖: <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-w…...
Linux: 已占用接口
Linux: 已占用接口 1. netstat(适用于旧系统)1.1 书中对该命令的介绍 2. ss(适用于新系统,替代 netstat)3. lsof(查看详细进程信息)4. fuser(快速查找占用端口的进程)5. …...
Vscode的通义灵码占用空间过大问题【.lingma】
C盘空间发现没装几个软件但是空间占用太离谱了, 最后排查发现是一个.lingma的文件夹问题,这个文件夹用了我居然差不多一百G的空间, 点进去。删除掉ai训练时产生的dbc文件就好了, windowsI 打开系统设置,搜索存储&#…...
鸿蒙Next如何自定义标签页
前言 项目需求是展示标签,标签的个数不定,一行展示不行就自行换行。但是,使用鸿蒙原生的 Grid 后发现特别的难看。然后就想着自定义控件。找了官方文档,发现2个重要的实现方法,但是,官方的demo中讲的很少&…...
知识拓展:Python 接口实现方式对比:Protocol vs @implementer
Python 接口实现方式对比:Protocol vs implementer 1. 两种接口实现方式 1.1 Python Protocol(结构化子类型) from typing import Protocolclass DownloadHandlerProtocol(Protocol):def download_request(self, request: Request, spider:…...
开源程序wordpress在海外品牌推广中的重要作用
WordPress作为全球最流行的开源内容管理系统(CMS),在全球网站搭建中占据超过40%的市场份额。其强大的功能、灵活性和易用性使其成为企业进行海外品牌推广的首选平台。以下是WordPress在海外品牌推广中的重要性分析: 1. 多语言支持与本地化 WordPress通…...
【Python爬虫(89)】爬虫“反水”:助力数字版权保护的逆向之旅
【Python爬虫】专栏简介:本专栏是 Python 爬虫领域的集大成之作,共 100 章节。从 Python 基础语法、爬虫入门知识讲起,深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑,覆盖网页、图片、音频等各类数据爬取ÿ…...
k8s面试题总结(五)
1.考虑一种情况,即公司希望通过维持最低成本来提高其效率和技术运营速度。您认为公司将如何实现这一目标? 公司可以通过构建 CI/CD 管道来实现 DevOps 方法,但是这里可能出现的一个问题是配置可能需要一段时间才能启动并运行。 因此&#x…...
文章精读篇——用于遥感小样本语义分割的可学习Prompt
题目:Learnable Prompt for Few-Shot Semantic Segmentation in Remote Sensing Domain 会议:CVPR 2024 Workshop 论文:10.48550/arXiv.2404.10307 相关竞赛:https://codalab.lisn.upsaclay.fr/competitions/17568 年份&#…...
Spring Boot2.0之十 使用自定义注解、Json序列化器实现自动转换字典类型字段
前言 项目中经常需要后端将字典类型字段值的中文名称返回给前端。通过sql中关联字典表或者自定义函数不仅影响性能还不能使用mybatisplus自带的查询方法,所以推荐使用自定义注解、Json序列化器,Spring的缓存功能实现自动转换字典类型字段。以下实现Spri…...
从电子管到量子计算:计算机技术的未来趋势
计算机发展的历史 自古以来人类就在不断地发明和改进计算工具,从结绳计数到算盘,计算尺,手摇计算机,直到1946年第一台电子计算机诞生,虽然电子计算机至今虽然只有短短的半个多世纪,但取得了惊人的发展吗,已经经历了五代的变革。计算机的发展和电子技术的发展密切相关,…...
将CUBE或3DL LUT转换为PNG图像
概述 在大部分情况下,LUT 文件通常为 CUBE 或 3DL 格式。但是我们在 OpenGL Shader 中使用的LUT,通常是图像格式的 LUT 文件。下面,我将教大家如何将这些文件转换为 PNG 图像格式。 条形LUT在线转换(不是8x8网络)&am…...
python文件的基本操作,文件读写
1.文件 1.1文件就是存储在某种长期存储设备上的一段数据 1.2文件操作 打开文件-->读写文件-->关闭文件 注意:可以只打开和关闭文件不进行任何操作 1.3文件对象的方法 1.open():创建一个file对象,默认以只读模式打开 2.read(n):n表示从文件中…...
华为认证考试证书下载步骤(纸质+电子版)
华为考试证书可以通过官方渠道下载相应的电子证书,部分高级认证如HCIE还支持申请纸质证书。 一、华为电子版证书申请步骤如下: ①访问华为培训与认证网站 打开浏览器,登录华为培训与认证官方网站 ②登录个人账号 在网站首页,点…...
正式页面开发-登录注册页面
整体路由设计: 登录和注册的切换是切换组件或者是切换内容(v-if和 v-else),因为点击两个之间路径是没有变化的。也就是登录和注册共用同一个路由。登录是独立的一级路由。登录之后进到首页,有三个大模块:文章分类&…...
nss刷题5(misc)
[HUBUCTF 2022 新生赛]最简单的misc 打开后是一张图片,没有其他东西,分离不出来,看看lsb,红绿蓝都是0,看到头是png,重新保存为png,得到一张二维码 扫码得到flag [羊城杯 2021]签到题 是个动图…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
