SPI协议如何读取寄存器的值
SPI(SerialPeripheralInterface)协议

SPI(SerialPeripheralInterface)协议SPI是串⾏外设接⼝(Serial Peripheral Interface)的缩写,是Motorola推出的⼀种同步串⾏接⼝技术,是⼀种⾼速的、全双⼯、同步的通信总线。
全双⼯:host能与外围从设备之间的发送线和接收线各⾃独⽴,能同时进⾏发送数据和接收数据。
源同步传输⽂章内容SPI介绍SPI协议通信时序详解SPI数据传输⽅式SPI总线优缺点1、SPI介绍应⽤场景SPI协议主要⽤于短距离的通信系统中,特别是嵌⼊式系统:存储器:RAM,EEPROM,Flash等数模转换器:A/D, D/A转换器等驱动接⼝:LED显⽰驱动器,I/O接⼝芯⽚,UART接收器等。
主从模式控制:SPI以主从⽅式进⾏⼯作,这种模式通常包含⼀个master和⼀个或多个slave,需要⾄少4根线(在单向传输时3根也可以),分别为:SDO/MOSI(master output slave input):主设备数据输出,从设备数据输⼊;SDI/MISO(master input slave output):主设备数据输⼊,从设备数据输出;SCLK:时钟信号,由主设备产⽣;CS/SS:⽚选信号,主设备控制并⽤于选择与其通信的从设备。
多Slave的SPI协议SPI协议可以操作在⼀个master对应⼀个或者多个slave的条件下,此时有多个CS/SS⽚选信号,但是⼀个时间只能有⼀个⽚选信号有效。
slave的输出端⼝MISO都是三态驱动;⾼电平,低电平和不选中时输出为⾼阻态。
数据交换(data exchanges)SPI设备之间的数据传输称为数据交换⽽不是数据传输。
这是因为SPI设备不能在进⾏数据通信的过程中仅充当transmitter和recieiver的⾓⾊,⽽是在每个时钟周期内,主从SPI设备都会发送1bit⼤⼩的数据,相当于主从设备进⾏了1bit的数据交换。
在数据的传输过程中,每次接收到的数据必须在下⼀次数据传输之前被采样,如果之前接收的数据没有被采样,那么这些已经收到的数据可能被丢弃,导致 SPI 模块最终失效,因此,在程序中,⼀般都会在 SPI 传输完数据之后,去读取 SPI 设备⾥⾯的数据,即使这些数据是在我们程序中是没有⽤的。
SD读卡器初始化跟读寄存器的SPI口程序

