STM32的SPI硬件CRC校验(个人学习记录)

这篇具有很好参考价值的文章主要介绍了STM32的SPI硬件CRC校验(个人学习记录)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、功能实现

        为了保证SPI通信数据的准确性,需要通过对每个数据进行CRC校验,保证设备运行正常。

二、基本原理

SPI通信可以通过以下步骤使用CRC:
● 设置CPOL、CPHA、LSBFirst、BR、SSM、SSI和MSTR的值;
● 在SPI_CRCPR寄存器输入多项式;
● 通过设置SPI_CR1寄存器CRCEN位使能CRC计算,该操作也会清除寄存器SPI_RXCRCR 和SPI_TXCRC;
● 设置SPI_CR1寄存器的SPE位启动SPI功能;
● 启动通信并且维持通信,直到只剩最后一个字节或者半字;
● 在把最后一个字节或半字写进发送缓冲器时,设置SPI_CR1的CRCNext位,指示硬件在发送完成最后一个数据之后,发送CRC的数值。在发送CRC数值期间,停止CRC计算;
● 当最后一个字节或半字被发送后,SPI发送CRC数值,CRCNext位被清除。同样,接收到的CRC与SPI_RXCRCR值进行比较,如果比较不相配,则设置SPI_SR上的CRCERR标志位,当设置了SPI_CR2寄存器的ERRIE时,则产生中断。

按照下述步骤清除CRC数值:
1. 关闭SPI模块(SPE=0);(实测可以不需要)
2. 清除CRCEN位为’0’;
3. 设置CRCEN位为’1’;
4. 使能SPI模块(SPE=1)。(实测可以不需要)

三、硬件配置

主机选用STM32F407VGT6,SPI2,从机选用STM32F103ZET6,SPI3,进行SPI通信并通过硬件CRC校验;

硬件接线:       

                                     主机------------从机

CS:                            PB12-----------PA15

CLOCK:                     PB13-----------PB3

MISO:                        PB14-----------PB4

MOSI:                        PB15-----------PB5

四、主机代码

#define SPI2_CS_ACTIVE() GPIO_ResetBits(GPIOB,SPI2_CS_PIN) //CS低电平时SPI2数据传输开始
#define SPI2_CS_INACTIVE() GPIO_SetBits(GPIOB,SPI2_CS_PIN) //CS高电平时SPI2数据传输截止
u16 TxData[4] = { 0x0001, 0x0002, 0x0003, 0x0004};

void SPI2_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
   	SPI_InitTypeDef  SPI_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);//使能SPI2时钟
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 ;
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
  	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
	
  	GPIO_PinAFConfig(GPIOB,GPIO_PinSource13,GPIO_AF_SPI2); //PB13复用为 SPI2
  	GPIO_PinAFConfig(GPIOB,GPIO_PinSource14,GPIO_AF_SPI2); //PB14复用为 SPI2
    GPIO_PinAFConfig(GPIOB,GPIO_PinSource15,GPIO_AF_SPI2); //PB15复用为 SPI2

	
	//这里只针对SPI口初始化
	RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2,ENABLE);//复位SPI2
	RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2,DISABLE);//停止复位SPI2
	
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //全双工模式
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		    //主SPI
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;		//16位帧结构
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		//串行同步时钟的空闲状态为高电平
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//串行同步时钟的第二个跳变沿被采样
  	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//NSS信号由软件(使用SSI位)管理
  	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;	//预分频值为4
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//数据传输从MSB位LSB位开始
	SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值计算的多项式
	SPI_Init(SPI2, &SPI_InitStructure);  //初始化外设SPIx寄存器
	

	SPI_CalculateCRC(SPI2,ENABLE);    //开启硬件CRC校验
	SPI_Cmd(SPI2, ENABLE);         //使能SPI外设
}

void SPI2_WriteByte(u16 txData)
{		 			 
	unsigned int crcval;

	SPI2_CS_ACTIVE();//拉低CS信号
	
	SPI_TransmitCRC( SPI2 );//开启CRC计算
	while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET){}//等待发送区空  
	SPI_I2S_SendData(SPI2, txData); //通过外设SPIx发送一个byte  数据
	
	delay_us(3);        //用逻辑分析仪测了数据发送总时间约为2.5us左右
	SPI2_CS_INACTIVE();//拉高CS信号


	crcval = SPI_GetCRC( SPI2, SPI_CRC_Tx );  //获取SPI1发送CRC寄存器的值
	printf( "CRC:%04x\r\n", crcval );        //打印输出CRC校验值

	SPI_CalculateCRC(SPI2,DISABLE);    //清除CRC校验值
	SPI_CalculateCRC(SPI2,ENABLE);
}

