有没有比itx更小的itx主板孔位尺寸图可以插无线网卡

2933人阅读
STM32学习笔记(24)
废话不多说讲重点!!!
【软件中如何设置SPI的极性和相位】&
SPI分主设备和从设备,两者通过SPI协议通讯。&而设置SPI的模式,是从设备的模式,决定了主设备的模式。&
所以要先去搞懂从设备的SPI是何种模式,然后再将主设备的SPI的模式,设置和从设备相同的模式,即可正常通讯。&对于从设备的SPI是什么模式,有两种:&
(1)固定的,有SPI从设备硬件决定的&
SPI从设备,具体是什么模式,相关的datasheet中会有描述,需要自己去datasheet中找到相关的描述,即:&
关于SPI从设备,在空闲的时候,是高电平还是低电平,即决定了CPOL是0还是1;&然后再找到关于设备是在上升沿还是下降沿去采样数据,这样就是,在定了CPOL的值的前提下,对应着可以推算出CPHA是0还是1了。
CC2500&-&Low-Cost&Low-Power&2.4&GHz&RF&Transceiver的datasheet中SPI的时序图是:
从图中可以看到,最开始的SCLK和结束时候的SCLK,即空闲时刻的SCLK,是低电平,推导出CPOL=0,然后可以看到数据采样的时候,即数据最中间的那一点,对应的是SCLK的第一个边沿,所以CPHA=0(此时对应的是上升沿)。
SSD1289&-&240&RGB&x&320&TFT&LCD&Controller&Driver的datasheet中提到:&
“SDI&is&shifted&into&8-bit&shift&register&on&every&rising&edge&of&SCK&in&the&order&of&data&bit&7,&data&bit&6&……&data&bit&0.”&
意思是,数据是在上升沿采样,所以可以断定是CPOL=0,CPHA=0,或者CPOL=1,CPHA=1的模式,但是至于是哪种模式。&
按理来说,接下来应该再去确定SCLK空闲时候是高电平还是低电平,用以确定CPOL是0还是1,但是datasheet中没有提到这点。&
所以,此处,目前不太确定,是两种模式都支持,还是需要额外找证据却确定CPOL是0还是1.
(2)可配置的,由软件自己设定&
从设备也是一个SPI控制器,4种模式都支持,此时只要自己设置为某种模式即可。&然后知道了从设备的模式后,再去将SPI主设备的模式,设置为和从设备模式一样,即可。 &
对于如何配置SPI的CPOL和CPHA的话,不多细说,多数都是直接去写对应的SPI控制器中对应寄存器中的CPOL和CPHA那两位,写0或写1即可。&
C中的SPI就是一个SPI的controller控制器,即支持软件配置CPOL和CPHA的值,四种模式都支持,此处C作为SPI从设备,设置了CPOL=1,CPHA=0的模式,因此,此处对应主芯片中的SPI控制器,作为Master主设备,其SPI的模式也要设置为CPOL=1,CPHA=0,即可。
【SPI的读写程序设计】&文中标红的是特别注意看的地方主要是熟悉flash芯片的指令集,以及存储芯片扇区和块的理解,最重要的是擦除都是以扇区擦除的方式。
本节将利用SPI来实现对外部FLASH(W25X16)的读写,并将结果显示在TFTLCD模块上。本节分为如下几个部分:
3.17.1 SPI&简介
3.17.2&硬件设计
3.17.3&软件设计
3.17.4&下载与测试
& 1 SPI&简介
SPI&是英语Serial Peripheralinterface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,STM32也有SPI接口。
SPI接口一般使用4条线:
MISO&主设备数据输入,从设备数据输出。
MOSI&主设备数据输出,从设备数据输入。
SCLK时钟信号,由主设备产生。
CS从设备片选信号,由主设备控制。
SPI主要特点有:可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。
SPI总线四种工作方式&SPI&模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。SPI主模块和与之通信的外设备时钟相位和极性应该一致。
不同时钟相位下的总线数据传输时序见下图:
图3.17.1.1不同时钟相位下的总线传输时序(CPHA=0/1)
STM32的SPI功能很强大,SPI时钟最多可以到18Mhz,支持DMA,可以配置为SPI协议或者I2S协议。
本节,我们将利用STM32的SPI来读取外部SPIFLASH芯片(W25X16),实现类似上节的功能。这里对SPI我们只简单介绍一下SPI的使用,STM32的SPI详细介绍请参考《STM32参考手册》第422页,22节。然后我们再介绍下SPIFLASH芯片。
这节,我们使用STM32的SPI1的主模式,下面就来看看SPI1部分的设置步骤吧,STM32的主模式配置步骤如下:
1)配置相关引脚的复用功能,使能SPI1时钟。
我们要用SPI1,第一步就要是能SPI1的时钟,SPI1的时钟通过APB2ENR的第12位来设置。其次要设置SPI1的相关引脚为复用输出,这样才会连接到SPI1上否则这些IO口还是默认的状态,也就是标准输入输出口。这里我们使用的是PA5、6、7这3个(SCK.、MISO、MOSI,CS使用软件管理方式),所以设置这三个为复用IO。
2)设置SPI1工作模式。
这一步全部是通过SPI1_CR1来设置,我们设置SPI1为主机模式,设置数据格式为8位,然后通过CPOL和CPHA位来设置SCK时钟极性及采样方式。并设置SPI1的时钟频率(最大18Mhz),以及数据的格式(MSB在前还是LSB在前)。
3)使能SPI1。
这一步通过SPI1_CR1的bit6来设置,以启动SPI1,在启动之后,我们就可以开始SPI通讯了。
SPI1的使用就介绍到这里,接下来介绍一下W25X16。W25X16是华邦公司推出的继W25X10/20/40/80(从1Mb~8Mb)后容量更大的FLASH产品,W25X16的容量为16Mb,还有容量更大的W25X32/64,ALIENTEK所选择的W25X16容量为16Mb,也就是2M字节,同AT45DB161是一样大小的。
W25X16将2M的容量分为32个块(Block),每个块大小为64K字节,每个块又分为16个扇区(Sector),每个扇区4K个字节。W25X16的最少擦除单位为一个扇区,也就是每次必须擦除4K个字节。这样我们需要给W25X16开辟一个至少4K的缓存区,这样对SRAM要求比较高(相对于AT45DB161来说),但是它有价格及供货上的优势。
W25X16的差些周期为10000次,具有20年的数据保存期限,支持电压为2.7~3.6V,W25X16支持标准的SPI,还支持双输出的SPI,最大SPI时钟可以到75Mhz(双输出时相当于150Mhz),更多的W25X16的介绍,请参考W25X16的DATASHEET。
2&硬件设计
本节实验功能简介:开机的时候先检测W25X16是否存在,然后在主循环里面用1个按键用来执行写入W25X16的操作,另外一个按键用来执行读出操作,在TFTLCD模块上显示相关信息。同时用DS0提示程序正在运行。
所要用到的硬件资源如下:
1)STM32F103RBT6。
2)DS0(外部LED0)。
3)KEY0和KEY2。
4)TFTLCD液晶模块。
5)W25X16。
前面4部分的资源,我们前面已经介绍了,请大家参考相关章节。这里只介绍W25X16与STM32的连接,板上的W25X16是直接连在STM32F103RBT6上的,连接关系如下图:
图3.17.2.1STM32F103RBT6与W25X16连接电路图
3&软件设计
打开上一节的工程,首先在HARDWARE文件夹下新建一个FLASH的文件夹和SPI的文件夹。然后新建一个flash.c和flash.h的文件保存在FLASH文件夹下,新建spi.c和spi.h的文件,保存在SPI文件夹下,并将这两个文件夹加入头文件包含路径。
打开spi.c文件,输入如下代码:
#include&spi.h&& & & & & & & & & & & & & & & & &&
//SPI口初始化
//这里针是对SPI1的初始化
voidSPIx_Init(void)
&&&& RCC-&APB2ENR|=1&&2;&&&&&& //PORTA时钟使能&&&&&&&&&&& &
&&&& RCC-&APB2ENR|=1&&12;&&&&& //SPI1时钟使能
&&&&&&&&&&&&&&&& &&
&&&& //这里只针对SPI口初始化
&&&& GPIOA-&CRL&=0X000FFFFF;
&&&& GPIOA-&CRL|=0XBBB00000;//PA5.6.7复用&&&&&& &&&&
&&&& GPIOA-&ODR|=0X7&&5;&&& //PA5.6.7上拉&&&&&&
&&&& SPI1-&CR1|=0&&10;//全双工模式&&&&&&&&&&
&&&& SPI1-&CR1|=1&&9; //软件nss管理
&&&& SPI1-&CR1|=1&&8;&
&&&& SPI1-&CR1|=1&&2; //SPI主机
&&&& SPI1-&CR1|=0&&11;//8bit数据格式&&&&&&&
&&&& SPI1-&CR1|=1&&1; //空闲模式下SCK为1 CPOL=1
&&&& SPI1-&CR1|=1&&0; //数据采样从第二个时间边沿开始,CPHA=1&
&&&& SPI1-&CR1|=7&&3; //Fsck=Fcpu/256
&&&& SPI1-&CR1|=0&&7; //MSBfirst&&
&&&& SPI1-&CR1|=1&&6; //SPI设备使能
&&&& SPIx_ReadWriteByte(0xff);//启动传输&&&&&&&&&&&&&&&
//SPI&速度设置函数
//SpeedSet:
//SPI_SPEED_2&& 2分频&& (SPI 36M@sys 72M)
//SPI_SPEED_8&& 8分频&& (SPI 9M@sys 72M)
//SPI_SPEED_16& 16分频& (SPI 4.5M@sys 72M)
//SPI_SPEED_256256分频&(SPI281.25K@sys 72M)
voidSPIx_SetSpeed(u8 SpeedSet)
&&&& SPI1-&CR1&=0XFFC7;//Fsck=Fcpu/256
&&&& if(SpeedSet==SPI_SPEED_2)//二分频
&&&&&&&&&&&&&&&& SPI1-&CR1|=0&&3;//Fsck=Fpclk/2=36Mhz&&&&&&&&&&
&&&& }else if(SpeedSet==SPI_SPEED_8)//八分频
&&&&&&&&&&&&&&&& SPI1-&CR1|=2&&3;//Fsck=Fpclk/8=9Mhz
&&&& }else if(SpeedSet==SPI_SPEED_16)//十六分频
&&&&&&&&&&&&&&&& SPI1-&CR1|=3&&3;//Fsck=Fpclk/16=4.5Mhz
&&&& }else&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&& &//256分频
&&&&&&&&&&&&&&&& SPI1-&CR1|=7&&3;//Fsck=Fpclk/256=281.25Khz&低速模式
&&&& SPI1-&CR1|=1&&6; //SPI设备使能&&&&&&&& &
//SPIx读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
u8SPIx_ReadWriteByte(u8 TxData)
{&&&& u8 retry=0;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&& while((SPI1-&SR&1&&1)==0)//等待发送区空&&&&&
&&&& {& retry++;
&&&&&&&&&&&&&&&& if(retry&200)return 0;
&&&& }&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &
&&&& SPI1-&DR=TxD&&&&&&& &&&&&&&&&& &&//发送一个byte
&&&& retry=0;
&&&& while((SPI1-&SR&1&&0)==0) //等待接收完一个byte&
&&&& {&&&&& retry++;
&&&&&&&&&&&&&&& if(retry&200)return 0;
&&&& }&&&&&&&&& & &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&
&&&& return SPI1-&DR;&&&&&&&&& //返回收到的数据&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& && &
此部分代码主要初始化SPI,这里我们选择的是SPI1,所以在SPIx_Init函数里面,其相关的操作都是针对SPI1的,其初始化步骤和我们上面介绍的一样。在初始化之后,我们就可以开始使用SPI1了,在SPIx_Init函数里面,把SPI1的波特率设置成了最低(281.25Khz)。在外部函数里面,我们通过SPIx_SetSpeed来设置SPI1的速度,而我们的数据发送和接收则是通过SPIx_ReadWriteByte函数来实现的。、
保存spi.c,并把该文件加入RDWARE组下面,然后我们打开spi.h在里面输入如下代码:
#ifndef __SPI_H
#define __SPI_H
#include &sys.h&
// SPI总线速度设置
#define SPI_SPEED_2&& 0
#define SPI_SPEED_8&& 1
#define SPI_SPEED_16& 2
#define SPI_SPEED_256 3&
void SPIx_Init(void);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //初始化SPI口
void SPIx_SetSpeed(u8 SpeedSet); //设置SPI速度&&
u8 SPIx_ReadWriteByte(u8 TxData);//SPI总线读写一个字节
&&&&&此部分代码我们就不多介绍了,保存spi.h,然后我们打开flash.c,在里面输入如下代码:
#include &flash.h&
#include &spi.h&
#include &delay.h&&
//4Kbytes为一个Sector
//16个扇区为1个Block
//容量为2M字节,共有32个Block,512个Sector
//初始化SPI FLASH的IO
void SPI_Flash_Init(void)
&&&& RCC-&APB2ENR|=1&&2;&&&&&& //PORTA时钟使能&&&&&&&&&&&& &&&&
&&&& //这里
&&&& GPIOA-&CRL&=0XFFF000FF;
&&&& GPIOA-&CRL|=0X;//PA2.3.4推挽&&&&&& &&&&
&&&& GPIOA-&ODR|=0X7&&2;&&& //PA2.3.4上拉
&&&& SPIx_Init();&&&&&&&&&&&&&&&&&& && //初始化SPI
//读取SPI_FLASH的状态寄存器
//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 SPI_Flash_ReadSR(void)&&
&&&& u8byte=0;&&
&&&& SPI_FLASH_CS=0;&&&&&&&&&&&&&&&&&&&&&&&&&&& //使能器件&&
&&&& SPIx_ReadWriteByte(W25X_ReadStatusReg);&&& //发送读取状态寄存器命令&&&
&&&& byte=SPIx_ReadWriteByte(0Xff);&&&&&&&&&&&& //读取一个字节&
&&&& SPI_FLASH_CS=1;&&&&&&&&&&&&&&&&&&&&&&&&&&& //取消片选&&&&
//写SPI_FLASH状态寄存器
//只有SPR,TB,BP2,BP1,BP0(bit7,5,4,3,2)可以写!!!
void SPI_FLASH_Write_SR(u8 sr)&&
{&& SPI_FLASH_CS=0;&&&&&&&&&&&&&&&&&&&&&&&&&&& //使能器件&&
&&&& SPIx_ReadWriteByte(W25X_WriteStatusReg);&& //发送写取状态寄存器命令&&&
&&&& SPIx_ReadWriteByte(sr);&&&&&&&&&&&&&& //写入一个字节&
&&&& SPI_FLASH_CS=1;&&&&&&&&&&&&&&&&&&&&&&&&&&& //取消片选&&&& &&&&& &&&&&&
//SPI_FLASH写使能&&&&&&&&&
//将WEL置位&&
void SPI_FLASH_Write_Enable(void)&&
&&&& SPI_FLASH_CS=0;&&&&&&&&&&&&&&&&&&&&&&&&&&& //使能器件&&
&&&SPIx_ReadWriteByte(W25X_WriteEnable);&&&&& //发送写使能&
&&&& SPI_FLASH_CS=1;&&&&&&&&&&&&&&&&&&&&&&&&&&& //取消片选&&&& &&&&& &&&&&&
//SPI_FLASH写禁止&&&&&&&&&
//将WEL清零&
void SPI_FLASH_Write_Disable(void)&&
{&SPI_FLASH_CS=0;&&&&&&&&&&&&&&&&&&&&&&&&&&& //使能器件&&
&&&SPIx_ReadWriteByte(W25X_WriteDisable);&&&& //发送写禁止指令&&&
&&&& SPI_FLASH_CS=1;&&&&&&&&&&&&&&&&&&&&&&&&&&& //取消片选&&&& &&&&& &&&&&&
} &&&&&&&&&&&&&&&&&&&&&&&&& &&&&
//读取芯片ID W25X16的ID:0XEF14
u16 SPI_Flash_ReadID(void)
{u16Temp = 0;&& &
&&&& SPI_FLASH_CS=0;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&
&&&& SPIx_ReadWriteByte(0x90);//发送读取ID命令&& &&&
&&&& SPIx_ReadWriteByte(0x00);&&&&&& &&&&
&&&& SPIx_ReadWriteByte(0x00);&&&&&& &&&&
&&&& SPIx_ReadWriteByte(0x00);&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&
&&&& Temp|=SPIx_ReadWriteByte(0xFF)&&8;&
&&&& Temp|=SPIx_ReadWriteByte(0xFF);&&&&&&&&
&&&& SPI_FLASH_CS=1;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&
&&&& returnT
}&&&&&&&&&&&&&&&&&&&&&&&&& &&&&
//读取SPI FLASH&
//在指定地址开始读取指定长度的数据
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(24bit)
//NumByteToRead:要读取的字节数(最大65535)
void SPI_Flash_Read(u8* pBuffer,u32ReadAddr,u16 NumByteToRead)&&
{& u16&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&& SPI_FLASH_CS=0;&&&&&&&&&&&&&&&&&&&&&&&&&&& //使能器件&&
&&&SPIx_ReadWriteByte(W25X_ReadData);&&&&&&&& //发送读取命令&&
&&&SPIx_ReadWriteByte((u8)((ReadAddr)&&16));& //发送24bit地址&&&
&&&SPIx_ReadWriteByte((u8)((ReadAddr)&&8));&&
&&&SPIx_ReadWriteByte((u8)ReadAddr);&&
&&&for(i=0;i&NumByteToRi++)
&&&&&&&pBuffer=SPIx_ReadWriteByte(0XFF);&&//循环读数&
&&&& SPI_FLASH_CS=1;&&&&&&&&&&&&&&&&&&&&&&&&&&& //取消片选&&&& &&&&& &&&&&&
//SPI在一页(0~65535)内写入少于256个字节的数据
//在指定地址开始写入最大256字节的数据
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!&&&&&&&&&&&
void SPI_Flash_Write_Page(u8* pBuffer,u32WriteAddr,u16 NumByteToWrite)
&&&SPI_FLASH_Write_Enable();&&&&&&&&&&&&&&&&& //SET WEL
&&&& SPI_FLASH_CS=0;&&&&&&&&&&&&&&&&&&&&&&&&&&& //使能器件&&
&&&SPIx_ReadWriteByte(W25X_PageProgram);&&&&& //发送写页命令&&
&&&SPIx_ReadWriteByte((u8)((WriteAddr)&&16)); //发送24bit地址&&&
&&&SPIx_ReadWriteByte((u8)((WriteAddr)&&8));&&
&&&SPIx_ReadWriteByte((u8)WriteAddr);&&
&&&for(i=0;i&NumByteToWi++)SPIx_ReadWriteByte(pBuffer);//循环写数&
&&&& SPI_FLASH_CS=1;&&&&&&&& &&&&&&&&&&&&&&&&&&&//取消片选
&&&& SPI_Flash_Wait_Busy();&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& && //等待写入结束
//无检验写SPI FLASH
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void SPI_Flash_Write_NoCheck(u8*pBuffer,u32 WriteAddr,u16 NumByteToWrite)&&
{ &&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&& &
&&&& u16 &&
&&&& pageremain=256-WriteAddr%256;//单页剩余的字节数&&&&&&&&&&&&&&& &&&&&&&&&& &&&&
&&&& if(NumByteToWrite&=pageremain)pageremain=NumByteToW//不大于256个字节
&&&& while(1)
&&&& {&&&&&&&&& &&
&&&&&&&&&&&&&&&& SPI_Flash_Write_Page(pBuffer,WriteAddr,pageremain);
&&&&&&&&&&&&&&&& if(NumByteToWrite==pageremain)//写入结束了
&&&& &&&&&&&&&&& else//NumByteToWrite&pageremain
&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&&&&&&& pBuffer+=
&&&&&&&&&&&&&&&&&&&&&&&&&&&& WriteAddr+=&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& NumByteToWrite-=&&&&&&&&&&&&&&&&&&&&&&&&&& & //减去已经写入了的字节数
&&&&&&&&&&&&&&&&&&&&&&&&&&&& if(NumByteToWrite&256)pageremain=256;//一次可以写入256个字节
&&&&&&&&&&&&&&&&&&&&&&&&&&&& elsepageremain=NumByteToW &&&&&&&& &&//不够256个字节了
&&&&&&&&&&&&&&&& }
&&&& };&&&&&&&& &&&
//写SPI FLASH&
//在指定地址开始写入指定长度的数据
//该函数带擦除操作!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)& &&&&&&&&&&&&&&& &&&
u8 SPI_FLASH_BUF[4096];
void SPI_Flash_Write(u8* pBuffer,u32WriteAddr,u16 NumByteToWrite)&&
&&&& u16&& &&
&&&& u16&&&
&&&& secpos=WriteAddr/4096;//扇区地址0~511 for w25x16
&&&& secoff=WriteAddr%4096;//在扇区内的偏移
&&&& secremain=4096-//扇区剩余空间大小&&
&&&& if(NumByteToWrite&=secremain)secremain=NumByteToW//不大于4096个字节
&&&& while(1)
&&&& {&&&&&&&&&
&&&&&&&&&&&&&&&& SPI_Flash_Read(SPI_FLASH_BUF,secpos*);//读出整个扇区的内容
&&&&&&&&&&&&&&&& for(i=0;i&i++)//校验数据
&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&&&&&&& if(SPI_FLASH_BUF[secoff+i]!=0XFF)//需要擦除& &&
&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&& if(i&secremain)//需要擦除
&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&&&&&&& SPI_Flash_Erase_Sector(secpos);//擦除这个扇区
&&&&&&&&&&&&&&&&&&&&&&&&&&&& for(i=0;i&i++) && //复制
&&&&&&&&&&&&&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& SPI_FLASH_BUF[i+secoff]=pBuffer;& &
&&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&&&&&&& SPI_Flash_Write_NoCheck(SPI_FLASH_BUF,secpos*);//写入整个扇区&
&&&&&&&&&&&&&&&& }elseSPI_Flash_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间.&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&& if(NumByteToWrite==secremain)//写入结束了
&&&&&&&&&&&&&&&& else//写入未结束
&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&&&&&&& secpos++;//扇区地址增1
&&&&&&&&&&&&&&&&&&&&&&&&&&&& secoff=0;//偏移位置为0&&&&&&&&&&& &
&&&&&&&&&&&&&&&& && &&&&&&&& pBuffer+=& //指针偏移
&&&&&&&&&&&&&&&&&&&&&&&&&&&& WriteAddr+=//写地址偏移&&&&&& &&
&&&&&&&&&&&&&&&& && &&&&&&&& NumByteToWrite-=&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&& //字节数递减
&&&&&&&&&&&&&&&&&&&&&&&&&&&& if(NumByteToWrite&4096)secremain=4096;&&&&&&&&& //下一个扇区还是写不完
&&&&&&&&&&&&&&&&&&&&&&&&&&&& elsesecremain=NumByteToW&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //下一个扇区可以写完了
&&&&&&&&&&&&&&&& }&&&&&&&&&
&&&& };&&&&&&&& &&&&&&&&&& &
//擦除整个芯片
//整片擦除时间:
//W25X16:25s
//W25X32:40s
//W25X64:40s
//等待时间超长...
void SPI_Flash_Erase_Chip(void)&&
{&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&SPI_FLASH_Write_Enable();&&&&&&&&&&&&&&&&& //SET WEL
&&&SPI_Flash_Wait_Busy();&&
& && SPI_FLASH_CS=0;&&&&&&&&&&&&&&&&&&&&&&&&&&& //使能器件&&
&&&SPIx_ReadWriteByte(W25X_ChipErase);&&&&&&& //发送片擦除命令&
&&&& SPI_FLASH_CS=1;&&&&&&&& &&&&&&&&&&&&&&&&&&&//取消片选&&&& &&&&& &&&&&&
&&&& SPI_Flash_Wait_Busy();&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&//等待芯片擦除结束
//擦除一个扇区
//Dst_Addr:扇区地址0~511 for w25x16
//擦除一个山区的最少时间:150ms
void SPI_Flash_Erase_Sector(u32Dst_Addr)&&
&&&& Dst_Addr*=4096;
&&&SPI_FLASH_Write_Enable();&&&&&&&&&&&&&&&&&//SET WEL &&&&&& &
&&&SPI_Flash_Wait_Busy();&&
& && SPI_FLASH_CS=0;&&&&&&&&&&&&&&&&&&&&&&&&&&& //使能器件&&
&&&SPIx_ReadWriteByte(W25X_SectorErase);&&&&& //发送扇区擦除指令
&&&SPIx_ReadWriteByte((u8)((Dst_Addr)&&16));& //发送24bit地址&&&
&&&SPIx_ReadWriteByte((u8)((Dst_Addr)&&8));&&
&&&SPIx_ReadWriteByte((u8)Dst_Addr);&
&&&& SPI_FLASH_CS=1;&&&&&&&&&&&&&&&&&&&&&&&&&&& //取消片选&&&& &&&&& &&&&&&
&&&SPI_Flash_Wait_Busy();&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&//等待擦除完成
//等待空闲
void SPI_Flash_Wait_Busy(void)&&
&&&& while((SPI_Flash_ReadSR()&0x01)==0x01);&&//&等待BUSY位清空
//进入掉电模式
void SPI_Flash_PowerDown(void)&&
& && SPI_FLASH_CS=0;&&&&&&&&&&&&&&&&&&&&&&&&&&& //使能器件&&
&&&SPIx_ReadWriteByte(W25X_PowerDown);&&&&&&& //发送掉电命令&
&&&& SPI_FLASH_CS=1;&&&&&&&&&&&&&&&&&&&&&&&&&&& //取消片选&&&& &&&&& &&&&&&
&&&delay_us(3);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //等待TPD&
void SPI_Flash_WAKEUP(void)&&
& && SPI_FLASH_CS=0;&&&&&&&&&&&&&&&&&&&&&&&&&&& //使能器件&&
&&&SPIx_ReadWriteByte(W25X_ReleasePowerDown);&& //&send W25X_PowerDown command 0xAB&&&
&&&& SPI_FLASH_CS=1;& &&&&&&&&&&&&&&&&&&&&&&&&&&//取消片选&&&& &&&&& &&&&&&
&&&delay_us(3);&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //等待TRES1
此部分代码里面一个最关键的函数就是voidSPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite),该函数可以在W25X16的任意地址开始写入任意长度(必须不超过W25X16的容量)的数据。我们这里简单介绍一下思路:先获得首地址(WriteAddr)所在的扇区,并计算在扇区内的偏移,然后判断要写入的数据长度是否超过本扇区所剩下的长度,如果不超过,再先看看是否要删除,如果不要,则直接写入数据即可,如果要则读出整个扇区,在偏移处开始写入指定长度的数据,然后擦除这个扇区,再一次性写入。当所需要写入的数据长度超过一个扇区的长度的时候,我们先按照前面的步骤把扇区剩余部分写完,再在新扇区内执行同样的操作,如此循环,直到写入结束。
其他的代码就比较简单了,我们这里不介绍了。保存falsh.c,然后加入到HARDWARE组下面,再打开flahs.h,在该文件里面输入如下代码:
#ifndef __FLASH_H
#define __FLASH_H&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&
#include &sys.h&
//Mini STM32开发板
//W25X16&驱动函数
//正点原子@ALIENTEK
#define&&&&&& SPI_FLASH_CSPAout(2)& //选中FLASH&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
////////////////////////////////////////////////////////////////////////////
//W25X16读写
#define FLASH_ID 0XEF14
#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 SPI_Flash_Init(void);
u16&SPI_Flash_ReadID(void);& &&&&&& &&&&//读取FLASH ID
u8& SPI_Flash_ReadSR(void);&&&&&&& //读取状态寄存器
void SPI_FLASH_Write_SR(u8 sr);& &&&&&&&&&&& //写状态寄存器
void SPI_FLASH_Write_Enable(void);& //写使能
void SPI_FLASH_Write_Disable(void);&&&&&&& //写保护
void SPI_Flash_Read(u8* pBuffer,u32ReadAddr,u16 NumByteToRead);&& //读取flash
void SPI_Flash_Write(u8* pBuffer,u32WriteAddr,u16 NumByteToWrite);//写入flash
void SPI_Flash_Erase_Chip(void);&&& &&&&&&&&&&& &&//整片擦除
void SPI_Flash_Erase_Sector(u32Dst_Addr);//扇区擦除
void SPI_Flash_Wait_Busy(void);&&&&&&&&&& //等待空闲
void SPI_Flash_PowerDown(void);&&&&&&&&&& //进入掉电模式
void SPI_Flash_WAKEUP(void);&&&&&&&&&&&&&&&&&&&&&&&&&&&& & //唤醒
这里面就定义了一些与W25X16操作相关的命令,这些命令在W25X16的数据手册上都有详细的介绍,感兴趣的大家可以参考该数据手册,其他的就没啥好说的了。保存此部分代码。
最后,我们在test.c里面,修改main函数如下:
//要写入到W25X16的字符串数组
const u8 TEXT_Buffer[]={&MiniSTM32SPI TEST&};
#define SIZE sizeof(TEXT_Buffer)&&
int main(void)
{&&&&&&&&&&&&&&
&&&& u16i=0;
&&&& u8datatemp[SIZE];
&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&
& && Stm32_Clock_Init(9);//系统时钟设置
&&&& delay_init(72);&&&&&&&&&&&&&& //延时初始化
&&&& uart_init(72,9600);//串口1初始化&&
&&&& LED_Init();&&&&&& && &&&&&&&&&&&&&&&&&&&& //LED初始化
&&&& KEY_Init();&&&&&& && &&&&&&&&&&&&&&&&&&&& //按键初始化
&&&& LCD_Init();&&& &&&&&&&&&&&&&& //TFTLCD液晶初始化
&&&& SPI_Flash_Init();&& //SPI FLASH&初始化
&&&& POINT_COLOR=RED;//设置字体为蓝色&&&&&&&&&&& &&
&&&& LCD_ShowString(60,50,&MiniSTM32&);
&&&& LCD_ShowString(60,70,&SPITEST&);&&&&
&&&& LCD_ShowString(60,90,&ATOM@ALIENTEK&);
&&&& LCD_ShowString(60,110,&&);&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& &
&&&& while(SPI_Flash_ReadID()!=FLASH_ID)//检测不到W25X16
&&&& {&&&&&&&&& &&
&&&&&&&&&&&&&&&& i=SPI_Flash_ReadID();
&&&&&&&&&&&&&&&& printf(&ID:%d&,i);
&&&&&&&&&&&&&&&& LCD_ShowString(60,130,&W25X16Check Failed!&);
&&&&&&&&&&&&&&&& delay_ms(500);
&&&&&&&&&&&&&&&& LCD_ShowString(60,130,&&& Please Check!&&& &);
&&&&&&&&&&&&&&&& delay_ms(500);
&&&&&&&&&&&&&&&& LED0=!LED0;//DS0闪烁
&&&& LCD_ShowString(60,130,&W25X16Ready!&);
&&&& //显示提示信息
&&&& LCD_ShowString(60,150,&KEY0:WriteKEY2:Read&);
&&&& POINT_COLOR=BLUE;//设置字体为蓝色&&&&&&&&& &
&&&& while(1)
&&&&&&&&&&&&&&&& key=KEY_Scan();
&&&&&&&&&&&&&&&& if(key==1)//KEY0按下,写入SPIFLASH
&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&&&&&&& LCD_Fill(0,170,239,319,WHITE);//清除半屏&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& LCD_ShowString(60,170,&StartWrite W25X16....&);
&&&&&&&&&&&&&&&&&&&&&&&&&&&& SPI_Flash_Write((u8*)TEXT_Buffer,1000,SIZE);//从1000字节处开始,写入SIZE长度的数据
&&&&&&&&&&&&&&&&&&&&&&&&&&&& LCD_ShowString(60,170,&W25X16Write Finished!&);//提示传送完成
&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&& if(key==3)//KEY1按下,读取写入的字符传字符串并显示
&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&&&&&&& LCD_ShowString(60,170,&StartRead W25X16.... &);
&&&&&&&&&&&&&&&&&&&&&&&&&&&& SPI_Flash_Read(datatemp,1000,SIZE);//从1000地址处开始,读出SIZE个字节
&&&&&&&&&&&&&&&&&&&&&&&&&&&& LCD_ShowString(60,170,&TheData Readed Is:& &);//提示传送完成
&&&&&&&&&&&&&&&&&&&&&&&&&&&& LCD_ShowString(60,190,datatemp);//显示读到的字符串
&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&& i++;
&&&&&&&&&&&&&&&& delay_ms(1);
&&&&&&&&&&&&&&&& if(i==200)
&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&&&&&&& LED0=!LED0;//提示系统正在运行&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& i=0;
&&&&&&&&&&&&&&&& }&&&&&&&&&&&&&&&&&&&&& &&
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:111411次
积分:1959
积分:1959
排名:第18557名
原创:73篇
转载:70篇
评论:17条
(1)(12)(2)(3)(19)(16)(8)(20)(16)(11)(7)(6)(1)(10)(10)

我要回帖

更多关于 itx主板孔位尺寸图 的文章

 

随机推荐