STM32F4

您所在的位置:网站首页 spi物理层 STM32F4

STM32F4

2024-01-20 00:15| 来源: 网络整理| 查看: 265

目录

1. 什么是SPI

2. SPI物理层

3. SPI协议层

3.1 SPI基本通讯过程

3.2 数据有效性

3.3 CPOL/CPHA及通讯模式

4. SPI框图及通讯过程

4.1 SPI框图

4.2 通讯过程

5. SPI初始化结构体

6. Flash芯片(W25Q128)简介

7. 库函数配置SPI1的主模式

8. 实验程序

8.1 实验程序讲解

8.1.1 main.c

8.1.2 SPI.c

8.1.3 SPI.h

8.1.4 W25Q128.c

8.1.5 W25Q128.h

1. 什么是SPI

        SPI 是由摩托罗拉公司提出的通讯协议,即串行外设接口(Serial Peripheral Interface),SPI是一种高速、全双工(可以同时接收和发送)、同步通信的通信总线,被广泛的应用于ADC、MCU的通信过程中,其相对于IIC最显著的特点就是通讯的速度快,要求通讯速率较高的场合。所以对于通讯速率要求不高的场合,通常使用IIC;通讯速率要求较高的场合,通常使用SPI。 

同样的,和IIC协议一样,学习SPI协议,首先也是从其物理层和协议层开始。

2. SPI物理层

这里通过和IIC协议进行比较,来进一步学习SPI协议。

①:IIC协议是通过寻址的方式来找到通讯的从机,那么SPI是通过什么方式呢?

SPI不同于IIC,不是通过寻址的方式来和从机进行通信的,每个从机都挂载着一条独立的SS信号线,该信号线也称为从设备选择信号线,常常称作片选信号线,也称为NSS,CS(其中STM32F4的芯片引脚就是CS)。每个从机的SS信号线独占主机的一个引脚,也可以说是,有多少个从设备,主机上就有多少条片选信号线。将该片选信号线置低电平0,则意味着选择该从机进行SPI通信;将该片选信号线置高电平1,则意味着停止通讯。

        事实上,每个从设备都有独立的这一条SS信号线,该信号线独占主机的一个引脚。IIC协议中通过设备地址来寻址,选中总线上某个设备并与其进行通讯;而SPI协议中没有设备地址,它是用SS信号线来寻址,当主机选中从设备时,就将所选的从设备的信号线置为低电平0,即意味着该设备被选中,即片选有效,接着主机开始与被选中的从设备进行SPI通讯。所以SPI通讯以SS线置低电平为开始信号,以SS线被拉高作为结束信号。

②:IIC通讯只需要2根串行总线即可,SPI通讯的主机需要哪些特殊的引脚呢?

SCK(Serial Clock):时钟信号线,用于通讯数据同步。它由通讯的主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不同,STM32的SPI时钟频率最大为f_{pclk}/2,两个设备之间通讯时,通讯速率受限于低速设备。

MOSI(Master Output,Slave Input):主设备输出/从设备输入引脚。主机的设备从这条信号线输出,从机由这条信号线读入主机发送的数据,即这条信号线上数据的方向为主机到从机。

MISO(Master Input,Slave Output):主设备输入/从设备输出引脚。主机从这条信号线读入数据,从机的数据由这条信号线输出到主机,即在这条线上数据的方向为从机到主机。

注意:也正是因为这两条MOSI和MISO信号的存在,SPI通讯才能实现全双工,也就是发送和接收可以同步进行,大大增强了通讯的效率。因为IIC通讯只有一条串行数据总线SDA,一根线是不可能单方向的发送,同时也能反方向的接收数据的。而SPI通讯的两根数据线,一根可以用来发送数据,另外一根可以用来接受数据。

3. SPI协议层

SPI协议定义了通讯的起始和停止信号、数据有效性、时钟同步等环节。

3.1 SPI基本通讯过程

①:NSS信号,也就是上面提及的SS信号、CS信号,这三个信号表示的意义是相同的,都表示从机片选信号。NSS信号线由高到低,是SPI通讯的起始信号。NSS是每个从机各自独占的信号线,当从机在自己的NSS线检测到起始信号后,就知道自己被主机选中了,开始准备与主机进行通讯。