int main()
{
    delay_init(168);
	uint16_t i;
	USART3_Init(115200);
	SPI2_Init();

	printf("host mode\r\n");

	while(1)
	{	
		for(i=0;i<4;i++)
		{
			SPI2_WriteByte(TxData[i]);
	        delay_ms(1000);    //延时一段时间,防止从机数据处理不过来导致发送顺序出错
		}
		while(1);
	}
}

五、从机代码

void SPI3_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	SPI_InitTypeDef  SPI_InitStructure;
	
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_AFIO |RCC_APB2Periph_GPIOB |         
    RCC_APB2Periph_GPIOA, ENABLE );//PORTB时钟使能 
	RCC_APB1PeriphClockCmd(	RCC_APB1Periph_SPI3,  ENABLE );//SPI3时钟使能 	
	/**SPI3配置时需要关闭JTAG **/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
	
	//片选信号
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;  // PA15 推挽 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //上拉输入
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);
 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;  //PB13/14/15复用推挽输出 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB

 	GPIO_SetBits(GPIOB,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5);  //PB13/14/15上拉

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
	SPI_InitStructure.SPI_NSS =SPI_NSS_Hard;
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
	SPI_InitStructure.SPI_CRCPolynomial =7;
	SPI_Init(SPI3, &SPI_InitStructure);  //初始化外设SPIx寄存器

	SPI_CalculateCRC(SPI3,ENABLE);    //使能CRC校验
	SPI_Cmd(SPI3, ENABLE);            //使能SPI外设
	SPI_TransmitCRC( SPI3 );
}

u16 RxData,CRCData,CRCRecieve;

int main(void)
{		
	delay_init();	    	 //延时函数初始化
	USART1_Init(115200);
	SPI3_Init();
	printf("slave mode\r\n");	 
		
    while (1)
	{
		SPI_TransmitCRC( SPI3 );//开启CRC计算
		
		while (SPI_I2S_GetFlagStatus( SPI3, SPI_I2S_FLAG_RXNE ) == RESET){} 
		RxData = SPI_I2S_ReceiveData( SPI3 );    //接收数据 

		while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_RXNE) == RESET){}
		CRCRecieve=SPI_I2S_ReceiveData(SPI3);      //接收主机的CRC校验值
			
		CRCData = SPI_GetCRC( SPI3, SPI_CRC_Rx );  //获取从机的CRC校验值
		
		printf("RxData:%04x\r\n",RxData);    
		printf("CRCRecieve:%04x\r\n",CRCRecieve);
		printf("CRCData:%04x\r\n",CRCData);
			
		SPI_CalculateCRC(SPI3,DISABLE);    //清除从机CRC校验值
		SPI_CalculateCRC(SPI3,ENABLE);
		
    }
}

六、运行结果

主机串口打印

STM32的SPI硬件CRC校验(个人学习记录)

从机串口打印:

STM32的SPI硬件CRC校验(个人学习记录)

七、总结

不知道为啥,SPI传输的第一个数据总是不正确,后面的数据不会有影响,我不理解。但是其他的数据和CRC都是对的,说明硬件CRC成功开启了。

关于SPI波特率的设置,因为SPI2、SPI3都是挂在APB1线上,最大预分频系数是2。主机的APB1时钟是42MHZ,从机APB1的时钟是36MHZ,所以为了保证从机能够接收正确,预分频系数最小是设置到4。

关于主机片选信号拉高延时时间的确定,可以通过示波器或者逻辑分析仪测量一下,测量一个数据发送的总时长,确保数据和CRC校验值全部发完之后再拉高。

此文章纯属刚入行小白的学习记录,如有不对之处,望指正,感谢!文章来源地址https://www.toymoban.com/news/detail-502672.html

