STM32读写SPI FLASH

一、简介

SPI是串行外设接口(Serial Peripheral lnterface)的缩写。SPI是一种高速的、全双工、同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,如今越来越多的芯片集成了这种通信协议,如NRF24L01、VS1053、SD卡等。

(1)速度:串口的通信一般也就是115200bps,但是SPI的通信速度可以达到10Mbps,接近快了一百倍,所以在配置的时候需要注意,一般不超过10Mbps。

(2)同步:采用同步方式(Synchronous)传输数据,主设备会根据将要交换的数据来产生相应的时钟脉冲(Clock Pulse), 时钟脉冲组成了时钟信号(Clock Signal) , 时钟信号通过时钟极性 (CPOL) 和 时钟相位 (CPHA) 控制着两个 SPI 设备间何时数据交换以及何时对接收到的数据进行采样,来保证数据在两个设备之间是同步传输。—简单地说,发送数据的时候,必须同时接收到数据,由时钟控制。

(3)全双工:发送数据的时候能够接收数据,接收数据的时候能够发送数据,即可以同时双向通信。

二、 spi四种模式

SPI的相位(CPHA)和极性(CPOL)都可以为0或1,对应的4种组合构成了SPI的4种模式
Mode 0: CPOL=0, CPHA=0
Mode 1 :CPOL=0, CPHA=1
Mode 2 :CPOL=1, CPHA=0
Mode 3 :CPOL=1, CPHA=1

时钟极性CPOL: 即SPI空闲时,时钟信号SCLK的电平(1:空闲时高电平; 0:空闲时低电平)
时钟相位CPHA:即SPI在SCLK第几个边沿开始采样(0:第一个边沿开始; 1:第二个边沿开始)
极性:polarity
相位:phase
常用的是mode 0 和mode 3,这两种模式的相同的地方是都在时钟上升沿采样传输数据,区别这两种方式的简单方法就是看空闲时,时钟的电平状态,低电平为mode 0 ,高电平为mode 3。

三、spi四线

SPI FLASH 一般用于存储LCD显示屏所要显示的图片,视频数据。
四根线:SDI(数据输入)、SDO(数据输出)、SCLK(时钟)、CS(片选)。
或者说是MOSI、MISO、SCLK、CS四根,CS和SS是一样的,只是表示方法不同。

SCLK:串行时钟线,用于数据的同步。
MOSI:主机输出数据,从机接收数据。
MISO:主机接收数据,从机输出数据。
SS/CS:控制从机是否工作,往往是低电平有效,低电平选中从设备。

STM32读写SPI FLASH_第1张图片
就比如STM32和LCD屏,使用SPI进行通信,单片机就是主机,LCD就是从机,单片机主机发送数据给从机LCD。
STM32读写SPI FLASH_第2张图片
其中的SCLK、MOSI、MISO三根线是可以复用连接的,唯独片选信号线CS是要连接到器件N,这也代表了多个从设备接在一起 的时候,被片选的设备才可以进行工作,只能多选一,当其中一个设备被选中CS引脚为低电平的时候,其他引脚一定要设置为高电平,避免传输数据的时候发生紊乱。

四、编程

SPI读取W25Q128

(1)读取设备ID

1.根据设备数据手册读时序图,根据固件库参考手册编写函数
(1)GPIO初始化、SPI初始化
(2)SPI write初始化(主机发送数据的时候,从机会返回数据给单片机)
(3)读取ID,读取id的目的是验证自己的写数据函数是否正确。

如果出现可上可下的梯形时序图,那么表示可以是任意数据,下图简单示例一下,学会看图。
根据你所采用的SPI模式进行对比,例如SPI模式0,传输数据开始:
(1)片选信号从高变低,选中从设备。
(2)空闲时时钟的电平状态为低电平,时钟第一个边沿触发,从下图读出的数据就是0000 0100,即0x04,一字节数据发送完毕。
(3)片选信号从高变低,不选中从设备。

STM32读写SPI FLASH_第3张图片

读从设备的ID,Read Manufacturer / Device lD (90h),读取厂商的ID,90h是命令,具体得看从器件的数据手册,一般你Ctrl+F搜索ID就可以找得到,通信开始拉低片选信号,结束时候拉高。
STM32读写SPI FLASH_第4张图片
大概意思:

读取设备lD指令,该指令是通过驱动CS引脚拉低,并移动指令90h后跟一个0x00的24位地址来启动的。最高有效位(MSB)优先。

初始化、发送字节数据、读取ID的部分代码

static GPIO_InitTypeDef  	GPIO_InitStructure;
static SPI_InitTypeDef  	SPI_InitStructure;
#define W25QXX_SS			PBout(14)

void w25qxx_init(void)
{
   
	/*!< Enable the SPI clock,使能SPI1硬件时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

	/*!< Enable GPIO clocks,使能GPIOB硬件时钟 */
	RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB, ENABLE);
	
	//SPI1端口配置 PB3 PB4 PB5
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5; 	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;	//复用功能									
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz									
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽复用输出	 									
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉									
	GPIO_Init(GPIOB,&GPIO_InitStructure); 	
	
	/*!< Connect SPI1 pins to AF3 AF4 AF5 */  
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI1);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_SPI1);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI1);

	//初始化片选引脚 PB14
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; 				
	//输出功能						
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
	//速度50MHz								
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		
	//推挽复用输出						
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 		
	//上拉							
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; 									
	

你可能感兴趣的:(单片机,单片机,嵌入式,stm32)