当前位置: 首页 > news >正文

Linux内核编程(十九)SPI子系统的应用与驱动编写

本文目录

  • 一、 SPI驱动框架图
  • 二、编写SPI驱动device框架
  • 三、编写SPI驱动driver框架
  • 四、实验一编写mcp2515驱动
    • 1. 注册字符设备或杂项设备框架
    • 2. SPI写数据
    • 3. SPI读寄存器数据
  • 4. MCP2515相关配置

  

对于SPI基础知识这里不做过多讲解,详情查看:SPI基础知识实践讲解-STM32版。

一、 SPI驱动框架图

   本框图中spi核心层和spi适配器驱动层不需要我们去关心,如果未来要去原厂工作的话,可以深入了解其工作原理和内容,这里我们不做过多介绍。
在这里插入图片描述

二、编写SPI驱动device框架

  1. 查看开发板中可用的SPI引脚。
    在这里插入图片描述
  2. 修改设备树文件。
    (1)修改spi控制器源码设备树文件。
       将控制器的pinctrl-0复用引脚的spi0m0修改为我们所使用的spi0m1。由于原厂工程师已经写完spi控制器的引脚复用功能,所以我们只需要修改即可。
spi0: spi@fe610000 {compatible = "rockchip,rk3066-spi";reg = <0x0 0xfe610000 0x0 0x1000>;  // SPI 控制器寄存器基地址interrupts = <GIC SPI 103 IRQ TYPE LEVEL HIGH>;  // 中断配置#address-cells = <1>;  // 地址单元数量#size-cells = <0>;  // 大小单元数量clocks = <&cru CLK_SPI>, <&cru PCLK_SPIO>;  // SPI 和 APB 时钟clock-names = "spiclk", "apb pclk";  // 时钟名称dmas = <&dmac0 20>, <&dmac0 21>;  // DMA 通道配置(TX, RX)dma-names = "tx", "rx";  // DMA 通道名称pinctrl-names = "default", "high-speed";  // 引脚控制模式// pinctrl-0 = <&spi0m0_cs0 &spi0m0_csl &spi0m0_pins>;  // 默认引脚控制配置pinctrl-0 = <&spi0m1_cs0  &spi0m1_pins>;  // 默认引脚控制配置//  pinctrl-1 = <&spi0m0_cs0 &spi0m0_csl &spi0m0_pins_high_speed>;  // 高速模式引脚配置pinctrl-1 = <&spi0m1_cs0  &spi0m1_pins_high_speed>;  // 高速模式引脚配置status = "disabled";  // 当前 SPI 控制器状态,禁用状态
};

(2)添加引用spi控制器
   在开发板设备树根节点下添加以下节点。如果设备树中没有reg 和 spi-max-freguengy这俩个属性就会返回错误。返回错误设备注册不成功。从而就不会和驱动匹配上(具体分析spi控制器的注册流程)。以下的SPI工作模式以及传输模式等都需要根据具体的SPI外设来设置!!

