Linux总线之SPI

article/2025/9/18 15:12:45

文章目录

  • 1.spi总线驱动
    • 1.1spi简介
    • 1.2spi时序解析
    • 1.3spi驱动框架
    • 1.4spi设备驱动的API
    • 1.5spi驱动的实例
    • 1.6m74hc595设备树的填充
      • 1.6.1m74hc595操作数码管的原理图
      • 1.6.2控制器的设备树
      • 1.6.3编写自己的设备树
    • 1.7spi相关的结构体及函数
    • 1.8spi驱动的实例2
    • 1.9让数码管流水显示0-f

1.spi总线驱动

1.1spi简介

SPI 是串行外设接口(Serial Peripheral Interface)的缩写。是 Motorola 公司推出的一种同步串行接口技术,是一种高速的,全双工,同步的通信总线。SPI优点支持全双工通信通信简单数据传输速率快1):高速、同步、全双工、非差分、总线式2):主从机通信模式缺点没有指定的流控制,没有应答机制确认是否接收到数据,所以跟IIC总线协议比较在数据的可靠性上有一定的缺陷。

1.2spi时序解析

可以一主机多从机,具体和那个从机通讯通过cs片选决定。MISO   :主机输入,从机输出MOSI   :主机输出,从机输入CLK    :时钟线(只能主机控制)CS     :片选线数据传输的四种方式:
CPOL(时钟极性) : 0:时钟起始位低电平      1:时钟起始为高电平  
CPHA(时钟相位)0:第一个时钟周期采样    1:第二个时钟周期采样

在这里插入图片描述

例如:

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由高电平到低电平的跳变,所以数据采集是在上升沿,数据发送

是在下降沿。

1.3spi驱动框架

在这里插入图片描述

配置spi核心层和spi控制器驱动到内核中

spi控制器驱动配置:

Device Drivers —>

[*] SPI support  ---> <*>   STMicroelectronics STM32 SPI controller      

spi核心层配置:

CONFIG_SPI_MASTER=y  

重新编译内核

make uImage LOADADDR=0xc2000000

将编译好的内核拷贝到tftpboot目录下

1.4spi设备驱动的API

1.分配并初始化对象struct spi_driver {int			(*probe)(struct spi_device *spi);int			(*remove)(struct spi_device *spi);struct device_driver	driver;};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(结构体变量名);

1.5spi驱动的实例

#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
int m74hc595_probe(struct spi_device* spi)
{printk("%s:%d\n", __func__, __LINE__);return 0;
}
int m74hc595_remove(struct spi_device* spi)
{printk("%s:%d\n", __func__, __LINE__);return 0;
}struct of_device_id oftable[] = {{.compatible = "hqyj,m74hc595",},{}
};
MODULE_DEVICE_TABLE(of,oftable);struct spi_driver m74hc595 = {.probe = m74hc595_probe,.remove = m74hc595_remove,.driver = {.name = "m74hc595",.of_match_table = oftable,},
};
module_spi_driver(m74hc595);
MODULE_LICENSE("GPL");

1.6m74hc595设备树的填充

1.6.1m74hc595操作数码管的原理图

在这里插入图片描述

1.6.2控制器的设备树

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.6.3编写自己的设备树

&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 = <0>; //片选编号spi-max-frequency = <10000000>; //10MHZ                                                                     };
};

1.7spi相关的结构体及函数

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);

1.8spi驱动的实例2

#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>int m74hc595_probe(struct spi_device* spi)
{unsigned char buf[] = {0x4,0x6d};printk("%s:%d\n", __func__, __LINE__);spi_write(spi,buf,2);return 0;
}
int m74hc595_remove(struct spi_device* spi)
{printk("%s:%d\n", __func__, __LINE__);return 0;
}struct of_device_id oftable[] = {{.compatible = "hqyj,m74hc595",},{}
};
MODULE_DEVICE_TABLE(of,oftable);struct spi_driver m74hc595 = {.probe = m74hc595_probe,.remove = m74hc595_remove,.driver = {.name = "m74hc595",.of_match_table = oftable,},
};
module_spi_driver(m74hc595);
MODULE_LICENSE("GPL");

1.9让数码管流水显示0-f

m74hc595.h

#ifndef __M74HC595_H__
#define __M74HC595_H__#define SEG_WHICH _IOW('k',0,int)
#define SEG_DAT  _IOW('k',1,int)
#endif

