spi cpol极性和cpha相位

2024-04-24 18:58
文章标签 spi 相位 极性 cpol cpha

本文主要是介绍spi cpol极性和cpha相位,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        在spi通信中,需要设置cpol极性和cpha相位,保持master和slave两端时钟一致,相互匹配才能正常通信。主要原因是spi没有握手信号不可靠传输。

        参考文章:高手带你理解SPI中的极性CPOL和相位CPHA

名词解释

        CKPOL (Clock Polarity) = CPOL = POL = Polarity = (时钟)极性

        CKPHA (Clock Phase) = CPHA = PHA = Phase = (时钟)相位

        SCK=SCLK=SPI的时钟

        Edge=边沿,即时钟电平变化的时刻,即上升沿(rising edge)或者下降沿(falling edge)

        对于一个时钟周期内,有两个edge,分别称为:

        (1)Leading edge=前一个边沿=第一个边沿,对于开始电压是1,那么就是1变成0的时候,对于开始电压是0,那么就是0变成1的时候。

        (2)Trailing edge=后一个边沿=第二个边沿,对于开始电压是1,那么就是0变成1的时候(即在第一次1变成0之后,才可能有后面的0变成1),对于开始电压是0,那么就是1变成0的时候。

        CPOL和CPHA,分别都可以是0或时1,对应的四种组合就是:

        CPOL=0,时钟空闲低电平,当SCLK有效的时候,就是高电平,就是所谓的active-high;

        CPOL=1,时钟空闲高电平,当SCLK有效的时候,就是低电平,就是所谓的active-low;

        CPHA=0,表示第一个边沿:

                对于CPOL=0,idle时候的是低电平,第一个边沿就是从低变到高,所以是上升沿;

                对于CPOL=1,idle时候的是高电平,第一个边沿就是从高变到低,所以是下降沿;

        CPHA=1,表示第二个边沿:

                对于CPOL=0,idle时候的是低电平,第二个边沿就是从高变到低,所以是下降沿;

                对于CPOL=1,idle时候的是高电平,第一个边沿就是从低变到高,所以是上升沿;

波形图

        参考手册《IMX8QXPAEC.pdf》4.10.1 LPSPI timing parameters

        默认设置CPOL=0,CPHA=0;时钟空闲低电平,第一个边沿采样。

 代码设置

        Cortex-M4代码设置:

/*! @brief LPSPI clock polarity configuration.*/
typedef enum _lpspi_clock_polarity
{kLPSPI_ClockPolarityActiveHigh = 0U, /*!< CPOL=0. Active-high LPSPI clock (idles low)*/kLPSPI_ClockPolarityActiveLow  = 1U  /*!< CPOL=1. Active-low LPSPI clock (idles high)*/
} lpspi_clock_polarity_t;/*! @brief LPSPI clock phase configuration.*/
typedef enum _lpspi_clock_phase
{kLPSPI_ClockPhaseFirstEdge = 0U, /*!< CPHA=0. Data is captured on the leading edge of the SCK and changed on thefollowing edge.*/kLPSPI_ClockPhaseSecondEdge = 1U /*!< CPHA=1. Data is changed on the leading edge of the SCK and captured on thefollowing edge.*/
} lpspi_clock_phase_t;
/*! @brief LPSPI master configuration structure.*/
typedef struct _lpspi_master_config
{lpspi_clock_polarity_t cpol;       /*!< Clock polarity. */lpspi_clock_phase_t cpha;          /*!< Clock phase. */
} lpspi_master_config_t;
/*! @brief LPSPI slave configuration structure.*/
typedef struct _lpspi_slave_config
{lpspi_clock_polarity_t cpol;       /*!< Clock polarity. */lpspi_clock_phase_t cpha;          /*!< Clock phase. */
} lpspi_slave_config_t;

        Transmit Command Register (TCR) 

         在A35核中,dts中没有设置项,代码spi-fsl-lpspi.c中也没有设置,默认都是0模式。

