STM32MP157A-FSMP1A单片机移植Linux系统SPI总线驱动
SPI总线驱动整体上与I2C总线驱动类型,差别主要在设备树和数据传输上,由于SPI是由4根线实现主从机的通信,在设备树上配置时需要对SPI进行设置。
原理图可知,数码管使用的SPI4对应了单片机上的PE11-->SPI4-NSS,PE12-->SPI4-SCK,PE13-->SPI4-MISO,PE14-->SPI4-MOSI
设备树信息
需要注意在SPI4设备树信息中,一定要加spi-max-frequency属性,该属性用于设置spi的主频,如果没有,可能出现无法正常启动spi或启动spi后控制数码管时,数码管显示出现错位现象
驱动源码
#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/cdev.h> // 包含字符设备相关的头文件
#include <linux/slab.h> // 包含内存分配相关的头文件
#include <linux/spi/spi.h> // 包含 SPI 相关的头文件
#include "spi_test.h" // 包含自定义头文件//创建设备号
static int major;
//创建类
static struct class *cls;
//创建设备
static struct device *device;
//创建SPI设备
static struct spi_device *spi_dev;
//保存字符设备数据
static char spi_buf[128];static int myspi_open(struct inode *inode, struct file *file)
{unsigned int cmajor;//保存次设备号cmajor = iminor(inode);//将次设备号保存到file结构体的private_data中file->private_data = (void *)cmajor;printk("spi_open\n");return 0;
}static int myspi_close(struct inode *inode, struct file *file)
{printk("spi_close\n");return 0;
}static ssize_t myspi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{unsigned int ret;//从内核空间读取数据到用户空间,如果读取数据的长度大于spi_buf的长度,按照最大长度读取if(count > sizeof(spi_buf)){count = sizeof(spi_buf);}ret = copy_to_user(buf, spi_buf, count);if(ret < 0){printk("copy_to_user failed\n");return -1;}printk("spi_read\n");return 0;
}static ssize_t myspi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{unsigned int ret;//将用户空间的数据拷贝到内核空间,如果传输数据的长度大于spi_buf的长度,按照最大长度传输if (count > sizeof(spi_buf)){count = sizeof(spi_buf);}ret = copy_from_user(spi_buf, buf, count);if (ret < 0){printk("copy_from_user failed\n");return -1;}printk("spi_write\n");return 0;
}static int myspi_write_data(const uint8_t cmd, const uint8_t data)
{uint8_t spi_buf1[2] = {cmd, data};int ret = 0;printk("cmd = %x\n", spi_buf1[0]);ret = spi_write(spi_dev, spi_buf1, 2);return ret;
}static long myspi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{uint8_t data;unsigned long ret ;//从用户空间读取数据ret = copy_from_user(&data, (void *)arg, sizeof(data));if (ret < 0){printk("copy_from_user failed\n");return -1;}//根据cmd的值进行不同的操作 switch (cmd){case SET_DAT0:ret = myspi_write_data(0x01, data);break;case SET_DAT1:ret = myspi_write_data(0x02, data);break;case SET_DAT2:ret = myspi_write_data(0x04, data);break;case SET_DAT3:ret = myspi_write_data(0x08, data);break; case SET_DAT4:ret = myspi_write_data(0x0f, data);break;default:break;}if (ret != 0){printk("spi_write failed\n");return -1;}printk("spi_ioctl, data = %x\n", data);return 0;
}//定义file_operations结构体
struct file_operations fops = {.owner = THIS_MODULE,.open = myspi_open,.release = myspi_close,.read = myspi_read,.write = myspi_write,.unlocked_ioctl = myspi_ioctl,
};//编写spi设备驱动
int myspi_probe(struct spi_device *spi)
{//unsigned char buf[]={0X01,0X6D};//0X01表示写数据,0X6D表示写入的数据//spi_write(spi,buf,sizeof(buf));//给从机发送一个数据,让最左边数码管显示数字5printk("myspi_probe\n");spi_dev = spi;//1.创建设备号major = register_chrdev(0, "myspi", &fops);if (major < 0){printk("register_chrdev failed\n");return -1;}//2.创建类cls = class_create(THIS_MODULE, "myspi");if (IS_ERR(cls)){printk("class_create failed\n");unregister_chrdev(major, "myspi");return -1;}//3.创建设备device = device_create(cls, NULL, MKDEV(major, 0), NULL, "myspi");if (IS_ERR(device)){printk("device_create failed\n");class_destroy(cls);unregister_chrdev(major, "myspi");return -1;}return 0;
}int myspi_remove(struct spi_device *spi)
{printk("myspi_remove\n"); device_destroy(cls, MKDEV(major, 0));class_destroy(cls);unregister_chrdev(major, "myspi");return 0;
}static const struct of_device_id spi_table[] = {{ .compatible = "johnson,m74hc595", },{ /* sentinel */ },
};struct spi_driver myspi_driver = {.probe = myspi_probe,.remove = myspi_remove,.driver = {.name = "m74hc595",.of_match_table = spi_table,},
};//一键注册宏定义
module_spi_driver(myspi_driver);
MODULE_LICENSE("GPL"); //声明开源许可
头文件
#ifndef __SPITEST_H__
#define __SPITEST_H__#define SET_DAT0 _IOW('s', 0, int)
#define SET_DAT1 _IOW('s', 1, int)
#define SET_DAT2 _IOW('s', 2, int)
#define SET_DAT3 _IOW('s', 3, int)
#define SET_DAT4 _IOW('s', 4, int)#endif
应用程序 --> 实现在数码管上依次显示数字
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include "spi_test.h"const uint8_t num[10] = {0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F};int main()
{int fd = 0;int date = 0;//打开设备文件fd = open("/dev/myspi", O_RDWR);if (fd < 0){printf("open myspi failed\n");return -1;}while(1){ioctl(fd, SET_DAT0, &num[date]);sleep(1);ioctl(fd, SET_DAT1, &num[date]);sleep(1);ioctl(fd, SET_DAT2, &num[date]);sleep(1);ioctl(fd, SET_DAT3, &num[date]);sleep(1);ioctl(fd, SET_DAT4, &num[date]);if (++date > 9){date = 0;}sleep(1);} //关闭设备文件close(fd);return 0;
}
相关文章:

