news 2026/10/5 10:25:22

ARM裸机开发-SPI

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ARM裸机开发-SPI

目录

一.背景

SPI四种工作模式

三种协议对比

ADXL345传感器

二.寄存器

con

config

start

三.实现

1.初始化

2.读写

原理

ADC调用


一.背景

SPI 是英语 Serial Peripheral interface(串行外设接口) 的缩写,顾名思义就是串行外围设备接口。是 Motorola首先在其 MC68HCXX 系列处理器上定义的。SPI 接口主要应用在 EEPROM,FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。
SPI 是一种高速的,全双工,同步的串行通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
标准SPI采用四线组网方式,如下图:
SCLK:时钟信号线。与I2C类似的,所有设备都都需要时钟信号线进行同步,该信号由主机负责提供;
➢MOSI:主出从入,相当于主机的数据发送线;
➢MISO:主入从出,相当于主机的数据接收线;
➢CS:片选信号,与I2C不同,SPI设备没有所谓的从机地址,连接在总线上的设备通过CS片选信号选择。在同一时刻,总线上只有一个外设被选择,CS信号线通常是低电平有效的。
以上的四线方式构成了SPI全双工串行同步通信方式。需要注意的是,对于MOSI和MISO来说不是必须存在的,可以只有MOSI或者只有MISO。当然这样的话就只能实现单工通信方式了,这样的SPI成为三线SPI。至于到底采用三线方式还是四线方式取决于外设本身。例如,OLCD只需要主机发送数据而不需要从机发送数据,就可以使用三线SPI的连接方式。
SPI一主机多从机,通过拉低CS片选信号选择设备。
SPI的数据传输的时序:要理解SPI的通信时序。需要搞清楚SPI的两个重要概念。时钟极性(Clock Polarity 简称CPOL)和时钟相位(Clock Phase简称CPHA)。注意这两个概念都是跟时钟信号线相关的。
  • CPOL:规定了时钟信号线在空闲时的状态,CPOL=0表示时钟信号线在空闲时为低电平;CPOL=1表示时钟信号线在空闲是为高电平;
  • CPHA:与I2C不同,SPI的数据接收方并不是在时钟高或者低电平时采样的,而是在时钟信号处于沿时,至于是在上升沿还是下降沿取决于CPHA。CPHA=0表示是在时钟信号变化的第一个沿时采样
CPHA=1表示是在时钟信号变化的第二个沿时采样。
因此不难理解,这样的排列组合总共能够组合 出四种方式,具体使用哪种方式是由外设厂家规定的,因此在使用SPI之前就不得不读懂外设的说明文档。一下就是四种方式的时序图,来自《IMX6ULL参考手册.pdf》P794页。

SPI四种工作模式

CPOL=1, CPHA=0:空闲时SCLK为高电平,SPI在下降沿采样
CPOL= 1,CPHA=1:空闲时SCLK为高电平,SPI在上升沿采样
CPOL=0, CPHA=0:空闲时SCLK为低电平,SPI在上升沿采样
CPOL=0, CPHA=1:空闲时SCLK为低电平,SPI在下降沿采样
无论哪种工作方式,SPI这种串行通信方式都是MSB先行的。

三种协议对比

UARTI2CSPI
全双工、异步、串行半双工、同步、串行全双工、同步、串行
两根线 TXD RXD两根线 SCL SDA四根线 SCLK MOSI MISO CS
< 5MHZ100KHZ - 3.4MHZ1M - 100MHZ
点对点多主多从一主多从
低位先行高位先行高位先行

ADXL345传感器

测量X,Y,Z三轴的重力加速度

写时寄存器地址最高位为低电平,读时为高电平。

INT1/2中断引脚,里面有寄存器可以设置XYZ三轴的阈值,当超过阈值触发中断

SDO->MISO

SDA->MOSI

CS->片选

CS接17号,SCL接18号,MISO/SDO接19号,MOSI/SDA接20号引脚

二.寄存器

con

将60MHZ分频为1MHZ

四位,将哪一位置1就是将该通道设置为主机模式

三种启动方式:

1.切换通道

2.片选线拉低

3.SMC位,向发送缓冲区写数据自动开启

EN:在配置其他寄存器之前,将此位置1

config

SCLK_CTL置1,默认高电平

SS_POL:片选极性,(极性即默认电平的高低),上面引脚接线图将CS接到GPIO引脚,所以可通过GPIO设置,此处默认即可。

SS_CTL:置0对应上面reg寄存器的发送数据就开始通信,置1说明片选线拉低才通信。

SCLK_POL:表示空闲时为高还是低电平。

SCLK_PHA即CPHA,表示第几个沿发送数据,时钟极性和相位都应置1.

start

RR:置1表示超过一位字节数据在接收缓冲区

TE同理。

三.实现

1.初始化