#define TCR_CPOL    BIT(31)
#define TCR_CPHA    BIT(30)

        用户程序使用SPI_IOC_RD_MODE设置mode无效,SPI驱动中没有设置的代码:

	unsigned char mode = 0;ret = ioctl(fd, SPI_IOC_RD_MODE,&mode);if(ret < 0){perror("ioctl SPI_IOC_RD_MODE");return -1;}

        驱动中手动设置CPHA模式:temp |= TCR_CPHA;

static void fsl_lpspi_set_cmd(struct fsl_lpspi_data *fsl_lpspi)
{   u32 temp = 0;if (!fsl_lpspi->is_slave) {temp |= fsl_lpspi->config.bpw - 1; temp |= fsl_lpspi->config.prescale << 27; temp |= (fsl_lpspi->config.mode & 0x3) << 30; temp |= (fsl_lpspi->config.chip_select & 0x3) << 24;/** Set TCR_CONT will keep SS asserted after current transfer.* For the first transfer, clear TCR_CONTC to assert SS.* For subsequent transfer, set TCR_CONTC to keep SS asserted.*/if (!fsl_lpspi->usedma) {temp |= TCR_CONT;if (fsl_lpspi->is_first_byte)temp &= ~TCR_CONTC;elsetemp |= TCR_CONTC;}} else { temp |= fsl_lpspi->config.bpw - 1;temp |= (fsl_lpspi->config.mode & 0x3) << 30;temp |= TCR_CPHA;}writel(temp, fsl_lpspi->base + IMX7ULP_TCR);dev_dbg(fsl_lpspi->dev, "TCR=0x%x\n", temp);
}

        根据文章stm32 硬件SPI接收 数据的干扰、丢包的一些感想_奥利奥冰茶的博客-CSDN博客_spi丢包

        SPI丢包大概率是时钟上升沿采样容易收到毛刺波形的干扰,使用CPHA=1模式,在下降沿采数据比较干净不容易收到干扰,测试效果如下:

1MHz:【T=100us】【cpha=0】SPI TEST OVER:total 199970, 0, 17, packages,time:26063671SPI TEST OVER:total 199974, 0, 15, packages,time:25902166SPI TEST OVER:total 199979, 0, 11, packages,time:25812487SPI TEST OVER:total 199959, 0, 22, packages,time:25739095【T=100us】【cpha=1】SPI TEST OVER total:199994, lost:0, error:3, time:40820 msSPI TEST OVER total:199993, lost:0, error:5, time:40819 msSPI TEST OVER total:199994, lost:0, error:3, time:40819 ms

        测试代码:

