STM32F1笔记(十三)SPI

SPI:Serial Peripheral interface,串行外围设备接口。

SPI接口一般使用4条线通信:

MISO主设备数据输入,从设备数据输出。

MOSI主设备数据输出,从设备数据输入。

SCLK时钟信号,由主设备产生。

从图中可以看出,主机和从机都有一个串行移位寄存器,主机通过向它的SPI串行寄存器写入一个字节来发起一次传输。寄存器通过MOSI信号线将字节传送给从机,从机也将自己的移位寄存器中的内容通过MISO信号线返回给主机。这样,两个移位寄存器中的内容就被交换。外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的一个字节,就必须发送一个空字节来引发从机的传输,这个空字节通常称为dummy_byte。

SPI总线四种工作方式是为了和不同外设进行数据交换,其输出串行同步时钟极性和相位可以进行配置。

时钟极性CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。

时钟相位CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。

SPI主从设备的时钟相位和极性应该一致。

 

STM32F1的SPI时钟最多可以到18Mhz。可用DMA。

SPI配置示例

void SPI2_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef SPI_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB, GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI2, &SPI_InitStructure);SPI_Cmd (SPI2, ENABLE);SPI2_ReadWriteByte(0xff); 
}  

SPI_Direction:选择半双工、全双工。

SPI_Mode:选择主机模式、从机模式。

SPI_DataSize:选择8位还是16位帧格式传输。

SPI_CPOL:设置时钟极性为高电平还是低电平。

SPI_CPHA:设置时钟相位,选择在时钟的第几个跳变沿数据被采样。

SPI_NSS:设置NSS信号由硬件(NSS管脚)还是软件控制。

SPI_BaudRatePrescaler:设置SPI波特率预分频值。示例选择256即本次SPI传输速度=36M/256=140.625KHz。

SPI_FirstBit:设置数据传输顺序是MSB位在前还是LSB位在前。大部分应用是MSB在前。

SPI_CRCPolynomial:设置CRC校验多项式,提高通信可靠性,大于1即可。

 

标准库里SPI发送一个字节函数为

SPI_I2S_SendData(SPI2, data);

接受一个字节函数为

data = SPI_I2S_ReceiveData(SPI2);

因此需要我们再封装几个函数,SPI写任意字节,读任意字节,读写任意字节。

 

SPI最常见的应用场景是读写FLASH。

正点原子战舰板子上的FLASH为W25Q128。该款FLASH的容量为128Mb也就是16M字节。将16M的容量分为256个块(Block),每个块大小为64K字节,每个块又分为16个扇区(Sector),每个扇区4K字节。W25Q128最小擦除单位为一个扇区,也就是每次必须擦除4K字节。这样就需要开辟一个至少4K的缓存区,即单片机需要有4K以上的SRAM才能很好操作。W25Q128最大SPI时钟能达80Mhz。

 

FLASH拿到手通常先测试能否到它的ID

从W25QXX datasheet  里看到,主机给它发0x90,0x00,0x00,0x00,即可读取16位ID

u16 W25QXX_ReadID(void)
{u16 Temp = 0;W25QXX_CS = 0;SPI2_ReadWriteByte(0x90);SPI2_ReadWriteByte(0x00);SPI2_ReadWriteByte(0x00);SPI2_ReadWriteByte(0x00);Temp |= SPI2_ReadWriteByte(0xFF) << 8;Temp |= SPI2_ReadWriteByte(0xFF);W25QXX_CS = 1;return Temp;
} 

这里要注意读ID时MOSI发送的是0xFF,这个就是DUMMY_BYTE,大多DUMMY_BYTE是0xFF,少部分设备会有特殊要求

FLASH读取数据,先发0x03和读取数据的地址起点,然后即可读取。

代码如下