m74hc595.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/fs.h>
#include "m74hc595.h"
/*&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 = "m74hc595";reg = <0>;spi-max-frequency = <10000000>;};
};
*/
#define NAME "m74hc595"
int major = 0;
struct class *cls;
struct device *dev;
struct spi_device *gspi;
u8 code[] = {0x3f, //00x06, //10x5b, //20x4f, //30x66, //40x6d, //50x7d, //60x07, //70x7f, //80x6f, //90x77, //A0x7c, //b0x39, //c0x5e, //d0x79, //e0x71, //f
};u8 which[] = {0x1, //sg00x2, //sg10x4, //sg20x8, //sg3
};int m74hc595_open(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 args)
{	switch(cmd){case SEG_WHICH:spi_write(gspi,&which[args],1);break;case SEG_DAT:spi_write(gspi,&code[args],1);break;default: printk("ioctl error\n");break;}return 0;
}int m74hc595_close(struct inode *inode, struct file *file)
{printk("%s:%d\n",__func__,__LINE__);return 0;
}
struct file_operations fops = {.open = m74hc595_open,.unlocked_ioctl = m74hc595_ioctl,.release = m74hc595_close,
};int	m74hc595_probe(struct spi_device *spi)
{u8 buf[2] = {0xf,0x0};printk("%s:%d\n",__func__,__LINE__);gspi = spi;spi_write(gspi,buf,ARRAY_SIZE(buf));major = register_chrdev(0,NAME,&fops);if(major < 0){printk("register chrdev error\n");return major;}cls = class_create(THIS_MODULE,NAME);if(IS_ERR(cls)){printk("class create  error\n");return PTR_ERR(cls);}dev = device_create(cls,NULL,MKDEV(major,0),NULL,NAME);if(IS_ERR(dev)){printk("device create  error\n");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,NAME);return 0;
}const struct of_device_id of_match[] = {{.compatible = "hqyj,m74hc595",},{},
};
MODULE_DEVICE_TABLE(of,of_match);struct spi_driver m74hc595 = {.probe = m74hc595_probe,.remove = m74hc595_remove,.driver = {.name = "m74hc595",.of_match_table = of_match,},	
};
module_spi_driver(m74hc595);
MODULE_LICENSE("GPL");

test.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "m74hc595.h"int main(int argc, const char *argv[])
{int which=0;int data=0;int fd;fd = open("/dev/m74hc595",O_RDWR);if(fd < 0){perror("open error");return -1;}while(1){ioctl(fd,SEG_WHICH,which++);ioctl(fd,SEG_DAT,data++);if(which >= 4)which=0;if(data >= 16)data = 0;sleep(1);}close(fd);return 0;
}

http://chatgpt.dhexx.cn/article/E66R3F0c.shtml

相关文章

SPI总线协议详解

目录 一.概述 二.特点 1.寻址方式 2.采用主-从模式(Master-Slave) 的控制方式 3.采用同步方式(Synchronous)传输数据 4.极性和相位 三.SPI总线传输的模式 四.SPI和I2C的区别 一.概述 SPI(serial peripheral interface)是一种同步串行通信协议&#xff0c;由一个主设备和…

SPI简介

SPI全称是Serial Perripheral Interface&#xff0c;也就是串行外围设备接口。SPI是Motorola公司推出的一种同步串行接口技术&#xff0c;是一种高速&#xff0c;全双工的同步通信总线。SPI时钟频率相比IIC要高很多&#xff0c;最高可以工作在上百MHZ。 SPI以主从方式工作&…

SPI通信总线基本概念

SPI总线概述 SPI总线介绍 SPI(Serial Peripheral interface)&#xff1a;是由Motorola公司开发的串行外围设备接口&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线。主要应用在 EEPROM&#xff0c;FLASH&#xff0c;实时时钟&#xff0c;AD转换器&…

SPI通信总线

SPI通信总线 注意 常用的内部通信接口&#xff1a;UART、IIC、SPI&#xff0c;大多数是用于芯片之间的通信&#xff0c;特点是速度快&#xff0c;距离比较短 常用的外部通信接口&#xff1a;RS-232&#xff0c;RS-485&#xff0c;CAN&#xff0c;大多用于远距离传输&#xf…

FPGA——SPI总线详解(概念)

目录 SPI简介 SPI4种模式&#xff1a; SPI时序 使用SPI总线实现对flash的控制 flash芯片管脚&#xff1a; flash芯片存储 写使能模块 读状态模块 擦除模块 页读模块 页写模块 SPI简介 SPI, Serial Perripheral Interface, 串行外围设备接口, 是 Motorola 公司推出的一…

SPI总线详解笔记

目录 1. 简介 1.1 概述 1.2 特征 1.3 操作模式 2. 外部信号说明 2.1 概述 2.2 信号详细说明 2.2.1 MOSI 2.2.2 MISO 2.2.3 SS 2.2.4 SCK 3. 存储器映射/寄存器定义 3.1 寄存器说明 3.1.1 SPI Control Register 1 3.1.2 SPI Control Register 2 3.1.3 SPI Baud R…

SPI总线规范

SPI是英文Serial Peripheral Interface的缩写&#xff0c;中文意思是串行外围设备接口&#xff0c;SPI是Motorola公司推出的一种同步串行通讯方式&#xff0c;是一种三线同步总线&#xff0c;因其硬件功能很强&#xff0c;与SPI有关的软件就相当简单&#xff0c;使CPU有更多的时…

SPI总线(一):基本原理篇