到了这里,关于STM32的SPI硬件CRC校验(个人学习记录)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32硬件SPI通信详解-------附代码

    1.STM32内部集成了 硬件SPI收发电路 ,可以由 硬件自动执行时钟生成 、 数据收发 等功能, 减轻CPU的负担 2.可配置 8位/16位数据帧 、 高位先行/低位先行 3. 时钟频率 : fPCLK / (2, 4, 8, 16, 32, 64, 128, 256) 4.支持 多主机模型 、 主或从操作 5.可精简为 半双工/单工通信 6. 支持DMA 7. 兼

    2024年04月27日
    浏览(46)
  • STM32硬件SPI发送超8字节数据格式

    一般CPU提供的spi接口,支持的是整字节访问,如8bit、16bit等。而非整字节的spi外设(芯片)也是很常见,哪怕是整字节的,很多厂家也是做得与标准spi外设有差别,估计是避开专利问题。而芯片原厂提供的Demo也大多是采用GPIO模拟spi。一般情况下,根据芯片手册说明及访问时

    2024年02月05日
    浏览(41)
  • STM32的硬件SPI驱动AD7124的方法

    AD7124是一款适合高精度测量应用的低功耗、低噪声、完整模拟前端。该器件内置一个低噪声24位Σ-Δ型模数转换器(ADC),可配置来提供8个差分输入或15个单端或伪差分输入。片内低噪声级确保ADC中可直接输入小信号。可用于温度测量、压力测量、工业过程控制、仪器仪表和只能

    2024年02月07日
    浏览(78)
  • STM32F103硬件SPI驱动ADS1256

    最近实验室有几个项目都需要用到高分辨率AD转换,于是就开始了ADS1256的开发。 新手,焊得丑,见谅(能用就行) 二: 本以为很容易就能做完,结果被采样速率的问题困扰了很久。 代码如下,使用2.5V基准源进行测试,结果在读ADS时经常出现读出0xFFFFFF的情况,只能忍住悲伤

    2024年02月12日
    浏览(76)
  • STM32 硬件SPI+DMA实现快速刷TFT屏

    首先在TB上找一块SPI驱动的彩屏,下载商家提供的示例 例如我买的一款2.8寸SPI的TFT彩屏,商家提供的资料很齐全,模拟SPI和硬件SPI驱动的程序都有 打开硬件SPI驱动的工程,商家提供的代码是SPI2驱动,想换成其他的SPI可以到SPI.c文件中更改 打开main.c,测试一下简单颜色填充刷

    2024年04月15日
    浏览(63)
  • stm32 hal库硬件spi(软件spi)驱动1.8寸tft—lcd屏幕

    屏幕是嵌入式开发中的一个重要的部分,cdsn上有许多解释原理的,还有很多是采用正点原子的屏幕来驱动的,对于刚刚入门不久的我们可能没有资金去购买较为昂贵的屏幕。而对于底层原理我们暂时也不必了解的那么深入,能点亮屏幕就是我们最大的快乐。 除了中景园的资

    2024年02月03日
    浏览(53)
  • 【STM32篇】SPI时序驱动W25Q64(硬件SPI和模拟SPI)

            由于MCU的FLASH空间有限,在特殊使用场所中会存在FLASH存储不够使用的情况。例如上篇中驱动LCD屏,需要将一个中文字库保存到MCU的FLASH中是不太现实的(STM32F103ZET6内部FLASH大小512KB),为此可使用外部FLASH作为拓展。         W25Q64(64Mbit)是为系统提供一个最小的空

    2024年02月08日
    浏览(51)
  • STM32配合CubeMX硬件SPI驱动0.96寸OLED

    目录 一、简单介绍 1.1 OLED 1.2 SPI协议 接口 优点 缺点 数据传输 二、实战 2.1 工程配置 2.2 测试工程 2.3 波形分析 三、驱动OLED 3.1 初始化代码 3.2 清屏函数 3.3 设置坐标函数 3.4 显示字符函数 3.5 显示字符串函数 3.6 显示图片函数 附录 驱动代码文件 oled.c oled.h f6x8.h 1.1 OLED 有机发

    2024年02月02日
    浏览(39)
  • 基础篇010.2 STM32驱动RC522 RFID模块之二:STM32硬件SPI驱动RC522

    目录 1. 实验硬件及原理图 1.1 RFID硬件 1.2 硬件原理图 2. 单片机与RFID硬件模块分析 3. 利用STM32CubeMX创建MDK工程 3.1 STM32CubeMX工程创建 3.2 配置调试方式 3.3 配置时钟电路 3.4 配置时钟 3.5 配置GPIO 3.6 配置SPI 3.7 配置串口 3.8 项目配置 4. MDK工程驱动代码调试 4.1 按键、LED程序 4.1.1 Us

    2024年02月09日
    浏览(53)
  • (python)数据校验-CRC32校验

    目录 前言 数据校验概念 CRC校验算法 CRC计算原理 算法逻辑 流程图 CRC算法种类 代码实现CRC算法 python实现算法① python实现算法② 总结         在二次开发eCan上位机应用时,遇到了采用CRC(全称是循环冗余校验)32算法 校验文件传输完整性 的场景,浅浅地记录一下使用心得.  

    2023年04月16日
    浏览(74)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包