Linux系统驱动(十八)SPI总线(未整理)

news2024/9/23 1:32:35

文章目录

  • 一、SPI总线协议简介
  • 二、SPI子系统驱动
    • (二)SPI子系统API
    • (三)SPI设备树节点
  • 三、代码示例

一、SPI总线协议简介

高速、同步、全双工、非差分、总线式
传输速度在几十M

差分总线和非差分总线
非差分总线:受压降影响,通信距离短,IIC、SPI、UART
差分总线:抗干扰能力较强,传输距离相对较远,

485总线理论上可以传输1200m

DB9就是串口,有9个引脚,

四根线

四种工作模式,
MODE0和MODE3常用,

spi总线特点

SPI 是串行外设接口(Serial Peripheral Interface)的缩写。它

是 Motorola 公司推出的一种同步串行接口技术,是一种高

速的,全双工,同步的通信总线。

SPI优点:

支持全双工通信,通信简单,数据传输速率快

1):高速、同步、全双工、非差分、总线式

2):主从机通信模式

缺点:

没有指定的流控制,没有应答机制确认是否接收到数据,

所以跟IIC总线协议比较在数据的可靠性上有一定的缺陷。

spi管脚及模式

可以一主机多从机,具体和那个从机通讯通过cs片选决定。

MISO :主机输入,从机输出

MOSI :主机输出,从机输入

SCK :时钟线(只能主机控制)

CS :片选线

数据传输的四种方式:

CPOL(时钟极性) : 0:时钟起始位低电平,1:时钟起始为高电平

CPHA(时钟相位) :0:第一个时钟周期采样,1:第二个时钟周期采样

spi协议解析
在这里插入图片描述
CPOL=0,CPHA=0:此时空闲态时,SCLK处于低电平,数据

采样是在第1个边沿,也就是 SCLK由低电平到高电平的跳变,

所以数据采样是在上升沿,数据发送是在下降沿。

CPOL=0,CPHA=1:此时空闲态时,SCLK处于低电平,数据

发送是在第1个边沿,也就是 SCLK由低电平到高电平的跳变,

所以数据采样是在下降沿,数据发送是在上升沿。

CPOL=1,CPHA=0:此时空闲态时,SCLK处于高电平,数据

采集是在第1个边沿,也就是 SCLK由高电平到低电平的跳变,

所以数据采集是在下降沿,数据发送是在上升沿。

CPOL=1,CPHA=1:此时空闲态时,SCLK处于高电平,数据

发送是在第1个边沿,也就是 SCLK由高电平到低电平的跳变,

所以数据采集是在上升沿,数据发送是在下降沿。

二、SPI子系统驱动

在这里插入图片描述

锁存器芯片:IO口扩展,可以锁存,稳定输出

(二)SPI子系统API


(三)SPI设备树节点

spi4: spi@44005000 {
			#address-cells = <1>; //对子节点描述
			#size-cells = <0>;
			compatible = "st,stm32h7-spi";
			reg = <0x44005000 0x400>;
			interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
			clocks = <&rcc SPI4_K>;
			resets = <&rcc SPI4_R>;
			dmas = <&dmamux1 83 0x400 0x01>,
			       <&dmamux1 84 0x400 0x01>;
			dma-names = "rx", "tx";
			power-domains = <&pd_core>;
			status = "disabled"; //1.是否使能
		};

问:如何将控制器驱动和核心层选配到内核中?

将stm32mp157a中spi控制器设备树和核心层选配到内核中

spi控制器驱动配置:(make menuconfig)
Device Drivers —>
[] SPI support —>
<
> STMicroelectronics STM32 SPI controller

spi核心层配置:
Device Drivers —>
[*] SPI support —>

重新编译内核
make uImage LOADADDR=0xc2000000

将编译好的内核拷贝到tftpboot目录下
cp arch/arm/boot/uImage ~/tftpboot/
2.2spi子系统API
1.分配并初始化对象
struct spi_driver {
int (*probe)(struct spi_device *spi);
//匹配成功执行的函数
int (*remove)(struct spi_device *spi);
//分离的时候执行的函数
struct device_driver driver;
//父类
const struct spi_device_id *id_table;
//idtable匹配方式
};
struct device_driver {
const char *name;
const struct of_device_id of_match_table;
}
2.注册
#define spi_register_driver(driver)
__spi_register_driver(THIS_MODULE, driver)
3.注销
void spi_unregister_driver(struct spi_driver sdrv)
4.一键注册注销的宏
module_spi_driver(变量名)
2.3spi子系统驱动实例
#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
int m74hc595_probe(struct spi_device
spi)
{
printk(“%s:%s:%d\n”, FILE, func, LINE);
return 0;
}
int m74hc595_remove(struct spi_device
spi)
{
printk(“%s:%s:%d\n”, FILE, func, LINE);
return 0;
}
struct of_device_id oftable[] = {
{.compatible = “hqyj,m74hc595”,},
{}
};
struct spi_driver m74hc595 = {
.probe = m74hc595_probe,
.remove = m74hc595_remove,
.driver = {
.name = “m74hc595”,
.of_match_table = oftable,
}
};
module_spi_driver(m74hc595);
MODULE_LICENSE(“GPL”);