相关文章&#xff1a; SPI总线&#xff08;二&#xff09;&#xff1a;驱动分析篇 SPI总线&#xff08;三&#xff09;&#xff1a;驱动实例 1、什么是SPI&#xff1f; SPI是串行外设接口(Serial Peripheral Interface)的缩写。是 Motorola 公司推出的一 种同步串行接口技术&a…

关于IIC和SPI总线

IICvs SPI 现今&#xff0c;在低端数字通信应用领域&#xff0c;我们随处可见IIC (Inter-Integrated Circuit) 和 SPI (Serial Peripheral Interface)的身影。原因是这两种通信协议非常适合近距离低速芯片间通信。Philips&#xff08;for IIC&#xff09;和Motorola&#xff08…

I2C和SPI总线对比

最近2周一直在调试IIC和SPI总线设备&#xff0c;这里记录一下2种总线&#xff0c;以备后忘。 一 IIC总线 I2C--INTER-IC串行总线的缩写&#xff0c;是PHILIPS公司推出的芯片间串行传输总线。它以1根串行数据线&#xff08;SDA&#xff09;和1根串行时钟线&#xff08;SCL&#…

SPI总线介绍

一、概述. SPI, Serial Perripheral Interface, 串行外围设备接口, 是 Motorola 公司推出的一种同步串行接口技术. SPI 总线在物理上是通过接在外围设备微控制器(PICmicro) 上面的微处理控制单元 (MCU) 上叫作同步串行端口(Synchronous Serial Port) 的模块(Module)来实现…

I2C总线和SPI总线的异同点

文章目录 1、内部总线、系统总线、外部总线的概念2、总线通信的基本概念3、I2C和SPI的经典物理层结构4、I2C总线与SPI总线的区别5、I2C总线和SPI总线的共同点 1、内部总线、系统总线、外部总线的概念 总线的分类方式是根据离芯片远近等级进行分类的&#xff1a;内部总线是外设…

SPI总线

【1】SPI总线相关的概念 1》SPI接口是Motorola 首先提出的全双工同步串行外围接口&#xff0c;采用主从模式&#xff08;Master Slave&#xff09;架构&#xff1b; 2》支持多slave模式应用&#xff0c;一般仅支持单Master。 3》时钟由Master控制&#xff0c;在时钟移位脉冲下…

1、SPI总线详解

概述 SPI&#xff08;Serial Peripheral interface&#xff09;串行外围设备接口&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线。 SPI接口主要应用在 EEPROM&#xff0c;FLASH&#xff0c;实时时钟&#xff0c;AD转换器&#xff0c;还有数字信号处理…

SPI协议及其工作原理详解

一、概述. SPI, Serial Perripheral Interface, 串行外围设备接口, 是 Motorola 公司推出的一种同步串行接口技术. SPI 总线在物理上是通过接在外围设备微控制器(PICmicro) 上面的微处理控制单元 (MCU) 上叫作同步串行端口(Synchronous Serial Port) 的模块(Module)来实现的…

SPI总线详解

1. SPI的简介和应用场景 SPI通信协议由摩托罗拉公司于20世纪80年代中期开发而成&#xff0c;SPI是种一个串行设接口&#xff0c;高速&#xff0c;全双工&#xff0c;同步的通信总线&#xff0c;芯片上只占用了四根线&#xff0c;这能大大的节约了芯片的管脚&#xff0c; 应用的…

Log4j2基本使用

文章目录 1. Log4j2入门2. Log4j2配置3. Log4j2异步日志4. Log4j2的性能 Apache Log4j 2是对Log4j的升级版&#xff0c;参考了logback的一些优秀的设计&#xff0c;并且修复了一些问题&#xff0c;因此带 来了一些重大的提升&#xff0c;主要有&#xff1a; 异常处理&#xff…

Logback 对比 Log4j2

Logback 对比 Log4j2 测试分为本地测试端和服务器端,分别对gateway网关进行日志输出的压测 同步日志,不打印日志 logback(150并发,0间隔,循环50次) log4j2(150并发,0间隔,循环50次) 同步日志,打印日志(大小4k,循环输出100次) logback(150并发,0间隔,循环50次) log4j2(150并…

Log4j(四)——Log4j1与Log4j2的区别

前言 几乎每个大型应用程序都包含自己的日志或跟踪API。为了符合这一规则&#xff0c;欧盟SEMPRER项目决定编写自己的跟踪API。这是在1996年初。经过无数次的增强、几个版本和大量的工作之后&#xff0c;API演变成了log4j&#xff0c;这是一个流行的Java日志包。这个包是在Apa…

log4j与log4j2性能对比及log4j升级至log4j2方案

1.前言 之前某个服务在压测环境中出现了问题&#xff0c;分析之后得知是log4jLogger对象争用厉害&#xff0c;很多线程阻塞在此。 以上问题证明log4j在高并发高QPS情况下&#xff0c;是存在性能问题的。 之后把log4j升级成了log4j2&#xff0c;并采取异步日志模式&#xff0c…