&spi0 {status ="okay";mcp2515:mcp2515@0{status ="okay";compatible="my-mcp2515";reg = <0>; /* 1. 选择片选0 */spi-max-frequency = <24000000>; /* 2. 设置SPI时钟最大频率为24MHz,不要超过50M *///3. 设置工作模式,如果不写,则默认为0,0spi-cpha = <1>;  // 设置时钟相位spi-cpol = <0>;  // 设置时钟极性 //4. 设置传输模式,高位先传还是低位先传。默认为高位先传。//spi-lsb-first = <1>;  // 设置为 LSB 优先//5. 选择片选信号为高电平/低电平选中。默认为低电平选中。// spi-cs-high = <1>;      // 设置片选信号为高电平有效}
}

   reg 属性用于设置 SPI 设备的片选引脚,而 spi-max-frequency 属性则用于设置 SPI 总线的最大时钟频率。通常,SPI 设备的片选和时钟频率都需要在设备树中进行配置,以便正确地初始化 SPI 设备。

三、编写SPI驱动driver框架

#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/kernel.h>static int mcp2515_probe(struct spi_device *spi)
{return 0;
}static int mcp2515_remove(struct spi_device *spi)
{return 0;
}static const struct of_device_id mcp2515_of_match[] = {{ .compatible = "my-mcp2515", },{  }
};
MODULE_DEVICE_TABLE(of, mcp2515_of_match);MODULE_DEVICE_TABLE(spi, mcp2515_id_table);static struct spi_driver mcp2515_driver = {.driver = {.name = "mcp2515",.owner = THIS_MODULE,.of_match_table = mcp2515_of_match,},.probe = mcp2515_probe,.remove = mcp2515_remove,
};static int __init mcp2515_init(void)
{return spi_register_driver(&mcp2515_driver);
}static void __exit mcp2515_exit(void)
{spi_unregister_driver(&mcp2515_driver);
}module_init(mcp2515_init);
module_exit(mcp2515_exit);
MODULE_LICENSE("GPL");

四、实验一编写mcp2515驱动

   MCP2515 是由 Microchip 提供的一款独立的 CAN (Controller Area Network) 控制器,它通过 SPI 接口与主机通信。即SPI转CAN的一个模块。

1. 注册字符设备或杂项设备框架

#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>static ssize_t myread(struct file *fp, char __user *ubuf, size_t size, loff_t *loft)
{return 0;
}static int my_open(struct inode *node, struct file *fp)
{return 0;
}ssize_t my_write(struct file *fp, const char __user *ubuf, size_t size, loff_t *loft)
{// 若不需要实际的写操作,可以直接返回0或-EINVALreturn 0;
}static const struct file_operations myfops = {.read = myread,.open = my_open,.write = my_write,
};static struct miscdevice mcp2515_misc = {.minor = MISC_DYNAMIC_MINOR,.name = "mcp2515",.fops = &myfops,
};static int mcp2515_probe(struct spi_device *spi)
{int ret;ret = misc_register(&mcp2515_misc);if (ret) {pr_err("Failed to register misc device\n");return ret;}return 0;
}static int mcp2515_remove(struct spi_device *spi)
{pr_info("MCP2515 SPI device removed\n");misc_deregister(&mcp2515_misc);return 0;
}static const struct of_device_id mcp2515_of_match[] = {{ .compatible = "my-mcp2515", },{ }
};static struct spi_driver mcp2515_driver = {.driver = {.name = "mcp2515",  //不会与之匹配.owner = THIS_MODULE,.of_match_table = mcp2515_of_match,},.probe = mcp2515_probe,.remove = mcp2515_remove,
};static int __init mcp2515_init(void)
{pr_info("MCP2515 driver loading\n");return spi_register_driver(&mcp2515_driver);
}static void __exit mcp2515_exit(void)
{pr_info("MCP2515 driver unloading\n");spi_unregister_driver(&mcp2515_driver);
}module_init(mcp2515_init);
module_exit(mcp2515_exit);MODULE_LICENSE("GPL");

2. SPI写数据

成功时:返回发送的字节数,通常是 len。
失败时:返回负的错误代码,通常为 -EINVAL(无效参数)或 -EIO(输入/输出错误)等。

int spi_write(struct spi_device *spi, const void *buf, unsigned len);
/*spi:指向目标 SPI 设备的指针。这是你要向其发送数据的 SPI 设备。buf:指向包含要发送的数据的缓冲区的指针。这些数据将被通过 SPI 总线发送。len:要发送的数据的字节数。表示从 buf 中发送的字节数。
*/

●示例: 我们通过mcp2515手册可知,对其进行写操作需要写入0x02。使用spi_write来进行写操作。

#include <linux/spi/spi.h>struct spi_device *spi;
void mcp2515_write_reg(char reg, char value)
{int ret;char write_buf[] = {0x02, reg, value};  // MCP2515 写寄存器的指令// 向 MCP2515 发送数据ret = spi_write(spi, write_buf, sizeof(write_buf));if (ret < 0) {printk(KERN_ERR "MCP2515 write reg failed: %d\n", ret);}
}

3. SPI读寄存器数据

这里有以下两个API函数。
(1)spi_read(直接读)
成功时:返回接收的字节数(通常是 len)。失败时:返回负的错误代码。

int spi_read(struct spi_device *spi, void *buf, unsigned len);
/*spi:指向 SPI 设备的指针。buf:指向存放接收数据的缓冲区的指针。接收到的数据将存放在这个缓冲区中。len:要接收的数据的字节数。
*/

(2)spi_write_then_read(先写后读)
   这个函数用于 SPI 设备的 “write then read” 操作,即先发送数据,然后读取数据。成功时:返回传输的字节数,通常等于 n_tx 或 n_rx,这取决于设备的特性。失败时:返回负的错误代码(如 -EINVAL 或 -EIO 等)。

int spi_write_then_read(struct spi_device *spi, const void *txbuf, unsigned n_tx, void *rxbuf, unsigned n_rx);
/*spi:指向 SPI 设备的指针,表示我们将要操作的 SPI 设备。txbuf:指向要发送的缓冲区的指针。它包含我们要发送的数据。n_tx:要发送的字节数。rxbuf:指向接收数据的缓冲区的指针。读取到的数据会存放在这个缓冲区中。n_rx:要接收的字节数。
*/

●示例: mcp2515读寄存器的值,我们查看其手册发现,要想读寄存器的值需要先写入0x03命令,然后发送要读取寄存器的地址,再进行读取值。所以我们需要先写后读。

#include <linux/spi/spi.h>
struct spi_device *spi;char mcp2515_read_reg(char reg)
{int ret;u8 write_buf[] = { 0x03, reg };  // 0x03 是读取寄存器命令,具体命令值请参考 MCP2515 数据手册u8 read_buf;  // 用于存储读取到的数据// SPI write then read 操作ret = spi_write_then_read(spi, write_buf, sizeof(write_buf), &read_buf, sizeof(read_buf));if (ret < 0) {printk(KERN_ERR "SPI write then read error: %d\n", ret);return ret;  // 返回错误代码}printk(KERN_INFO "Read value from MCP2515 register 0x%02X: 0x%02X\n", reg, read_buf);return read_buf;  // 返回读取到的寄存器值
}

4. MCP2515相关配置

(1)复位操作(进入配置模式):通过查看器件手册来获取复位命令,再SPI来对其进行写入。

struct spi_device *spi;
static int mcp2515_reset()
{int ret;u8 write_buf[] = { 0xc0 };  // 假设 0xc0 是复位命令,具体命令根据 datasheet 确定// 向 MCP2515 设备写入复位命令ret = spi_write(spi, write_buf, sizeof(write_buf));if (ret < 0) {printk(KERN_ERR "SPI write error: %d\n", ret);return ret;}printk(KERN_INFO "MCP2515 reset command sent successfully.\n");return 0;
}

相关文章:

Linux内核编程(十九)SPI子系统的应用与驱动编写

本文目录 一、 SPI驱动框架图二、编写SPI驱动device框架三、编写SPI驱动driver框架四、实验一编写mcp2515驱动1. 注册字符设备或杂项设备框架2. SPI写数据3. SPI读寄存器数据 4. MCP2515相关配置 对于SPI基础知识这里不做过多讲解&#xff0c;详情查看&#xff1a;SPI基础知识实…...

MVC 文件夹结构详解

MVC 文件夹结构详解 MVC(Model-View-Controller)是一种广泛应用于软件开发中的设计模式,它通过将应用程序分为三个核心组件——模型(Model)、视图(View)和控制器(Controller)——来组织代码,提高代码的可维护性和可扩展性。在MVC模式中,每个组件都有其特定的职责,…...

远程操作Linux服务器 _Xshell、Xftp以及Linux常见操作命令

工具推荐 Xshell和Xftp是两款由NetSarang公司开发的、广受欢迎的软件工具&#xff0c;它们分别专注于终端模拟和文件传输&#xff0c;为用户提供了便捷的操作和强大的功能。以下是对这两款软件的详细解析&#xff1a; 一、Xshell 定义与功能 Xshell是一个强大的安全终端模拟软…...

单链表的实现(数据结构)

一. 单链表的实现 我们在上一篇中简单的认识了链表的组成和结构&#xff0c;并打印出链表&#xff0c;那么今天就来具体实现一下单链表对于数据增加、删减、插入等。 接下来就是我们在链表中对于数据的增、删、插的实现&#xff0c;对于我们的链表来说在任何地方增加数据都需…...

印刷质量检测笔记

一、印刷质量检测的背景与挑战 印刷品的质量检测&#xff0c;特别是针对高精度要求的印刷产品&#xff0c;如包装材料、标签、书籍封面等&#xff0c;一直是制造业中的一个关键环节。印刷品可能存在的质量问题多种多样&#xff0c;包括但不限于颜色偏差、文字模糊、漏印、多印…...

16、论文阅读:Mamba YOLO:用于目标检测的基于 SSM 的 YOLO

Mamba YOLO: SSMs-Based YOLO For Object Detection 总结前言感受野为什么Transformer 的结构被引入&#xff0c;显著扩展了模型的感受野&#xff1f;状态空间模型SSM 介绍相关工作实时目标检测端到端目标检测器视觉状态空间模型 方法预处理整体架构ODSS BlockLocalSpatial Blo…...

python项目实战---使用图形化界面下载音乐

音乐下载 设计思路&#xff1a; 设计界面编写爬虫代码绑定爬虫打包exe文件 这个是最终的设计成果&#xff0c;所有的下载歌曲都在“下载mp3”文件夹里面 完整代码 逻辑代码 import os.path import reimport requests from PyQt5.QtWidgets import QApplication,QWidget,QM…...

无人机干扰与抗干扰,无人机与反制设备的矛与盾

无人机干扰与抗干扰&#xff0c;以及无人机与反制设备之间的关系&#xff0c;可以形象地比喻为矛与盾的较量。以下是对这两方面的详细探讨&#xff1a; 一、无人机干扰与抗干扰 1. 无人机干扰技术 无人机干扰技术是指通过各种手段对无人机系统进行干扰&#xff0c;使其失去正…...

JAVA基础:单元测试;注解;枚举;网络编程 (学习笔记)

单元测试 操作步骤&#xff1a; a.导包import org.junit; b.三个注解 Test Before After c.点击Test 运行就可以了 用在不需要控制台输入的情境下&#xff1a;javaweb&#xff0c;框架项目&#xff0c;微服务项目 供开发人员自己做测试。 package com.page…...

Meta 上周宣布正式开源小型语言模型 MobileLLM 系列

在 7 月发布之后&#xff0c;Meta 上周宣布正式开源能够在智能手机上运行的小型语言模型 MobileLLM 系列。 Meta 在四个月前发布了这两个参数量小于 10 亿的语言模型 MobileLLM 125M 及 MobileLLM 350M。如今&#xff0c;Meta 又开发出了更大参数量的模型版本&#xff0c;包括…...

安全篇(1)判断安全固件

判断安全固件的方法 一、通过串口开机打印 改方法适用Android与Tina 1.开机打印为SBOOT为安全 [289]HELLO! SBOOT is starting! 2.开机打印boot0为非安全 [88]BOOT0 commit : 1cbb5ea8b3 二、通过读数据 1.getprop | grep verifiedbootstate 这条命令的输出表示设备的…...

ArcGIS005:ArcMap常用操作101-150例动图演示

摘要&#xff1a;本文涵盖了GIS软件操作的多方面内容&#xff0c;包括地图文档的新建、打开、保存及版本兼容性处理&#xff1b;错误与警告的查阅及帮助文档的使用技巧&#xff1b;地图打印比例尺的调整与地图信息的完善&#xff1b;图层操作的撤销与恢复&#xff0c;界面元素的…...

如何用ChatGPT结合Python处理遥感数据

在科技飞速发展的时代&#xff0c;遥感数据的精准分析已经成为推动各行业智能决策的关键工具。从无人机监测农田到卫星数据支持气候研究&#xff0c;空天地遥感数据正以前所未有的方式为科研和商业带来深刻变革。然而&#xff0c;对于许多专业人士而言&#xff0c;如何高效地处…...

matlab 质心重合法实现点云配准

目录 一、算法原理1、原理概述2、参考文献二、代码实现三、结果展示1、初始位置2、配准结果本文由CSDN点云侠原创,原文链接,首发于:2024年11月5日。 一、算法原理 1、原理概述 质心重合法是将源点云 P P P...

ubuntu双屏只显示一个屏幕另一个黑屏

简洁的结论&#xff1a; 系统环境 ubuntu22.04 nvidia-535解决方案 删除/etc/X11/xorg.conf 文件 记录一下折腾大半天的问题。 ubuntu系统是22.04,之前使用的时候更新驱动导致桌面崩溃&#xff0c;重新安装桌面安装不上&#xff0c;请IT帮忙&#xff0c;IT一番操作过后也表示…...

小菜家教平台:基于SpringBoot+Vue打造一站式学习管理系统

前言 现在已经学习了很多与Java相关的知识&#xff0c;但是迟迟没有进行一个完整的实践&#xff08;之前这个项目开发到一半&#xff0c;很多东西没学搁置了&#xff0c;同时原先的项目中也有很多的问题&#xff09;&#xff0c;所以现在准备从零开始做一个基于SpringBootVue的…...

网络自动化03:简单解释send_config_set方法并举例

目录 拓扑图设备信息 netmiko涉及方法send_config_set()方法的简单示例代码输出结果代码解释导入模块配置信息config_device_interface_description 函数主程序块总结 send_config_set方法参数&#xff1a;1. enter_config_mode2. config_commands3. enter_config_mode4. error…...

跳表原理笔记

课程地址 跳表是一种基于随机化的有序数据结构&#xff0c;它提出是为了赋予有序单链表以 O(logn) 的快速查找和插入的能力 创建 首先在头部创建一个 sentinel 节点&#xff0c;然后在 L1 层采用“抛硬币”的方式来决定 L0 层的指针是否增长到 L1 层 例如上图中&#xff0c;L…...

计算机毕业设计Hadoop+PySpark深度学习游戏推荐系统 游戏可视化 游戏数据分析 游戏爬虫 Scrapy 机器学习 人工智能 大数据毕设

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…...

AI开发-三方库-torch-torchvision

1 需求 数据集&#xff1a;torchvision.datasets torchvision.datasets.MNIST数据变换&#xff1a;torchvision.transforms torchvision.transforms.Composetorchvision.transforms.ToTensortorchvision.transforms.Normalize模型&#xff1a;torchvision.models可视化工具&…...

解析 MySQL 数据库容量统计、存储限制与优化技巧

管理 MySQL 数据库时&#xff0c;了解数据库中的数据量和存储占用情况是非常重要的&#xff0c;尤其是在面对大规模数据时。无论是为了优化数据库性能&#xff0c;还是为了进行容量规划&#xff0c;准确地统计数据库的容量可以帮助我们做出更好的决策。mysql的客户端工具是Navi…...

智能工厂的软件设计 思维进阶与数学程序

本文要点 讨论 “智能工厂的软件设计”中的“数学程序”。 这里 “数学程序” 是指能“格物致知”来理解“相续”一词。 完整的表述是&#xff1a; 思想素养提升的 思维进阶法&#xff08;三种 数学程序 &#xff1a; 格物致知 &#xff09;之思维导图&#xff1a; 二叉树及其…...

技术速递|GitHub Copilot upgrade assistant for Java 技术预览发布!

作者&#xff1a;Nick Zhu - Senior Program Manager 排版&#xff1a;Alan Wang 随着人工智能和大型语言模型&#xff08;LLMs&#xff09;的不断发展&#xff0c;Agent&#xff08;“智能代理”&#xff09;和智能代理化工作流程正在迅速成为AI领域的下一个前沿。这些自主系统…...

淘宝有哪些API是用来获取商品列表的?(商品id列表)

淘宝商品详情接口item_get是通过商品id或者商品链接来获取商品详情数据的&#xff0c;但是不少客户是没有商品id的&#xff0c;这时需要通过接口来拿到商品id。 可以获取商品id的API有&#xff1a; item_search 通过关键字搜索商品列表 item_search_shop 获取店铺所有商品列…...

D59【python 接口自动化学习】- python基础之异常

day59 捕获异常常见问题 学习日期&#xff1a;20241105 学习目标&#xff1a;异常 -- 75 避坑指南&#xff1a;编写捕获异常程序时经常出现的问题 学习笔记&#xff1a; 捕获位置设置不当 设置范围不当 捕获处理设置不当 嵌套try-except语法错误 总结 位置&#xff0c;范围…...

解决 Spring 异步处理中的 JDK 动态代理问题及相关错误分析

解决 Spring 异步处理中的 JDK 动态代理问题及相关错误分析 遇到的问题&#xff1a; 在使用 Spring 的 Async 注解开启异步处理时&#xff0c;遇到以下错误&#xff1a; The bean ServiceImplChannel could not be injected as a com.wn.order.pay.recharge.controller.Serv…...

从xss到任意文件读取

xss一直是一种非常常见且具有威胁性的攻击方式。然而&#xff0c;除了可能导致用户受到恶意脚本的攻击外&#xff0c;xss在特定条件下还会造成ssrf和文件读取&#xff0c;本文主要讲述在一次漏洞挖掘过程中从xss到文件读取的过程&#xff0c;以及其造成的成因。 0x01 前言 xss一…...

nuiapp vue3 uni-ui uni.uploadFile 图片上传

<div style"position: relative;margin-top: 0.8em;"> <div style"position: absolute;left: 1.5em;top: 2em;">施工图片</div> <div style"position: absolute; left: 7em;top: 0em;right: 0em;bottom…...

【计算机科学】位运算:揭开二进制世界的奥秘

位运算是计算机运算的一种基础操作&#xff0c;直接作用于数据的二进制位&#xff08;bit&#xff09;&#xff0c;在计算机中具有极高的效率。无论是编写高效算法&#xff0c;还是进行底层开发&#xff0c;位运算都扮演着重要角色。本文将从位运算的起源、常见操作符、应用场景…...

弹性裸金属服务器和传统裸金属服务器有什么区别?

弹性裸金属服务器是一种结合了传统裸金属服务器和云计算资源两种特点的服务器&#xff0c;是一种云计算服务&#xff0c;下面我们就来了解一下弹性裸金属服务器和传统裸金属服务器之间有什么区别吧&#xff01; 弹性裸金属服务器能够支持企业快速部署新的硬件和软件系统&#x…...