// spi3_channel0初始化 void spi3_channel0_init(void) { // 1. spi引脚复用功能 IOMUXC_SetPinMux(IOMUXC_UART2_TX_DATA_GPIO1_IO20, 0); // CS IOMUXC_SetPinMux(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0); // SCLK IOMUXC_SetPinMux(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0); // MISO IOMUXC_SetPinMux(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0); // MOSI // 2. spi引脚电气属性 IOMUXC_SetPinConfig(IOMUXC_UART2_TX_DATA_GPIO1_IO20, 0x10B1); IOMUXC_SetPinConfig(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0x10B1); IOMUXC_SetPinConfig(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0x10B1); IOMUXC_SetPinConfig(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0x10B1); // 3. 通信前,将CS拉高 GPIO_Type_t t = { .direction = gpio_output, .default_value = 1 }; gpio_init(GPIO1, 20, &t); // 4. SPI寄存器 ECSPI3->CONREG = 0; ECSPI3->CONREG |= (7 << 20) | (0x0E << 12) | (2 << 8) | (1 << 4) | (1 << 3) | (1 << 0); ECSPI3->CONFIGREG = 0; ECSPI3->CONFIGREG |= (1 << 20) | (1 << 4) | (1 << 0); };

电气属性更改高压摆率即可,其余和点灯功能相同。

2.读写

原理

SPI是全双工移位通信:主从两侧各有一个移位寄存器。每个时钟沿到来时,主机通过 MOSI 往外“移出”1位,同时从 MISO “移入”1位。也就是——每“写”一位的同时必然“读”到一位。

写即是读:你往总线“写”一个字节(移出8位),同一过程里也会“读”回从机在MISO上的8(可能是无效/占位字节)。

读即是写:你想从从机“读”数据,必须提供时钟,所以主机必须同时“写”出一个占位字节(通常是0xFF或0x00),用这些时钟把从机的数据“移入”。

// spi读写 unsigned char spi3_read_write(unsigned char data) { while ((ECSPI3->STATREG & (1 << 0)) == 0); ECSPI3->TXDATA = data; while ((ECSPI3->STATREG & (1 << 3)) == 0); return ECSPI3->RXDATA; }
ADC调用
spi写:
主机发送寄存器地址->主机发送要写入的数据
spi读:
主机发送寄存器地址->发送占位字节Dummy(0xFF 0x00) ->从机回复数据
// adxl345写 void adxl345_write(unsigned char reg_addr, unsigned char data) { // 拉低CS gpio_set_value(GPIO1, 20, 0); // 发送寄存器地址 spi3_read_write(reg_addr);//发完会回复一个字节,无用不管 // 发送数据 spi3_read_write(data); // 拉高CS gpio_set_value(GPIO1, 20, 1); } // adxl345读 unsigned char adxl345_read(unsigned char reg_addr) { unsigned char ret = 0; // 拉低CS gpio_set_value(GPIO1, 20, 0); // 发送寄存器地址 spi3_read_write(reg_addr | 0x80); // 发送Dummy ret = spi3_read_write(0xFF); // 拉高CS gpio_set_value(GPIO1, 20, 1); return ret; }

struct ADXL345_Data { short x; short y; short z; float xg; float yg; float zg; }; // adxl345初始化 void adxl345_init(void) { // 关闭中断 adxl345_write(0x2E, 0x08); // 设置满分辨率 + 设置满量程 adxl345_write(0x31, 0x0B); // 低功耗模式 + 速率 adxl345_write(0x2C, 0x08); // 配置测量模式 + 唤醒模式 adxl345_write(0x2D, 0x0B); } // 获得adxl345三轴加速度 struct ADXL345_Data adxl345_collect(void) { struct ADXL345_Data ret; // 读取x轴数据 ret.x = adxl345_read(0x32); ret.x |= adxl345_read(0x33) << 8; // 读取y轴数据 ret.y = adxl345_read(0x34); ret.y |= adxl345_read(0x35) << 8; // 读取z轴数据 ret.z = adxl345_read(0x36); ret.z |= adxl345_read(0x37) << 8; // 获得x y z三轴加速度 ret.xg = ret.x * 0.0039; ret.yg = ret.y * 0.0039; ret.zg = ret.z * 0.0039; return ret; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/5 10:21:49

Chart MCP Server MCP 服务说明文档

1. 服务概述一句话简介&#xff1a;历史图表模式搜索引擎MCP服务器&#xff0c;2400万模式嵌入&#xff0c;10年历史数据&#xff0c;15000股票服务名称&#xff1a;Chart MCP Server (Chart Library)版本号&#xff1a;1.1.1开发者/提供方&#xff1a;grahammccain协议类型&am…

作者头像 李华
网站建设 2026/10/5 10:20:42

最弱模型竟成顶级AI解码器

AI蒸馏&#xff0c;实锤了&#xff1f;2026年&#xff0c;硅谷最敏感的一桩悬案&#xff0c;就是AI蒸馏。每当, 一款新模型, 突然变强, 跑分, 直追GPT, 回答, 又带着的味道, 同一个问题, 就会开始, 在业内游荡。所有人都在怀疑&#xff0c;却没有人能把证据拍在桌上。直到今天&…

作者头像 李华
网站建设 2026/10/5 10:18:39

快速上手LangGraph:5分钟搭建能记住状态的AI智能体编排系统

快速上手LangGraph&#xff1a;5分钟搭建能记住状态的AI智能体编排系统 【免费下载链接】langgraph Build resilient agents. 项目地址: https://gitcode.com/GitHub_Trending/la/langgraph 做过Agent的人都踩过同一个坑&#xff1a;LLM跑着跑着就"失忆"了&am…

作者头像 李华