STM32MP157A-FSMP1A单片机移植Linux系统SPI总线驱动

news2025/2/26 21:54:03

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));//给从机发送一个数据,让最左边数码管显示数字5
    printk("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;
}

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

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

相关文章

java医院多维度综合绩效考核源码,医院绩效管理系统,支持一键核算和批量操作,设有审核机制,允许数据修正

医院绩效考核管理系统&#xff0c;java医院绩效核算系统源码&#xff0c;采用多维度综合绩效考核的形式&#xff0c;针对院内实际情况分别对工作量、KPI指标、科研、教学、管理等进行全面考核。医院可结合实际需求&#xff0c;对考核方案中各维度进行灵活配置&#xff0c;对各维…

C语言学习笔记-初阶(13)scanf介绍

当我们有了变量&#xff0c;我们需要给变量输入值就可以使用 scanf 函数&#xff0c;如果需要将变量的值输出在屏幕上的时候可以使用 printf 函数&#xff0c;下面看⼀个例子&#xff1a; #include <stdio.h> int main() {int score 0;printf("请输⼊成绩:")…

如何让传统制造企业从0到1实现数字化突破?

随着全球制造业不断向智能化、数字化转型&#xff0c;传统制造企业面临着前所未有的机遇与挑战。数字化转型不仅是技术的革新&#xff0c;更是管理、文化、业务流程等全方位的变革。从零开始&#xff0c;如何带领一家传统制造企业走向数字化突破&#xff0c;是许多企业领导者面…

【HarmonyOS Next】鸿蒙应用公钥和证书MD5指纹的获取

【HarmonyOS Next】鸿蒙应用公钥和证书MD5指纹的获取 一、问题背景 政府的icp备案时&#xff0c;或者某些三方SDK以来的管理后台&#xff0c;都需要配置鸿蒙应用的公钥和证书MD5指纹 二、解决方案 专有名词解释&#xff1a; 华为AppGallery Connect简称 AGC平台&#xff0…

【原创工具】同文件夹PDF文件合并 By怜渠客

【原创工具】同文件夹PDF文件合并 By怜渠客 原贴&#xff1a;可批量合并多个文件夹内的pdf工具 - 吾爱破解 - 52pojie.cn 他这个存在一些问题&#xff0c;并非是软件内自主实现的PDF合并&#xff0c;而是调用的pdftk这一工具&#xff0c;但楼主并没有提供pdftk&#xff0c;而…

【红队利器】单文件一键结束火绒6.0

关于我们 4SecNet 团队专注于网络安全攻防研究&#xff0c;目前团队成员分布在国内多家顶级安全厂商的核心部门&#xff0c;包括安全研究领域、攻防实验室等&#xff0c;汇聚了行业内的顶尖技术力量。团队在病毒木马逆向分析、APT 追踪、破解技术、漏洞分析、红队工具开发等多个…

Linux中文件目录类指令

1、pwd指令 基本语法&#xff1a;pwd 功能&#xff1a;显示当前工作目录的绝对路径 1.相对路径访问和绝对路径访问 当前处于home目录下&#xff0c;访问a.txt文件 相对路径访问&#xff1a;kim/better/a.txt&#xff0c;从当前位置开始定位 绝对路径访问&#xff1a;/home…

开源模型应用落地-LangChain实用小技巧-获取token消耗(五)

一、前言 在当今的自然语言处理领域&#xff0c;LangChain 框架因其强大的功能和灵活性而备受关注。掌握一些实用的小技巧&#xff0c;能够让您在使用 LangChain 框架时更加得心应手&#xff0c;从而更高效地开发出优质的自然语言处理应用。 计算 Token 消耗对有效管理和优化语…

LangChain大模型应用开发:LangGraph快速构建Agent工作流应用

介绍 大家好&#xff0c;博主又来给大家分享知识了。今天给大家分享的内容是使用LangChain进行大规模应用开发中的LangGraph快速构建Agent工作流应用。 通过对前几次对LangChain的技术分享。我们知道LangChain作为一个强大的工具集&#xff0c;为开发者们提供了丰富的资源和便…