void W25QXX_Read(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)   
{ u16 i;   			W25QXX_CS = 0;SPI2_ReadWriteByte(0x03);SPI2_ReadWriteByte((u8) ((ReadAddr) >> 16));SPI2_ReadWriteByte((u8) ((ReadAddr) >> 8)); SPI2_ReadWriteByte((u8) ReadAddr);for(i = 0; i < NumByteToRead; i++){ pBuffer[i] = SPI2_ReadWriteByte(0XFF);}W25QXX_CS = 1;  				    	      
} 

 

W25Q128写使能,要给flash写数据,必须先写使能。

从W25QXX datasheet  里看到,只要发0x06即可写使能。

void W25QXX_Write_Enable(void)   
{W25QXX_CS=0;SPI2_ReadWriteByte(0x06);W25QXX_CS=1;  	      
} 

 

写使能后还不能立即往FLASH里面写数据,需要将写入数据的FLASH地址擦除。

void W25QXX_Erase_Sector(u32 Dst_Addr)   
{  	  Dst_Addr *= 4096;W25QXX_Write_Enable();W25QXX_Wait_Busy();W25QXX_CS = 0;SPI2_ReadWriteByte(0x20);SPI2_ReadWriteByte((u8) ((Dst_Addr) >> 16)); SPI2_ReadWriteByte((u8) ((Dst_Addr) >> 8));   SPI2_ReadWriteByte((u8) Dst_Addr);W25QXX_CS = 1;W25QXX_Wait_Busy();
} 

 

FLASH写数据需要考虑跨扇区写入的问题,因为FLASH只提供了往一个页page写数据的命令0x02。