⑥:NSS信号由低变高,是SPI通讯的停止信号,表示本次通讯结束,从机的选中状态被取消。

②③④⑤:分别表示触发、采样、触发、采样。SCL高电平期间,不管是MOSI还是MISO输入或者输出,此时信号正在传动,处于不稳定状态,不进行采样。当SCL低电平期间,主从传输的数据进入稳定状态,这个时间段进行采样。

3.2 数据有效性

SPI使用MOSI及MISO信号线来传输数据,使用SCK信号线进行数据同步。

MOSI及MISO数据线在SCK的每个时钟周期传输一位数据,如果需要传输8次,则需要循环传输,且数据输入输出是同时进行的。

3.3 CPOL/CPHA及通讯模式

由CPOL及CPHA的不同状态,SPI分成了四种模式,主机与从机需要工作在相同模式下才可以正常通讯,实际中采用较多的是模式0和模式3;

4. SPI框图及通讯过程 4.1 SPI框图

 

通讯引脚:STM32F4板载了SPI1,SPI2,SPI3。通常情况下使用SPI1,传输速度较快。SPI2和SPI3可以作为I2S音频协议使用。

时钟控制逻辑:通过控制SPI的BR寄存器来控制SPI协议的波特率。产生SPI时钟。BR[0:2]位控制f_{pclk}时钟的分频因子,对f_{pclk}的分频结果就是SCK引脚的输出时钟频率。

数据控制逻辑:SPI的MOSI及MISO都连接到数据移位寄存器上,数据移位寄存器的数据来源于接收缓冲区及发送缓冲区。

通过写SPI的数据寄存器DR把数据填充到发送缓冲区中。

通过读数据寄存器DR,可以获取接收缓冲区中的内容。

数据帧长度可以通过控制寄存器CR1的DFF位配置成8位及16位。

模式:配置LSBFIRST可选择MSB先行还是LSB先行。

4.2 通讯过程

5. SPI初始化结构体

跟其他外设一样,STM32标准库提供了SPI初始化结构体及初始化函数来配置SPI外设。

typedef struct { uint16_t SPI_Direction; //设置SPI单双向模式 uint16_t SPI_Mode; //设置SPI主/从机模式 uint16_t SPI_DataSize; //设置SPI的数据帧长度,可选8/16位 uint16_t SPI_CPOL; //设置时钟极性,可选高低电平 uint16_t SPI_CPHA; //设置时钟相位,可选奇偶边沿采样 uint16_t SPI_NSS; //设置NSS引脚由SPI硬件控制还是软件控制 uint16_t SPI_BaudRatePrescaler; //设置时钟分频因子,fpclk/分频数=fSCK uint16_t SPI_FirstBit; //设置MSB/LSB先行 设置高位先行还是低位先行 uint16_t SPI_CRCPolynomial; //设置CRC校验的表达式 }SPI_InitTypeDef;

SPI_Direction:设置SPI通讯方向,可设置为双线全双工SPI_Direction_2Lines_FullDuplex,双线只接收SPI_Direction_2Lines_RxOnly,单线只接收SPI_Direction_1Line_Rx,单线只发送SPI_Direction_1Line_Tx。

SPI_Mode:设置SPI工作在主机模式SPI_Mode_Master,还是从机模式SPI_Mode_Slave。注意:这两个模式的最大区别就是如果设置为主机模式,那么时钟SCK的时序是由通讯的主机产生的,如果设置为从机模式,那么SCK时钟的时序是由外来的SCK信号提供的。

SPI_DataSize:设置SPI通讯时数据帧的大小是8位SPI_DataSize_8b还是16位SPI_DataSize_16b。

SPI_CPOL:设置时钟极性,高电平SPI_CPOL_High,低电平SPI_CPOL_Low。

SPI_CPHA:设置时钟相位,SCK奇数边沿采集SPI_CPHA_1Edge,SCK偶数边沿采集SPI_CPHA_2Edge。

SPI_NSS:配置NSS引脚的使用模式,可以选择为硬件模式SPI_NSS_Hard,软件模式SPI_NSS_Soft。硬件模式下SPI片选信号由SPI硬件自动产生,软件模式则需要亲自把相应的GPIO端口拉高或置低产生非片选和片选信号。

SPI_BaudRatePrescaler:设置波特率分频因子,分频后时钟即为SPI的SCK信号线的时钟频率。

SPI_FirstBit:配置串行的通讯协议是高位在前还是低位在前。

SPI_CRCPolynomial:SPI计算CRC校验的多项式,若我们使用CRC校验,就使用这个成员的参数,来计算CRC的值。

6. Flash芯片(W25Q128)简介

        W25Q128 是华邦公司推出的大容量SPI FLASH产品,W25Q128的容量为128Mb,该系列还有W25Q80/16/32/64等。ALIENTEK所选择的W25Q128容量为128Mb,也就是16M字节。

        W25Q128 将16M的容量分为256个块(Block),每个块的大小为64K字节,每个块又分为16个扇区Sector,每个扇区4K个字节。W25Q128的最小擦除单位为一个扇区,也就是每次必须擦除4K个字节。因此,我们必须给W25Q128开辟一个至少4K的缓存区,这样对SRAM要求比较高,要求芯片必须有4K以上SRAM才能很好的操作。

        W25Q128 的擦写周期多达10W次,具有20年的数据保存期限,支持电压为2.7~3.6V,W25Q128支持标准的SPI,最大的SPI时钟可以到80MHz。

Flash的存储特性:

1. 在写入数据前必须先擦除。

2. 擦除时会把数据位全重置为1。

3. 写入数据时只能把为1的数据改为0。

4. 擦除时必须按照最小单元来擦除。(一般是整个扇区)

7. 库函数配置SPI1的主模式

STM32F4的SPI功能很强大,SPI 时钟最高可以到 37.5MHz ,支持 DMA,可以配置为 SPI 协议或者 I2S 协议。

1. 配置相关引脚的复用功能,使能SPI1时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);       //使能 SPI1 时钟