STM32MP157A-FSMP1A单片机移植Linux系统SPI总线驱动
SPI总线驱动整体上与I2C总线驱动类型,差别主要在设备树和数据传输上,由于SPI是由4根线实现主从机的通信,在设备树上配置时需要对SPI进行设置。 原理图可知,数码管使用的SPI4对应了单片机上的PE11-->SPI4-NSS,PE12-->SPI4-S…...

系统基础与管理(2025更新中)
一、Linux 核心架构与组件 内核架构 核心职责: 管理进程生命周期、内存分配、硬件驱动交互及文件系统操作。 模块化设计支持动态加载硬件驱动(如modprobe加载内核模块),提升灵活性和扩展性。 内存管理:…...
Python--内置函数与推导式(下)
3. 内置函数 数学运算类 函数说明示例abs绝对值abs(-10) → 10pow幂运算pow(2, 3) → 8sum求和sum([1,2,3]) → 6divmod返回商和余数divmod(10, 3) → (3, 1) 数据转换类 # 进制转换 print(bin(10)) # 0b1010 print(hex(255)) # 0x…...

可狱可囚的爬虫系列课程 14:10 秒钟编写一个 requests 爬虫
一、前言 当重复性的工作频繁发生时,各种奇奇怪怪提高效率的想法就开始萌芽了。当重复代码的模块化封装已经不能满足要求的时候,更高效的方式就被揭开了神秘的面纱。本文基于这样的想法,来和大家探讨如何 10 秒钟编写一个 requests 爬虫程序。…...

Windows golang安装和环境配置
【1】、golang 1.19 sdk下载 https://download.csdn.net/download/notfindjob/90422529 【2】、安装 【3】、配置 GOPATH目录 【4】、LiteIDE下载安装 https://download.csdn.net/download/notfindjob/90422580 【5】、打开LiteIDE,选择查看->管理GOPATH&…...

IP-------GRE和MGRE
4.GRE和MGRE 1.应用场景 现实场景 居家工作,公司工作,分公司工作----------需要传输交换数据--------NAT---在该场景中需要两次NAT(不安全) 为了安全有两种手段-----1.物理专线---成本高 2.VPN--虚拟专用网---隧道技术--封装技…...

LabVIEW形状误差测量系统
在机械制造领域,形状与位置公差(GD&T)直接影响装配精度与产品寿命。国内中小型机加工企业因形状误差导致的返工率高达12%-18%。传统测量方式存在以下三大痛点: 设备局限:机械式千分表需人工读数,精度…...

