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

SPI总线入门

1. SPI 协议介绍

1.1 什么是 SPI 协议

        SPI(Serial Peripheral Interface)是一种同步串行通信协议,用于在微控制器和外部设备之间进行数据传输。它由一个主设备(通常是微控制器 MCU)和一个或多个从设备组成,即一主多从模式。它通常用于短距离、高速、全双工的通信,它在许多嵌入式系统和电子设备中被广泛应用,如存储器芯片、传感器、显示器驱动器、无线模块等。

        在 SPI 协议中,主设备是通信的发起方和控制方,而从设备则是被动接收和响应主设备的命令和数据。主设备通过时钟信号来同步数据传输,同时使用多个双向数据线来实现数据的传输和接收。

        SPI 协议是一种全双工通信方式,意味着主设备和从设备可以同时发送和接收数据。它还使用一种选择信号(通常称为片选或使能信号),用于选择与主设备进行通信的特定从设备。

  1. 主设备通过 MOSI 线向从设备发送数据。在每个时钟周期中,主设备将一个位发送到 MOSI 线上,从设备在下一个时钟周期中读取该位。
  2. 从设备通过 MISO 线向主设备发送数据。在每个时钟周期中,从设备将一个位发送到 MISO 线上,主设备在下一个时钟周期中读取该位。
  3. 数据传输可以是全双工的,即主设备和从设备可以同时发送和接收数据。
  4. 数据传输的长度可以是可变的,通常以字节为单位。
  5. 数据传输可以是单向的,即主设备只发送数据或只接收数据。
  6. 数据传输可以是多主设备的,即多个主设备可以与多个从设备进行通信。

1.2 SPI的硬件接口

        SPI 主要使用 4 根线,时钟线(SCLK),主输出从输入线(MOSI),主输入从输出线(MISO)和片选线(CS)。

通信线说明
SCLK时钟线,也叫做 SCK。由主机产生时钟信号。
MOSI主设备输出从设备输入线,也叫做 SDO。意为主机向从机发送数据。
MISO主设备输入从设备输出线,也叫做 SDI。意为主机接收从机的数据。
CS片选线,也叫做 NSS。从机使能信号,由主机控制。当我们的主机控制某个从机时,需要将从机对应的片选引脚电平拉低或者是拉高。

        主设备是通过片选线选择要与之通信的从设备。每个从设备都有一个片选线,当片选线为低电平时,表示该从设备被选中。(也有一些设备以高电平有效,需要根据其数据手册确定)。

1.3 SPI 的模式选择

        SPI 协议定义了多种传输模式,也称为 SPI 模式或时序模式,用于控制数据在时钟信号下的传输顺序和数据采样方式。SPI 的传输模式主要由两个参数决定:时钟极性 (CKPL) 和相位 (CKPH)。

以下是常见的 SPI 模式:

  1. 模式 0(CKPL=0,CKPH=0):

    • 时钟极性(Clock Polarity)为 0,表示时钟空闲状态为低电平。
    • 时钟相位(Clock Phase)为 0,表示数据在时钟信号的第一个边沿(时钟上升沿)进行采样和稳定。
  2. 模式 1(CKPL=0,CKPH=1):

    • 时钟极性为 0,时钟空闲状态为低电平。
    • 时钟相位为 1,数据在时钟信号的第二个边沿(时钟下降沿)进行采样和稳定。
  3. 模式 2(CKPL=1,CKPH=0):

    • 时钟极性为 1,时钟空闲状态为高电平。
    • 时钟相位为 0,数据在时钟信号的第一个边沿(时钟下降沿)进行采样和稳定。
  4. 模式 3(CKPL=1,CKPH=1):

    • 时钟极性为 1,时钟空闲状态为高电平。
    • 时钟相位为 1,数据在时钟信号的第二个边沿(时钟上升沿)进行采样和稳定。

2. GPIO模拟SPI 接口示例

2.1 电路原理图

单片机SPI2接入了一片W25Q80DV型的Flash芯片,下面就以通过SPI读取芯片信息为例,演示软件模拟SPI时序的代码。

W25Q80DV的Read JEDEC ID (9Fh)的时序图

2.2 软件代码

#include "at32f403a_407_conf.h"
 
uint8_t spi_send_recv(uint8_t data)
{
    uint8_t val;
    for(int i=0;i<8;i++){
        val <<= 1;
        if(data & 0x80)
            gpio_bits_set(GPIOB, GPIO_PINS_15);
        else
            gpio_bits_reset(GPIOB, GPIO_PINS_15);
        data <<= 1;
        
        gpio_bits_set(GPIOB, GPIO_PINS_13); //sck high
        if(gpio_input_data_bit_read(GPIOB, GPIO_PINS_14))
            val |= 0x1;
        gpio_bits_reset(GPIOB, GPIO_PINS_13); //sck low
    }
    return val;
}

uint32_t w25q80_read_MFD()
{
    uint32_t id = 0;
    uint8_t data;
    gpio_bits_reset(GPIOB, GPIO_PINS_12); //cs low
    spi_send_recv(0x9f); //send cmd 9F
    data = spi_send_recv(0xff); //recv manufacturer ID (EF)
    id |= data << 16;
    data = spi_send_recv(0xff); //recv memory type ID15-ID8(40)
    id |= data << 8;
    data = spi_send_recv(0xff); //recv memory type ID17-ID0(14)
    id |= data;
    gpio_bits_set(GPIOB, GPIO_PINS_12); //cs high
    return id;
}
uint32_t mfd;

int main(void)
{
	//打开GPIO时钟
	crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
	
	//配置为输出
	gpio_init_type gpio_init_struct;
	gpio_init_struct.gpio_pins  = GPIO_PINS_12|GPIO_PINS_13|GPIO_PINS_15;
	gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
	gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
	gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
	gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
	gpio_init(GPIOB, &gpio_init_struct);

    gpio_bits_set(GPIOB, GPIO_PINS_12); //cs high
    
    mfd = w25q80_read_MFD();
	for(;;){
        
	}
}

程序运行正确的话,mdf的值应为 0x00EF4014。


http://www.kler.cn/news/368427.html

相关文章:

  • 利用 Puppeteer-Extra 插件提升自动化测试和网页抓取的效率与隐蔽性
  • 力扣 中等 740.删除并获得点数
  • LDR6328:助力小家电实现TYPE-C接口快充输入
  • Flutter鸿蒙next 中如何实现 WebView【跳、显、适、反】等一些基础问题
  • S-Function
  • 【功能安全】技术安全概念TSC
  • Python中的变量有哪些类型?
  • 超全(OD逆向常用断点)包括多个语言,易语言也有
  • 人工智能的未来:重塑生活与工作的变革者
  • 高效租房流程管理:Spring Boot租房系统解析
  • 聚簇索引和非聚簇索引B+树的关系
  • 研发效能DevOps: Vite 使用 Vue Router
  • Echarts_柱状图属性汇总
  • 数据分析每周挑战——睡眠质量影响因素研究
  • 《YOLO 目标检测》—— YOLO v3 详细介绍
  • Mybatis-plus-扩展功能
  • 【题解】—— LeetCode一周小结43
  • 《BLEU: a Method for Automatic Evaluation of Machine Translation》翻译
  • 数据库如何保证主键唯一性
  • Python如何处理zip压缩文件(Python处理zip压缩文件接口源码)
  • ES6面试题:(第二天)
  • 如何使用git上传项目至github。记一次上传github经历
  • Spring IoC DI
  • 基于NERF技术重建学习笔记
  • 算法 - 高精度算法(加减乘除)
  • 计算结构体及其中元素的大小