在这里插入图片描述

spi收发数据的接口
int spi_write(struct spi_device *spi, const void *buf, size_t len)
//发数据
int spi_read(struct spi_device *spi, void *buf, size_t len)       
//接收数据
int spi_write_then_read(struct spi_device *spi,                  
  const void *txbuf, unsigned n_tx,
  void *rxbuf, unsigned n_rx);
//同时收发
&spi4{
    pinctrl-names  = "default","sleep";
    pinctrl-0   = <&spi4_pins_b>;      //工作状态管脚复用
    pinctrl-1   = <&spi4_sleep_pins_b>;//休眠状态管脚复用
 cs-gpios = <&gpioe 11 0>;  //设置片选
 status = "okay";           //使能控制器
    m74hc595@0{
        compatible = "hqyj,m74hc595";
        reg = <0x0>;           //片选的下标
        spi-max-frequency = <10000000>; //10MHz
        //spi-cpol;  //mode0模式
        //spi-cpha;
    };
};

三、代码示例

数码管驱动

#include <linux/module.h>
#include <linux/init.h>
#include <linux/spi/spi.h>
#include <linux/fs.h>
#include "m74hc595.h"

#define CHRNAME "m74hc595"

int major;
struct class *cls;
struct device *dev;
struct spi_device * spidriver;

int code[]={
	0x3f,
    0x06,
    0x5b,
    0x4f,
    0x66,
    0x6d,
    0x7d,
    0x07,
    0x7f,
    0x6f,
    0x77,
    0x7c,
    0x39,
    0x5e,
    0x79,
    0x71
};

int m74hc595_open(struct inode *inode, struct file *file){
    printk("%s:%d\n",__func__,__LINE__);
    return 0;
}

int m74hc595_close(struct inode *inode, struct file *file){
    printk("%s:%d\n",__func__,__LINE__);
    return 0;
}

long m74hc595_ioctl(struct file *file, unsigned int cmd, unsigned long arg){
    u8 data[2]={0};
    int ret;
    switch (cmd){
    case SET_LIGHT_ONE:
        data[0]=0x01;
        data[1]=code[arg];
        ret = spi_write(spidriver,data,2);
        if(ret){
            pr_err("spi_write error:%d\n",__LINE__);
            return -ENAVAIL;
        }
        break;
    case SET_LIGHT_TWO:
        data[0]=0x2;
        data[1]=code[arg]|0x80;
        ret = spi_write(spidriver,data,2);
        if(ret){
            pr_err("spi_write error:%d\n",__LINE__);
            return -ENAVAIL;
        }
        break;

    case SET_LIGHT_THREE:
        data[0]=0x4;
        data[1]=code[arg];
        ret = spi_write(spidriver,data,2);
        if(ret){
            pr_err("spi_write error:%d\n",__LINE__);
            return -ENAVAIL;
        }
        break;
    
    case SET_LIGHT_FOUR:
        data[0]=0x8;
        data[1]=code[arg];
        ret = spi_write(spidriver,data,2);
        if(ret){
            pr_err("spi_write error:%d\n",__LINE__);
            return -ENAVAIL;
        }
        break;
    default:
        pr_err("cmd error\n");
        return -ENAVAIL;
    }
    return 0;
}
struct file_operations fops = {
    .open=m74hc595_open,
    .release=m74hc595_close,
    .unlocked_ioctl=m74hc595_ioctl,
};