date = SD_read_byte(); //读最开始的 0xfe
for(j=0;j<16;j++) //读 16 位 CSD 寄存器 { if(j==0) { date1 = SD_read_byte(); } if(j==4) { date2 = SD_read_byte(); } else date = SD_read_byte(); } date = SD_read_byte(); date = SD_read_byte(); P1 = date1; date = SD_read_byte(); //delayms(); //delayms(); //delayms(); //delayms(); //delayms(); //delayms(); //delayms();
SD_write_byte(0x40); SD_write_byte(0x00); SD_write_byte(0x00); SD_write_byte(0x00); SD_write_byte(0x00); SD_write_byte(0x95); SD_write_byte(0xff); date = SD_read_byte();
SD_write_byte(0x69); SD_write_byte(0x00); SD_write_byte(0x00); SD_write_byte(0x00); SD_write_byte(0x00); SD_write_byte(0xff); SD_write_byte(0xff); date = SD_read_byte(); SD_write_byte(0xff); } while(date !=0x00); delayms(); while(1) { SD_write_byte(0x4a); SD_write_byte(0x00);
单片机SPI通信原理及应用

单片机SPI通信原理及应用SPI(Serial Peripheral Interface)是一种串行外设接口协议,被广泛应用于单片机系统中。
它通过同时使用四条信号线(SCLK、MISO、MOSI、SS)实现了高速全双工的通信。
本文将介绍SPI通信的原理和应用。
一、SPI通信的原理SPI通信包括主设备和从设备之间的数据传输。
主设备通过SCLK (Serial Clock)产生时钟信号来驱动数据传输,MOSI(Master Out, Slave In)用于从主设备发送数据到从设备,MISO(Master In, Slave Out)用于从设备将数据发送回主设备。
SS(Slave Select)信号用于选择从设备。
SPI通信采用的是同步传输方式,数据的传输是在时钟的边沿上进行的。
主设备通过SCLK产生的时钟信号控制数据的传输速率。
通过MOSI和MISO线,主设备和从设备之间可以传输8位的数据帧。
在SPI通信中,主设备负责发起通信并控制整个通信过程。
主设备首先将SS信号拉低以选择从设备,然后按照时钟信号的边沿,将数据逐位地通过MOSI发送给从设备。
同时,从设备也通过MISO将数据逐位地发送回主设备。
通信结束后,主设备将SS信号拉高以结束通信。
二、SPI通信的应用SPI通信广泛应用于嵌入式系统中,可以连接各种外设,如传感器、存储器、显示器等。
下面是几个常见的SPI通信应用场景。
1. 驱动显示器SPI通信常用于连接液晶显示器或OLED显示器。
通过SPI总线,主设备可以向显示器发送显示内容的数据,控制显示器的刷新和切换。
同时,显示器也可以向主设备发送触摸或按键等操作的数据。
2. 连接存储器SPI通信可以连接各种存储器,如闪存、EEPROM等。
主设备可以通过SPI总线读取和写入存储器中的数据,实现数据的存储和读取功能。
3. 模拟数字转换器(ADC)SPI通信可以连接ADC芯片,用于将模拟信号转换为数字信号。
主设备通过SPI总线请求ADC芯片进行采样,并接收转换后的数字信号。
SD卡SPI读写中文资料

7S P I模式本文是小弟自己翻译的(处女作哦~~~~~),难免有不妥之处,望交流指教!联系方式 QQ:286225453 Email:ioro55555@7.1介绍SPI模式SPI模式由二次传递协议组成,这个协议由Flash(基于SD卡)提供。
本模式是SD卡协议的子协议,目的是用SPI信道通讯。
SPI模式在SD卡上电后第一个复位指令(CMD0)执行后被选择,并且在接通电源时不能改变。
SPI标准定义7.2 SPI总线SD卡信道由指令和数据位(起始位和结束位)组成,SPI信道由字节定向。
每一个指令或数据块由8位的字节和CS标志构成。
类似SD卡协议, SPI通讯由指令、响应和数据组成。
全部的主机与SD卡之间的通信由主机控制。
主机执行每一跟CS标志为低的总线。
SPI模式与SD模式的响应特性有以下三方面不同∶1、被选择的卡始终对指令作出反应。
2、一个附加的(8BIT)响应产生。
3、在SD卡遇到数据检索问题时,它会作出错误反应,而不是像在SD模式中一样执行一次空操作。
除命令响应之外,每一个数据块在写操作期间会作出专门的信息响应标志反应发送给SD卡。
数据块可以大到一个扇区小到一个字节。
读/写操作由CSD(指令信号译码器)寄存器操作。
7.2.1模式选择SD卡在上电后自动SD模式。
如果CS标志在接受复位指令(CMD0)期间为低,它将进入SPI模式并且处于空闲状态。
如果SD卡识别到需要保持SD模式,它不会对指令作出任何反应并且保持在SD模式中。
如果需要SPI模式,SD卡将转到SPI模式并且进行SPI模式R1响应。
回到SD模式的必须重新上电。
在SPI 模式下,SD卡遵守部分协议系统。
支持SPI模式的SD卡指令始终有效。
7.2.2总线传送保护SPI模式每一个SD卡在总线上的数据传输由CRC(循环冗余码校验)保护。
在SPI模式, SD卡提供一种非保护模式(起动系统,建立可靠的数据联系来排除硬件或固件需要执行的CRC(循环冗余码校验)生成并且核验操作)。
SPI协议详解

SPI协议详解SPI(Serial Peripheral Interface)总线是⼀种⾼速、串⾏、全双⼯通信总线,由Motorola公司设计并推⼴。
优点是⽀持全双⼯通信,传输速率快,SCLK时钟频率最⾼可以达到50MHz左右。
缺点是没有流控制机制,不像I2C有应答机制,也不像UART有数据帧校验机制。
总线引脚SPI总线以主从⽅式⼯作,⽀持多主多从、单主多从、单主单从模式,拥有四个信号线:MISO – Master Input Slave Output,主设备数据输⼊,从设备数据输出;MOSI – Master Output Slave Input,主设备数据输出,从设备数据输⼊;SCLK – Serial Clock,时钟信号,由主设备产⽣;需要注意的是,SCLK只有在数据传输的过程中产⽣时钟周期,不进⾏数据传输时保持⾼电平或者低电平;CS – Chip Select,从设备使能信号,由主设备控制。
其中CS信号线主要⽤于⽚选,实际通信使⽤MISO/MOSI/SCLK三根信号线。
单主单从模式如下:单主多从模式如下:(每个SPI设备由⼀根独⽴的CS⽚选信号进⾏⽚选)总线时序根据CPOL(时钟极性)和CPHA(时钟相位)的组合区分,SPI总线时序有四种模式。
SPI通信的双⽅必须同时⼯作在其中⼀种模式下,往往是主控制器匹配SPI设备的⼯作模式。
Mode0:CPOL=0,CPHA=0Mode1:CPOL=0,CPHA=1Mode2:CPOL=1,CPHA=0Mode3:CPOL=1,CPHA=1其中SPI 0和SPI 3两种模式最常⽤。
CPOL⽤来控制SCLK信号的Active状态是⾼电平还是低电平。
0 - SCLK⾼电平为Active状态1 - SCLK低电平为Active状态CPHA⽤来控制MOSI和MISO在第⼏个SCLK边沿进⾏数据采样。
0 - 第⼀个SCLK边沿采样,第⼆个边沿发送1 - 第⼀个SCLK边沿发送,第⼆个边沿采样总结:SPI总线协议本⾝并不复杂,这就意味着复杂性在SPI设备驱动的软件编码上,具体体现在:1)SPI总线协议没有数据校验机制,因此,必须根据SPI设备⽀持的SCLK时钟频率范围设置SPI时钟频率,实际应⽤中,可能会碰到⽰波器量时序信号没问题,但是SPI设备不回复数据或者回复数据错误的情况,⼤概率就是因为时钟频率不满⾜SPI设备要求导致的;2)SPI控制器的发送是直接将数据写⼊⼀个移位寄存器中,该移位寄存器跟随SCLK时钟发送数据;SPI控制器的接收与发送同步进⾏,也就是说发送数据的同时,也在接收数据,⽽接收数据是写⼊⼀个缓存寄存器中,如果缓存寄存器的值不及时读取的话,后续接收的数据会直接丢弃⽽不是覆盖到该缓存寄存器中,因此,每⼀次写数据之后,⼀定要读取数据,即使读取的数据⽆意义。
AT25M01使用说明SPIEEPROMSTM32精编版