鸿蒙Next-方法装饰器以及防抖方法注解实现

以下是关于 鸿蒙Next&#xff08;HarmonyOS NEXT&#xff09;中 MethodDecorator 的详细介绍及使用指南&#xff0c;结合了多个技术来源的实践总结&#xff1a; 一、MethodDecorator 的概念与作用 MethodDecorator 是鸿蒙Next框架中用于装饰类方法的装饰器&#xff0c;属于 Ark…

计算机网络:应用层 —— 电子邮件

文章目录 电子邮件的起源与发展电子邮件的组成电子邮件协议邮件发送和接收过程邮件发送协议SMTP协议多用途因特网邮件扩展MIME 电子邮件的信息格式 邮件读取协议邮局协议POP因特网邮件访问协议IMAP 基于万维网的电子邮件 电子邮件&#xff08;E-mail&#xff09;是因特网上最早…

zyNo.26

[GXYCTF2019]Ping Ping Ping&#xff08;Web&#xff09; 传/&#xff1f;ip1有ping回显&#xff0c;说明后端可能通过php参数接受了ip参数&#xff0c;并且拼接到了最终执行的命令里形成了ping -c 3$ip&#xff0c;这样可能存在一个命令注入漏洞 要判断是否符合 ping -c 3$ip …

ui设计公司兰亭妙微分享:科研单位UI界面设计

科研单位的UI界面设计是一项至关重要的任务&#xff0c;它不仅关乎科研工作的效率&#xff0c;还直接影响到科研人员的用户体验。以下是对科研单位UI界面设计的详细分析&#xff1a; 一、设计目标 科研单位的UI界面设计旨在提升科研工作的效率与便捷性&#xff0c;同时确保科…

OpenGL ES -> GLSurfaceView绘制点、线、三角形、正方形、圆(顶点法绘制)

XML文件 <?xml version"1.0" encoding"utf-8"?> <com.example.myapplication.MyGLSurfaceViewxmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"…

AndroidAOSP定制隐藏某个应用的图标

AndroidAOSP定制隐藏某个应用的图标 1.前言: 之前在做AOSP定制的时候需要隐藏某些App的图标&#xff0c;或者默认不显示某个定制的App图标&#xff0c;这样可以让用户感觉不到已经安装了某个App,或者在做系统定制的时候需要修改桌面icon,有些系统的App图标默认不需要显示&…

最小化重投影误差求解PnP

问题描述 已知n个空间点 P i [ x i , y i , z i ] T P_i[x_i,y_i,z_i]^T Pi​[xi​,yi​,zi​]T&#xff0c;其投影的像素坐标 p i [ u i , v i ] T p_i[u_i,v_i]^T pi​[ui​,vi​]T求相机的位姿R&#xff0c;T。 问题分析 根据相机模型&#xff0c;像素点和空间点的位置…

unity学习52:UI的最基础组件 rect transform,锚点anchor,支点/轴心点 pivot

目录 1 image 图像&#xff1a;最简单的UI 1.1 图像的基本属性 1.2 rect transform 1.3 image的component: 精灵 → 图片 1.4 修改颜色color 1.5 修改材质 1.6 raycast target 1.7 maskable 可遮罩 1.8 imageType 1.9 native size 原生大小 2 rect transform 2.1 …

【Python系列】PYTHONUNBUFFERED=1的作用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Linux中的cgdb的基本使用

1.cgdb的简介 Linux中的cgdb是一个基于GDB&#xff08;GNU Debugger&#xff09;的图形化调试前端&#xff0c;它结合了GDB的命令行界面功能和代码查看窗口&#xff0c;为开发者提供了一个更为直观的调试体验。 cgdb的作用和功能&#xff1a; 直观调试体验&#xff1a;cgdb提供…

解决idea2019创建springboot项目爆红的问题

通过spring Initializr创建springboot项目时&#xff0c;由于idea版本太低&#xff0c;创建完成后需要手动修改pom.xml&#xff0c;对小白不太友好 一个简便的方法&#xff0c;配置好pom.xml文件的各个版本&#xff1a; 在 https://start.aliyun.com/ 上选择好后复制pom.xml代…