SPI_flash代码分析
spiFLASH芯片WQ的单片机驱动代码
spiFLASH芯片WQ的单片机驱动代码#include "w25q80.h"// 注:W25Q80由256 BYTE 组成一个PAGE,不可PGAE擦除,可以进行BYTE PROGRAM 或者PAGE PROGRAM// 由16 PAGE 组成一个SECTOR,可SECTOR擦除// 由16 SECTOR组成一个BLOCK,可BLOCK 擦除// 由16 BLOCK 组成一个FULL MEMEORY,可FULL MEMORY 擦除// 所以,总容量是1M bytes// W25Q80主要命令字#define READ_ARRAY 0x03#define SECTOR_ERASE 0x20#define BYTE_OR_PAGE_PROGRAM 0x02#define WRITE_ENABLE 0x06#define WRITE_DISABLE 0x04#define READ_STATUS_REGISTER 0x05#define Manufacturer_DeviceID 0x9F// 定义W25Q80的CS脚对应MCU的IO#define W25Q80_CS P1_2// SPI硬件初始化void Spi_Init(void){PERCFG |= 0x02; // SPI1映射到P1口P1SEL |= 0xE0; // P15~P17作复用功能(clk mosi miso)P1SEL &= ~0x04; // P12作GPIOP1DIR |= 0x04; // P12作输出P1_2 = 1; // P12输出高电平U1CSR &= ~0xA0; // SPI主方式U1GCR &= ~0xC0; // CPOL=0 CPHA=0U1GCR |= 0x20; // MSBU1BAUD = 0; // 波特率设为sysclk/8U1GCR |= 0x11;// SPI发送与接收字节static u8 Spi_ReadWriteByte(u8 TxData){U1DBUF = TxData; // 发送数据while( !(U1CSR&0x02) ); // 等待发送完成U1CSR &= 0xFD; // 清除发送完成标志return U1DBUF;}// CS线拉低,使能芯片static void W25Q80_Enable( void ){volatile u8 i;W25Q80_CS = 0;for ( i=5; i>0; i-- ); // 延时}// CS线拉高,禁能芯片#define W25Q80_Disable() ( W25Q80_CS = 1 )// 设置FLASH芯片"写使能"static void SetW25Q80WriteEnable(void){W25Q80_Enable();Spi_ReadWriteByte(WRITE_ENABLE);W25Q80_Disable();}// 设置FLASH芯片"写禁能"//static void ClearW25Q80WriteEnable(void)//{// W25Q80_Enable();// Spi_ReadWriteByte(WRITE_DISABLE);// W25Q80_Disable();//}// 读取FLASH芯片的状态字节,可判断芯片是否busystatic u8 ReadW25Q80StatusRegister(void){u8 temp;W25Q80_Enable();Spi_ReadWriteByte(READ_STATUS_REGISTER);temp = Spi_ReadWriteByte(0xF0);W25Q80_Disable();return temp;}// 读取FLASH的内容,读取的字节数没有限制void ReadW25Q80Operation(u32 addr,u8 *databuf,u32 len){u32 i = 0;u8 temp;temp = ReadW25Q80StatusRegister();while( temp&0x01 ) // 等待FLASH芯片结束BUSY状态{temp = ReadW25Q80StatusRegister();if ( ++i>1000000 ) return;}W25Q80_Enable();Spi_ReadWriteByte(READ_ARRAY);Spi_ReadWriteByte((u8)(addr >>16));Spi_ReadWriteByte((u8)(addr >>8));Spi_ReadWriteByte((u8)addr);for ( i=0; i<len; i++ ){databuf[i] = Spi_ReadWriteByte(0xF0);}W25Q80_Disable();}// 写入FLASH,一次最多写256字节,注意不要越界(不要超过页边界)void WriteW25Q80Operation(u32 addr,u8 *databuf,u16 len){u32 i = 0;u8 temp;temp = ReadW25Q80StatusRegister();while( temp&0x01 ) // 等待FLASH芯片结束BUSY状态{temp = ReadW25Q80StatusRegister();if ( ++i>1000000 ) return;}SetW25Q80WriteEnable(); // 设置芯片写使能W25Q80_Enable();Spi_ReadWriteByte(BYTE_OR_PAGE_PROGRAM);Spi_ReadWriteByte((u8)(addr >>16));Spi_ReadWriteByte((u8)(addr >>8));Spi_ReadWriteByte((u8)addr);for ( i=0; i<len; i++ ){Spi_ReadWriteByte(databuf[i]);}W25Q80_Disable();}// 对FLASH进行SECTOR擦除void EraseW25Q80Operation(u32 addr){u32 i = 0;u8 temp;temp = ReadW25Q80StatusRegister();while( temp&0x01 ) // 等待FLASH芯片结束BUSY状态{temp = ReadW25Q80StatusRegister();if ( ++i>1000000 ) return;}SetW25Q80WriteEnable(); // 设置芯片写使能W25Q80_Enable();Spi_ReadWriteByte(SECTOR_ERASE);Spi_ReadWriteByte((u8)(addr >>16));Spi_ReadWriteByte((u8)(addr >>8));Spi_ReadWriteByte((u8)addr);W25Q80_Disable();}// 读取FLASH芯片的JEDEC ID信息void ReadW25Q80DeviceID(u8 *buf){W25Q80_Enable();Spi_ReadWriteByte(Manufacturer_DeviceID);buf[0] = Spi_ReadWriteByte(0xF0);buf[1] = Spi_ReadWriteByte(0xF0);buf[2] = Spi_ReadWriteByte(0xF0);W25Q80_Disable();}。
STM32驱动SPI接口FLASH
/* SPI_FLASH_CS_LOW(),是一个宏定义,就是拉低 CS(PA4) */
SPI_FLASH_CS_LOW();
/*W25X_DeviceID=0XAB,是 读 器 件 地 址 的 命 令 , 发 送 完 该 命 令 后 连
续发三个任意数字,在发第五个任意数后可以读出地址 */ SPI_FLASH_SendByte(0XAB);
/*指定 NSS 信号由软件管理*/
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
/SPI_BaudRatePrescaler 用来定义波特率预分频的值,这个值用以设置发送
和接收的 SCK 时钟/
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
/* 等待接收完一字节数据 */
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
/* 返回接收到的数据 */
return SPI_I2S_ReceiveData(SPI1); } 现在我们再来看看读器件地址函数: / ************************************************************** ***************** * Function Name : SPI_FLASH_ReadDeviceID(void)
*****************/ u8 SPI_FLASH_SendByte(u8 byte) {
/* 等待 SPI 发送寄存器里的数据发送结束 */
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
spi flash原理
spi flash原理
SPI Flash是一种用于存储程序代码、数据和固件的非易失性
存储设备。
它的工作原理基于SPI(Serial Peripheral Interface)协议,通过使用串行通信接口实现数据传输。
SPI Flash由一个存储阵列和一个控制器组成。
存储阵列由多
个存储单元组成,每个存储单元可以存储一个比特(0或1)。
控制器负责控制数据的读取和写入。
读取数据时,首先需要向控制器发送一个读取指令,指令中包含待读取的数据的地址。
控制器通过串行通信接口将指令发送给存储阵列,并从中读取数据。
读取的数据会通过串行通信接口返回给外部设备。
写入数据时,首先需要向控制器发送一个写入指令,指令中包含待写入的数据的地址和数据内容。
控制器将指令和数据发送给存储阵列,并将数据写入到指定地址中。
为了提高数据读取和写入的速度,SPI Flash通常会采用分页
和扇区的方式进行数据存储。
分页将存储阵列划分为多个页,每页可以存储一定数量的数据。
扇区则将多个页组合在一起,形成一个扇区。
在读取和写入数据时,可以按页或扇区为单位进行操作,提高数据传输的效率。
除了存储程序代码和数据,SPI Flash还具有一些其他的功能。
例如,它可以用于存储引导程序,作为启动设备使用。
同时,SPI Flash还支持坏块管理功能,可以在出现坏块时自动将数
据转移到其他健康的块中,提高存储的可靠性。
总的来说,SPI Flash通过使用SPI协议实现了数据的高速读取和写入,同时具有坏块管理和其他功能,是一种常用的存储设备。
SPI接口的FLASH
SPI接⼝的FLASHSPI flash W25Qxx:W25Q系列的spiflash。
每页(Page)256B,每16个page为⼀个sector(扇区=4KB),每16个扇区为⼀个block(块=64KB)W25Q16=16Mb=2MB=2048KB=32block=512sector=8192page;操作:SPI flash写操作必须确保为0XFF才能写⼊,否则需要檫除操作,檫除的最⼩单位为Sector即4KB,所以有的会在单⽚机内部开⼀个4K的缓存(有点奢侈),写之前先读出来,檫除数据,合并数据(在檫除数据的同时进⾏操作,合并完了在检查檫除是否完成,不闲着;操作系统级的将因此进⼊挂起。
要么设定⼀个合适的超时时间,要么有⼀个专门的轮训这些标志完成则发信号量),再写⼊。
SPI SPI flash驱动规范:1 硬件SPI/软件SPI涉及的MOSI/MISO/SCK的IO设置、SPI设置读写⼀个字节。
2 存储器件IC涉及的⽚选、调⽤SPI读写⼀个字节操作在某个指定地址读写⼀个字节/多个字节,檫除等操作。
3业务层次的读写记录,APP升级等。
⼀主多从可以通过不同⽚选来发送(都⽚选则都会收到),但对接收,如果关闭某个⽚选则可能得不到及时相应;如果都打开则同时来时的处理。
IO模拟SPI⼀主多从如右图,先操作译码器(速度要快)再操作SPI的其它三根⼝线即可。
GPIO模拟的SPI操作灵活,但效率不⾼。
同时这种⽅法不适⽤于SPI的DMA传输,仅适合数据量少、对传输速度要求不同的场合。
硬件SPI的⽚选可以软件控制也能硬件控制(DMA传输时必须)关于IO模拟SPI驱动的另⼀种编程⽅法:SCLK⽤PWM输出⽅波(脉宽周期按⼿册),其它的4线配置SCLK进⾏操作,通过读SCLK引脚GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)来配合时序,不满⾜就等,满⾜就进⾏其它IO的置⾼置低(配置SYSTICK或NOP进⾏延时)关于如何根据时序图⽤IO模拟写驱动/上升沿采样下降沿发送数据的含义,以TM7705为例:上图表⽰对主机MCU⽽⾔:写的时候:MOSI上上升沿采样,上升沿前低电平时就要发送bit数据即:SCLK=0延时⼀⼩段时间就将send_data的MSB发出,然后SCLK=1再延时⼀段时间,接着进⾏下⼀个bit的操作。
SPI-FLASH实验课件
本实验使用到硬件资源如下: (1)D1指示灯 (2)K_UP和K_DOWN按键 (3)串口1 (4)TFTLCD模块 (5)SPI (6)外部FLASH(EN25QXX)
普中STM32开发板带您进入ARM世界
EN25QXX与STM32F1的连接电路
普中STM32开发板带您进入ARM世界
}SPI_InitTypeDef;
普中STM32开发板带您进入ARM世界
SPI_Direction:用于设置 SPI 的通信方向,可设置为双线全双工 (SPI_Direction_2Lines_FullDuplex),双线只接收 (SPI_Direction_2Lines_RxOnly),单线只接收 (SPI_Direction_1Line_Rx)、单线只发送模式 (SPI_Direction_1Line_Tx)。
W25Q128 将 16M 的容量分为 256 个块( Block),每个块大小为 64K 字节,每个块又分为16 个扇区( Sector),每个扇区 4K 个字节 。 W25Q128 的最小擦除单位为一个扇区,也就是每次必须擦除 4K 个字 节。这样我们需要给 W25Q128 开辟一个至少 4K 的缓存区,这样对 SRAM 要求比较高,要求芯片必须有 4K 以上 SRAM 才能很好的操作。
uint16_t SPI_NSS; //设置 NSS 引脚由 SPI 硬件控制还是软件控 制
uint16_t SPI_BaudRatePrescaler;//设置时钟分频因子
uint16_t SPI_FirstBit;t16_t SPI_CRCPolynomial; //设置 CRC 校验的表达式
SPI_I2S_FLAG); 使用较多的是发送完成标志(SPI_I2S_FLAG_TXE)和接收完成标志(
SPI读写串行FLASH
手把手教你学stm32f051系列教程-------------库函数操作版本2.11SPI读写串行FLASHSPI(Serial Peripheral Interface--串行外设接口)总线系统是一种同步串行外设接口,它可以使MCU与各种外围设备以串行方式进行通信以交换信息。
SPI有三个寄存器分别为:控制寄存器SPCR,状态寄存器SPSR,数据寄存器SPDR。
外围设备包括FLASHRAM、网络控制器、LCD显示驱动器、A/D转换器和MCU等。
SPI总线系统可直接与各个厂家生产的多种标准外围器件直接接口,该接口一般使用4条线:串行MOSI I 时钟线(SCLK)、主机输入/从机输出数据线MISO、主机输出/从机输入数据线MOS 和低电平有效的从机选择线SS(有的SPI接口芯片带有中断信号线INT、有的SPI接口芯片没有主机输出/从机输入数据线MOSI)。
本实验通过SPI读写串行FLASH,串行FLASH采样W25X16。
硬件准备:硬件配置入下图所示,在TFT转接板和SD卡共用一个SPI接口:|PF5-CS:W25X16-CS||PB13-SPI2-SCK:W25X16-CLK||PB14-SPI2-MISO:W25X16-DO||PB15-SPI2-MOSI:W25X16-DIO|CS:FLASH片选信号引脚。
SCK:FLASH时钟信号引脚。
MISO:FLASH主入从出引脚。
MOSI:FLASH主出从进引脚。
硬件按照如上方式连接后,下面来配置驱动程序。
软件配置:采用库函数编写驱动,工程目录如下图所示,用户需要编写FALSH驱动函数w25x16.c驱动函数和主函数main.c.下面我们首先来讨论w25x16.c的驱动编写。
首先对FLASH进行初始化,包括初始化几个方面:时钟设置,IO端口复用,SPI参数设置,01.void SPI_FLASH_Init(void)02.{03.04.GPIO_InitTypeDef GPIO_InitStruct;05.SPI_InitTypeDef SPI_InitStruct;06.07.RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOF|RCC_AHBPeriph_GPIOB,ENABLE);//配置gpio时钟08.09.RCC_APB1PeriphClockCmd(FLASH_SPI2,ENABLE);//配置spi时钟10.11.GPIO_InitStruct.GPIO_Pin=FLASH_SCK_PIN;12.GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;13.GPIO_InitStruct.GPIO_Speed=GPIO_Speed_Level_3;14.GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;15.GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;16.GPIO_Init(FLASH_SCK_PORT,&GPIO_InitStruct);//时钟gpio端口模式17.18./*!<Configure SPI pins:MISO*/19.GPIO_InitStruct.GPIO_Pin=FLASH_MISO_PIN;20.GPIO_Init(FLASH_MISO_PORT,&GPIO_InitStruct);21.22./*!<Configure SPI pins:MOSI*/23.GPIO_InitStruct.GPIO_Pin=FLASH_MOSI_PIN;24.GPIO_Init(FLASH_MOSI_PORT,&GPIO_InitStruct);25.26./*Connect PXx to SPI_SCK*/27.GPIO_PinAFConfig(FLASH_SCK_PORT,FLASH_SCK_SOURCE,FLASH_SCK_AF);28.29./*Connect PXx to SPI_MISO*/30.GPIO_PinAFConfig(FLASH_MISO_PORT,FLASH_MISO_SOURCE,FLASH_MISO_AF);31.32./*Connect PXx to SPI_MOSI*/33.GPIO_PinAFConfig(FLASH_MOSI_PORT,FLASH_MOSI_SOURCE,FLASH_MOSI_AF);34.//设置gpio端口的复用35.36.GPIO_InitStruct.GPIO_Pin=FLASH_CS_PIN;37.GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT;38.GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;39.GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;40.GPIO_InitStruct.GPIO_Speed=GPIO_Speed_Level_3;41.GPIO_Init(FLASH_CS_PORT,&GPIO_InitStruct);42.43.SPI_FLASH_CS_HIGH();44.45.SPI_InitStruct.SPI_Direction=SPI_Direction_2Lines_FullDuplex;//配置spi方向46.SPI_InitStruct.SPI_Mode=SPI_Mode_Master;//配置spi模式47.SPI_InitStruct.SPI_DataSize=SPI_DataSize_8b;//配置数据格式48.SPI_InitStruct.SPI_CPOL=SPI_CPOL_High;//配置时钟高电平稳态49.SPI_InitStruct.SPI_CPHA=SPI_CPHA_2Edge;//配置时钟bit位捕获方式50.SPI_InitStruct.SPI_NSS=SPI_NSS_Soft;//设置nss管脚软件管理51.SPI_InitStruct.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_2;//设置spi波特率分频值52.SPI_InitStruct.SPI_FirstBit=SPI_FirstBit_MSB;//指定数据传输从msb位开始53.SPI_InitStruct.SPI_CRCPolynomial=7;//指定用于CRC计算的值54.SPI_Init(SPI2,&SPI_InitStruct);//调入结构体55.SPI_RxFIFOThresholdConfig(SPI2,SPI_RxFIFOThreshold_QF);//设置接收缓冲56.SPI_Cmd(SPI2,ENABLE);/*!<SD_SPI enable*/57.}在stm32f0xx_spi.h文件中设置了spi参数结构体,如下代码所示,初始化的时候直接进行调用:58.typedef struct59.{60.uint16_t SPI_Direction;61.uint16_t SPI_Mode;62.uint16_t SPI_DataSize;63.uint16_t SPI_CPOL;64.uint16_t SPI_CPHA;65.uint16_t SPI_NSS;66.uint16_t SPI_BaudRatePrescaler;67.uint16_t SPI_FirstBit;68.uint16_t SPI_CRCPolynomial;69.}SPI_InitTypeDef;//spi参数结构体初始化后,开始编写读和写W25X16的代码,时序关系我们需要参考w25x16的数据手册:首先通过SPI接口发送字节,同时接收:70.uint8_t SPI_FLASH_SendByte(uint8_t byte)71.{72.while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE)==RESET);//判断是否发送完成73.SPI_SendData8(SPI2,byte);//SPI发送字节74.75./*Wait to receive a byte*/76.while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE)==RESET);//是否已经读取77./*Return the byte read from the SPI bus*/78.return SPI_ReceiveData8(SPI2);//SPI接收79.}w25x166上面的发送命令接收数据是基本操作步骤,下面写读取器件ID代码,参考w25x1代码参考手册中的时序图:80.uint32_t SPI_FLASH_ReadDeviceID(void)81.{82.uint32_t Temp=0;83.84./*Select the FLASH:Chip Select low*/85.SPI_FLASH_CS_LOW();86.87./*Send"RDID"instruction*/88.SPI_FLASH_SendByte(W25X_DeviceID);89.SPI_FLASH_SendByte(Dummy_Byte);90.SPI_FLASH_SendByte(Dummy_Byte);91.SPI_FLASH_SendByte(Dummy_Byte);92.93./*Read a byte from the FLASH*/94.Temp=SPI_FLASH_SendByte(Dummy_Byte);95.96./*Deselect the FLASH:Chip Select high*/97.SPI_FLASH_CS_HIGH();98.99.return Temp;100.}读取制造ID参考时序图:101.uint32_t SPI_FLASH_ReadID(void)102.{103.uint32_t Temp=0,Temp0=0,Temp1=0,Temp2=0; 104.105./*Select the FLASH:Chip Select low*/106.SPI_FLASH_CS_LOW();107.108./*Send"RDID"instruction*/109.SPI_FLASH_SendByte(W25X_JedecDeviceID); 110.111./*Read a byte from the FLASH*/112.Temp0=SPI_FLASH_SendByte(Dummy_Byte); 113.114./*Read a byte from the FLASH*/115.Temp1=SPI_FLASH_SendByte(Dummy_Byte); 116.117./*Read a byte from the FLASH*/118.Temp2=SPI_FLASH_SendByte(Dummy_Byte); 119.120./*Deselect the FLASH:Chip Select high*/121.SPI_FLASH_CS_HIGH();122.123.Temp=(Temp0<<16)|(Temp1<<8)|Temp2; 124.125.return Temp;126.}W25X16页写参考时序图:127.void SPI_FLASH_PageWrite(uint8_t*pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite) 128.{129./*Enable the write access to the FLASH*/130.SPI_FLASH_WriteEnable();131.132./*Select the FLASH:Chip Select low*/133.SPI_FLASH_CS_LOW();134./*Send"Write to Memory"instruction*/135.SPI_FLASH_SendByte(W25X_PageProgram);136./*Send WriteAddr high nibble address byte to write to*/137.SPI_FLASH_SendByte((WriteAddr&0xFF0000)>>16);138./*Send WriteAddr medium nibble address byte to write to*/139.SPI_FLASH_SendByte((WriteAddr&0xFF00)>>8);140./*Send WriteAddr low nibble address byte to write to*/141.SPI_FLASH_SendByte(WriteAddr&0xFF);142.143.if(NumByteToWrite>SPI_FLASH_PerWritePageSize)144.{145.NumByteToWrite=SPI_FLASH_PerWritePageSize;146.//printf("\n\r Err:SPI_FLASH_PageWrite too large!");147.}148.149./*while there is data to be written on the FLASH*/150.while(NumByteToWrite--)151.{152./*Send the current byte*/153.SPI_FLASH_SendByte(*pBuffer);154./*Point on the next byte to be written*/155.pBuffer++;156.}157.158./*Deselect the FLASH:Chip Select high*/159.SPI_FLASH_CS_HIGH();160./*Wait the end of Flash writing*/161.SPI_FLASH_WaitForWriteEnd();162.}W25x16扇区擦除时序图:163.void SPI_FLASH_SectorErase(uint32_t SectorAddr)164.{165./*Send write enable instruction*/166.SPI_FLASH_WriteEnable();167.SPI_FLASH_WaitForWriteEnd();168./*Sector Erase*/169./*Select the FLASH:Chip Select low*/170.SPI_FLASH_CS_LOW();171./*Send Sector Erase instruction*/172.SPI_FLASH_SendByte(W25X_SectorErase);173./*Send SectorAddr high nibble address byte*/174.SPI_FLASH_SendByte((SectorAddr&0xFF0000)>>16); 175./*Send SectorAddr medium nibble address byte*/176.SPI_FLASH_SendByte((SectorAddr&0xFF00)>>8); 177./*Send SectorAddr low nibble address byte*/178.SPI_FLASH_SendByte(SectorAddr&0xFF);179./*Deselect the FLASH:Chip Select high*/180.SPI_FLASH_CS_HIGH();181./*Wait the end of Flash writing*/182.SPI_FLASH_WaitForWriteEnd();183.}W25x16块擦除参考时序图:184.void SPI_FLASH_BulkErase(void)185.{186./*Send write enable instruction*/187.SPI_FLASH_WriteEnable();188.189./*Bulk Erase*/190./*Select the FLASH:Chip Select low*/191.SPI_FLASH_CS_LOW();192./*Send Bulk Erase instruction*/193.SPI_FLASH_SendByte(W25X_ChipErase);194./*Deselect the FLASH:Chip Select high*/195.SPI_FLASH_CS_HIGH();196.197./*Wait the end of Flash writing*/198.SPI_FLASH_WaitForWriteEnd();199.}主函数如下:200./********************(C)COPYRIGHT2011青风电子******************************** 201.*文件名:main.c202.*描述:I2C读写(AT24C02)测试。
spi flash 信号完整性分析
spi flash信号完整性分析信号完整性通常指高速电路设计中由互连线引起的问题。
信号接收端对信号的逻辑电平、时序和相位会有一定的要求,信号在传输过程中,不能出现过大的失真,否则无法有效识别。
在最近的点阵屏调试中,就遇到了此类问题。
点阵屏通讯接口为SPI接口,在对点阵屏传送信号时,点阵屏出现乱码,并且连接线越长,出现乱码的几率越大。
采用示波器捕捉SPI时钟线的波形,黄色线为发送端的时钟波形,绿色线为时钟接收端波形。
正常信号为3.3V 的矩形波,但图中明显出现了严重的信号过冲问题。
其中发送端略好,过冲幅度大致为0.5V到0.9V,接收端过冲进一步加大,幅度扩大到1.5V到2.0V。
大幅度的震荡,造成了时序和数据的错配,进而造成点阵屏乱码。
是什么造成了信号的传输失真呢?信号在沿着传输线传播时,其路径上的每一步都有相应的瞬态阻抗。
当遇到瞬态阻抗发生突变,信号会在此处形成反射,引起信号电平下冲、过冲或振铃。
如果传输路径中,有多个阻抗突变点,信号就会形成多次反射,反射信号叠加在原有信号上,加剧信号的上冲或下冲。
知道了问题所在和发生机理,问题就好处理了。
首先是尝试将SPI的传输速度由6MHz降低到1MHz,但乱码现象没有得到任何改善。
其次,在信号接收端,对地增加330pF滤波电容,振荡幅度明显降低,但信号沿坡度变缓。
随着加大电容值,振荡幅度没有明显的进一步降低,而边沿坡度迅速变缓,且在边沿中间部位出现尖刺,通过增加330pF滤波电容的方式,点阵屏没有再出现乱码。
第三,尝试在发送端接1K上拉电阻,提高信号驱动能力。
查看波形,发送端的信号过冲和下冲现象完全滤除。
但在点阵屏一端,时钟线仍有很大的过冲和下冲现象。
最后,在接收端对地接100Q电阻,查看波形,接收端信号过冲和下冲现象基本上消除,信号幅度会略有降低,大致为3.1V。
随着电阻阻值越小,过冲和下冲现象的滤除效果越好,但信号幅度降得越低。
信号的过冲、下冲和振荡,归根结底是信号通路阻抗不连续造成的,做好阻抗匹配才是最根本的解决办法。
SPI NOR FLASH存储器的原理与常见问题分析
SPI NOR FLASH存储器的原理与常见问题分析1.前言FLASH闪存,一般简称为“FLASH”,它属于内存器件的一种,是一种非易失性(Non-Volatile)内存。
FLASH因其特殊的浮栅结构得以在掉电后长久地保存数据,这使得Flash成为各类便携型数字设备的存储介质。
本文主要介绍了SPI NOR FLASH存储器的基本原理以及常见的问题,可以帮助读者进一步了解和应对产品中的FLASH相关问题。
2.SPI NOR FLASH存储器的原理介绍1.FLASH的基础介绍FLASH是使用浮栅场效应管(Floating Gate FET)作为基本存储单元来存储数据的,图一(a)的模型中可以看出,与普通的MOSFET相比,区别仅在于浮栅,FLASH就是利用浮栅中是否存储电荷来表征数字0和1的。
对NPN的场效应管来说,在栅极和源极之间加一个VTH电压后,MOS管就可以导通,但如果在图示的浮栅中增加了一些电子,这些电子抵消了VTH的部分电压,原先的VTH可能就无法使MOS管导通,通过判断MOS管是否导通可以判断浮栅当中有无电子,即可以对应状态0和1。
图一、FLASH基础单元原理而FLASH就是由如上的存储单元组成,通常的FLASH可以按单元结构分为NOR和NAND FLASH,其主要区别在于单独存储单元的排列上,如图二所示,NOR FLASH的每个CELL之间是并联的关系,其中漏极一同连接到位线(Bit line)上,栅极接到字线(Word line)上,而NAND FLASH的每个CELL之间是串联的关系,其中源极和漏极CELL之间互连,栅极接到字线上。
这部分是FLASH存储单元的结构区分。
图二、FLASH单元结构区分如果要对FLASH内部的数据进行操作,还需要控制器去控制擦除、编程、读取的电压,根据控制器与外部通信的总线,可以分为Parallel(CFI)和SPI两种类型。
并口的FLASH数据位宽大,可以满足大量数据快速读取的需求,但管脚多也反映着其占用面积大;SPI FLASH使用SPI总线通信,只需要4根线即可通信,较为便捷,适用于一些小型化的设备中。
25X系列SPI FLASH芯片编程操作
一、 恒通2009智通型编程器2008年BIOS之家全新打造恒通2009智通型编程器恒通2009智通型编程器是。
采用双核mcu处理方式,已经更换为2毫米厚度PCB,双层设计,PCB背面带有绝缘背板保护,并采用环形磁环电感和高速齐纳二极管改进供电模块,新版烧写更加稳定可靠。
最新软件发布0.98D9,全面支持8脚 SPI flash BIOS 芯片支持芯片超过1500种,包括EPROM , EEPROM , FLASH , PIC , AVR , MCS-51 , MCS-48, 27Cxx , 28Cxx 28Fxx , 29Fxx , AT29Cxxx , 24Cxx , 93Cxx , PIC16xxx , DS12xx , AT89Cxx , AT89Cx051 , AT25xxx , AT90Sxxx , EPROM16bit , 29Fx00 , 28Fx00。
适用于升级维修电脑主板BIOS、手机、VCD、DVD、彩电、复印机,传真机,打印机等;可修改VCD/DVD/彩电开机画面;可用于汽车存储器代码读写;可用于开发MCS-51系列,AVR 系列,PIC系列单片机。
内置PLCC32和HUB/LPC适配器(支持29/39/49LVxxx,低电压3.3V),支持高速编程,编程速度比PCB3,PCB3B+ 提高50%,比PCB3.5,PCB4C 提高20%。
能够解锁AM29F040B。
并能通过板上跳线切换PCB3B<->PCB4.5C,从而能兼容所有老版本软件。
2.工作环境* 本编程器与PC机并口进行通讯,通过配套软件对各种芯片进行读写等操作* 5M硬盘空间* Win9X、WinNT、Win2000、WinXP操作系统二、硬件结构及安装方法一、硬件安装注意:计算机的并口要在BIOS中设置为ECP或ECP+EPP。
若不能联机,请每种设置下都试试!恒通2009的硬件分布图:各接口功能综述:1、编程电压调整跳线,用来设置27系列芯片的编程电压。
spi flash 原理
spi flash 原理SPI(Serial Peripheral Interface)Flash是一种基于SPI总线通信协议的存储器芯片。
它通常作为嵌入式设备中的非易失性存储器使用,可以存储设备的固件、配置信息以及其他需要持久保存的数据。
SPI Flash的主要工作原理如下:1. SPI总线通信:SPI Flash通过SPI总线与主控设备进行通信。
SPI总线由4个信号线组成,包括主设备的主线(Master Out Slave In,MOSI)、主线(Master In Slave Out,MISO)、时钟线(Clock,SCLK)和片选线(Chip Select,CS)。
2. 命令传输:主控设备通过SPI总线向SPI Flash发送命令,以读取、写入或擦除存储芯片中的数据。
常见的命令包括读取数据、写入数据、读取设备ID等。
3. 内部结构:SPI Flash的内部结构通常由多个扇区(Sector)组成,每个扇区又由多个页(Page)组成。
每页的大小通常是256字节或512字节。
数据可以按扇区或页进行读写操作。
4. 读取数据:当主控设备发送读取命令后,SPI Flash会将请求的数据从存储区域读取出来,并通过MISO线传输给主控设备。
5. 写入数据:主控设备发送写入命令后,SPI Flash会将要写入的数据存储到指定的存储区域中。
通常先擦除要写入的区域,然后按页进行写入操作。
6. 擦除数据:SPI Flash可以按扇区或整个芯片进行擦除操作。
擦除操作会将擦除区域的数据全部置为1,恢复成初始状态。
SPI Flash具有易于集成、低功耗和高速的特点,广泛应用于嵌入式系统、通信设备、工业控制等领域。
基于STM32F0的SPI通信的FLASH程序分析
基于STM32F0的SPI通信的FLASH程序分析Ⅰ、概述关于SPI(Serial Peripheral Interface)串行外设接口可以说是单片机或者嵌入式软件开发人员必须掌握的一项通信方式,就是你在面试相关工作的时候都可能会问及这个问题。
在这里问一个简单的问题:硬件SPI和软件模拟SPI的区别是有哪些?估计这个问题会问倒很多人。
SPI通信中分为SPI主机和从机,在实际应用中作为主机是比较常见的一种,因为SPI的通信速度远比I2C的通信速度大,所以现在市面上有很多SPI从设备。
本文SPI读写操作,以SPI通信的FLASH(25Q16)为从设备进行举例。
串口发送10字节数据,接收满10字节自动保存,间隔500ms读写数据,通过串口打印出来。
Ⅱ、下载文章提供的“软件工程”都是在硬件板子上进行多次测试、并保证没问题才上传至360云盘,请放心下载测试,如有问题请检查一下你的板子是否有问题。
ST标准外设库和参考手册、数据手册等都可以在ST官网下载,你也可以到我的360云盘下载。
关于F0系列芯片的参考手册有多个版本(针对F0不同芯片),但有一个通用版本,就是“STM32F0x128参考手册V8(英文)2015-07”建议参考该手册,以后如果你换用一种型号芯片也方便了解。
Ⅲ、准备工作建议准备F0的参考手册和数据手册,方便查阅相关知识,没有的请到ST官网或到我360云盘下载。
今天总结的软件工程是基于“TIM基本延时配置详细过程”修改而来,因此需要将该软件工程下载准备好。
我每次都是提供整理好的软件工程供大家下载,但是,如果你是一位学习者,建议自己亲手一步一步操作:打开工程->新建文件(spi.c spi.h) ->添加到工程中->添加源代码。
Ⅳ、SPI原理。
浅析spi flash驱动及其程序
浅析spi flash驱动及其程序SPI Flash 首先它是个Flash,Flash是什么东西就不多说了(非易失性存储介质),分为NOR和NAND两种(NOR和NAND的区别本篇不做介绍)。
SPI一种通信接口。
那么严格的来说SPI Flash是一种使用SPI通信的Flash,即,可能指NOR也可能是NAND。
但现在大部分情况默认下人们说的SPI Flash指的是SPI NorFlash。
早期Norflash 的接口是parallel的形式,即把数据线和地址线并排与IC的管脚连接。
但是后来发现不同容量的Norflash不能硬件上兼容(数据线和地址线的数量不一样),并且封装比较大,占用了较大的PCB板位置,所以后来逐渐被SPI(串行接口)Norflash所取代。
同时不同容量的SPI Norflash管脚也兼容封装也更小。
,至于现在很多人说起NOR flash直接都以SPI flash来代称。
NorFlash根据数据传输的位数可以分为并行(Parallel,即地址线和数据线直接和处理器相连)NorFlash和串行(SPI,即通过SPI接口和处理器相连)NorFlash;区别主要就是:1、SPI NorFlash每次传输一bit位的数据,parallel连接的NorFlash每次传输多个bit位的数据(有x8和x16bit两种);2、SPI NorFlash比parallel便宜,接口简单点,但速度慢。
NandFlash是地址数据线复用的方式,接口标准统一(x8bit和x16bit),所以不同容量再兼容性上基本没什么问题。
但是目前对产品的需求越来越小型化以及成本要求也越来越高,所以SPI NandFlash渐渐成为主流,并且采用SPI NANDFlash方案,主控也可以不需要传统NAND控制器,只需要有SPI接口接口操作访问,从而降低成本。
另外SPI NandFlash封装比传统的封装也小很多,故节省了PCB板的空间。
MCU的GPIO模拟SPI源代码
MCU的GPIO模拟SPI源代码写程序:void SPIx_WriteByte(u8 TxData){u8 j=0;SPI_FLASH_CLK_LOW(); //clk=0if(TxData&0x80){SPI_FLASH_DI_HIGH();} //mosi=1else{SPI_FLASH_DI_LOW();} //mosi=0for(j=0;j<3;j++); //延时SPI_FLASH_CLK_HIGH(); //clk=1,一个上升沿写入一位for(j=0;j<5;j++); //延时SPI_FLASH_CLK_LOW(); //clk=0if(TxData & 0x40){SPI_FLASH_DI_HIGH();} //mosi=1else{SPI_FLASH_DI_LOW();} //mosi=0for(j=0;j<3;j++); //延时SPI_FLASH_CLK_HIGH();for(j=0;j<5;j++);SPI_FLASH_CLK_LOW();if(TxData&0x20){SPI_FLASH_DI_HIGH();} //mosi=1 else{SPI_FLASH_DI_LOW();} //mosi=0 for(j=0;j<3;j++); //延时SPI_FLASH_CLK_HIGH();for(j=0;j<5;j++);SPI_FLASH_CLK_LOW();if(TxData&0x10){SPI_FLASH_DI_HIGH();} //mosi=1 else{SPI_FLASH_DI_LOW();} //mosi=0 for(j=0;j<3;j++); //延时SPI_FLASH_CLK_HIGH();for(j=0;j<5;j++);SPI_FLASH_CLK_LOW();if(TxData&0x08){SPI_FLASH_DI_HIGH();} //mosi=1 else{SPI_FLASH_DI_LOW();} //mosi=0 for(j=0;j<3;j++); //延时SPI_FLASH_CLK_HIGH();for(j=0;j<5;j++);SPI_FLASH_CLK_LOW();if(TxData&0x04){SPI_FLASH_DI_HIGH();} //mosi=1 else{SPI_FLASH_DI_LOW();} //mosi=0 for(j=0;j<3;j++); //延时SPI_FLASH_CLK_HIGH();for(j=0;j<5;j++);SPI_FLASH_CLK_LOW();if(TxData&0x02){SPI_FLASH_DI_HIGH();} //mosi=1 else{SPI_FLASH_DI_LOW();} //mosi=0 for(j=0;j<3;j++); //延时SPI_FLASH_CLK_HIGH();for(j=0;j<5;j++);SPI_FLASH_CLK_LOW(); //clk=0if(TxData&0x01){SPI_FLASH_DI_HIGH();}else{SPI_FLASH_DI_LOW();}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_HIGH(); //clk=1for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW(); //clk=0 }读程序0x80==0x80u8 SPIx_ReadByte(void){u8 i=0,j=0;for(j=0;j<3;j++); //延时SPI_FLASH_CLK_HIGH(); //clk=1if(GPIOC->IDR&0x80==0x80){i=i+0x80;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW(); //clk=0,下降沿读数for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x80==0x80){i=i+0x40;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x80==0x80){i=i+0x20;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x80==0x80){i=i+0x10;}for(j=0;j<3;j++); //延时for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x80==0x80) {i=i+0x08;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x80==0x80) {i=i+0x04;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x80==0x80) {i=i+0x02;}for(j=0;j<3;j++); //延时for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x80==0x80){i=i+0x01;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();return i;}读程序0x40==0x40u8 SPIx_ReadByte(void){u8 i=0,j=0;for(j=0;j<3;j++); //延时SPI_FLASH_CLK_HIGH(); //clk=1if(GPIOC->IDR&0x40==0x40){i=i+0x80;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW(); //clk=0,下降沿读数for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x40==0x40) {i=i+0x40;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x40==0x40) {i=i+0x20;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x40==0x40) {i=i+0x10;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x40==0x40) {i=i+0x08;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x40==0x40) {i=i+0x04;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x40==0x40) {i=i+0x02;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x40==0x40){i=i+0x01;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();return i;}读程序0x20==0x20u8 SPIx_ReadByte(void){u8 i=0,j=0;for(j=0;j<3;j++); //延时SPI_FLASH_CLK_HIGH(); //clk=1if(GPIOC->IDR&0x20==0x20){i=i+0x80;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW(); //clk=0,下降沿读数for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();{i=i+0x40;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x20==0x20) {i=i+0x20;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x20==0x20) {i=i+0x10;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();{i=i+0x08;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x20==0x20) {i=i+0x04;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x20==0x20) {i=i+0x02;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x20==0x20){i=i+0x01;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();return i;}读程序0x10==0x10读程序0x08==0x08读程序0x04==0x04读程序0x02==0x02u8 SPIx_ReadByte(void){u8 i=0,j=0;for(j=0;j<3;j++); //延时SPI_FLASH_CLK_HIGH(); //clk=1if(GPIOC->IDR&0x02==0x02)for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW(); //clk=0,下降沿读数for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x02==0x02){i=i+0x40;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x02==0x02){i=i+0x20;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x02==0x02)for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x02==0x02) {i=i+0x08;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x02==0x02) {i=i+0x04;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x02==0x02)for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x02==0x02){i=i+0x01;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();return i;}读程序0x01==0x01u8 SPIx_ReadByte(void){u8 i=0,j=0;for(j=0;j<3;j++); //延时SPI_FLASH_CLK_HIGH(); //clk=1if(GPIOC->IDR&0x01==0x01){i=i+0x80;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW(); //clk=0,下降沿读数for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x01==0x01){i=i+0x40;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x01==0x01){i=i+0x20;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x01==0x01){i=i+0x10;}for(j=0;j<3;j++); //延时for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x01==0x01) {i=i+0x08;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x01==0x01) {i=i+0x04;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x01==0x01) {i=i+0x02;}for(j=0;j<3;j++); //延时for(j=0;j<5;j++);SPI_FLASH_CLK_HIGH();if(GPIOC->IDR&0x01==0x01) {i=i+0x01;}for(j=0;j<3;j++); //延时SPI_FLASH_CLK_LOW();return i;}。
Xilinx FPGA SPI-Flash Bootloader & Program
Xilinx FPGA SPI-FlashBootloader & Program整理:朱浩 2014.03.03Xilinx ISE Design Suite 13.2一、 MicroBlaze_SPI_BootloaderBootloader 的作用:由于FPGA 内部的block ram 空间容量有限,无法直接运行大尺寸的用户应用程序代码。
这可通过先在FPGA 内部运行一个小的bootloader 程序,再由此程序读取并转移flash 中srec 格式的数据到外部DDR RAM 中运行,这样可以运行容量比较大的代码。
1. SDK 软件上Project 代码运行代码运行区域区域区域设设置1.1. 右击Project 并选择Generate Linker Script.1.2. In the Basic tab, Use the drop-down list to select the DDR3 memorySelect MCB_DDR3_S0_AXI_BASEADDR, for all the code sections. Click Generate then Yes to overwrite the existing linker script.2.Creating a SREC Flash Image2.1. 右击Project并选择C/C++ Build Settings,选择Build Steps内容如下::2.2. 修改Post-Build Steps的command内容如下mb-objcopy -O srec uf911c.elf uf911c.srec前面是编译产生的elf文件,后面是要转成的srec文件名字,srec文件在Bootloader时需要用到,这两个文件都在..\workspace\uf911c\Debug文件夹下。
每次对Project编译时除生成elf文件外,还将生成新的srec文件。
atlys开发板之SPI FLASH实验
ATLYS开发板之SPI flash实验通过本篇,您可以了解到如何在MicroBlaze系统中实现对SPI FLASH的擦除和读写及校验的方法。
一、简介本开发板上使用了ST公司的8Mbit SPI串行接口的FLASH,芯号为N25Q128。
SPI的接口速率最大可以达到108Mhz。
FLASH的容量由256个Sector组成,每个Sector有256个Page,每个Page有256个byte。
所以总共为16777216个byte。
N25Q128的擦除方法有两种,一种为Bulk(128Mbit)擦除,一种为Sector(512Kbit)擦除。
N25Q128的编程方法为Page编程,一次可以写入256字节。
FPGA通过命令的方式对N25Q128进行操作,不管是读,编程,擦除或其它操作首先在第一个字节要对N25Q128写入命令号。
根据命令格式的不同,有些命令后面不跟地址和数据,有些命令后面需要输出地址或数据,有些命令命令后面既需要地址又需要数据。
以下是N25Q128所支持的命令具体细节信息,请查看DATASHEET。
二、SPI FLASH硬件设计1.电路设计FPGA和N25Q128的硬件连接非常简单,只有四跟线 SPI FLASH的片选信号CS, SPI 的时钟信号 SCK , FLASH FLASH数据写入信号 SDI和数据读出信号 SDO。
步骤一:打开XPS的BSB向导,选择工程要存放的位置和PLB总线类型,以及指定板级支持包的路径,点击OK。
步骤二:一直点击下一步,默认设置就可以直到出现选择microblaze的Local Memory为最大的64kb步骤三:继续点击下一步出现让你选择处理器外围设备,选择如下步骤四:继续点击next直到完成BSB向导。
设置参数如下:参数代表的含义:Include both Receiver and Transmitter FIFOs这是代表是否SPI接口包含接收FIFO 寄存器,这里选择包含TRUERatio of PLB Clock Frequency To SCK Frequency代表SPI接口和SPI FLASH的时钟sck周期是PLB时钟的几倍,这里选择4倍。
采用SPI Flash存储中文字符库
采用SPI Flash存储中文字符库在嵌入式系统中,有时候需要中文字符来表示我们的某些信息,但是中文字符库本身占据空间比较大,因此有时候仅仅对系统中需要的字符进行编码,其它的则省掉,但是这样对于编程调用字符时是比较麻烦的,只能一个一个进行调用然户显示。
然而,有时候在比较大的系统中需要很多的中文字符,如果还是对需要的进行一个个编码将显得非常费时,此时有必要采用一个字库来完成我们的工作。
在嵌入式系统中,用得比较多的是GBK2312B编码的字库(还有一个是Unicode编码),编码后得到的是一个字符数组,每一个中文字符对应多个字节(具体字节数看取模的大小),需要显示某个字符只需取得该字符的GBK内码,然后找到该字符对应数组中的地址,最后将这个字符对应的所有字节按照预定的格式写入液晶屏即可。
这样操作带来的简便就是,你想显示某个字符只需以字符串的格式输入该字符然后调用显示函数就行了。
这时有个问题出现了,7千多个字符编码后得占用多大空间啊?大概有200KB,但是对于现在的MCU,本身自带的rom就很宝贵,另外MCU的ROM越大其成本就越高。
所以,如果将200kb的字库写入MCU将不太划算。
不将字库存入MCU,就得存入另外一种介质中,这种介质可能是SD卡,SPI Flash。
对于SD卡我没有试过,虽然容量大,但据说读取速度比较慢,另外封装较大,占板子面积,感觉适用与大的系统吧,比如MP3;而SPI flash, 体积小,容量也还可以,我所了解的也有8M的,可能还有更大容量的。
好了,废话了这么多,那么本文接下来就绍如何用SPI flash 做中文字库:第一步,当然需要你将你所用的SPIflasn的初始化以及读写函数写好(我使用的W25X16,2M,传输速率最大74MHZ,很快的;板子主芯片STM32F103RBT6)。
写函数:void W25X_Write_Bytes(uint32_t addr,u8* pBuffer, u16 nBytes) 注:W25X16写时,需要先擦除。
SPIFLASH学习笔记(三)擦除操作
SPIFLASH学习笔记(三)擦除操作
Block Erase (D8H)
BLOCK ERASE(D8H)命令⽤于在块级别擦除。
每块有64页,每页2176字节(2048 + 128字节)。
每个块为136 KB。
BLOCK ERASE 命令(D8H)在
⼀次⼀个块。
BLOCK ERASE操作的命令序列如下:
•06H(WRITE ENBALE命令)
•D8H(块擦除命令)
•0FH(GET FEATURES命令读取状态寄存器)
在执⾏块擦除操作之前,必须发出写使能(06H)命令。
与任何更改存储器内容的命令,必须执⾏WRITE ENABLE命令才能设置WEL⼀点。
如果未发出WRITE ENABLE命令,则其余的擦除序列将被忽略。
写使能命令后必须跟⼀个块擦除(D8H)命令。
此命令需要⼀个24位地址。
后排地址被注册后,控制逻辑将⾃动控制时序和擦除验证操作。
设备正忙于块擦除操作期间的时间。
GET FEATURES(0FH)命令可⽤于监视状态操作。
当进⾏块擦除操作时,⽤户可以发出从缓存命令中正常读取的命令(03H / 0BH / 3BH / 6BH / BBH / EBH)读取缓存中的数据。
软复位操作
RESET(FFH)命令停⽌所有操作。
例如,在进⾏编程或擦除或读取操作时,复位命令可以使设备进⼊等待状态。
在缓存程序或缓存读取期间,重置还可以停⽌先前的操作和挂起的操作。
OIP发送复位命令后,可以从300ns读取状态。
详细讲解重用外设驱动代码_SPI_NOR_Flash存储器
详细讲解重用外设驱动代码_SPI_NOR_Flash存储器第六章为重用外设驱动代码,本文内容为6.2 SPI NOR Flash 存储器。
6.2 SPI NOR Flash 存储器SPI NOR Flash 是一种SPI 接口的非易失闪存芯片,本节以台湾旺宏电子的MX25L1606为例详细介绍在AMetal 中如何使用类似的Flash 存储器。
>>>6.2.1 基本功能MX25L1606 总容量为16M(16×1024×1024)bits,即2M字节。
每个字节对应一个存储地址,因此其存储数据的地址范围为0x000000 ~ 0x1FFFFF。
在MX25L1606 中,存储器有块(block)、扇区(sector)和页(page)的概念。
页大小为256 字节,每个扇区包含16页,扇区大小为4K(4096)字节,每个块包含16 个扇区,块的大小为64K(65536)字节,其组织结构示意图详见表6.5。
表6.5 MX25L1606 存储器组织结构MX25L1606 的通信接口为标准4 线SPI 接口(支持模式0 和模式3),即CS、MOSI、MISO、CLK,详见图6.3。
其中,CS(#1)、SO(#2)、SI(#5)、SCLK(#6)分别为SPI 的CS、MISO、MOSI 和CLK 信号引脚。
特别地,WP(#3)用于写保护,HOLD(#7)用于暂停数据传输。
一般来说,这两个引脚不会使用,可通过上拉电阻上拉至高电平。
MicroPort-NorFlash 模块通过MicroPort 接口与AM824-Core 相连。
图6.3 SPI Flash 电路原理图>>>6.2.2 初始化AMetal 提供了支持常见的MX25L8006、MX25L1606……等系列SPI Flash 器件的驱动函数,使用其它各功能函数前必须先完成初始化,其函数原型(am_mx25xx.h)为:该函数意在获取器件的实例句柄mx25xx_handle。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
SPI_flash代码分析以下是主函数int main(void){Xuint8 send_data[16], recv_data[16];Xuint8 error, SF_sr;Xuint16 sector_select, page_select;Xuint32 i, j;xil_printf("Serial Flash Test\r\n");/* 初始化 FLASH_SPI控制器 *///1、初始化SPI//2、设这控制寄存器CR为主MASTER transaction inhibit disable,人工选择从设备以及设置SPI为master//3、初始化SSR(从设备选择寄存器)为不选择任何一个从设备。
Initialize_Spi_Controller(XPAR_SPI_FLASH_BASEADDR);/* 使能SPI控制器 */// Description : 设置SPICR寄存器的SPI System Enable位//1、设置SPE=1,SPI SYSTEM ENABLEXSpi_Set_Enable(XPAR_SPI_FLASH_BASEADDR);/* 设置FLASH的WRSR寄存器,设置成功说明FLASH控制已经OK */do{//设置FLASH以使FLASH任何一部分都受保护protectedSF_write_status_register (XPAR_SPI_FLASH_BASEADDR, 0x7c);SF_sr = SF_read_status_register(XPAR_SPI_FLASH_BASEADDR);} while(SF_sr != 0x7C);/* 设置FLASH的WRSR寄存器,使能All sector可写 */do{//设置FLASH以使FLASH任何一部分都不受保护protectedSF_write_status_register (XPAR_SPI_FLASH_BASEADDR, 0x00);SF_sr = SF_read_status_register(XPAR_SPI_FLASH_BASEADDR);} while(SF_sr != 0x00);/*整片擦除 */xil_printf("\r\nChip Erase Starting\r\n");SF_bulk_erase(XPAR_SPI_FLASH_BASEADDR);xil_printf("Chip Erase Complete - verifying\r\n");/*整片校验看是不是全0XFF*/SF_start_read(XPAR_SPI_FLASH_BASEADDR, 0x00, 0x00, 0x00,SCK_FASTER_THAN_20MHz);error = 0;for (i = 0; i < SF_BYTES/16; i++){/*每次接收16个字节校验*/spi_transfer(XPAR_SPI_FLASH_BASEADDR,send_data, recv_data, 16);for (j = 0; j < 16; j++){if(recv_data[j] != 0xFF){xil_printf("Error at i = %x, j = %x\r\n", i,j);j = 16;i = SF_BYTES;error = 1;}}}if(!error)xil_printf("Erase verified\r\n");SF_end_read (XPAR_SPI_FLASH_BASEADDR);/*SPI FLASH page编程*/xil_printf("\r\nData being written\r\n");for(sector_select = 0; sector_select < SF_SECTORS; sector_select++) for(page_select = 0; page_select < SF_PAGES_PER_SECTOR; page_select++) {/*发送 page编程命令 */SF_start_page_program (XPAR_SPI_FLASH_BASEADDR, sector_select,page_select, 0x00);for (i = 0; i < SF_BYTES_PER_PAGE; i+=16){for(j = 0; j < 16; j++)send_data[j] = i + j;/*每次发送16个字节 */spi_transfer(XPAR_SPI_FLASH_BASEADDR,send_data, recv_data, 16);}SF_end_page_program (XPAR_SPI_FLASH_BASEADDR);}xil_printf("Test Data Written; reading back\r\n", i);/*SPI FLASH 读取数据进行验证*/SF_start_read (XPAR_SPI_FLASH_BASEADDR, 0x00, 0x00, 0x00,SCK_FASTER_THAN_20MHz);error = 0;for (i = 0; i < SF_BYTES; i+=16){/*每次读取16个字节进行验证 */spi_transfer(XPAR_SPI_FLASH_BASEADDR,send_data, recv_data, 16);for(j = 0; j < 16; j++){if(recv_data[j] != ((i + j) & 0xFF)){xil_printf("Error at i = %x, j = %x\r\n", i,j);xil_printf("Data read was %x\r\n", recv_data[j]);xil_printf("Exp. data was %x\r\n", (i+j));j = 16;i = SF_BYTES;error = 1;}}}if(!error)xil_printf("Flash Test PASSED!\r\n");elsexil_printf("Flash test failed!\r\n");SF_end_read (XPAR_SPI_FLASH_BASEADDR);return 0;}接下来我们一句一句话分析主函数main()1、Initialize_Spi_Controller(XPAR_SPI_FLASH_BASEADDR);以下是这个函数的定义#define Initialize_Spi_Controller(BaseAddress) \{ \XSpi_WriteReg(BaseAddress, XSP_SRR_OFFSET,XSP_SRR_RESET_MASK); \XSpi_WriteReg(BaseAddress, XSP_CR_OFFSET, INIT_CREG); \XSpi_WriteReg(BaseAddress, XSP_SSR_OFFSET, SPI_NONE_SELECT); \}这三句话分别代表的含义是:XSpi_WriteReg(BaseAddress, XSP_SRR_OFFSET,XSP_SRR_RESET_MASK);代表初始化FPGA内部SPI接口的reset register,即重置FPGA内部SPI接口。
以下是关于寄存器SRR的描述。
通过文档《xps_spi.pdf》有关SRR的描述,只能向SRR中写入0x0000000A.XSpi_WriteReg(BaseAddress, XSP_CR_OFFSET, INIT_CREG);代表初始化FPGA内部的SPI接口中的控制寄存器control register,以下是关于CR控制寄存器的描述写入的值为#define INIT_CREG (XSP_CR_TRANS_INHIBIT_MASK | XSP_CR_MANUAL_SS_MASK | XSP_CR_MASTER_MODE_MASK)代表禁止FPGA内部的SPI接口传输数据,人工选择从设备,FPGA 内部的SPI接口为主设备masterXSpi_WriteReg(BaseAddress, XSP_SSR_OFFSET, SPI_NONE_SELECT);以下是SSR寄存器的描述。
:初始化FPGA内部的SPI接口中的slave select register,写入的值为不选择任何一个从设备。
2、XSpi_Set_Enable(XPAR_SPI_FLASH_BASEADDR);以下是该函数的定义#define XSpi_Set_Enable(BaseAddress) \{ \Xuint16 Control; \Control = XSpi_ReadReg(BaseAddress, XSP_CR_OFFSET); \Control |= XSP_CR_ENABLE_MASK; \XSpi_WriteReg(BaseAddress, XSP_CR_OFFSET, Control); \}该函数代表重新初始化Control register,以使能FPGA内部的SPI接口可用即将控制寄存器CR中的SPE位置1。
3、do{//设置FLASH以使FLASH任何一部分都受保护protectedSF_write_status_register (XPAR_SPI_FLASH_BASEADDR, 0x7c);SF_sr = SF_read_status_register(XPAR_SPI_FLASH_BASEADDR);} while(SF_sr != 0x7C);首先分析SF_write_status_register (XPAR_SPI_FLASH_BASEADDR, 0x7c);该函数的定义为:void SF_write_status_register (Xuint32 BaseAddress, Xuint8 data){Xuint8 op_code[2], bogus_data[2];// 设置SPI Flash 的写使能SF_write_enable(BaseAddress);//选中第一个设备使能SPI_FLASH_CS_LOW();// 写SPI FLASH的状态寄存器op_code[0] = WRSR;op_code[1] = data;spi_transfer(BaseAddress, op_code, bogus_data, 2);//关闭选中设备以使任何一个设备都没有选中SPI_FLASH_CS_HIGH();// 等待写寄存器/编程/擦除命令操作结束poll_until_complete(BaseAddress);// 设置SPI Flash 的写不使能SF_write_disable(BaseAddress);}这个函数的功能主要是要将data的值写入到STATUS REGISTER中去。