0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

浅析FLASH读写----SPI原理及应用

ss 作者:工程师谭军 2018-10-07 11:32 次阅读
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板的空间。
怎么用说白了对于Flash就是读写擦,也就是实现flash的驱动。先简单了解下spi flash的物理连接。
之前介绍SPI的时候说过,SPI接口目前的使用是多种方式(具体指的是物理连线有几种方式),Dual SPI、Qual SPI和标准的SPI接口(这种方式肯定不会出现在连接外设是SPI Flash上,这玩意没必要全双工),对于SPI Flash来说,主要就是Dual和Qual这两种方式。具体项目具体看了,理论上在CLK一定的情况下, 线数越多访问速度也越快。我们项目采用的Dual SPI方式,即两线。
浅析FLASH读写----SPI原理及应用

应用环境如下: 控制器 STM32F103

FLASH M25P64

读写方式 SPI

编程环境 MDK

以SPI方式读写FLASH的基本流程如下:

(1)设置SPI的工作模式。

(2)flash初始化。

(3)SPI写一个字节、写使能函数、写数据函数,读数据函数等编写。

(4)主函数编写。

一 设置SPI工作模式。

宏定义

#define SPI_FLASH_CS_LOW() GPIO_ResetBits(GPIOA,GPIO_Pin_4)

#define SPI_FLASH_CS_HIGH() GPIO_SetBits(GPIOA,GPIO_Pin_4)

/* M25P64 SPI Flash supported commands */

#define WRSR 0x01 /* Write Status Register instruction */

#define WREN 0x06 /* Write enable instruction */

#define WRDI 0x04 /* Write disable instruction */

#define READ 0x03 /* Read from Memory instruction */

#define RDSR 0x05 /* Read Status Register instruction */

#define RDID 0x9F /* Read identification */

#define FAST_READ 0x0B /* Fast read Status Register instruction */

#define SE 0xD8 /* Sector Erase instruction */

#define BE 0xC7 /* Bulk Erase instruction */

#define PP 0x02 /* Page prigrame instruction */

#define RES 0xAB /* Sector Erase instruction */

#define WIP_FLAG 0x01 /* Write In Progress (WIP) flag */

#define DUMMY_BYTE 0xA5

#define SIZE sizeof(TEXT_Buffer)

#define SPI_FLASH_PAGESIZE 0x100

#define FLASH_WriteAddress 0x000000

#define FLASH_ReadAddress FLASH_WriteAddress

#define FLASH_SectorToErase FLASH_WriteAddress

#define M25P64_FLASH_ID 0x202017

#define countof(a) (sizeof(a) / sizeof(*(a)))

#define BufferSize (countof(Tx_Buffer)-1)

SPI初始化

void Init_SPI1(void)

{

SPI_InitTypeDef SPI_InitStructure;

GPIO_InitTypeDef GPIO_InitStructure;

/* Enable SPI and GPIO clocks */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA , ENABLE);

/* Configure SPI pins: SCK, MISO and MOSI */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Configure I/O for Flash Chip select */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Deselect the FLASH: Chip Select high */

SPI_FLASH_CS_HIGH();

/* SPI configuration */

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //双工模式

SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //SPI主模式

SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //8bit数据

SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //CLK空闲时为高电平

SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //CLK上升沿采样,因为上升沿是第二个边沿动作,所以也可以理解为第二个边沿采样

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //片选用软件控制

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; //SPI频率:72M/4 = 18M

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //高位在前

SPI_InitStructure.SPI_CRCPolynomial = 7; //crc7,stm32spi带硬件ecc

SPI_Init(SPI1, &SPI_InitStructure);

/* Enable the SPI */

SPI_Cmd(SPI1, ENABLE);

SPI_FLASH_SendByte(0xFF); // 启动传输

}

二 FLASH初始化

void Init_FLASH(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

/* Enable GPIO clocks */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOA , ENABLE);

/* PA0--SPI_FLASH_HOLD */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

/* PC4-- SPI_FLASH_WP */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOC, &GPIO_InitStructure);

GPIO_SetBits(GPIOA,GPIO_Pin_0);

GPIO_ResetBits(GPIOC,GPIO_Pin_4);

Init_SPI1();

}

三 函数编写

/* 通过SPIx发送一个数据,同时接收一个数据*/

u8 SPI_FLASH_SendByte(u8 byte)

