i.MX6ULL 裸机 ECSPI 驱动开发详解:

news2026/4/13 3:50:54
在嵌入式裸机开发中SPI串行外设接口是最常用的高速同步串行总线之一广泛用于连接 Flash、加速度传感器、ADC、OLED 屏等外设。i.MX6ULL 作为 Cortex-A7 内核的工业级 MPU内置了 4 路增强型可配置 SPI 外设ECSPI支持主机 / 从机模式、最高 60MHz 总线时钟能满足绝大多数 SPI 外设的驱动需求。本文基于正点原子 i.MX6ULL-MINI 开发板从零实现 ECSPI3 主机模式的裸机驱动结合寄存器原理逐行拆解代码详细讲解 SPI 驱动开发的核心逻辑与注意事项最终实现通用的 SPI 全双工读写能力。一、SPI 总线核心原理回顾在讲解 i.MX6ULL 的 ECSPI 外设前先明确 SPI 总线的核心特性这是驱动代码设计的基础四线制硬件架构标准 SPI 采用 4 根信号线通信主从机的连接关系固定SCLK串行时钟线主机输出用于同步收发数据时钟频率由主机配置MOSI主发从收线主机发送数据、从机接收数据MISO主收从发线从机发送数据、主机接收数据CS片选线主机输出有效电平与外设有关同一时刻只能拉低一个从机的 CS 引脚确保总线只有一个从机处于工作状态。全双工通信特性SPI 是全双工总线发送和接收过程完全同步主机在 SCLK 的驱动下通过 MOSI 向从机移位发送 1 个 bit 的同时会通过 MISO 从从机移位接收 1 个 bit。也就是说每完成 8 个时钟周期1 字节的发送必然同时完成 1 字节的接收这也是 SPI 驱动通常只用一个读写函数就能完成收发的核心原因。4 种 SPI 时序模式SPI 的时序由两个核心参数决定必须和从机设备手册严格匹配否则会出现采样错误CPOL时钟极性决定总线空闲时 SCLK 的电平状态。CPOL0空闲时 SCLK 为低电平CPOL1空闲时 SCLK 为高电平。CPHA时钟相位决定数据采样的时钟沿。CPHA0在 SCLK 的第一个跳变沿采样数据CPHA1在 SCLK 的第二个跳变沿采样数据。两个参数组合出 4 种 SPI 模式本文驱动默认配置为模式 3CPOL1CPHA1适配 ADXL345 等绝大多数常用 SPI 传感器。二、i.MX6ULL ECSPI 外设核心寄存器i.MX6ULL 的 ECSPI 外设配置完全基于寄存器实现驱动代码的本质就是对寄存器的正确配置。本文只讲解代码中用到的核心寄存器完整寄存器说明可参考《i.MX6ULL 参考手册》第 20 章。2.1 控制寄存器CONREG该寄存器是 ECSPI 的核心配置寄存器32 位有效决定了外设使能、主从模式、时钟分频、突发长度等核心参数代码中重点配置的位段如下表格位段位宽代码配置功能说明BURST_LENGTH31-20720突发传输长度值为 N 表示一次传输 N1 个 bit配置为 7 即一次传输 8bit1 字节PRE_DIVIDER15-121412预分频器值为 N 对应 N1 分频配置为 14 即 15 分频POST_DIVIDER11-828后分频器值为 N 对应 2^N 分频配置为 2 即 4 分频CHANNEL_MODE7-414通道主从模式bit0 对应通道 0置 1 表示通道 0 配置为主机模式SMC313传输启动模式置 1 表示向 TXFIFO 写入数据时自动启动 SPI 传输EN010ECSPI 外设使能位置 1 开启外设置 0 关闭外设2.2 配置寄存器CONFIGREG该寄存器主要用于配置 SPI 时序模式、片选极性等参数和从设备时序匹配的核心配置都在这个寄存器中表格位段位宽代码配置功能说明SCLK_POL7-414时钟极性配置bit0 对应通道 0置 1 表示 CPOL1空闲时 SCLK 为高电平SCLK_PHA3-010时钟相位配置bit0 对应通道 0置 1 表示 CPHA1第二个时钟沿采样数据2.3 状态寄存器STATREG该寄存器是只读寄存器用于获取 ECSPI 的工作状态驱动中通过该寄存器判断收发是否完成重点用到两个位TE(bit0)TXFIFO 空标志位置 1 表示发送 FIFO 为空可写入新的发送数据RR(bit3)RXFIFO 就绪标志位置 1 表示接收 FIFO 中有有效数据可读取。2.4 数据寄存器TXDATA发送数据寄存器向该寄存器写入数据会将数据压入 TXFIFO在 SMC1 的模式下会自动启动 SPI 传输RXDATA接收数据寄存器从该寄存器读取数据会取出 RXFIFO 中的有效数据同时自动清除 RR 标志位。三、硬件设计与工程结构3.1 硬件引脚复用本文使用 i.MX6ULL 的 ECSPI3 外设开发板上该外设的引脚与 UART2 引脚复用具体映射关系如下同时采用软件片选的方式使用 GPIO1_IO20 作为 CS 引脚比硬件片选更灵活表格功能芯片引脚复用配置宏定义ECSPI3_MOSIUART2_CTS_BIOMUXC_UART2_CTS_B_ECSPI3_MOSIECSPI3_MISOUART2_RTS_BIOMUXC_UART2_RTS_B_ECSPI3_MISOECSPI3_SCLKUART2_RX_DATAIOMUXC_UART2_RX_DATA_ECSPI3_SCLKSPI_CS (软件)UART2_TX_DATAIOMUXC_UART2_TX_DATA_GPIO1_IO203.2 工程文件结构驱动工程分为两个文件结构极简便于移植和复用spi.h头文件驱动函数的外部声明spi.c源文件ECSPI 初始化、核心读写函数的实现。四、驱动代码逐行深度解析4.1 头文件 spi.h头文件仅做函数声明对外暴露两个核心接口符合 SPI 驱动的最小化设计原则c运行#ifndef __SPI_H__ #define __SPI_H__ // ECSPI初始化函数完成引脚、时钟、模式的全部配置 extern void spi_init(void); // SPI全双工读写函数发送1个数据的同时接收1个数据 extern unsigned int spi_write_read(unsigned int data); #endif // ! __SPI_H__这里的spi_write_read是 SPI 驱动的核心基于 SPI 全双工特性一个函数即可完成发送、接收两种操作仅发送数据调用函数后忽略返回值即可仅接收数据向函数传入 0xFF空数据接收返回值即可。4.2 初始化函数 spi_init ()初始化函数分为引脚复用与电气属性配置、软件片选 GPIO 配置、ECSPI 核心寄存器配置三个部分逐行解析如下c运行#include fsl_common.h #include fsl_iomuxc.h #include MCIMX6Y2.h #include spi.h void spi_init(void) { // 第一部分引脚复用配置 IOMUXC_SetPinMux(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0); IOMUXC_SetPinMux(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0); IOMUXC_SetPinMux(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0); IOMUXC_SetPinMux(IOMUXC_UART2_TX_DATA_GPIO1_IO20, 0);IOMUXC_SetPinMux是 NXP SDK 封装的引脚复用配置函数第一个参数是引脚复用的宏定义指定了引脚的功能第二个参数是 SION 位软件输入使能这里配置为 0关闭强制输入。前三个引脚分别配置为 ECSPI3 的 MOSI、MISO、SCLK 功能第四个引脚配置为 GPIO1_IO20用于软件片选。c运行// 第二部分引脚电气属性配置 IOMUXC_SetPinConfig(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0x10B1); IOMUXC_SetPinConfig(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0x10B1); IOMUXC_SetPinConfig(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0x10B1); IOMUXC_SetPinConfig(IOMUXC_UART2_TX_DATA_GPIO1_IO20, 0x10B1);IOMUXC_SetPinConfig用于配置引脚的电气特性所有 SPI 相关引脚统一配置为0x10B1该值的二进制为0 0001 0000 1011 0001对应 PAD 寄存器的 bit16~bit0关键位拆解如下bit16(HYS)0关闭迟滞比较器SPI 引脚作为高速输出无需迟滞bit12(PKE)1使能上下拉 / 状态保持器功能bit11(ODE)0关闭开路输出SPI 采用推挽输出模式bit7-6(SPEED)10配置引脚速度为 100MHz 中速满足 SPI 高速通信需求bit5-3(DSE)110驱动能力配置为 R0/6保证 SPI 信号的驱动强度bit0(SRE)1开启高压摆率加快电平跳变速度减少高速信号的畸变。c运行// 第三部分软件片选GPIO配置 GPIO1-GDIR | (1 20); // GPIO1_IO20配置为输出模式 GPIO1-DR | (1 20); // GPIO1_IO20默认输出高电平不选中从机SPI 片选默认低电平有效这里初始化 GPIO 为输出模式默认输出高电平确保总线空闲时没有从机被选中。软件片选的优势在于时序控制完全自主不受 ECSPI 硬件通道限制可适配任意 CS 引脚的硬件设计。c运行// 第四部分ECSPI核心寄存器配置 ECSPI3-CONREG 0; // 先清零控制寄存器避免默认值干扰 ECSPI3-CONREG | (1 0); // 使能ECSPI3外设 // 配置突发长度、分频系数、主机模式、传输启动模式 ECSPI3-CONREG | (7 20) | (14 12) | (2 8) | (1 4) | (1 3); ECSPI3-CONFIGREG 0; // 清零配置寄存器 // 配置SPI模式3CPOL1CPHA1 ECSPI3-CONFIGREG | (1 20) | (1 4) | (1 0); }寄存器清零裸机开发中外设初始化的通用规范先清零寄存器再按需配置避免芯片默认值导致的未知问题。时钟频率计算i.MX6ULL 的 ECSPI 根时钟固定为 60MHz最终 SCLK 频率计算公式为SCLK(PRE_DIVIDER1)×2POST_DIVIDER60MHz​本文配置PRE_DIVIDER14、POST_DIVIDER2最终 SCLK 频率 60/(15×4)1MHz属于 SPI 通用安全频率可根据从设备手册调整分频系数修改时钟。模式配置CONFIGREG的配置最终实现 SPI 模式 3需和从设备的时序要求严格匹配若从设备使用模式 0只需将对应位清零即可。4.3 全双工读写函数 spi_write_read ()该函数是 SPI 驱动的核心实现单字节的全双工收发代码量极少但完全覆盖了 SPI 传输的完整流程逐行解析如下c运行unsigned int spi_write_read(unsigned int data) { // 清除通道选择位固定使用ECSPI3的通道0 ECSPI3-CONREG ~(3 18); // 等待TXFIFO为空确保上一次传输完成避免FIFO溢出 while ((ECSPI3-STATREG (1 0)) 0); // 写入待发送数据到TXFIFO自动启动SPI传输 ECSPI3-TXDATA data; // 等待RXFIFO就绪确保接收数据完成 while ((ECSPI3-STATREG (1 3)) 0); // 读取接收数据同时清除RR标志位 unsigned int ret ECSPI3-RXDATA; // 返回接收到的数据 return ret; }通道选择CONREG的 bit19-18 是通道选择位这里清零后固定使用通道 0和初始化中的通道配置保持一致避免通道选择错误。发送前等待循环等待TE位置 1确保发送 FIFO 为空上一次的数据已经完全发送再写入新数据防止 FIFO 溢出导致的数据丢失。启动传输向TXDATA写入数据后由于初始化中SMC1ECSPI 会自动启动 SPI 传输在 SCLK 的驱动下完成数据的移位收发。接收等待循环等待RR位置 1确保接收 FIFO 中有有效数据。这里要注意SPI 全双工特性决定了发送完成的同时接收也必然完成等待接收就绪就是等待整个传输流程结束。数据读取读取RXDATA寄存器获取接收数据读操作会自动清除RR标志位释放 RXFIFO 空间为下一次传输做准备。五、驱动使用示例以 SPI 接口的 ADXL345 三轴加速度传感器为例演示上述驱动的实际使用方法该传感器使用 SPI 模式 3和我们的驱动配置完全匹配。5.1 片选控制宏定义首先封装片选的控制宏SPI 通信的核心规则是通信前拉低 CS通信全程保持 CS 低电平通信结束后拉高 CS。c运行// 拉低片选选中ADXL345 #define ADXL345_CS_SELECT() GPIO1-DR ~(1 20) // 拉高片选取消选中 #define ADXL345_CS_DESELECT() GPIO1-DR | (1 20)5.2 寄存器读写函数ADXL345 的 SPI 读写规则写寄存器先发送寄存器地址最高位为 0再发送待写入的数据读寄存器先发送寄存器地址最高位为 1再发送空数据0xFF读取返回的寄存器值。c运行// ADXL345写寄存器函数 void adxl345_write_reg(unsigned char addr, unsigned char data) { ADXL345_CS_SELECT(); // 通信前拉低片选 spi_write_read(addr 0x7F); // 发送写命令最高位清0 spi_write_read(data); // 发送待写入数据 ADXL345_CS_DESELECT();// 通信结束拉高片选 } // ADXL345读寄存器函数 unsigned char adxl345_read_reg(unsigned char addr) { unsigned char reg_val; ADXL345_CS_SELECT(); spi_write_read(addr | 0x80); // 发送读命令最高位置1 reg_val spi_write_read(0xFF); // 发送空数据读取寄存器值 ADXL345_CS_DESELECT(); return reg_val; }5.3 设备 ID 读取验证ADXL345 的设备 ID 寄存器地址为 0x00固定值为 0xE5可通过读取该寄存器验证 SPI 驱动是否正常工作c运行#include stdio.h int main(void) { // 必须先初始化系统时钟打开所有外设时钟 init_clock(); // 初始化SPI驱动 spi_init(); // 读取ADXL345设备ID unsigned char dev_id adxl345_read_reg(0x00); printf(ADXL345 Device ID: 0x%X\r\n, dev_id); while(1) { // 后续业务逻辑 } return 0; }若串口打印出ADXL345 Device ID: 0xE5说明 SPI 驱动工作完全正常。六、开发中的常见坑与注意事项外设时钟必须提前使能i.MX6ULL 的所有外设都需要 CCM 时钟控制器使能后才能工作若只配置 ECSPI 寄存器而不使能时钟所有寄存器操作都会无效。裸机开发中建议在 main 函数开头先初始化 CCM打开全部外设时钟。SPI 模式必须与从设备严格匹配CPOL 和 CPHA 的配置错误是 SPI 通信失败的最常见原因必须严格按照从设备数据手册的时序要求配置哪怕只差一个参数也会出现采样数据全 0 或全 0xFF 的问题。片选时序的严格控制多字节读写过程中CS 引脚必须全程保持低电平不能中途拉高每次完整的读写操作结束后必须拉高 CS让从机复位传输状态否则从机会出现数据错位。时钟频率不能超过从设备上限不同 SPI 从设备的最高时钟频率差异极大比如 SPI Flash 最高可达 100MHz而部分传感器仅支持 10MHz 以下的时钟。若通信出现偶发错误可先降低 SPI 时钟频率验证。数据位宽的匹配初始化中BURST_LENGTH配置为 7对应 8bit 数据位宽这是绝大多数 SPI 设备的标准配置。若使用 16bit 位宽的设备需将该值改为 1516bit否则会出现数据移位错误。七、总结本文从零实现了 i.MX6ULL ECSPI3 的主机模式裸机驱动基于 SPI 全双工特性设计了通用的读写接口完整覆盖了引脚配置、寄存器时序、实际使用的全流程。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…