int m74hc595_probe(struct spi_device *spi){
    printk("%s:%d\n",__func__,__LINE__);
    spidriver = spi;
    // 1.注册字符设备驱动
    major = register_chrdev(0, CHRNAME, &fops);
    if (major < 0)
    {
        pr_err("register_chrdev error\n");
        return major;
    }
    // 2.自动创建设备节点
    cls = class_create(THIS_MODULE, CHRNAME);
    if (IS_ERR(cls))
    {
        pr_err("class_create error\n");
        unregister_chrdev(major, CHRNAME);
        return PTR_ERR(cls);
    }
    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, CHRNAME);
    if (IS_ERR(dev))
    {
        pr_err("device_create error\n");
        class_destroy(cls);
        unregister_chrdev(major, CHRNAME);
        return PTR_ERR(dev);
    }
    return 0;
}
int m74hc595_remove(struct spi_device *spi){
    printk("%s:%d\n",__func__,__LINE__);
    device_destroy(cls,MKDEV(major,0));
    class_destroy(cls);
    unregister_chrdev(major, CHRNAME);
    return 0;
}

struct of_device_id m74hc595_of_match_table[]={
    { .compatible="hqyj,m74hc595" },
    {},
};
struct spi_driver m74hc595_driver={
    .probe=m74hc595_probe,
    .remove=m74hc595_remove,
    .driver={
        .name="m74hc595",
        .of_match_table=m74hc595_of_match_table,
    }
};
module_spi_driver(m74hc595_driver);
MODULE_LICENSE("GPL");


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

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

相关文章

微信小程序开发了支付系统(必须要进行发货管理)

开发了一个小程序&#xff0c;然后必小程序支付后&#xff0c;一定要发货&#xff1f;线上购买线下取货如何发货&#xff1f; 这其实就是你服务类目选择错了&#xff0c;有的分类是必须要有发货管理的&#xff0c;但是有的就不需要&#xff0c;所以有些时候微信的规则还真的挺…

【vue】h 函数的使用

文章目录 1. 引言2. h 函数3. h 函数的使用3.1 v-if3.2 v-for3.3 v-on3.4 组件3.5 渲染插槽 4. h函数的使用场景参考链接 1. 引言 在绝大多数情况下&#xff0c;Vue 推荐使用模板语法来创建应用。然而在某些使用场景下&#xff0c;我们真的需要用到 JavaScript 完全的编程能力。…

C++ 面试题常用总结 详解(满足c++ 岗位必备,不定时更新)

&#x1f4da; 本文主要总结了一些常见的C面试题&#xff0c;主要涉及到语法基础、STL标准库、内存相关、类相关和其他辅助技能&#xff0c;掌握这些内容&#xff0c;基本上就满足C的岗位技能&#xff08;红色标记为重点内容&#xff09;&#xff0c;欢迎大家前来学习指正&…

01 网络编程-概念引入

目录 1、互联网与物联网 2、计算机网络分类 &#xff08;1&#xff09;按地理范围分类 &#xff08;2&#xff09;按网络拓扑分类 &#xff08;3&#xff09;按网络用途分类 3、套接字 4、网络的七层模型&#xff08;OSI--国际化标准&#xff09; 5、TCP/IP四层协议栈 …

qml ChartView实现动态数据曲线

文章目录 一、qml静态数据曲线二、qml ChartView实现动态数据曲线三、使用C++给曲线提供数据更多qml教程,请参考QML入门进阶教程专栏:https://mingshiqiang.blog.csdn.net/category_9951228_2.html 本篇博客介绍使用qml实现动态数据曲线,效果图如下: 本篇博客代码通过C+…

DolphinScheduler3.2.2在centos7上伪集群部署

DolphinScheduler 是一个分布式易扩展的可视化工作流任务调度系统。集成了很多数据处理常用的功能&#xff0c;包括定时任务&#xff0c;脚本执行&#xff0c;错误预警等。 它具有以下一些主要特点和优势&#xff1a; 分布式架构&#xff1a;支持大规模任务的调度和管理&#…

centos7卸载docker报错No Packages marked for removal

执行&#xff1a; yum -y remove docker* 报错&#xff1a; No Packages marked for removal 执行&#xff1a; yum list installed | grep docker yum remove -y docker-ce.x86_64 docker-ce-cli.x86_64 containerd.io.x86_64

进程的退出以及线程

接上节&#xff1a; 1.wait 本身是一个阻塞操作&#xff0c;谁调用它就会使调用者阻塞 2.父进程要获得子进程的退出状态 要两个进程配合操作&#xff1a; 子进程&#xff1a; exit(退出状态值&#xff09; 退出状态值 只有最低为有效&#xff0c;范围为[0-255] 父进程 wa…

<Qt> 系统 - 网络编程 | 音视频

目录 前言&#xff1a; 一、QUdpSocket &#xff08;一&#xff09;核心 API 概览 &#xff08;二&#xff09;设计一个UDP回显服务器 二、QTCPSocket &#xff08;一&#xff09;核心 API 概览 &#xff08;二&#xff09;设计一个TCP回显服务器 三、HTTP Client 四、…