{

/* 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, byte); //往发送寄存器写入要发送的数据

/* 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);

}

/* brief Enables the write access to the FLASH. */

void SPI_FLASH_WriteEnable(void)

{

/* Select the FLASH: Chip Select low */

SPI_FLASH_CS_LOW();

/* Send “Write Enable” instruction */

SPI_FLASH_SendByte(WREN);

/* Deselect the FLASH: Chip Select high */

SPI_FLASH_CS_HIGH();

}

/*brief Erases the specified FLASH sector. */

void SPI_FLASH_SectorErase(u32 SectorAddr)

{

/* Send write enable instruction */

SPI_FLASH_WriteEnable();

/* Sector Erase */

/* Select the FLASH: Chip Select low */

SPI_FLASH_CS_LOW();

/* Send Sector Erase instruction */

SPI_FLASH_SendByte(SE);

/* Send SectorAddr high nibble address byte */

SPI_FLASH_SendByte((SectorAddr & 0xFF0000) 》》 16);

/* Send SectorAddr medium nibble address byte */

SPI_FLASH_SendByte((SectorAddr & 0xFF00) 》》 8);

/* Send SectorAddr low nibble address byte */

SPI_FLASH_SendByte(SectorAddr & 0xFF);

/* Deselect the FLASH: Chip Select high */

SPI_FLASH_CS_HIGH();

}

/*brief Writes more than one byte to the FLASH with a single WRITE cycle */

void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)

{

/* Enable the write access to the FLASH */

SPI_FLASH_WriteEnable();

/* Select the FLASH: Chip Select low */

SPI_FLASH_CS_LOW();

/* Send “Write to Memory ” instruction */

SPI_FLASH_SendByte(PP);

/* Send WriteAddr high nibble address byte to write to */

SPI_FLASH_SendByte((WriteAddr & 0xFF0000) 》》 16);

/* Send WriteAddr medium nibble address byte to write to */

SPI_FLASH_SendByte((WriteAddr & 0xFF00) 》》 8);

/* Send WriteAddr low nibble address byte to write to */

SPI_FLASH_SendByte(WriteAddr & 0xFF);

while(NumByteToWrite--)

{

SPI_FLASH_SendByte(*pBuffer);

pBuffer++;

}

/* Deselect the FLASH: Chip Select high */

SPI_FLASH_CS_HIGH();

}

/*brief Writes block of data to the FLASH. In this function, the number of */

void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)

{

u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;

Addr = WriteAddr % SPI_FLASH_PAGESIZE;

count = SPI_FLASH_PAGESIZE - Addr;

NumOfPage = NumByteToWrite / SPI_FLASH_PAGESIZE;

NumOfSingle = NumByteToWrite % SPI_FLASH_PAGESIZE;

if (Addr == 0) /* WriteAddr is SPI_FLASH_PAGESIZE aligned */

{

if (NumOfPage == 0) /* NumByteToWrite 《 SPI_FLASH_PAGESIZE */

{

SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);

}

else /* NumByteToWrite 》 SPI_FLASH_PAGESIZE */

{

while (NumOfPage--)

{

SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PAGESIZE);

WriteAddr += SPI_FLASH_PAGESIZE;

pBuffer += SPI_FLASH_PAGESIZE;

}

SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);

}

}

else /* WriteAddr is not SPI_FLASH_PAGESIZE aligned */

{

if (NumOfPage == 0) /* NumByteToWrite 《 SPI_FLASH_PAGESIZE */

{

if (NumOfSingle 》 count) /* (NumByteToWrite + WriteAddr) 》 SPI_FLASH_PAGESIZE */

{

temp = NumOfSingle - count;

SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);

WriteAddr += count;

pBuffer += count;

SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);

}

else

{

SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);

}

}

else /* NumByteToWrite 》 SPI_FLASH_PAGESIZE */

{

NumByteToWrite -= count;

NumOfPage = NumByteToWrite / SPI_FLASH_PAGESIZE;

NumOfSingle = NumByteToWrite % SPI_FLASH_PAGESIZE;

SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);

WriteAddr += count;

pBuffer += count;

while (NumOfPage--)

{

SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PAGESIZE);

WriteAddr += SPI_FLASH_PAGESIZE;

pBuffer += SPI_FLASH_PAGESIZE;

}

if (NumOfSingle != 0)

{

SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);

}

}

}

}

/*brief Reads a block of data from the FLASH. */

void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)