void W25QXX_Write_Page(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{u16 i;W25QXX_Write_Enable();W25QXX_CS = 0;SPI2_ReadWriteByte(0x02);SPI2_ReadWriteByte((u8) ((WriteAddr) >> 16));SPI2_ReadWriteByte((u8) ((WriteAddr) >> 8));SPI2_ReadWriteByte((u8) WriteAddr);for(i = 0; i < NumByteToWrite; i++){SPI2_ReadWriteByte(pBuffer[i]);}W25QXX_CS = 1;W25QXX_Wait_Busy();
} void W25QXX_Write_NoCheck(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)   
{ 			 		 u16 pageremain;pageremain = 256 - WriteAddr % 256;if(NumByteToWrite <= pageremain){pageremain = NumByteToWrite;}while(1){W25QXX_Write_Page(pBuffer , WriteAddr, pageremain);if(NumByteToWrite == pageremain){    break;}else{pBuffer += pageremain;WriteAddr += pageremain;	NumByteToWrite -= pageremain;if(NumByteToWrite > 256){pageremain = 256;}else{pageremain = NumByteToWrite;}}};	    
} u8 W25QXX_BUFFER[4096];void W25QXX_Write(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)   
{u32 secpos;u16 secoff;u16 secremain;u16 i;u8 * W25QXX_BUF;W25QXX_BUF = W25QXX_BUFFER;	     secpos = WriteAddr / 4096;  secoff = WriteAddr % 4096;secremain = 4096 - secoff;  if(NumByteToWrite <= secremain){secremain = NumByteToWrite;}while(1) {	W25QXX_Read(W25QXX_BUF, secpos * 4096, 4096);for(i = 0; i < secremain; i++){if(W25QXX_BUF[secoff + i] != 0XFF){break;}}if(i < secremain){W25QXX_Erase_Sector(secpos);for(i = 0; i < secremain; i++){W25QXX_BUF[i + secoff] = pBuffer[i];	  }W25QXX_Write_NoCheck(W25QXX_BUF, secpos * 4096, 4096);}else{W25QXX_Write_NoCheck(pBuffer, WriteAddr, secremain);}if(NumByteToWrite == secremain){break;}else{secpos++;secoff = 0;pBuffer += secremain;WriteAddr += secremain;NumByteToWrite -= secremain;if(NumByteToWrite > 4096){secremain = 4096;}else{secremain = NumByteToWrite;}}	 }
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/374366.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在WebLogic 12c上运行RichFaces 4.1.0.Final

您可能已经注意到&#xff0c;我只是喜欢JSF。 不仅是Mojarra的规范和参考实现&#xff0c;而且是市场上最具创意的组件套件。 这是我一直以来最喜欢的PrimeFaces &#xff0c;当然还有RichFaces 。 这就是为什么在这里找到“在xxx上运行xxx”帖子的原因:)今天是我的RichFaces和…

C语言开发笔记(一)自动转换和强制转换

整型数据和实行数据之间可以进行运算&#xff0c;而且字符型数据可以和整型数据通用&#xff0c;所以整型、实型、字符型数据之间也是可以进行运算的&#xff0c;但在运算处理之前&#xff0c;不同类型的数据要事先转换成同一种数据类型。转换方法有两种&#xff1a;自动转换和…

Maven 导出依赖Jar,生成source.jar,javadoc.jar

下载最新版的Maven http://maven.apache.org/download.cgi 解压到本地文件夹新建环境变量 MAVEN_HOME maven解压目录在path加入 %MAVEN_HOME%/bin;需要确保已经有Java环境变量 &#xff08;打开cmd java -version,javac -version两个命令看正常不&#xff09;一、导出到默认目…

asp.net 分布式应用开发

Net Framework推出的许多新技术为上述任务的实现提供了相对简单的解决方案。其中&#xff0c;基于SOAP的Web Service在处理分布式应用时具有比传统的DCOM/CORBA明显的优点&#xff0c;结合基于Web的ASP.NET页面开发技术和SQL Server数据存储技术&#xff08;或Xml文档&#xff…

C语言开发笔记(三)自加和自减

看到一段代码&#xff0c;被坑了。 #include <stdio.h>int main(void) {int a 7;printf("%d\n", a);printf("%d\n", a--);printf("%d\n", -a);printf("%d\n", -a--);printf("%d\n", a);return 0; } 结果为 -a的逻辑…

python语言属于哪一种语言_Python与Java:你应该学习哪种语言,他们有什么区别?...

在企业招聘中&#xff0c; Python和Java经常是需求最大的编程语言。这两种编程功能强大&#xff0c;灵活且面向对象的语言&#xff0c;通常在组织中和各种其他设置中使用。这可能会导致我们提出一个不可避免的问题&#xff1a;哪个更好&#xff1f; 这是一个复杂的问题&#xf…

关于手机端CSS Sprite图标定位的一些领悟

今天在某个群里面闲逛&#xff0c;看见一个童鞋分享了一个携程的移动端的页面。地址这里我也分享下吧&#xff1a;http://m.ctrip.com/html5/在手机端我都很少用雪碧图合并定位图标&#xff0c;用的比较多就是用字体图标来代替&#xff0c;有些图标不多的时候就自己单个的切出来…

c语言程序源代码_程序的编译、链接和执行

同学们总是抱怨每次见到一道面试题都很难把它转化为程序源代码。然而不幸的是&#xff0c;即使是程序源代码对于计算机来说也还是太高级了。要想让计算机执行一段程序&#xff0c;我们必须把它翻译成最底层的机器指令才行。这其中要经历很多步骤。幸运的是有很多现成的工具可以…

【程序员眼中的统计学(1)】信息图形化:第一印象

信息图形化&#xff1a;第一印象 作者 白宁超 2015年10月13日23:23:13 摘要&#xff1a;程序员眼中的统计学系列是作者和团队共同学习笔记的整理。首先提到统计学&#xff0c;很多人认为是经济学或者数学的专利&#xff0c;与计算机并没有交集。诚然在传统学科中&#xff0c;其…

JBoss AS 7.0.2“ Arc”发布–使用绑定选项

有关JBoss AS7方面的更多好消息。 JBoss AS 7.0.2.Final“ Arc”已经发布&#xff01; 自AS 7.0.1发布以来已经过去了一个月。 在这短时间内&#xff0c;已修复了许多错误&#xff0c;并实现了更多功能和改进。 所有这些错误修复和功能已包含在此7.0.2版本中。 此新版本主要包…

Android N 新特性 + APP开发注意事项

1. 多窗口MultiWindow 多窗口MultiWindow&#xff0c;这是Android N里对开发者影响比较大的特性&#xff0c;也是大家疑问比较多的地方。站在开发者的角度其实不必太担心这个特性会导致我们需要修改很多代码来适配系统。Google的工程师们也不希望这个特性导致很多应用出现问题&…

C语言开发笔记(六)实参和形参

举例说明 #include <stdio.h>void swap(int x, int y) {int temp 0;temp x;x y;y temp; }int main(void) {int a 1, b 2;swap(a, b);printf("a%d, b%d\n", a, b);return 0; }结果为 在函数调用时&#xff0c;a的值传给x&#xff0c;b的值传给y。执行完…

优化方案电子版_关于小区分支道路整修设计方案的讨论稿(No.2020121)

各位业主&#xff0c;大家好&#xff01; 关于绿洲比华利花园主干道翻新和次干道整修前期勘查和设计方案&#xff0c;经业委会及小区专家小组、设计单位申都设计公司工程设计人员结合本小区的实际情况进行了深入讨论&#xff0c;优化设计&#xff0c;形成如下三个独立方案&…

为什么有的开关电源需要加自举电容?

一、什么是自举电路&#xff1f; 1.1 自举的概念 首先&#xff0c;自举电路也叫升压电路&#xff0c;是利用自举升压二极管&#xff0c;自举升压电容等电子元件&#xff0c;使电容放电电压和电源电压叠加&#xff0c;从而使电压升高。有的电路升高的电压能达到数倍电源电压。…

VS2010报错 error:LINK1123:转换到COF期间失败,文件无限或损坏

右键工程-配置属性-清单工具-输入和输出&#xff0c;嵌入清单一项重新选择为否&#xff0c;如下图 修改后重新生成和运行&#xff0c;发现程序正常运行了。

springboot 整合mybatis_SpringBoot整合Mybatis、MybatisPuls

文末视频讲解SpringBoot的版本是2.2.0一、整合Mybatis1-1、引入pom文件<dependency> <groupId>mysqlgroupId> <artifactId>mysql-connector-javaartifactId> <version>8.0.19version> dependency> <dependency> &l…

为旧版代码创建存根–测试技术6

任何阅读此博客的人都可能已经意识到&#xff0c;目前我正在开发一个包含大量旧代码的项目&#xff0c;这些旧代码庞大&#xff0c;扩展且编写时从未进行过任何测试。 在使用此遗留代码时&#xff0c;有一个行为异常的类非常普遍&#xff0c;整个团队都一次又一次地犯错。 为了…

python性能解决_我们如何发现并解决Python代码中性能下降的问题

Python部落(python.freelycode.com)组织翻译&#xff0c;禁止转载&#xff0c;欢迎转发。 作者&#xff1a;Omer Lachish 最近&#xff0c;我们已经开始使用RQ库代替Celery库作为我们的任务运行引擎。第一阶段&#xff0c;我们只迁移了那些不直接进行查询工作的任务。这些任务包…

图灵机器人调用数据恢复_机器人也能撩妹?python程序员自制微信机器人,替他俘获女神芳心...

机器人也有感情还记得王传君饰演的《星语心愿之再爱》这部电影吗&#xff1f;王传君饰演的天才程序员“王鹏鹏”因工作原因不能陪伴照顾身在异地的女朋友“林亦男”&#xff0c;呆萌宅男“王鹏鹏”开发出一款以自己为原型的“王鹏鹏8.0”程序去陪伴异地恋的女友&#xff0c;后来…

Spark排错与优化

一. 运维 1. Master挂掉,standby重启也失效 Master默认使用512M内存&#xff0c;当集群中运行的任务特别多时&#xff0c;就会挂掉&#xff0c;原因是master会读取每个task的event log日志去生成spark ui&#xff0c;内存不足自然会OOM&#xff0c;可以在master的运行日志中看到…