spi四种工作模式时序图_框架-SPI四种模式+通用设备驱动实现

本文介绍了SPI协议的基本概念、物理线路说明,并详细解析了SPI的四种工作模式(CPOL和CPHA),包括各自的时序图。此外,文章还提出了一个通用的SPI驱动框架,总结了不同模式下的读写时序规律,提供了读写函数的实现思路。
摘要由CSDN通过智能技术生成

本文作者:李柱明本文链接:https://www.cnblogs.com/lizhuming/p/13907267.html

前言

  • SPI 介绍 为搜集百度资料+个人理解
  • 其余为原创(有误请指正)
  • 集四种模式于一身

笔录草稿

SPI介绍

  • SPI 协议简介SPI 协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串行外围设备接口,是一种高速 全双工 的通信总线。是一个环形总线结构由 ss(cs)、sck、sdi、sdo 构成其时序主要是在 sck 的控制下,两个双向移位寄存器进行数据交换。
  • 物理线说明SS从设备选择信号线,常称为片选信号线,也称为NSS、CS。用于选择从机。SCK (Serial Clock)时钟信号线用于通讯数据同步。MOSI (Master Output, Slave Input)主设备输出/从设备输入引脚。主机发出,从机接收。MISO (Master Input,,Slave Output)主设备输入/从设备输出引脚。从机发出,主机接收。
  • SPI 四种模式请移步到下面章节学习
  • SPI的协议层SPI协议定义了通讯的起始和停止信号、数据有效性、时钟同步等环节。基本通讯过程图解标号1:NSS信号线由高变低,是SPI通讯的起始信号。标号6:NSS信号由低变高,是SPI通讯的停止信号。
  • 简单时序图
  • 模式时序图

SPI四种模式 **

  • 四种模式由 CPOLCPHA 组合区分
  • CPOL时钟极性是指SPI通讯设备处于空闲状态时,SCK信号线的电平信号为 0 时SCK 空闲状态为 低电平为 1 时SCK 空闲状态为 高电平
  • CPHA时钟相位是指数据的采样的时刻为 0 时MOSI或MISO数据线上的信号将会在SCK时钟线的“奇数边沿”被采样。(即是第一个边沿)这种模式适合那种从设备一旦被片选后就输出数据到MISO线上。为 1 时数据线在SCK的“偶数边沿”采样。(即是第二个边沿)这种模式适合那种从设备被片选后还需要一个时钟才能 输出数据到MISO线上。
  • 四种模式( CPOL, CPHA )模式 0:( 0, 0 )SCK空闲为 低电平 ,数据在SCK的 上升沿 被采样模式 1:( 0, 1 )SCK空闲为 低电平 ,数据在SCK的 下降沿 被采样模式 2:( 1, 0 )SCK空闲为 高电平 ,数据在SCK的 下降沿 被采样模式 3:( 1, 1 )SCK空闲为 高电平 ,数据在SCK的 上升沿 被采样

SPI 驱动框架 **

框架

  • 实现方法参考I2C设备驱动拆解
  • 自己先在写出四种模式的读写时序,便会发现以下规律
  • 读写的逻辑差不多都一样,只是 SCK 信号线出现的位置及高低电平会因不同模式而不同。( 这里我就不分别写出4种模式的单独实现了,直接上规律表,然后实现统一的源码 )
f7b58a9c6827fa740a56f2eeab32bacd.png

由上规律得出 支持四种模式的 SPI 读写源码

  • SPI 写函数
/**  * @brief  SPI 写函数  * @param   * @retval   * @author lzm  */void spiWriteOneByte(eSPI_ID id, unsigned char data){unsigned char i;const spi_t * spi = &spiDriverElem[id];    // 位置1if(spi->CPHA){spiOut(spi->sckGpiox, spi->sckPin, spi->CPOL);}for(i=0; i<8; i++){        // 位置2spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL != spi->CPHA));if(data & 0x80){spiMosiOutHi(spi);}else{spiMosiOutLo(spi);}data <<= 1;spi->delayUsFun(spi->readDelayUsCnt);        // 位置3spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL == spi->CPHA));}    // 位置4if(!(spi->CPHA)){spiOut(spi->sckGpiox, spi->sckPin, spi->CPOL);}}
  • SPI 读函数
/**  * @brief  SPI 读函数  * @param   * @retval   * @author lzm  */unsigned char spiReadOneByte(eSPI_ID id){unsigned char i;unsigned char ret;const spi_t * spi = &spiDriverElem[id];    // 位置1    for(i=0; i<8; i++){        // 位置2spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL != spi->CPHA));ret <<= 1;if(spiMisoIn(spi))ret |= 0x01;elseret &= 0xfe;spi->delayUsFun(spi->readDelayUsCnt);        // 位置3spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL == spi->CPHA));}    // 位置4spiOut(spi->sckGpiox, spi->sckPin, spi->CPOL);return ret;}
  • SPI 读写函数
/**  * @brief  SPI 读写一体函数  * @param   * @retval   * @author lzm  */unsigned char spiRWOneByte(eSPI_ID id, unsigned char data){unsigned char i;unsigned char ret;const spi_t * spi = &spiDriverElem[id];    // 位置1if(spi->CPHA){spiOut(spi->sckGpiox, spi->sckPin, spi->CPOL);}for(i=0; i<8; i++){        // 位置2spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL != spi->CPHA));if(data & 0x80){spiMosiOutHi(spi);}else{spiMosiOutLo(spi);}data <<= 1;spi->delayUsFun(spi->readDelayUsCnt);        // 位置3spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL == spi->CPHA));ret <<= 1;if(spiMisoIn(spi))ret |= 0x01;elseret &= 0xfe;spi->delayUsFun(spi->readDelayUsCnt);}    // 位置4if(!(spi->CPHA)){spiOut(spi->sckGpiox, spi->sckPin, spi->CPOL);}}


本文作者:李柱明本文链接:https://www.cnblogs.com/lizhuming/p/13907267.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值