{

/* Select the FLASH: Chip Select low */

SPI_FLASH_CS_LOW();

/* Send “Read from Memory ” instruction */

SPI_FLASH_SendByte(READ);

/* Send ReadAddr high nibble address byte to read from */

SPI_FLASH_SendByte((ReadAddr & 0xFF0000) 》》 16);

/* Send ReadAddr medium nibble address byte to read from */

SPI_FLASH_SendByte((ReadAddr& 0xFF00) 》》 8);

/* Send ReadAddr low nibble address byte to read from */

SPI_FLASH_SendByte(ReadAddr & 0xFF);

while (NumByteToRead--) /* while there is data to be read */

{

/* Read a byte from the FLASH */

*pBuffer = SPI_FLASH_SendByte(DUMMY_BYTE);

/* Point to the next location where the byte read will be saved */

pBuffer++;

}

/* Deselect the FLASH: Chip Select high */

SPI_FLASH_CS_HIGH();

}

/*brief Reads FLASH identification. */

u32 SPI_FLASH_ReadID(void)

{

u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;

/* Select the FLASH: Chip Select low */

SPI_FLASH_CS_LOW();

/* Send “RDID ” instruction */

SPI_FLASH_SendByte(0x9F);

/* Read a byte from the FLASH */

Temp0 = SPI_FLASH_SendByte(DUMMY_BYTE);

/* Read a byte from the FLASH */

Temp1 = SPI_FLASH_SendByte(DUMMY_BYTE);

/* Read a byte from the FLASH */

Temp2 = SPI_FLASH_SendByte(DUMMY_BYTE);

/* Deselect the FLASH: Chip Select high */

SPI_FLASH_CS_HIGH();

Temp = (Temp0 《《 16) | (Temp1 《《 8) | Temp2;

return Temp;

}

四 主函数

void SPI1_Test(void)

{

/* Get SPI Flash ID */

FLASH_ID = SPI_FLASH_ReadID();

FLASH_ID = SPI_FLASH_ReadID();

if (FLASH_ID == M25P64_FLASH_ID)

{

/* Write Tx_Buffer data to SPI FLASH memory */

SPI_FLASH_BufferWrite(Tx_Buffer, FLASH_WriteAddress, BufferSize);

delay_ms(20);

DbgOutputstr(“Write message is ok!\r\n”);

/* Read data from SPI FLASH memory */

memset(Rx_Buffer,0,sizeof(Rx_Buffer));

SPI_FLASH_BufferRead(Rx_Buffer, FLASH_ReadAddress, BufferSize);

DbgOutputstr(“the message you write is:\r\n”);

DbgOutputstr((char *)Rx_Buffer);

DbgOutputstr(“\r\n”);//插入换行

/* Erase SPI FLASH Sector to write on */

SPI_FLASH_SectorErase(FLASH_SectorToErase);

delay_ms(10);

/* Read data from SPI FLASH memory No data -----Erase is ok */

memset(Rx_Buffer,0,sizeof(Rx_Buffer));

SPI_FLASH_BufferRead(Rx_Buffer, FLASH_ReadAddress, BufferSize);

DbgOutputstr(“the message you write is:\r\n”);

DbgOutputstr((char *)Rx_Buffer);

DbgOutputstr(“\r\n”);//插入换行

DbgOutputstr(“\r\n”);//插入换行

delay_ms(1000);

}

}


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FlaSh
    +关注

    关注

    10

    文章

    1549

    浏览量

    146643
  • SPI
    SPI
    +关注

    关注

    17

    文章

    1614

    浏览量

    89586