javaer快速入门 goweb框架 gin

gin 入门 前置条件 安装环境 配置代理 # 配置 GOPROXY 环境变量&#xff0c;以下三选一# 1. 七牛 CDN go env -w GOPROXYhttps://goproxy.cn,direct# 2. 阿里云 go env -w GOPROXYhttps://mirrors.aliyun.com/goproxy/,direct# 3. 官方 go env -w GOPROXYhttps://goproxy.…

【自动驾驶】自定义消息格式的话题通信(C++版本)

目录 新建消息文件更改包xml文件中的依赖关系更改cmakelist文件中的配置执行时依赖改变cmakelist编译顺序发布者程序调用者程序新建launch文件程序测试 新建消息文件 在功能包目录下&#xff0c;新建msg文件夹&#xff0c;下面新建mymsg.msg文件&#xff0c;其内容为 string …

机械行业数字化生产供应链产品解决方案(十六)

我们的机械行业数字化生产供应链产品解决方案通过全面应用物联网、人工智能和大数据技术&#xff0c;构建了一个高效的智能生产与供应链系统&#xff0c;能够在设计、生产和物流全环节中实现实时数据监控与动态优化。系统通过智能分析和预测&#xff0c;优化了生产计划和资源配…

Linux系统驱动(十九)块设备驱动

文章目录 一、块设备驱动简介&#xff08;一&#xff09;简介&#xff08;二&#xff09;块设备驱动相关概念 二、块设备驱动&#xff08;一&#xff09;框架图1. 虚拟文件系统&#xff08;VFS&#xff09;2. Disk Cache&#xff1a;硬盘的高速缓存3. 映射层&#xff08;mappin…

IP代理如何增强网络安全性?

在当今的数字时代&#xff0c;网络安全已成为一个关键问题&#xff0c;而使用 IP 代理可以成为增强网络安全的有效方法。根据请求信息的安全性&#xff0c;IP 代理服务器可分为三类&#xff1a;高级匿名代理、普通匿名代理和透明代理。此外&#xff0c;根据使用的用途&#xff…

NT35510的LCD函数详解01(洋桃电子-触摸屏开发者笔记)

NT35510的LCD函数详解01&#xff08;洋桃电子-触摸屏开发者笔记&#xff09; 资料下载&#xff1a; 洋桃电子 YoungTalk 探索最好的 STM32 教学 (doyoung.net) 接口类型 NT35510 数据手册&#xff08;英文&#xff09;.pdf NT35510 应用手册&#xff08;英文&#xff09;.…

Jenkins持续集成工具学习

一、从装修厨房看项目开发效率优化 二、持续集成工具 三、JavaEE项目部署方式对比 四、Jenkins+SVN持续集成环境搭建

WebGoC题解(18) 630.电线杆(2019NHOI小乙)

题目描述 小C在农场的附近看到有n颗电线杆排成一行&#xff0c;相邻之间距离为20。它们高度可能不一样&#xff0c;但高度相同的电线杆顶端有电线连接。如下面示意图中&#xff0c;电线杆用粗细为6的垂直直线画&#xff0c;电线用粗细为2的水平直线画。给定每个电线杆的高度&am…

Linux-Haproxy搭建Web群集

LVS在企业应用中抗负载能力强 不支持正则处理&#xff0c;不能实现动静分离对于大型网格&#xff0c;LVS的实施配置复杂&#xff0c;维护成本较高 Haproxy是一款可提供高可用性、负载均衡、及基于TCP和HTTP应用的代理的软件 适用于负载大的Web站点运行在硬件上可支持数以万计的…

AI大模型开发——4.transformer模型(0基础也可懂)(1)

无论是想怎样学习大模型&#xff0c;transformer都是一个绕不开的话题。transformer的出现彻底改变了nlp领域&#xff0c;进一步推动了大模型的产生&#xff0c;可以说&#xff0c;transformer就是大模型开发的鼻祖。 可能只通过说大家会有些不理解。大家可以看下方的大语言模型…

打卡第四十四天:最长公共子序列、不相交的线、最大子序和、判断子序列

一、最长公共子序列 题目 文章 视频 本题和最长重复子数组区别在于这里不要求是连续的了&#xff0c;但要有相对顺序&#xff0c;即&#xff1a;"ace" 是 "abcde" 的子序列&#xff0c;但 "aec" 不是 "abcde" 的子序列。 确定dp数…