django校园互助平台~源码
博主介绍:✌程序猿徐师兄、8年大厂程序员经历。全网粉丝15w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
Vue进阶之AI智能助手项目(五)——ChatGPT的调用和开发
AI智能助手项目 前端页面Layout布局页面-viewssrc/views/chat/layout/Permission.vuesrc/views/chat/layout/sider/index.vuesrc/views/chat/layout/sider/List.vuesrc/views/chat/layout/sider/Footer.vueComponents 组件Header/index.vueMessage/index.vue前端页面 Layout布…...
Jenkins重启后Maven的Project加载失败
个人博客地址:Jenkins重启后Maven的Project加载失败 | 一张假钞的真实世界 Jenkins重启后发现Maven的项目都没有正常加载。检查Jenkins的启动日志发现以下错误信息: java.io.IOException: Unable to read /home/jenkins/.jenkins/jobs/test-maven/conf…...

【docker】docker pull拉取中不断重复下载问题,解决方案之一,磁盘空间扩容
问题类似这样 存储空间不足 如果 Docker 运行环境的磁盘空间不足,拉取的镜像可能会被自动清理,导致重复下载。可以检查磁盘使用情况: df -h docker system df如果空间不足,可以清理一些不用的容器和镜像: docker sy…...
Ubuntu指令(一)
一、终端操作指令 打开终端,有两种便捷方式: 直接点击系统中的终端按钮;使用快捷键ctrl alt T。 关闭终端,同样有多种选择: 在终端输入exit指令;使用快捷键ctrl d;直接点击终端窗口的关闭…...

nnUNet V2修改网络——加入MultiResBlock模块
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 MultiRes Block 是 MultiResUNet 中核心组件之一,旨在解决传统 U-Net 在处理多尺度医学图像时的局…...

Spring Boot + Vue 接入腾讯云人脸识别API(SDK版本3.1.830)
一、需求分析 这次是基于一个Spring Boot Vue的在线考试系统进行二次开发,添加人脸识别功能以防止学生替考。其他有对应场景的也可按需接入API,方法大同小异。 主要有以下两个步骤: 人脸录入:将某个角色(如学生&…...

【SpringSecurity】springboot整合SpringSecurity实现登录校验与权限认证
【SpringSecurity】springboot整合SpringSecurity实现登录校验与权限认证 【一】SpringSecurity框架简介【二】SpringSecurity与shiro【1】SpringSecurity特点【2】shiro特点【3】SpringSecurity和shiro总结 【三】SpringSecurity过滤器【1】SpringSecurity中常见的过滤器【2】…...

【HarmonyOS Next】鸿蒙应用公钥和证书MD5指纹的获取
【HarmonyOS Next】鸿蒙应用公钥和证书MD5指纹的获取 一、问题背景 政府的icp备案时,或者某些三方SDK以来的管理后台,都需要配置鸿蒙应用的公钥和证书MD5指纹 二、解决方案 专有名词解释: 华为AppGallery Connect简称 AGC平台࿰…...
父组件用的是原生监听,子组件用的是onClick,子组件添加了stopPropagation还是没有阻止传播
父组件用事件监听,子组件用onClick,即使子组件加了stopPropagation还是没有阻止冒泡。父组件可能使用原生的addEventListener来绑定事件,而子组件用的是React的onClick事件。这时候,虽然子组件调用了e.stopPropagation()ÿ…...

ui设计公司兰亭妙微分享:科研单位UI界面设计
科研单位的UI界面设计是一项至关重要的任务,它不仅关乎科研工作的效率,还直接影响到科研人员的用户体验。以下是对科研单位UI界面设计的详细分析: 一、设计目标 科研单位的UI界面设计旨在提升科研工作的效率与便捷性,同时确保科…...

python绘制年平均海表温度、盐度、ph分布图
python绘制年平均海表温度、盐度、ph图 文章目录 python绘制年平均海表温度、盐度、ph分布图前言一、数据准备二、代码编写2.1. python绘制年平均海表温度(主要)2.2. python绘制年平均海表盐度(选看)2.3. python绘制年平均海表ph&…...

windows中kafka集群部署示例
注意 kafka包路径不要太长,不然启动时候 这里再单独下个zookeeper做为三个kafka实例broker的注册中心 修改Zookeeper配置文件 脚本内容 call bin/zkServer.cmd 不然的话就进bin目录双击zkServer.cmd 配置Zookeeper的另外一种方式 用Kafka自带的zookeeper 例如我复制一份 …...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...

push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...