zoukankan      html  css  js  c++  java
  • 【框架】SPI四种模式+通用设备驱动实现


    前言

    • 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. 标号1:NSS信号线由高变低,是SPI通讯的起始信号。
        2. 标号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种模式的单独实现了,直接上规律表,然后实现统一的源码
    R/W CPOL CPHA 位置1-SCK 位置2-SCK 位置3-SCK 位置4-SCK
    R 0 0 X 0 1 0
    R 0 1 X 1 0 0
    R 1 0 X 1 0 1
    R 1 1 X 0 1 1
    - - - - - - -
    W 0 0 X 0 1 0
    W 0 1 0 1 0 X
    W 1 0 X 1 0 1
    W 1 1 1 0 1 X

    由上规律得出 支持四种模式的 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];
    	
        // 位置1
    	if(spi->CPHA){
    		spiOut(spi->sckGpiox, spi->sckPin, spi->CPOL);
    	}
    	
    	for(i=0; i<8; i++)
    	{
            // 位置2
    		spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL != spi->CPHA));
    		if(data & 0x80){
    			spiMosiOutHi(spi);
    		}
    		else{
    			spiMosiOutLo(spi);
    		}
    		data <<= 1;
    		spi->delayUsFun(spi->readDelayUsCnt);
            // 位置3
    		spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL == spi->CPHA));
    	}
        // 位置4
    	if(!(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++)
    	{
            // 位置2
    		spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL != spi->CPHA));	
    		ret <<= 1;
    		if(spiMisoIn(spi))
    			ret |= 0x01;
    		else
    			ret &= 0xfe;
    		spi->delayUsFun(spi->readDelayUsCnt);
            // 位置3
    		spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL == spi->CPHA));
    	}
        // 位置4
    	spiOut(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];
    	
        // 位置1
    	if(spi->CPHA){
    		spiOut(spi->sckGpiox, spi->sckPin, spi->CPOL);
    	}
    	
    	for(i=0; i<8; i++)
    	{
            // 位置2
    		spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL != spi->CPHA));
    		if(data & 0x80){
    			spiMosiOutHi(spi);
    		}
    		else{
    			spiMosiOutLo(spi);
    		}
    		data <<= 1;
    		spi->delayUsFun(spi->readDelayUsCnt);
            // 位置3
    		spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL == spi->CPHA));
    		ret <<= 1;
    		if(spiMisoIn(spi))
    			ret |= 0x01;
    		else
    			ret &= 0xfe;
    		spi->delayUsFun(spi->readDelayUsCnt);
    	}
        // 位置4
    	if(!(spi->CPHA)){
    		spiOut(spi->sckGpiox, spi->sckPin, spi->CPOL);
    	}
    }
    
  • 相关阅读:
    css透明度的兼容!!!
    csshtml布局及部分知识小分享~~~
    js面向对象选项卡
    JQ弹出框移动-插件分享~~~
    nginx配置phpcms v9伪静态规则 phpcms伪静态 404 Not Found
    mysql数据库常见优化方法
    帝国ECMS静态生成为一行代码/静态页面打乱教程
    帝国cms 批量删除或者清空classurl(二级域名绑定)
    jquery实现一个网页同时调用多个倒计时
    PHPCMSV9 单文件上传功能代码
  • 原文地址:https://www.cnblogs.com/lizhuming/p/13907267.html
Copyright © 2011-2022 走看看