1.芯片访问规则符合AT25系列原则,可以找相关的例子,但是25M01 目前没有2.芯片工作原则,不考虑写保护问题,所有操作的第一步都是要发送写允许指令,然后重新片选有效,发送下一步的命令。
注意问题: SPI的 EEPROM的数据输出的原理是,在输入一个字节的同时输出一个字节,没有输入字节,就输出,所以,所谓的读数据,其实质是先发送一个数据,然后在接收一个数据。
操作如下:(1)寄存器读1)先片选,在发送写允许指令,片选无效2)片选,发送读寄存器指令,读寄存器,片选无效(2)寄存器写1)先片选,在发送写允许指令,片选无效2)片选,发送写寄存器指令,写数据,片选无效(3)写数据1)先片选,在发送写允许指令,片选无效2)片选,发送写数据指令,写数据,片选无效(4)读数据1)先片选,在发送写允许指令,片选无效2)片选,发送读数据指令,读数据,片选无效注意: STM32 的 SPI需要,每次都开启void SPI_EEPROM_Init(void){SPI_InitTypeDef SPI_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;/* Enable SPI1 and GPIO clocks *//*!< SPI_FLASH_SPI_CS_GPIO, SPI_FLASH_SPI_MOSI_GPIO,SPI_FLASH_SPI_MISO_GPIO, SPI_FLASH_SPI_DETECT_GPIOand SPI_FLASH_SPI_SCK_GPIO Periph clock enable */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_ AFIO, ENABLE);/*!< SPI_FLASH_SPI Periph clock enable */RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);/*!< Configure SPI_FLASH_SPI pins: SCK */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);/*!< Configure SPI_FLASH_SPI pins: MOSI */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;GPIO_Init(GPIOA, &GPIO_InitStructure);/*!< Configure SPI_FLASH_SPI pins: MISO */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, &GPIO_InitStructure);// 选通采用软件模式-------------------------/*!< Configure SPI_FLASH_SPI_CS_PIN pin: SPI_FLASH Card CS pin */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOA, &GPIO_InitStructure); //NSS1GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOC, &GPIO_InitStructure); //NSS2/* Deselect the FLASH: Chip Select high */NSS1_HIGH();NSS1_HIGH();/* SPI1 configuration *///W25X16: data input on the DIO pin is sampled on the rising edge of the CLK.//Data on the DO and DIO pins are clocked out on the falling edge of CLK.SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//SPI 模式 3//SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//SPI 模式 0SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//软件片选SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//硬件片选//SPI_InitStructure.SPI_NSS =SPI_NSS_Hard;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //72M/8=9Mhz, 供电SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &SPI_InitStructure);/* Enable SPI1*/SPI_Cmd(SPI1, DISABLE);}/*********************************************END OF FILE**********************/void NSS_CS_ENABLE(uint8_t NSS){if(NSS==1){ NSS1_LOW();NSS2_HIGH();}else if(NSS==2) { NSS2_LOW();NSS1_HIGH();}}void NSS_CS_DISABLE(){NSS1_HIGH();NSS2_HIGH();}void SPI_WREN(uint8_t nss){NSS_CS_ENABLE(nss);SPI_WriteByte(WREN);NSS_CS_DISABLE();// Delay_ms(1);}void SPI_WRDI(uint8_t nss){NSS_CS_ENABLE(nss);SPI_WriteByte(WRDI);NSS_CS_DISABLE();//Delay_ms(1);}void SPI_EEPROM_WRITE_Start(void) {SPI_Cmd(SPI1, ENABLE);SPI_WREN(1);NSS_CS_ENABLE(1);SPI_WriteByte(WRSR);SPI_WriteByte(0X02);NSS_CS_DISABLE( );SPI_WREN(2);NSS_CS_ENABLE(2);SPI_WriteByte(WRSR);SPI_WriteByte(0X02);NSS_CS_DISABLE( );SPI_Cmd(SPI1, DISABLE);}void SPI_EEPROM_WRITE_END(void){SPI_Cmd(SPI1, ENABLE);SPI_WRDI(1);SPI_WRDI(2);SPI_Cmd(SPI1, DISABLE);}uint8_t SPI_WriteByte(uint8_t data){/* Loop while DR register in not emplty */while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);/* Send byte through the SPI1 peripheral */SPI_I2S_SendData(SPI1, data);/* Wait to receive a byte */while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);/* Return the byte read from the SPI bus */return SPI_I2S_ReceiveData(SPI1);}uint8_t SPI_ReadByte(void){return (SPI_WriteByte(Dummy_Byte));//while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) == RESET); // return SPI_I2S_ReceiveData(SPI1);}uint8_t AT25_GetStatus(uint8_t NSS){uint8_t tmp=0;SPI_WREN(NSS);NSS_CS_ENABLE(NSS);SPI_WriteByte(RDSR);tmp = SPI_ReadByte();NSS_CS_DISABLE();return tmp;}void AT25_WaitReady(uint8_t NSS){while((0x01 & AT25_GetStatus(NSS))!=0);}/*单字节操作,读和写*/uint8_t AT25_ReadByte(uint32_t addr){uint8_t tmp;uint8_t nss=1;if(addr >=(uint32_t)(1024*128*2))return 0;if(addr>=(uint32_t)(1024*128)){addr=addr-(uint32_t)(1024*128);nss=2;}else nss=1;SPI_Cmd(SPI1,ENABLE);AT25_WaitReady(nss);SPI_WREN(nss);NSS_CS_ENABLE(nss);SPI_WriteByte(READ);SPI_WriteByte((uint8_t)((addr & 0x010000)>>16));/* A16*/ SPI_WriteByte((uint8_t)((addr & 0x00FF00)>>8));/* A15-A8*/ SPI_WriteByte((uint8_t)(addr & 0x0000FF));/* A7-A0*/ tmp = SPI_ReadByte();NSS_CS_DISABLE( );SPI_Cmd(SPI1,DISABLE);return tmp;}void AT25_WriteByte(uint8_t data, uint32_t addr){uint8_t nss=1;uint32_t tt=1024*128*2;if(addr >= tt)return ;if(addr>=(uint32_t)(1024*128)){addr=addr-(uint32_t)(1024*128);nss=2;}else nss=1;SPI_Cmd(SPI1,ENABLE);AT25_WaitReady(nss);SPI_WREN(nss);NSS_CS_ENABLE(nss);SPI_WriteByte(WRITE);SPI_WriteByte((uint8_t)((addr & 0x010000)>>16));/* A16*/SPI_WriteByte((uint8_t)((addr & 0x00FF00)>>8));/* A15-A8*/ SPI_WriteByte((uint8_t)(addr & 0x0000FF));/* A7-A0*/ SPI_WriteByte(data);NSS_CS_DISABLE( );SPI_Cmd(SPI1,DISABLE);}////////////多字节操作/*** @brief将缓冲区中的数据写到I2C EEPROM中*@param*@arg pBuffer:缓冲区指针*@arg WriteAddr: 写地址*@arg NumByteToWrite: 写的字节数* @retval无*/void SPI_EE_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite,uint8_t NSS) {u32 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;Addr = WriteAddr % I2C_PageSize;count = I2C_PageSize - Addr;NumOfPage = NumByteToWrite / I2C_PageSize;NumOfSingle = NumByteToWrite % I2C_PageSize;/* If WriteAddr is I2C_PageSize aligned*/if(Addr == 0){/* If NumByteToWrite < I2C_PageSize */if(NumOfPage == 0){SPI_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle,NSS);}/* If NumByteToWrite > I2C_PageSize */else{while(NumOfPage--){SPI_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize,NSS);WriteAddr +=I2C_PageSize;pBuffer += I2C_PageSize;}if(NumOfSingle!=0){SPI_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle,NSS);}}}/* If WriteAddr is not I2C_PageSize aligned*/else{/* If NumByteToWrite < I2C_PageSize */if(NumOfPage== 0){SPI_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle,NSS);}/* If NumByteToWrite > I2C_PageSize */else{NumByteToWrite -= count;NumOfPage = NumByteToWrite / I2C_PageSize;NumOfSingle = NumByteToWrite % I2C_PageSize;if(count != 0){SPI_EE_PageWrite(pBuffer, WriteAddr, count,NSS);WriteAddr += count;pBuffer += count;}while(NumOfPage--){SPI_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize,NSS);WriteAddr +=I2C_PageSize;pBuffer += I2C_PageSize;}if(NumOfSingle != 0){SPI_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle,NSS);}}}}/***@brief在EEPROM的一个写循环中可以写多个字节,但一次写入的字节数*不能超过EEPROM页的大小, AT24C02每页有 8 个字节*@param*@arg pBuffer:缓冲区指针*@arg WriteAddr: 写地址*@arg NumByteToWrite: 写的字节数* @retval无*/void SPI_EE_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite,uint8_t NSS) {SPI_Cmd(SPI1,ENABLE);AT25_WaitReady(NSS);SPI_WREN(NSS);NSS_CS_ENABLE(NSS);SPI_WriteByte(WRITE);SPI_WriteByte((uint8_t)((WriteAddr & 0x010000)>>16));/* A16*/SPI_WriteByte((uint8_t)((WriteAddr & 0x00FF00)>>8));/* A15-A8*/SPI_WriteByte((uint8_t)(WriteAddr & 0x0000FF));/* A7-A0*//* While there is data to be written */while(NumByteToWrite--){/* Send the current byte */SPI_WriteByte(*pBuffer);/* Point to the next byte to be written */pBuffer++;}/* Send STOP condition */NSS_CS_DISABLE();SPI_Cmd(SPI1,DISABLE);}/***@brief从EEPROM里面读取一块数据*@param*@arg pBuffer:存放从 EEPROM读取的数据的缓冲区指针*@arg WriteAddr: 接收数据的 EEPROM的地址*@arg NumByteToWrite: 要从 EEPROM读取的字节数*@retval 无*/void SPI_EE_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead,uint8_t NSS) {uint8_t nss=NSS;SPI_Cmd(SPI1,ENABLE);AT25_WaitReady(nss);SPI_WREN(NSS);NSS_CS_ENABLE(nss);SPI_WriteByte(READ);SPI_WriteByte((uint8_t)((ReadAddr & 0x010000)>>16));/* A16*/SPI_WriteByte((uint8_t)((ReadAddr & 0x00FF00)>>8));/* A15-A8*/ SPI_WriteByte((uint8_t)(ReadAddr & 0x0000FF));/* A7-A0*//* While there is data to be read */while(NumByteToRead){*pBuffer = SPI_ReadByte();pBuffer++;NumByteToRead--;}/* Enable Acknowledgement to be ready for another reception */NSS_CS_DISABLE( );SPI_Cmd(SPI1,DISABLE);}//*****wdz*******//void SPI_EE_BufferWrite2(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite){u32 temp=WriteAddr+NumByteToWrite-1;u32 number=WriteAddr+NumByteToWrite-1024*128;if(temp<1024*128){SPI_EE_BufferWrite(pBuffer,WriteAddr,NumByteToWrite,1);}else if(WriteAddr<1024*128 && temp>=1024*128){SPI_EE_BufferWrite(pBuffer,WriteAddr,NumByteToWrite-number,1);SPI_EE_BufferWrite(pBuffer+NumByteToWrite-number,0,number,2);}else if(WriteAddr>=1024*128){SPI_EE_BufferWrite(pBuffer,WriteAddr-1024*128,NumByteToWrite,2);}}void SPI_EE_BufferRead2(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead){u32 temp=ReadAddr+NumByteToRead-1;u32 number=ReadAddr+NumByteToRead-1024*128;if(temp<1024*128){SPI_EE_BufferRead(pBuffer,ReadAddr,NumByteToRead,1);}else if(ReadAddr<1024*128 && temp>=1024*128){SPI_EE_BufferRead(pBuffer,ReadAddr,NumByteToRead-number,1);SPI_EE_BufferRead(pBuffer+NumByteToRead-number,0,number,2);}else if(ReadAddr>=1024*128){SPI_EE_BufferRead(pBuffer,ReadAddr-1024*128,NumByteToRead,2);}}void SPI_Read_status(void){uint8_t mygetbyte;SPI_Cmd(SPI1,ENABLE);SPI_WREN(1);NSS1_LOW();SPI_WriteByte(RDSR);mygetbyte=SPI_ReadByte();USART_printf(USART3,"\r\n ST1=%d",mygetbyte);SPI_WREN(2);NSS2_LOW();SPI_WriteByte(RDSR);mygetbyte=SPI_ReadByte();USART_printf(USART3,"\r\n ST2=%d",mygetbyte);}。
SD卡的读取(SPI)
SPI模式下MCU对SD卡的控制及操作命令一、前言SD 卡有两个可选的通讯协议:SD 模式和 SPI模式 SD 模式是SD 卡标准的读写方式,但是在选用SD 模式时,往往需要选择带有SD 卡控制器接口的 MCU,或者必须加入额外的SD卡控制单元以支持SD 卡的读写然而,大多数MCU都没有集成SD 卡控制器接口,若选用SD 模式通讯就无形中增加了产品的硬件成本。
在SD卡数据读写时间要求不是很严格的情况下,选用 SPI模式可以说是一种最佳的解决方案因为在 SPI模式下,通过四条线就可以完成所有的数据交换,并且目前市场上很多MCU都集成有现成的SPI接口电路,采用 SPI模式对 SD卡进行读写操作可大大简化硬件电路的设计二、硬件电路实现以NXP的LPC2210 ARM7MCU为例,下图是周立功开发的实现板电路这里,将LPC2210MCU的SPI0用于SD卡的控制和数据读写。
对SPI0的两个数据线加了上拉电阻以便于MMC卡兼容。
卡供电采用了可控方式,通过GPIO口控制MOS管对其进行供电。
卡检测电路也使用GPIO口实现。
通过读GPIO口数据,检查卡是否写保护和完全插入。
具体内容可以参考周立功的说明书,百度文库里边有三、SD卡物理接口我们看到的SD卡一包如下所示,包含9个引脚和一个写保护开关:其引脚定义如下:注:1. S:电源;I:输入;O:推挽输出;PP:推挽I/O。
2. 扩展的DAT线(DAT1 ~ DAT3)在上电后处于输入状态。
它们在执行SET_BUS_WIDTH命令后作为DAT线操作。
当不使用DAT1 ~ DAT3 线时,主机应使自己的DAT1~DAT3线处于输入模式。
这样定义是为了与MMC卡保持兼容。
3. 上电后,这条线为带50KΩ上拉电阻的输入线(可以用于检测卡是否存在或选择 SPI 模式)。
用户可以在正常的数据传输中用 SET_CLR_CARD_DETECT(ACMD42)命令断开上拉电阻的连接。
实验05 SPI接口存储器AT25F1024读写与显示
//-----------------------------------------------------------------
//删除AT25F1024A芯片未加保护的所有区域数据
//说明:程序运行时,按下K1~K4所执行的操作如下:
// K1:先清除数据,然后在前面写入256个字节(0x00-0xFF)
//最末尾写入256个随机字节(中间部分不写入)
// K2:读取并显示最前面256个字节(有序)
// K3:读取并显示最后面256个字节(无序)
// K4:读取并显示厂家/设备ID(AT25F1024A: VID/PID=1F60)
void Write_3_Bytes_SPI_Address(INT32U addr)
{
WriteByte((INT8U) (addr >> 16 & 0xFF));
WriteByte((INT8U) (addr >> 8 & 0xFF));
WriteByte((INT8U) (addr & 0xFF));
//
//-----------------------------------------------------------------
#include <reg52.h>
#include <intrins.h>
#include <stdlib.h>
#define INT8U unsigned char
//延时函数
//-----------------------------------------------------------------
25系列SPI总线存储器的读写方法
25系列SPI总线Flash存储器的读写方法一、概况25系列存储芯片已经广泛应用于液晶电视、液晶显示器、主板、笔记本、卫星接收机等产品,用于储存固件程序或者产品数据,维修行业沿袭旧称,也把此芯片称之为8脚BIOS芯片,维修过程中经常需要对此芯片进行读取或者擦写等操作。
首先我们来简单了解一下25芯片的有关知识:1、芯片分类与引脚定义25芯片属于SPI总线标准的串行Flash存储器,维修行业最常遇到的25芯片容量从512K到32Mbit,可以从型号中看出来。
例如:a、MX25L4005,其含义是1、MXic公司生产的;2、属于25系列芯片;3、容量是4Mbit,其对应的数据文件应该是4Mbit / 8 = 512KBb、PM25LV512,其含义是1、P-FLASH公司生产;2、属于25系列芯片;3、容量是512Kbit,其对应的数据文件应该是512Kbit / 8 = 64KBc、W25X40,其含义是1、Winbond公司生产的;2、属于25系列芯片;3、容量是4Mbit,其对应的数据文件应该是4Mbit / 8 = 512KBd、EN25T80,其含义是1、EON公司生产的;2、属于25系列芯片;3、容量是8Mbit,其对应的数据文件应该是8Mbit / 8 = 1MB代换原则:统一系列,容量相同,一般可以代换;例如W25X40,其参数、性能和编程方法与MX25L4005相同,可以互换。
最常见的8脚封装1、/CS 片选,此脚为低电平时,此25芯片才工作;2、DO 串行数据输出;3、/WP 写保护,低电平时禁止写入操作;4、GND 地5、DIO 串行数据输入/输出;6、CLK 串行时钟输入;7、/HOLD 保持8、VCC 供电,大多数25芯片采用3.3V供电2、SPI总线同步外设接口(SPI)是由摩托罗拉公司开发的全双工同步串行总线,包括1根串行同步时钟信号线以及2根数据线,该总线大量用在与EEPROM、ADC、FRAM和显示驱动器之类的慢速外设器件通信。
SPI协议的数据读写实现(spi_slave)
SPI协议的数据读写实现(spi_slave)⼀、SPI协议介绍⼆、程序设计1、spi_slave模块该模块接收8路16bit的数据信号ave1---ave8,以及标志数据有效的信号ave_valid;该模块作为SPI的slave端,可以通过spi_miso将ave数据发送出去;也可以通过spi_mosi接收master端发送来的数据,并将数据再通过godata发送出去;该模块采⽤的是模式0:CPOL = 0,CPHA = 0;该模块可以接收两种命令:读命令COMMAND_READ = 8'hA5、写命令COMMAND_WRITE = 8'H5A;`timescale 1ns/1psmodule spi_slave(input clk,//芯⽚外部输⼊的clk_50minput rst_n,//sys_rst模块输出的复位信号rst_ninput ave_valid,//average输出的平均值有效信号//spi_input_chose模块的输出信号,//sw_cnt控制spi_input_chose模块选择特定的数据输出给spi_slaveinput [15:0] ave1,input [15:0] ave2,input [15:0] ave3,input [15:0] ave4,input [15:0] ave5,input [15:0] ave6,input [15:0] ave7,input [15:0] ave8,//spi协议的相关信号input spi_cs,input spi_sck,input spi_mosi,output reg spi_miso,//spi slave的数据输出//下⾯3个信号是连接到para_rom1模块的,//和para_rom1模块输出两点校正的两个参数G\O有关output reg data_valid,output [4:0] addr,output reg [15:0] godata,//spi初始化完成标志output reg init_finish);// cs、sck、mosi的delay信号reg spi_cs_2,spi_cs_1;reg spi_sck_2,spi_sck_1;reg spi_mosi_2,spi_mosi_1;// cs、sck的下降沿/mosi的上升沿wire spi_cs_neg;wire spi_sck_neg;wire spi_sck_pos;wire spi_mosi_flag;always @(posedge clk or negedge rst_n)beginif(!rst_n)begin{spi_cs_2,spi_cs_1} <= 2'b11;{spi_sck_2,spi_sck_1} <= 2'b00;{spi_mosi_2,spi_mosi_1} <= 2'b00;endelsebegin{spi_cs_2,spi_cs_1} <= {spi_cs_1,spi_cs};{spi_sck_2,spi_sck_1} <= {spi_sck_1,spi_sck};{spi_mosi_2,spi_mosi_1} <= {spi_mosi_1,spi_mosi};endendassign spi_cs_neg = (spi_cs_2&(~spi_cs_1));assign spi_sck_neg = ~spi_sck_1&spi_sck_2;assign spi_sck_pos = ~spi_sck_2&spi_sck_1;assign spi_mosi_flag = spi_mosi_2;localparam IDLE = 6'b000001;localparam RXD_COM = 6'b000010;localparam JUDGE = 6'b000100;localparam TXD_NUM = 6'b001000;localparam TXD_DATA = 6'b010000;localparam RXD_PARA = 6'b100000;parameter COMMAND_READ = 8'hA5;parameter COMMAND_WRITE = 8'H5A;reg [5:0] state;reg [3:0] cnt; //计数接收命令参数的位数reg [3:0] cnt0; //发送数据的地址reg [4:0] cnt1; //计数发送数据的位数reg [4:0] cnt2; //计数接收两点校正参数的位数reg [4:0] cnt3; //cnt2和godata输出到的存储参数的存储器的地址有关 reg [7:0] para;reg [15:0] tdata;reg rd_flag;wire [15:0] data_out;reg rxd_finish;reg rxd_finish_en;reg [7:0] counter;assign addr = cnt2 - 1;always @(posedge clk or negedge rst_n)if(!rst_n)state <= IDLE;elsebegincase(state)IDLE:beginif(spi_cs_neg)state <= RXD_COM;elsestate <= IDLE;endRXD_COM:beginif(cnt == 4'b1000)state <= JUDGE;elsestate <= RXD_COM;endJUDGE:beginif(para == COMMAND_READ) state <= TXD_NUM;else if(para == COMMAND_WRITE)state <= RXD_PARA;elsestate <= IDLE;endTXD_NUM:beginstate <= TXD_DATA;endTXD_DATA:begin//每发送完8个ave数据回到idle状态if(cnt0 == 4'b1000 && cnt1 == 5'b00001)state <= IDLE;//每发送完⼀个ave数据,就进⼊TXD_NUM状态//此状态更新⼀次新的要发送的aveelse if(cnt1 == 5'b10000)state <= TXD_NUM;elsestate <= TXD_DATA;endRXD_PARA:beginif(cnt2 < 5'b10110)state <= RXD_PARA;elsestate <= IDLE;enddefault: state <= IDLE;endcaseendalways @(posedge clk or negedge rst_n)if(!rst_n)begincnt <= 4'b0;cnt0 <= 4'b0;cnt1 <= 5'b0;para <= 8'b0;tdata <= 16'b0;rd_flag <= 1'b0;spi_miso <= 1'b1;data_valid <= 1'b0;cnt3 <= 5'b0000;cnt2 <= 5'b0000;godata <= 16'b0;rxd_finish <= 1'b0;endelsebegincase(state)IDLE:begincnt <= 4'b0;cnt0 <= 4'b0;cnt1 <= 5'b0;para <= 8'b0;tdata <= 16'b0;godata <= 16'b0;rd_flag <= 1'b0;spi_miso <= 1'b1;cnt3 <= 5'b0000;cnt2 <= 5'b0000;data_valid <= 1'b0;endRXD_COM://接收命令参数beginif(cnt == 4'b1000)cnt <= 4'b0000;else if(spi_sck_pos)//上升沿接收数据begin//接收命令参数存⼊para 也即是写COMMAND_WRITE还是读COMMAND_READ cnt <= cnt + 4'b0001;//从⾼位到低位接收para[7 - cnt[2:0]] <= spi_mosi_flag;endelsebegincnt <= cnt;para <= para;endendJUDGE:beginif(para == COMMAND_READ)//识别到读ave数据的命令COMMAND_READ,//rd_flag拉⾼,直到读完8个数据再拉低rd_flag <= 1'b1;elserd_flag <= 1'b0;endTXD_NUM:begintdata <= data_out;endTXD_DATA://发送数据beginif(cnt1 == 5'b10000)begin//每发送完⼀个数据,cnt0+1,cnt0作为地址读取下⼀个要发送的数据cnt1 <= 5'b00000;cnt0 <= cnt0 + 4'b0001;endelse if(spi_sck_neg)//下降沿发送数据begincnt1 <= cnt1 + 5'b00001;//从⾼位到低位发送spi_miso <= tdata[15 - cnt1[4:0]];endelsebeginspi_miso <= spi_miso;cnt1 <= cnt1;endendRXD_PARA://接收两点校正的参数begin//这⾥表⽰每接收22个两点校正的参数拉⾼rxd_finishif(cnt2 == 5'b10101 && cnt3 == 5'b01111)rxd_finish <= 1'b1;elserxd_finish <= 1'b0;//接收完⼀个16位的参数,data_valid拉⾼,cnt2 + 1,//cnt2和godata输出到的存储参数的存储器的地址有关if(cnt3 == 5'b10000)begincnt3 <= 5'b0000;cnt2 <= cnt2 + 5'b00001;data_valid <= 1'b1;endelse if(spi_sck_pos)//上升沿接收数据begindata_valid <= 1'b0;cnt3 <= cnt3 + 5'b00001;godata[15 - cnt3[4:0]] <= spi_mosi_flag;endelsebegindata_valid <= data_valid;cnt3 <= cnt3;godata <= godata;endenddefault:begincnt <= 4'b0000;cnt0 <= 4'b0000;cnt1 <= 5'b00000;para <= 8'b0;tdata <= 12'b0;rd_flag <= 1'b0;spi_miso <= 1'b1;endendcaseendalways @(posedge clk or negedge rst_n)beginif(!rst_n)rxd_finish_en <= 1'b0;else if (rxd_finish)rxd_finish_en <= 1'b1;elserxd_finish_en <= rxd_finish_en;endalways @(posedge clk or negedge rst_n)beginif(!rst_n)counter <= 8'b0;//两点校正参数接收完成之后counter再计数⼀段时间,最后初始化完成 else if (rxd_finish_en && counter < 8'b11111111)counter <= counter + 1'b1;elsecounter <= counter;endalways @(posedge clk or negedge rst_n)beginif(!rst_n)init_finish <= 1'b0;else if (counter == 8'b11111111)init_finish <= 1'b1;elseinit_finish <= init_finish;endave8_rom ave8_rom (.clk(clk),.rst_n(rst_n),.rd(rd_flag),.addr(cnt0),.ave1_in(ave1),.ave2_in(ave2),.ave3_in(ave3),.ave4_in(ave4),.ave5_in(ave5),.ave6_in(ave6),.ave7_in(ave7),.ave8_in(ave8),.ave_valid(ave_valid),.ave_out(data_out));endmodule该模块的状态机有六个状态:localparam IDLE = 6'b000001;localparam RXD_COM = 6'b000010;localparam JUDGE = 6'b000100;localparam TXD_NUM = 6'b001000;localparam TXD_DATA = 6'b010000;localparam RXD_PARA = 6'b100000;分别是:空闲状态IDLE接收命令状态RXD_COM判断命令是读还是写的状态JUDGE读取要发送的ave数据的状态TXD_NUM发送ave数据的状态TXD_DATA接收数据的状态RXD_PARA以下五个计数变量的意思:reg [3:0] cnt; //计数接收命令参数的位数reg [3:0] cnt0; //发送数据的地址reg [4:0] cnt1; //计数发送数据的位数reg [4:0] cnt2; //计数接收两点校正参数的位数reg [4:0] cnt3; //cnt2和godata输出到的存储参数的存储器的地址有关下⾯代码可以看出是下降沿发送数据:else if(spi_sck_neg)//下降沿发送数据begincnt1 <= cnt1 + 5'b00001;//从⾼位到低位发送spi_miso <= tdata[15 - cnt1[4:0]];end下⾯代码可以看出是上升沿接收数据:else if(spi_sck_pos)//上升沿接收数据begin//接收命令参数存⼊para 也即是写COMMAND_WRITE还是读COMMAND_READ cnt <= cnt + 4'b0001;//从⾼位到低位接收para[7 - cnt[2:0]] <= spi_mosi_flag;end2、ave8_rom模块`timescale 1ns/1ps/*该模块在spi_slave1模块⾥⾯被例化,输出的ave_out会被spi slave发给master*/module ave8_rom (clk,//时钟rst_n,//复位信号rd,//读使能addr,//读地址ave_valid,//平均值有效信号ave1_in,//输⼊的8个通道的图像数据平均值ave2_in,//这是直接由平均值计算模块输⼊的,和spi没关系ave3_in,ave4_in,ave5_in,ave6_in,ave7_in,ave8_in,ave_out//平均值输出,其实是被外部的spi master读取的 );input clk;input rst_n;input rd;input [3:0] addr;input ave_valid;input [15:0] ave1_in;input [15:0] ave2_in;input [15:0] ave3_in;input [15:0] ave4_in;input [15:0] ave5_in;input [15:0] ave6_in;input [15:0] ave7_in;input [15:0] ave8_in;output [15:0] ave_out;reg [15:0] ave_table [7:0];assign ave_out = rd ? ave_table[addr] : 16'b1;always @(posedge clk or negedge rst_n)beginif(!rst_n)beginave_table[7] <= 16'b0000_0000_0000_1000;ave_table[6] <= 16'b0000_0000_0000_0111;ave_table[5] <= 16'b0000_0000_0000_0110;ave_table[4] <= 16'b0000_0000_0000_0101;ave_table[3] <= 16'b0000_0000_0000_0100;ave_table[2] <= 16'b0000_0000_0000_0011;ave_table[1] <= 16'b0000_0000_0000_0010;ave_table[0] <= 16'b0000_0000_0000_0001 ;endelse if (ave_valid && rd ==1'b0 )beginave_table[7] <= ave8_in;ave_table[6] <= ave7_in;ave_table[5] <= ave6_in;ave_table[4] <= ave5_in;ave_table[3] <= ave4_in;ave_table[2] <= ave3_in;ave_table[1] <= ave2_in;ave_table[0] <= ave1_in;endelsebeginave_table[7] <= ave_table[7];ave_table[6] <= ave_table[6];ave_table[5] <= ave_table[5];ave_table[4] <= ave_table[4];ave_table[3] <= ave_table[3];ave_table[2] <= ave_table[2];ave_table[1] <= ave_table[1];ave_table[0] <= ave_table[0];endendendmodule。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
竭诚为您提供优质文档/双击可除SPI协议如何读取寄存器的值
篇一:linux下spi读写外部寄存器的操作
spi写寄存器操作:
staticvoidmcp251x_write_reg(structspi_device*spi,ui nt8_treg,uint8_tval)
{
structmcp251x*chip=dev_get_drvdata(
intret;
down(
chip->spi_transfer_buf[0]=instRuction_wRite;
chip->spi_transfer_buf[1]=reg;
chip->spi_transfer_buf[2]=val;
ret=spi_write(spi,chip->spi_transfer_buf,3);
if(ret dev_dbg(
up(
}
staticvoidmcp251x_write_bits(structspi_device*spi,u int8_treg,uint8_tmask,uint8_tval){
structmcp251x*chip=dev_get_drvdata(
intret;
down(
chip->spi_transfer_buf[0]=instRuction_bit_modiFy;
chip->spi_transfer_buf[1]=reg;
chip->spi_transfer_buf[2]=mask;
chip->spi_transfer_buf[3]=val;
ret=spi_write(spi,chip->spi_transfer_buf,4);
if(ret dev_dbg(
up(
}
spi读寄存器操作:
staticuint8_tmcp251x_read_reg(structspi_device*spi, uint8_treg)
{
structmcp251x*chip=dev_get_drvdata(
uint8_t*tx_buf,*rx_buf;
uint8_tval;
intret;
tx_buf=chip->spi_transfer_buf;
rx_buf=chip->spi_transfer_buf+8;
down(
tx_buf[0]=instRuction_Read;
tx_buf[1]=reg;
ret=spi_write_then_read(spi,tx_buf,2,rx_buf,1);
if(ret {
dev_dbg(val=0;
}
else
val=rx_buf[0];
up(
returnval;
}
staticuint8_tmcp251x_read_state(structspi_device*sp i,uint8_tcmd){
structmcp251x*chip=dev_get_drvdata(
uint8_t*tx_buf,*rx_buf;
uint8_tval;
intret;
tx_buf=chip->spi_transfer_buf;
rx_buf=chip->spi_transfer_buf+8;
down(
tx_buf[0]=cmd;
ret=spi_write_then_read(spi,tx_buf,1,rx_buf,1);
if(ret {
dev_dbg(val=0;
}
else
val=rx_buf[0];
up(
returnval;
}
篇二:spi通讯协议介绍
spi通讯协议介绍
spiinterface
spi接口介绍
spi是由美国摩托罗拉公司推出的一种同步串行传输规范,常作为单片机外设芯片串行扩展接口。
spi有4个引脚:ss(从器件选择线)、sdo(串行数据输出线)、sdi(串行数据
输入线)和sck(同步串行时钟线)。
spi可以用全双工通信方式同时发送和接收8(16)位数据,过程如下:主机启动发送
过程,送出时钟脉冲信号,主移位寄存器的数据通过sdo移入到从移位寄存器,同时从移位寄存器中的数据通过sdi移人到主移位寄存器中。
8(16)个时钟脉冲过后,时钟停顿,
主移位寄存器中的8(16)位数据全部移人到从移位寄存器中,随即又被自动装入从接收缓冲器中,从机接收缓冲器满标志位(bF)和中断标志位(sspiF)置“1”。
同理,从移位寄存器
中的8位数据全部移入到主寄存器中,随即又被自动装入到主接收缓冲器中.主接收缓冲器满标志位(bF)和中断标志位(sspiF)置“1”。
主cpu检测到主接收缓冲器的满标志位或
者中断标志位置1后,就可以读取接收缓冲器中的数据。
同样,从cpu检测到从接收缓冲器满标志位或中断标志位置1后,就可以读取接收缓冲器中的数据,这样就完成了一次相互通信过程。
这里设置dspic30F6014为主控制器,isd4002为从器件,通过spi口完成通信控制的过程。
spi总线协议
spi是一个环形总线结构,由ss(cs)、sck、sdi、sdo 构成,其时序其实很简单,主要是在sck的控制下,两个双向移位寄存器进行数据交换。
假设下面的8位寄存器装的是待发送的数据10101010,上升沿发送、下降沿接收、高位先发送。
那么第一个上升沿。