SPI1_MISO、SPI1_MOSI以及SPI1_SCK连接在PB3、PB4、PB5上,所以采用库函数将对应的引脚全部复用为SPI1

GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI1);      //PB3 复用为 SPI1

GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI1);      //PB4 复用为 SPI1

GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_SPI1);      //PB5 复用为 SPI1

初始化GPIO的结构体中,将对应的Mode设置为复用

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;      //复用功能

2. 初始化SPI1结构体,设置SPI1工作模式等

void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);      //初始化SPI函数

//该结构的各个参数详情参照该文上述的讲解 typedef struct { uint16_t SPI_Direction; uint16_t SPI_Mode; uint16_t SPI_DataSize; uint16_t SPI_CPOL; uint16_t SPI_CPHA; uint16_t SPI_NSS; uint16_t SPI_BaudRatePrescaler; uint16_t SPI_FirstBit; uint16_t SPI_CRCPolynomial; }SPI_InitTypeDef; //SPI结构体的各个成员的配置如下 SPI_InitTypeDef SPI_InitStructure; SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //双线双向全双工 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主 SPI SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // SPI 发送接收 8 位帧结构 SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//串行同步时钟的空闲状态为高电平 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//第二个跳变沿数据被采样 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS 信号由软件控制 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //预分频 256 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从 MSB 位开始 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC 值计算的多项式 SPI_Init(SPI2, &SPI_InitStructure); //根据指定的参数初始化外设 SPIx 寄存器

3. 使能SPI1

SPI_Cmd(SPI1, ENABLE);      //使能 SPI1 外设

4. SPI传输数据

SPI通讯接口需要有发送数据和接收数据的函数。

void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);     //往SPIx数据寄存器写入数据Data,实现发送。

uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx) ;      //从SPIx数据寄存器读出接收到的数据。

5. 查看SPI传输状态

SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE);     //获取状态位,判断数据是否传输完成,发送区是否为空

8. 实验程序

实验现象:开机的时候先检测W25Q128是否存在,main函数检测按键,KEY1执行写入W25Q128操作,KEY0执行读出W25Q128操作,在LCD上显示相关信息。

注:W25Q128中头文件的指令表来自于下述表格