收藏 人收藏

    评论

    相关推荐

    基于FPGA的SPI Flash控制器的设计方案

    传统的Flash读写是通过CPU软件编程实现,其读写速度较慢,且占用CPU资源,另外由于Flash芯片本身功能指令较多,使得对芯片进行直接操作变得非常困难。本文提出一个基于FPGA的
    发表于 09-24 09:12 5591次阅读
    基于FPGA的<b class='flag-5'>SPI</b> <b class='flag-5'>Flash</b>控制器的设计方案

    STM32CubeMx入门教程(6):SPI读写FLAH的应用

    导语“本教程将使用CubeMX初始化SPI,使用SPI对W25Q64 FLASH进行读写操作,通过HAL库的读写应用来数据
    发表于 07-12 11:32 1378次阅读
    STM32CubeMx入门教程(6):<b class='flag-5'>SPI</b><b class='flag-5'>读写</b>FLAH的应用

    实现简单的SPI读写FLASH的方法

    实现简单的SPI读写FLASH一、前言继上篇文章SPI的相关知识,本章主要介绍使用SPI协议实现简单的
    发表于 12-10 06:59

    SPI如何读写串行FLASH

    SPI有哪几种通讯模式?SPI如何读写串行FLASH
    发表于 02-17 07:50

    使用NUC970_NonOS_BSP中读写SPI Flash例程,SPI Flash读写失败的原因?

    使用 NUC970_NonOS_BSP 中读写SPI Flash例程,操作SPI Flash(型:AT45DB041D),读失败,提示写成功
    发表于 09-01 06:43

    基于红牛开发板的spi flash读写图片

    你的MCU上有外部总线接口,SPI flash就是通过SPI口对flash进行读写。速度上,总线flas
    发表于 09-01 17:16 16次下载
    基于红牛开发板的<b class='flag-5'>spi</b> <b class='flag-5'>flash</b><b class='flag-5'>读写</b>图片

    SPI flash是什么,关于SPI FLASH读写问题

    SPI一种通信接口。那么严格的来说SPI Flash是一种使用SPI通信的Flash,即,可能指NOR也可能是NAND。
    的头像 发表于 09-18 14:38 10.1w次阅读
    <b class='flag-5'>SPI</b> <b class='flag-5'>flash</b>是什么,关于<b class='flag-5'>SPI</b> <b class='flag-5'>FLASH</b>的<b class='flag-5'>读写</b>问题

    浅析spi flash驱动及其程序

    怎么用说白了对于Flash就是读写擦,也就是实现flash的驱动。先简单了解下spi flash的物理连接。
    的头像 发表于 10-07 11:26 1.8w次阅读
    <b class='flag-5'>浅析</b><b class='flag-5'>spi</b> <b class='flag-5'>flash</b>驱动及其程序

    STM32F0xx_SPI读写(Flash) 配置详细过程

    STM32F0xx_SPI读写(Flash)配置详细过程
    的头像 发表于 04-07 11:40 4622次阅读
    STM32F0xx_<b class='flag-5'>SPI</b><b class='flag-5'>读写</b>(<b class='flag-5'>Flash</b>) 配置详细过程

    STM32_ SPI读写Flash

    STM32_SPI读写Flash
    的头像 发表于 04-08 10:26 4923次阅读
    STM32_ <b class='flag-5'>SPI</b><b class='flag-5'>读写</b><b class='flag-5'>Flash</b>

    实现简单的SPI读写FLASH

    实现简单的SPI读写FLASH一、前言继上篇文章SPI的相关知识,本章主要介绍使用SPI协议实现简单的
    发表于 11-26 19:21 22次下载
    实现简单的<b class='flag-5'>SPI</b><b class='flag-5'>读写</b><b class='flag-5'>FLASH</b>

    单片机学习笔记————STM32使用SPI读写串行Flash(三)

    第一步:读写相关函数在向 FLASH 芯片存储矩阵写入数据前,首先要使能写操作,通过“Write Enable”命令即可写使能。1.写使能命令/** * @brief 向Flash发送写使能命令
    发表于 12-22 19:15 4次下载
    单片机学习笔记————STM32使用<b class='flag-5'>SPI</b><b class='flag-5'>读写</b>串行<b class='flag-5'>Flash</b>(三)

    STM32F103学习笔记——SPI读写Flash(二)

    介绍1.软件设计流程SPI读写Flash流程:初始化通讯引脚及端口时钟;使能SPI时钟;配置SPI结构体;编写基本
    发表于 12-22 19:30 10次下载
    STM32F103学习笔记——<b class='flag-5'>SPI</b><b class='flag-5'>读写</b><b class='flag-5'>Flash</b>(二)

    SPI控制EF3内置FLASH读写

    电子发烧友网站提供《SPI控制EF3内置FLASH读写.pdf》资料免费下载
    发表于 09-27 10:19 1次下载
    <b class='flag-5'>SPI</b>控制EF3内置<b class='flag-5'>FLASH</b><b class='flag-5'>读写</b>

    SPI控制EF2内置FLASH读写

    电子发烧友网站提供《SPI控制EF2内置FLASH读写.pdf》资料免费下载
    发表于 09-26 15:16 3次下载
    <b class='flag-5'>SPI</b>控制EF2内置<b class='flag-5'>FLASH</b><b class='flag-5'>读写</b>