masterConfig.cpha = kLPSPI_ClockPhaseFirstEdge;
masterConfig.cpha = kLPSPI_ClockPhaseSecondEdge;
masterConfig.baudRate = 1000000;static void hello_task(void *pvParameters)
{uint8_t *tmp=NULL;uint32_t cnt = 0;uint32_t currentTime;char ch;tmp = (uint8_t *)(&cnt);send_buffer[0] = 'g';send_buffer[1] = 'e';send_buffer[2] = 'n';send_buffer[3] = 'v';send_buffer[4] = 0;send_buffer[5] = 0;send_buffer[6] = 0;send_buffer[7] = 0;spi_data.dataSize = 8;PRINTF("\r\n####################  spi3 master test ####################\n\r\n");PRINTF("	Build Time: %s--%s \n\r\n", __DATE__, __TIME__);PRINTF("##########################################################\r\n");PRINTF("please input enter start send data:\r\n");ch = GETCHAR();PRINTF("ch=%c\r\n",ch);for (;;){cnt++;send_buffer[4] = tmp[0];send_buffer[5] = tmp[1];send_buffer[6] = tmp[2];send_buffer[7] = tmp[3];if (kStatus_Success != LPSPI_RTOS_TransferBlocking(&handle, &spi_data))//自构建阻塞,可以发送数据{PRINTF("Command Transmission fails.\r\n");vTaskSuspend(NULL);}//延时微秒SDK_DelayAtLeastUs(100, SystemCoreClock);if (cnt == 1){currentTime = OSA_TimeGetMsec();PRINTF("SPI TEST START:%d\r\n",currentTime);SDK_DelayAtLeastUs(1000, SystemCoreClock);}if (cnt == 200000){currentTime = OSA_TimeGetMsec();PRINTF("SPI TEST OVER: %d\r\n",currentTime);PRINTF("please input enter start send data1:\r\n");ch = GETCHAR();cnt = 0;} }
}
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include<sys/time.h>#define DEV_SPI "/dev/spidev0.0"
#define LEN 8int main(int argc,char* argv[])
{int fd;int ret;unsigned char * cmp="genv";unsigned char mode = 0;unsigned char bits_per_word = 8;unsigned int speed = 1000000;unsigned int cnt = 0;unsigned int cnt_lost = 0;unsigned int cnt_error = 0;unsigned int cntrecv = 0;unsigned int cntrecvtotal = 200000;unsigned char *cntr= (unsigned char *)&cntrecv;unsigned int previous_index=0;int i = 0;unsigned char rx_buf[8]={0};struct spi_ioc_transfer msg = {.rx_buf = (unsigned long)rx_buf,.len = 8,};struct timeval tv;unsigned long long millisecondsSinceEpoch_s = 0;unsigned long long millisecondsSinceEpoch_e = 0;fd = open(DEV_SPI, O_RDONLY);if(fd < 0){perror("Open:");return -1;}#if 1ret = ioctl(fd, SPI_IOC_RD_MODE,&mode);if(ret < 0){perror("ioctl SPI_IOC_RD_MODE");return -1;}
#endif
#if 1ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits_per_word);if (ret < 0) {perror("ioctl SPI_IOC_RD_BITS_PER_WORD");return -1;}
#endifret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);if (ret == -1)perror("can't get max speed hz");for(;;){memset(rx_buf, 0, 8);ret = ioctl(fd, SPI_IOC_MESSAGE(1), &msg);if(ret < 1 ){continue;}else{ret=memcmp(rx_buf,cmp,4);if(ret){cnt_error++;continue;}else{cntr[0]=rx_buf[4];cntr[1]=rx_buf[5];cntr[2]=rx_buf[6];cntr[3]=rx_buf[7];if(cntrecv < previous_index || cntrecv > cntrecvtotal ){cnt_lost++;continue;}else{previous_index = cntrecv;//printf("cntrecv=%d\n ",cntrecv);cnt++;}//printf("cntrecv=%d\n",cntrecv);if(cntrecv == 1){gettimeofday(&tv, NULL);millisecondsSinceEpoch_s =(unsigned long long)(tv.tv_sec) * 1000 + (unsigned long long)(tv.tv_usec) / 1000;//printf("SPI TEST START:%llu\n", millisecondsSinceEpoch_s);}if(cntrecv >= cntrecvtotal){gettimeofday(&tv, NULL);millisecondsSinceEpoch_e =(unsigned long long)(tv.tv_sec) * 1000 + (unsigned long long)(tv.tv_usec) / 1000;printf("SPI TEST OVER total:%u, lost:%d, error:%d, time:%llu ms\n", cnt,cnt_lost,cnt_error,millisecondsSinceEpoch_e - millisecondsSinceEpoch_s);break;}}}}close(fd);
}

这篇关于spi cpol极性和cpha相位的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/932566

相关文章

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

stm32之软件SPI读写W25Q64存储器应用案例

系列文章目录 1. stm32之SPI通信协议 文章目录 系列文章目录前言一、电路接线图二、应用案例代码三、应用案例分析3.1 SPI通信模块3.2 W25Q64模块3.3 主程序 前言 提示:本文主要用作在学习江科大自化协STM32入门教程后做的归纳总结笔记,旨在学习记录,如有侵权请联系作者 本案例使用软件SPI通信的方式实现了STM32与W25Q64 Flas

Flink1.10基于工厂模式的任务提交与SPI机制

《2021年最新版大数据面试题全面开启更新》 Flink任务执行模式包含了yarn-session、standalone、per-job、local, 在1.10中又增加k8s的执行模式,那么在任务提交过程中如何根据不同的执行模式进行任务提交呢?主要通过两个接口来实现:PipelineExecutorFactory 与 PipelineExecutor。PipelineExecutorF

转载 SPI的比喻理解

SPI 传输是一个虚拟的移位寄存器方式。 你这么理解就可以: 主机和从机之间有一条 16 格的传送带。主机一格一格拨动它转动(相当于发送时钟)。 如果是主机发送,它就把一个个的东西放在传送带上,转动 8 次,就传到从机一侧了。这时,从机可以从传送带上将东西取下。如果从机没有取东西,这些东西再转 8 次又回到主机一侧。 如果是主机接收,从机就要把 8 个东西一次放上传送带。当主机转动 8 次,东西就

Java SPI机制源码

文章目录 SPI简介使用案例SPI的应用SPI机制源码SPI与类加载器双亲委派机制 SPI简介 Java的SPI(Service Provider Interface)机制允许第三方为应用程序提供插件式的扩展,而不需要修改应用程序本身的代码,从而实现了解耦。Java标准库本身就提供了SPI机制,通常是通过在META-INF/services目录下放置文件来实现的。 S

W25Q32驱动 基于HAL库的SPI

环境 芯片:STM32F103ZET6 库:来自HAL的STM32F1XX.H 原理图 cubeMX配置 W25Q32.h //// Created by seven on 2024/9/2.//#ifndef SPI_W25Q32_H#define SPI_W25Q32_H#include "spi.h"/*** 初始化W25Q32闪存芯片*/void W25Q32

STM32F10XX中SPI的DMA发送数据

参考资料: http://blog.csdn.net/jdh99/article/details/7603029 http://www.openedv.com/posts/list/3159.htm     上面提到的两篇博文比较详细深刻的说明了DMA的工作方式以及SPI的DMA传输方式的特点。结合对Stm32F103VET6中SPI的DMA传输方式的配置和学习谈谈感受,在看下面的内容之前请

解耦利器 - Java中的SPI机制

为什么需要SPI机制 SPI和API的区别是什么 SPI是一种跟API相对应的反向设计思想:API由实现方确定标准规范和功能,调用方无权做任何干预; 而SPI是由调用方确定标准规范,也就是接口,然后调用方依赖此接口,第三方实现此接口,这样做就可以方便的进行扩展,类似于插件机制,这是SPI出现的需求背景。 SPI : “接口”位于“调用方”所在的“包”中 概念上更依赖调用方。 组织上位于

【STM32项目设计】STM32F411健康助手--硬件SPI (硬件NSS/CS)驱动st7735--1.8寸TFT显示屏(1)

#include "lcd_driver.h"static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);//液晶IO初始化配置void LCD_Driver_Init(void){SPI_InitTypeDef SPI_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;/* 使

【MCAL】TC397+EB-tresos之SPI配置实战 - (同步/异步)

本篇文章首先从理论讲起,从AUTOSAR规范以及MCAL手册两个不同角度(前者偏理论,后者偏实践)介绍了SPI模块的背景概念与理论,帮助读者在实际配置之前能有个理论的框架。然后详细的介绍了在TC397平台使用EB tresos对SPI驱动模块进行配置与调试的实战过程,帮助第一次接触这个模块的读者能够更快的上手来实现符合自己项目要求的开发工作,完成SPI通信。文章分别从同步和异步两种方式介绍了配置