8.1 实验程序讲解

本实验程序基于STM32F4开发板。

实验现象:开机的时候先检测W25Q128是否存在,然后在主循环里面检测两个按键,其中按键KEY1用来执行写入W25Q128的操作,另外一个按键KEY0用来执行读出操作,在LCD上显示相关信息。

注意:

//注意 u16 W25QXX_ReadID(void) { u16 Temp=0; //定义一个16位的返回值 W25Q128_CS=0; //使能片选 SPI1_ReadWriteByte(0x90); //发送读取ID命令 0x90 SPI1_ReadWriteByte(0x00); SPI1_ReadWriteByte(0x00); SPI1_ReadWriteByte(0x00); //连续三次SPI1_ReadWriteByte(0x00);是读取器件ID的要求,伪字节定义为0x00 Temp|=SPI1_ReadWriteByte(0xFF)CR1|=SPI_BaudRate_Prescaler; //设置SPI速度,上一步清零,这一步将所需位写入相关的值 SPI_Cmd(SPI1,ENABLE); //使能SPI1 } //SPI1读写一个字节 //WriteData:要写入的字节 //返回值:读到的字节 u8 SPI1_ReadWriteByte(u8 WriteData) { while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET); //通过之前的学习,TXE为状态位用来判断缓存寄存器是否为空 //TXE若为0,则表示缓存寄存器非空;TXE若为1,则表示缓存寄存器空,只要跳出while循环,意味着TXE=1,缓存寄存器为空,可以写入下一个数值了 SPI_I2S_SendData(SPI1,WriteData); //通过SPI1发送一个字节的数据 while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)==RESET); //RXNE是用来判断接收缓存区是否为空的状态位,其状态位标志和TXE相同 return SPI_I2S_ReceiveData(SPI1); //返回通过SPI接收的数据 } 8.1.3 SPI.h #ifndef _SPI__H_ #define _SPI__H_ void SPI1_Init(void); void SPI1_SetSpeed(u8 SPI_BaudRate_Prescaler); u8 SPI1_ReadWriteByte(u8 WriteData); #endif 8.1.4 W25Q128.c #include "stm32f4xx.h" #include "W25Q128.h" #include "delay.h" #include "usart.h" #include "SPI.h" //W25Q80 //W25Q16 //W25Q32 //W25Q64 //W25Q128 u16 W25Q128_TYPE=W25Q128; //默认是W25Q128 //4Kbytes为一个Sector //16个扇区为1个Block //W25Q128 //容量为16M字节,共有128个Block,4096个Sector //初始化SPI FLASH的IO口 void W25Q128_Init(void) { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); //使能GPIOB时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE); //使能GPIOG时钟 //初始化GPIOB14,也就是F_CS片选信号线 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出 GPIO_InitStructure.GPIO_OType=GPIO_OType_PP; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_14; GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); //GPIOG7 NRF_CS W25Q128 和 NRF24L01 共用 SPI1,所以这两个器件在使用的时候,必须分时复用(通过片选控制)才行。 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7; GPIO_Init(GPIOG,&GPIO_InitStructure); GPIO_SetBits(GPIOG,GPIO_Pin_7); //PG7是NRF24L01外设的片选信号线 //意思就是STM32F4的SPI1接外设W25Q128 和 NRF24L01,目前SPI通信是一主多从,我们只需要W25Q128 //所以需要将外设NRF24L01的片选信号线置1,表示关闭该外设,防止干扰SPI FLASH通信 W25Q128_CS=1;//初始化默认关闭所有外设,也就是所有外设的片选信号线都置高电平 SPI1_Init(); SPI1_SetSpeed(SPI_BaudRatePrescaler_4); //总线时钟APB/2=fAPB1时钟 168/2=84M 84/4=21M时钟 W25Q128_TYPE=W25QXX_ReadID(); //读取FLASH ID } //读W25Q128状态寄存器 //BIT7 6 5 4 3 2 1 0 //SPR RV TB BP2 BP1 BP0 WEL BUSY //SPR:默认0,状态寄存器保护位,配合WP使用 //TB,BP2,BP1,BP0:FLASH区域写保护设置 //WEL:写使能锁定 //BUSY:忙标记位(1,忙;0,空闲) //默认:0x00 u8 W25Q128_ReadSR(void) { u8 byte=0; W25Q128_CS=0; //使能片选信号 SPI1_ReadWriteByte(W25X_ReadStatusReg); //发送读取状态寄存器命令 byte=SPI1_ReadWriteByte(0xff); //读取一个字节 W25Q128_CS=1; //取消片选信号 return byte; } //写W25Q128状态寄存器 //BIT7 6 5 4 3 2 1 0 //SPR RV TB BP2 BP1 BP0 WEL BUSY //只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写 void W25Q128_Write_SR(u8 Byte) { W25Q128_CS=0; SPI1_ReadWriteByte(W25X_WriteStatusReg); //发送写取状态寄存器命令 SPI1_ReadWriteByte(Byte); W25Q128_CS=1; //写和读取的思想是一样的,读就是设置一个中间变量,通过调用读写函数,把读到值赋给这个变量,最后返回,注意,读一定首先给状态寄存器一个读取的命令 //写也是首先给状态寄存器一个写的命令,然后通过调用读写函数将要写的值写入寄存器即可 } //W25Q128写使能 //将WEL置位 void W25Q128_Write_Enable(void) { W25Q128_CS=0; SPI1_ReadWriteByte(W25X_WriteEnable); //发送写使能指令 W25Q128_CS=1; } //W25Q128写禁止 //将WEL清零 void W25Q128_Write_Disable(void) { W25Q128_CS=0; SPI1_ReadWriteByte(W25X_WriteDisable); //发送写禁止指令 W25Q128_CS=1; } //读取芯片ID //返回值如下: //0XEF13,表示芯片型号为W25Q80 //0XEF14,表示芯片型号为W25Q16 //0XEF15,表示芯片型号为W25Q32 //0XEF16,表示芯片型号为W25Q64 //0XEF17,表示芯片型号为W25Q128 u16 W25QXX_ReadID(void) { u16 Temp=0; //定义一个16位的返回值 W25Q128_CS=0; //使能片选 SPI1_ReadWriteByte(0x90); //发送读取ID命令 0x90 SPI1_ReadWriteByte(0x00); SPI1_ReadWriteByte(0x00); SPI1_ReadWriteByte(0x00); //连续三次SPI1_ReadWriteByte(0x00);是读取器件ID的要求,伪字节定义为0x00 Temp|=SPI1_ReadWriteByte(0xFF)16)); //发送24bit地址,本次发送16-23位 SPI1_ReadWriteByte((u8)((ReadAddress)>>8));//本次发送8-15位 SPI1_ReadWriteByte((u8)ReadAddress); //本次发送0-7位 for(i=0;i>16)); //发送24位地址,同上一个函数,分三次发送,每次发送8位 SPI1_ReadWriteByte((u8)((WriteAddress)>>8)); SPI1_ReadWriteByte((u8)WriteAddress); for(i=0;i256) //因为一页最多只能写256个字节,如果下一页要写入的字节数大于256,只能先写满这一页,通过下一循环写剩余的 pageremain=256; else //如果要写入的字节数小于256,就意味着这一页是可以写完要写入的字节的 pageremain=Num; //把要写入的字节给到该页剩余的字节数,随着W25Q128_Write_Page(pBuffer,WriteAddress,pageremain);函数进行写一页的操作 } } } //写SPI FLASH //在指定地址开始写入指定长度的数据 //该函数带擦除操作!!! //pBuffer:数据存储区 //WriteAddress:开始写入的地址(24bit) //Num:要写入的字节数(最大65535) u8 W25Q128_BUFFER[4096]; //初始化全局变量W25Q128_BUFFER表示扇区能写入的最大字节数为4096 void W25QXX_Write(u8* pBuffer,u32 WriteAddress,u16 Num) { u32 SecAddress; //存储扇区地址 u16 SecMove; //存储扇区偏移量 u16 SecRemain; //存储扇区内剩余空间的大小 u16 i; u8* W25Q128_BUF; W25Q128_BUF=W25Q128_BUFFER; //定义8位的指针数组,用来存储所要写入的字节 SecAddress=WriteAddress/4096; //扇区地址(说白了就是一个扇区可以存放4096个字节,除以4096就表示到底放在了那个扇区,就是总字数除以每一页可以写入的字数就得到到底写在了哪一页) SecMove=WriteAddress%4096; //在扇区内的偏移(也就是一页中存放在什么位置,这个位置是相对于起始位置而言的) SecRemain=4096-SecMove; //扇区剩余空间大小(每个扇区能写入的最大字节数为4096,4096减去该扇区的偏移量就是该扇区内剩余空间的大小) //printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//测试用 这也是为什么要引头文件usart.h的原因 //%X打印十六进制数,\r\n:换行符 if(Num>8)); SPI1_ReadWriteByte((u8)SecAddress); W25Q128_CS=1; W25Q128_Wait_Busy(); //等待擦除完成 } //等待空闲 void W25Q128_Wait_Busy(void) { while((W25Q128_ReadSR()&0x01)==0x01); //等待W25Q128状态寄存器的BUSY位清空 //与&表示拿出SR最低位,也就是BUSY位,只要该位是1,就始终位于while循环中,只要跳出循环,该位就清0 } //进入掉电模式 void W25Q128_PowerDown(void) { W25Q128_CS=0; SPI1_ReadWriteByte(W25X_PowerDown); //发送掉电命令 W25Q128_CS=1; delay_us(3); } //唤醒 void W25Q128_WAKEUP(void) { W25Q128_CS=0; SPI1_ReadWriteByte(W25X_ReleasePowerDown); //发送唤醒命令 W25Q128_CS=1; delay_us(3); } 8.1.5 W25Q128.h #ifndef _W25Q128__H_ #define _W25Q128__H_ //W25X系列/Q系列芯片列表 //W25Q80 ID 0XEF13 //W25Q16 ID 0XEF14 //W25Q32 ID 0XEF15 //W25Q64 ID 0XEF16 //W25Q128 ID 0XEF17 #define W25Q80 0XEF13 #define W25Q16 0XEF14 #define W25Q32 0XEF15 #define W25Q64 0XEF16 #define W25Q128 0XEF17 #define NM25Q80 0X5213 #define NM25Q16 0X5214 #define NM25Q32 0X5215 #define NM25Q64 0X5216 #define NM25Q128 0X5217 #define NM25Q256 0X5218 extern u16 W25Q128_TYPE; //定义W25Q128芯片型号 #define W25Q128_CS PBout(14) //W25Q128的片选信号 ,采用位段命名PBout(14) //指令表 #define W25X_WriteEnable 0x06 #define W25X_WriteDisable 0x04 #define W25X_ReadStatusReg 0x05 #define W25X_WriteStatusReg 0x01 #define W25X_ReadData 0x03 #define W25X_FastReadData 0x0B #define W25X_FastReadDual 0x3B #define W25X_PageProgram 0x02 #define W25X_BlockErase 0xD8 #define W25X_SectorErase 0x20 #define W25X_ChipErase 0xC7 #define W25X_PowerDown 0xB9 #define W25X_ReleasePowerDown 0xAB #define W25X_DeviceID 0xAB #define W25X_ManufactDeviceID 0x90 #define W25X_JedecDeviceID 0x9F void W25Q128_Init(void); u8 W25Q128_ReadSR(void); void W25Q128_Write_SR(u8 Byte); void W25Q128_Write_Enable(void); void W25Q128_Write_Disable(void); u16 W25QXX_ReadID(void); void W25Q128_Read(u8 *pBuffer,u32 ReadAddress,u16 Num); void W25Q128_Write_Page(u8* pBuffer,u32 WriteAddress,u16 Num); void W25Q128_Write_NoCheck(u8* pBuffer,u32 WriteAddress,u16 Num); void W25QXX_Write(u8* pBuffer,u32 WriteAddress,u16 Num); void W25Q128_Erase_Chip(void); void W25Q128_Erase_Sector(u32 SecAddress); void W25Q128_Wait_Busy(void); void W25Q128_PowerDown(void); void W25Q128_WAKEUP(void); #endif

对该文内容有疑问, 或者内容上有写的不对的地方,欢迎批评更改!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3