• 1.1 SST25VF080B简介

1.1.1 主要特性

关键点:容量、速度(时钟速度、读写速度)、功耗。

容量:8MBit;

最高SPI时钟频率:50MHz;

低功耗模式下电流消耗:5uA,正常读模式电流:15mA;低功耗!采用不同的制造技术功耗要低很多。

整片擦除:35ms;扇区/块擦除:18ms;字节编程:7us;整片擦除的速度要快很多!

  • 1.2 系统框图与电路1.2.1 系统框图

关于内部存储矩阵的访问和存储结构同并行NorFlash的一致,只不过多了个串行接口,用于实现对串行数据的解码。

1.2.2 存储组织

扇区大小4KB,块大小:32/64KB;页大小为字节或字。

1.2.3 引脚及封装

引脚说明:

SCK、SI、SO、CE – SPI接口控制线

WP# -- 用于使能状态寄存器中的BPL位,有效时只允许锁定BPL,而不允许解锁BPL。不是说明使能保护!BPL位用于锁定控制扇区保护的相应位。

HOLD# -- 用于暂停与SPI的通信,而不需要复位器件;

1.2.4 典型电路

使用STM32F103驱动该器件时,典型的电路如图所示。

注意,WP为低,判定寄存器的锁定功能将启用。但不会太影响片内块的保护。

  • 1.3 保护机制

软件写保护:状态寄存器中的BP3—BP0、BPL提供片内块、状态寄存器的写保护。

硬件保护:WP#引脚—低电平,用于锁定状态寄存位7—BPL。由表2,WP#为高时,可以执行状态寄存器写命令,可随时更改状态寄存器。为低时,只能将BPL置为1,而不能从1置为0,即置1后,状态寄存器将锁定不变。

WP# àBPL、BP3—BP0

BPLàBP3、BP0

  • 1.4 编程接口

1.4.1 状态寄存器

状态寄存器用于用于获取FLASH的当前工作状态。

BUSY位:指示是否正在编程或擦除操作;

WEL位:指示器件是否处理可写的状态。RESET状态(0)指示不可写,默认在上电、完成写操作后,器件自行返回到不可写状态,以保护器件不受意外的擦写。因而每次写FLASH前,都必须先清除(写1),以使能器件的写。软件可控写。

AAI位:指示器件是否处理地址自动增加模式或者是字节编程模式。

BPL位:用于控制BPX是否可写。

BPX位:用于控制保护块的范围,属于软件保护,扇区保护如下。

这里的扇区保护比较简单,更为复杂的扇区保护机制可针对每个扇区进行保护。

1.4.2 命令接口

通信过程中,仅仅只有读ID、读数据、读状态寄存器需要在可保护CS不变而继续写数据。其它的则需要写完后接CS线。

  • 1.5 通信时序

1.单字SPI通信时序

无论SPI总线空闲时SCK为高或为低,保证在上升沿采样数据,下降沿输出数据。先传送高位,每次传送8位。

2. 读命令

3. 快速读模式

有可能内部使用了缓冲模式,可在更高的时钟速度(50MHz)下读数据。

4. 写使能

该命令可设置状态寄存器中的WEL位,使得可执行擦除和编程命令。

5. 写禁能

6. 字节编程

7. AAI编程

即自动地址增量的字编程,每个周期写1个字。

在最后,通过WRDI返回来正常模式。在每写完两个字后,需查询害怕状态。

在写字的过程中,有三种方式检测是否完成字编程。其中硬件检测:读SO的状态。可在写AAI命令之前,通过命令配置SO口为RD/BY#状态。或者也可通过读取状态寄存器来检测是否完成写操作。

8. 4KB的扇区擦除

9. 32K块擦除

10. 64K块擦除

11. 整片擦除

12. 读状态寄存器

13. 使能写状态寄存器和写状态寄存器

两条命令必须连续写,不允许被打断?以避免意外写状态寄存器。

l 当WP#为低电平时,BPL只能写1,不可写0.;此时若BPL位为高时,写状态寄存器命令将被忽略。即此时,状态寄存器只能被锁定(写1),而不能再解锁(写0)!锁定后将不能再任意改高保护方式,相当于将当前的保护方式给固定下来!

l 而若WP#为高电平,BPL位失效,状态寄存器不再被锁定,此时BPL、BPX可被更改。BPL位可设置为1,也可设置为0。可任意更改保护方式。

WP#的作用,锁定BPL为1。一旦BPL锁定为1,则BPX将不可再更改,即软件保护将被锁定。当WP#无效时,BPL可随时、任意更改,同时更改软件保护。

14. JEDEC Read-ID

获取SST制造商的ID和SST FLASH器件的ID。

  • 1.6 驱动设计

驱动框架如下图:

算法编写原则:

(1) 可以为每一种SPI Flash针对性的写一份驱动源码,但是当更换Flash时,需要修改的地方很多;当系统中有多个设备时,显示这不够用,因而最好的方法是实现面向对像的封装,将与Flash设备相关的信息封装在一个结构体内,具体的算法根据结构体中相关的数据来决定如何访问硬件,做到过程可以不依赖于实际的硬件;

(2) 尽量按标准的初始化、读写、关闭、控制接口设计API,这样可统一抽像出相应的结构,也易于使用和理解。留给最终用户调用的API应该尽量的少和易于理解;

(3) SPI Flash接口为SPI,操作方法与并行接口一致,但其扇区组织类似,从最大到最小区域分为芯片-块-扇区-页。编程算法则也是通过写命令序列的方式,如发送命令字-发送字节-发送数据-查询状态寄存器。保护方式是通过存储器中的一些非易失性的位置0或置1选择性地以扇区或块为保护单位。

  • 1.7 驱动代码
// SST25VF080B驱动接口
// By:lstzixing At ZLG
// Date: 2011-1
#include "STM32Lib\\stm32f10x.h"
#include "hal.h"

typedef unsigned long uint32;
typedef unsigned short uint16;
typedef unsigned char uint8;

#define SPI_FLASH_SIZE (1024*1024*2) // SPI Flash容量
#define SPI_FLASH_OK 0
#define SPI_FLASH_ERR_PARA 3 // SPI Flash参数错误

// SPI Flash擦除操作码
#define SPI_FLASH_ERASE_CHIP 0 // 整片擦除
#define SPI_FLASH_ERASE_SECTOR 1 // 扇区擦除
#define SPI_FLASH_ERASE_BLOCK 2 // 块擦除

// SPI状态寄存器和位
#define SPI_FLASH_REG_BIT_BUSY (1 << 0)
#define SPI_FLASH_REG_BIT_WEL (1 << 1)
#define SPI_FLASH_REG_BIT_BPX (0xF << 2)
#define SPI_FLASH_REG_BIT_AAI (1 << 6)
#define SPI_FLASH_REG_BIT_BPL (1 << 7)

#define SPIFlashSelect()         GPIO_ResetBits(GPIOC, GPIO_Pin_13) /* SST CS = L */
#define SPIFlashDeSelect()         GPIO_SetBits(GPIOC, GPIO_Pin_13) /* SST CS = H */

/*********************************************************************************************************
** Function name: SPIFlashInit
** Descriptions: 初始化SPI硬件,设置相关的GPIO口、SPI控制器
** Input parameters: none
** Output parameters: None
** Returned value: none
*********************************************************************************************************/
void SPIFlashInit(void)
{
    // 打开SPI1和GPIO时钟
    RCC->APB2ENR |= RCC_APB2ENR_SPI1EN |
                    RCC_APB2ENR_IOPAEN |
                    RCC_APB2ENR_IOPBEN |
                    RCC_APB2ENR_IOPCEN |
                    RCC_APB2ENR_IOPDEN |
                    RCC_APB2ENR_IOPEEN |
                    RCC_APB2ENR_IOPFEN;

    // PA5/6/7为复用模式, 50MHZ
    GPIOA->CRL &= ~(GPIO_CRL_CNF5 | GPIO_CRL_CNF6 | GPIO_CRL_CNF7 |
                    GPIO_CRL_MODE5 | GPIO_CRL_MODE6 | GPIO_CRL_MODE7);
    GPIOA->CRL |= GPIO_CRL_MODE5 | GPIO_CRL_MODE6 | GPIO_CRL_MODE7 |
                  GPIO_CRL_CNF5_1 | GPIO_CRL_CNF6_1 | GPIO_CRL_CNF7_1;

    // 配置PC.13为输出片选线
    GPIOC->CRH &= ~(GPIO_CRH_CNF13 | GPIO_CRH_MODE13);
    GPIOC->CRH |= GPIO_CRH_MODE13;

    // 配置SPI1,第一个时钟沿采样、主机、分频最大、使能、软件从机管理
    SPI1->CR1 = //SPI_CR1_CPHA |
                SPI_CR1_MSTR |
                //SPI_CR1_BR |
                SPI_CR1_SSI |
                SPI_CR1_SPE |
                SPI_CR1_SSM; 

    SPI1->CR2 = ;

    SPIFlashDeSelect();
}

/*********************************************************************************************************
** Function name: SPIWriteReadByte
** Descriptions: 向SPI发送并读取一数据
** Input parameters: data 要发送的数据
** Output parameters: None
** Returned value: uint16 读取的数据
*********************************************************************************************************/
static uint16 SPIWriteReadByte(uint16 data)
{
    // 发送一字节
    while((SPI1->SR & SPI_I2S_FLAG_TXE) == RESET);
    SPI1->DR = data;

    // 接收一字节
    while((SPI1->SR & SPI_I2S_FLAG_RXNE) == RESET);
    return(SPI1->DR);
}

/*********************************************************************************************************
** Function name: SPIFlashReadstatusReg
** Descriptions: 读状态寄存器
** Input parameters: none
** Output parameters: 当前状态寄存器的值
** BIT0 -- BUSY位,写忙标志
** BIT1 -- WEL位,FLASH处于写保护状态
** BIT6[5..2]--BP [3..0],扇区保护位
** BIT6 -- 指示正在自动自境编程中
** BIT7 -- BPL,BPX的保护位
** Returned value: none
*********************************************************************************************************/
static uint8 SPIFlashReadstatusReg (void)
{
    uint8 uByte;

    // 发送读状态寄存器命令
    SPIFlashSelect();
    {
        SPIWriteReadByte(0x5);
        uByte = SPIWriteReadByte(0xFF);
    }
    SPIFlashDeSelect();

    return uByte;
}

/*********************************************************************************************************
** Function name: SPIFlashWritestatusReg
** Descriptions: 写状态寄存器
** Input parameters: status 要写入的值
** Output parameters: none
** Returned value: none
*********************************************************************************************************/
static void SPIFlashWritestatusReg (uint8 status)
{
    // 发送使能状态寄存器写命令
    SPIFlashSelect();
    {
        SPIWriteReadByte(0x50);
    }
    SPIFlashDeSelect();

    // 写命令和状态值
    SPIFlashSelect();
    {
        SPIWriteReadByte(0x1);
        SPIWriteReadByte(status);
    }
    SPIFlashDeSelect();
}

/*********************************************************************************************************
** Function name: SPIFlashReadID
** Descriptions: 读SPI FLASH的JEDEC ID
** Input parameters: none
** Output parameters: 读的ID,从最高字节到最低字节:制造商ID(1B)-存储类型(1B)-存储容量(1B)
** Returned value: none
*********************************************************************************************************/
uint32 SPIFlashReadID (void)
{
    uint32 spiID;

    // 发送低速读命令0x9F,3字节地址,写入的字节
    SPIFlashSelect();
    {
        SPIWriteReadByte(0x9F);
        spiID = SPIWriteReadByte(;
        spiID |= SPIWriteReadByte(;
        spiID |= SPIWriteReadByte(0xff);
    }
    SPIFlashDeSelect();

    return spiID;
}

/*********************************************************************************************************
** Function name: SPIFlashRead
** Descriptions: 以低速方式(<=25MHZ)从SPI FLASH读数据
** Input parameters: readBuf 读数据存储的缓冲区首址
** readCnt 要读取的数据量
** Output parameters: uint32 实际读得的数据量。当读地址超出芯片容量时,将只读在芯片地址范围内
** 的数据
** Returned value: none
*********************************************************************************************************/
uint32 SPIFlashRead (uint32 readAddr, uint8 * readBuf, uint32 readCnt)
{
    uint32 i;
    uint8 addr[];

    // 检查参数
    if (readAddr >= SPI_FLASH_SIZE ||
        readBuf ==  ||
        readCnt == ) {
        return SPI_FLASH_ERR_PARA;
    }

    // 校正要读的数据总量
    if (readAddr + readCnt >= SPI_FLASH_SIZE) {
        readCnt = SPI_FLASH_SIZE - readAddr;
    }

    // 将地址转换为字节数组
    addr[] = (uint8)(readAddr >> );
    addr[] = (uint8)(readAddr >> );
    addr[] = (uint8)(readAddr & 0xff);

    // 等待SPI Flash完成写操作
    while (SPIFlashReadstatusReg() & SPI_FLASH_REG_BIT_BUSY );

    SPIFlashSelect();
    {
        // 发送低速读命令0x3,3字节地址
        SPIWriteReadByte(0x3);
        SPIWriteReadByte(addr[]);
        SPIWriteReadByte(addr[]);
        SPIWriteReadByte(addr[]);

        // 依次读readCnt个数据
        ; i < readCnt; i++) {
            readBuf[i] = SPIWriteReadByte(0xff);
        }
    }
    SPIFlashDeSelect();

    return i;
}

/*********************************************************************************************************
** Function name: SPIFlashFastRead
** Descriptions: 以高速方式(<=50MHZ)从SPI FLASH读数据
** Input parameters: readBuf 读数据存储的缓冲区首址
** readCnt 要读取的数据量
** Output parameters: uint32 实际读得的数据量。当读地址超出芯片容量时,将只读在芯片地址范围内
** 的数据
** Returned value: none
*********************************************************************************************************/
uint32 SPIFlashFastRead (uint32 readAddr, uint8 * readBuf, uint32 readCnt)
{
    uint32 i;
    uint8 addr[];

    // 检查参数
    if (readAddr >= SPI_FLASH_SIZE ||
        readBuf ==  ||
        readCnt == ) {
        return SPI_FLASH_ERR_PARA;
    }

    // 校正要读的数据总量
    if (readAddr + readCnt >= SPI_FLASH_SIZE) {
        readCnt = SPI_FLASH_SIZE - readAddr;
    }

    // 将地址转换为字节数组
    addr[] = (uint8)(readAddr >> );
    addr[] = (uint8)(readAddr >> );
    addr[] = (uint8)(readAddr & 0xff);

    // 等待SPI Flash完成写操作
    while (SPIFlashReadstatusReg() & SPI_FLASH_REG_BIT_BUSY );

    SPIFlashSelect();
    {
        // 发送低速读命令0x3,3字节地址,dummy字节
        SPIWriteReadByte(0xB);
        SPIWriteReadByte(addr[]);
        SPIWriteReadByte(addr[]);
        SPIWriteReadByte(addr[]);
        SPIWriteReadByte(0xff);

        // 依次读readCnt个数据
        ; i < readCnt; i++) {
            readBuf[i] = SPIWriteReadByte(0xff);
        }
    }
    SPIFlashDeSelect();

    return i;
}

/*********************************************************************************************************
** Function name: SPIFlashWriteByte
** Descriptions: 向SPI Flash指定地址处写一字节数据
** Input parameters: writeAddr 写入的地址
** udata 写入的值
** Output parameters: none
** Returned value: none
** Notes: 写之前必须注意到写保护的存储影响
*********************************************************************************************************/
uint32 SPIFlashWriteByte (uint32 writeAddr, uint8 uByte)
{
    uint8 addr[];

    // 检查写地址是否越界
    if (writeAddr >= SPI_FLASH_SIZE) {
        return SPI_FLASH_ERR_PARA;
    }

    // 将地址转换为字节数组
    addr[] = (uint8)(writeAddr >> );
    addr[] = (uint8)(writeAddr >> );
    addr[] = (uint8)(writeAddr & 0xff);

    // 等待SPI Flash完成写操作
    while (SPIFlashReadstatusReg() & SPI_FLASH_REG_BIT_BUSY );

    // 发送写使能命令
    SPIFlashSelect();
    {
        SPIWriteReadByte(0x06);
    }
    SPIFlashDeSelect();

    // 写入实际要写入的数据
    SPIFlashSelect();
    {
        // 发送低速读命令0x3,3字节地址,写入的字节
        SPIWriteReadByte(0x2);
        SPIWriteReadByte(addr[]);
        SPIWriteReadByte(addr[]);
        SPIWriteReadByte(addr[]);
        SPIWriteReadByte(uByte);
    }
    SPIFlashDeSelect();

    return SPI_FLASH_OK;
}

/*********************************************************************************************************
** Function name: SPIFlashFastWrite
** Descriptions: 以地址自增方式向指定FLASH地址处连续写字数据
** Input parameters: writeAddr 写入的起始地址
** writeBuferr 写数据存储的缓冲区
** uWord 写入的数据量,以字为单位
** Output parameters: none
** Returned value: none
** Notes: 写之前必须注意到写保护的存储影响
*********************************************************************************************************/
uint32 SPIFlashFastWrite (uint32 writeAddr, uint16 * writeBuferr, uint16 uWord)
{
    uint16 i;
    uint8 addr[];

     // 检查参数
    if (writeAddr >= SPI_FLASH_SIZE ||
        writeBuferr ==  ||
        uWord == ) {
        return SPI_FLASH_ERR_PARA;
    }

    // 检查写地址是否越界
    ) >= SPI_FLASH_SIZE) {
        uWord = (SPI_FLASH_SIZE - writeAddr) >> ;
    }

    // 将地址转换为字节数组
    addr[] = (uint8)(writeAddr >> );
    addr[] = (uint8)(writeAddr >> );
    addr[] = (uint8)(writeAddr & 0xff);

    // 等待SPI Flash完成写操作
    while (SPIFlashReadstatusReg() & SPI_FLASH_REG_BIT_BUSY );

    // 发送写使能命令
    SPIFlashSelect();
    {
        SPIWriteReadByte(0x06);
    }
    SPIFlashDeSelect();

    // 发送低速读命令0xAD,3字节地址,写入的字节
    SPIFlashSelect();
    {
        SPIWriteReadByte(0xAD);
        SPIWriteReadByte(addr[]);
        SPIWriteReadByte(addr[]);
        SPIWriteReadByte(addr[]);
        SPIWriteReadByte(writeBuferr[] >> 0x08);
        SPIWriteReadByte(writeBuferr[] & 0xFF);
    }
    SPIFlashDeSelect();

    // 发送其它字节
    ; i < uWord; i++) {
        // 等待SPI Flash完成写操作
        while (SPIFlashReadstatusReg() & SPI_FLASH_REG_BIT_BUSY );

        SPIFlashSelect();
        {
           // 发送引导命令和编程字数据
            SPIWriteReadByte(0xAD);
            SPIWriteReadByte(writeBuferr[i] >> 0x08);
            SPIWriteReadByte(writeBuferr[i] & 0xFF);
        }
        SPIFlashDeSelect();
   } 

    // 等待SPI Flash完成写操作
    while (SPIFlashReadstatusReg() & SPI_FLASH_REG_BIT_BUSY );

    // 发送写禁能命令,退出该模式
    SPIFlashSelect();
    {
        SPIWriteReadByte(0x04);
    }
    SPIFlashDeSelect();

    return SPI_FLASH_OK;
}

/*********************************************************************************************************
** Function name: SPIFlashChipErase
** Descriptions: 擦除整块芯片
** Input parameters: none
** Output parameters: none
** Returned value: none
** Note: 如果sectorAaddr
*********************************************************************************************************/
void SPIFlashErase (uint8 eraseType, uint32 eraseAddr)
{
    uint8 addr[];

    // 等待SPI Flash完成写操作
    while (SPIFlashReadstatusReg() & SPI_FLASH_REG_BIT_BUSY );

    // 发送写使能命令
    SPIFlashSelect();
    {
        SPIWriteReadByte(0x06);
    }
    SPIFlashDeSelect();

    // 根据类型选择擦除方式
    switch (eraseType) {
        // 选择整片擦除方式
        case SPI_FLASH_ERASE_CHIP:
            SPIFlashSelect();
            {
                SPIWriteReadByte(0x60);
            }
            SPIFlashDeSelect();
            break;

        // 扇区擦除方式
        case SPI_FLASH_ERASE_SECTOR:
            if (eraseAddr < SPI_FLASH_SIZE) {
                // 将地址转换为字节数组
                addr[] = (uint8)(eraseAddr >> );
                addr[] = (uint8)(eraseAddr >> );
                addr[] = (uint8)(eraseAddr & 0xff);

                // 发送扇区擦除命令,擦除的扇区地址
                SPIFlashSelect();
                {
                    SPIWriteReadByte(0x20);
                    SPIWriteReadByte(addr[]);
                    SPIWriteReadByte(addr[]);
                    SPIWriteReadByte(addr[]);
                }
                SPIFlashDeSelect();
            }
            break;

        // 32K块擦除方式
        case SPI_FLASH_ERASE_BLOCK:
            if (eraseAddr < SPI_FLASH_SIZE) {
                // 将地址转换为字节数组
                addr[] = (uint8)(eraseAddr >> );
                addr[] = (uint8)(eraseAddr >> );
                addr[] = (uint8)(eraseAddr & 0xff);

                // 发送块擦除命令,擦除的块地址
                SPIFlashSelect();
                {
                    SPIWriteReadByte(0x52);
                    SPIWriteReadByte(addr[]);
                    SPIWriteReadByte(addr[]);
                    SPIWriteReadByte(addr[]);
                }
                SPIFlashDeSelect();
            }
            break;

        default:
            break;
    }

}

/*********************************************************************************************************
** Function name: SPIFlashSetProtection
** Descriptions: 设定SPI存储器的保护模式,加保护或解保护
** Input parameters: isProtect 保护的模式,1--加保护, 0 -- 解保护
** startAddr 保护区域的起始地址
** stopAddr 保护区域的结束地址
** Output parameters: 0 -- 操作成功, 1 -- 操作失败(当为解保护时,硬件保护阻止了解保护)
** Returned value: none
*********************************************************************************************************/
uint32 SPIFlashSetProtection (uint8 isProtect, uint32 startAddr, uint32 stopAddr)
{
    uint8 BPXMask;
    uint8 status;

    // 等待SPI Flash完成写操作
    while (SPIFlashReadstatusReg() & SPI_FLASH_REG_BIT_BUSY );

    if (isProtect) {
        // 清除所有的保护位
        SPIFlashWritestatusReg();

        // 如果BPL只读,即不可更改BPX位
        if (SPIFlashReadstatusReg() & SPI_FLASH_REG_BIT_BPL) {

            // 当该区域已经加保护时,正确返回
            if ((status & SPI_FLASH_REG_BIT_BPX) > BPXMask) {
                ;
            } else {
                // 当未加保护时,返回错误,不可更改保护模式
                ;
            }

        } else {
            // 计算保护模式位
            if (startAddr > SPI_FLASH_SIZE) {
                ;
            } else if (startAddr >= 0xF0000) {
                BPXMask = ;
            } else if (startAddr >= 0xE0000) {
                BPXMask = ;
            } else if (startAddr >= 0xC0000) {
                BPXMask = ;
            } else if (startAddr >= 0x80000) {
                BPXMask = ;
            } else {
                BPXMask = ;
            }

            // BPL写读写,此时加上保护位即可,但不锁定BPL,以妨不可恢复
            SPIFlashWritestatusReg(BPXMask);

            ;
        }
    } else {
        // 解除保护,写BPL位为0,解除保护
        SPIFlashWritestatusReg();

        // 读保护位,如果值不为全0,则可能硬件加保护,解保护失败
        if (SPIFlashReadstatusReg() & SPI_FLASH_REG_BIT_BPX) {
            ;
        } else {
            ;
        }
    }
}

/* -------------------------------------------------- 测试代码 ---------------------------------------*/
uint32 id;
uint8 writeBuffer[];
uint8 readBuffer[];
uint8 status;

#define SPI_FLASH_SECTOR_SIZE (1024*4)
#define SPI_FLASH_BLOCK_SIZE (1024*32)

void SPIFlashTest (void)
{
    uint32 i, j;

    // 初始化SPI控制器
    SPIFlashInit();

    // 读ID测试,值应为0x00BF258E
    id = SPIFlashReadID();
    if (id != 0x00BF258E) {
        return;
    }

    // 先解除保护才可写
    SPIFlashSetProtection(, 0xF0000, 0xFFFFF);

    // 整片擦除测试
    SPIFlashErase(SPI_FLASH_ERASE_CHIP, );
    ; i < SPI_FLASH_SIZE / sizeof(readBuffer); i++) {
        SPIFlashRead(i * sizeof(readBuffer), readBuffer, sizeof(readBuffer));
        ; j < sizeof(readBuffer); j++) {
            if (readBuffer[j] != 0xff) {
                return;
            }
        }
    }

    // 字节写和读测试
    ; i < SPI_FLASH_SIZE; i++) {
        SPIFlashWriteByte(i, i);
        SPIFlashRead (i, readBuffer, );
        ] != (i & 0xff)) {
            return;
        }
    }

    // 扇区擦除测试
    ; i < SPI_FLASH_SIZE / (*); i++) {
        SPIFlashErase(SPI_FLASH_ERASE_SECTOR, i * (*));
    }
    ; i < SPI_FLASH_SIZE / sizeof(readBuffer); i++) {
        SPIFlashRead(i * sizeof(readBuffer), readBuffer, sizeof(readBuffer));
        ; j < sizeof(readBuffer); j++) {
            if (readBuffer[j] != 0xff) {
                return;
            }
        }
    }

    // 快速写测试
    ; i < SPI_FLASH_SIZE / sizeof(writeBuffer); i++) {
        ; j < sizeof(writeBuffer); j++) {
            writeBuffer[j] = j;
        }
        SPIFlashFastWrite( i * );
        SPIFlashFastRead ( i * sizeof(writeBuffer), (uint8 *)readBuffer, sizeof(readBuffer));

        // 交换字节顺序再比较
        ; j < ; j++) {
            uint16 * ptr = (uint16 *)&readBuffer[j << ];
            *ptr = ((*ptr & ) | (*ptr >> );
        }
        ) {
            return;
        }
    }

    // 扇区擦除测试
    ; i < SPI_FLASH_SIZE / (*); i++) {
        SPIFlashErase(SPI_FLASH_ERASE_BLOCK, i * (*));
    }
    ; i < SPI_FLASH_SIZE / sizeof(readBuffer); i++) {
        SPIFlashRead(i * sizeof(readBuffer), readBuffer, sizeof(readBuffer));
        ; j < sizeof(readBuffer); j++) {
            if (readBuffer[j] != 0xff) {
                return;
            }
        }
    }

    // 保护测试
    SPIFlashSetProtection(, 0xF0000, 0xFFFFF);
    SPIFlashSetProtection(, 0x80000, 0xFFFFF);
    SPIFlashSetProtection(, 0xF0000, 0xFFFFF);
}

FLASH 存储学习-串行SPI nor的更多相关文章

  1. FLASH 存储学习-串行SPI NOR FLASH

    1.1 SST25VF080B简介1.1.1 主要特性 关键点:容量.速度(时钟速度.读写速度).功耗. l 容量:8MBit: l 最高SPI时钟频率:50MHz: l 低功耗模式下电流消耗:5uA ...

  2. flash读写学习笔记与spi接口及简单测试验证(三)

    FPGA中的视频图像资源,以及想要永久存储的程序都是要存储在flash中,flash是FPGA一个不可缺少的部分,flash的种类有很多,根据winbond公司的128Mbit Qual SPI接口的 ...

  3. STM32-串行SPI nor

    源:FLASH 存储学习-串行SPI nor 1.1 SST25VF080B简介1.1.1 主要特性 关键点:容量.速度(时钟速度.读写速度).功耗. l 容量:8MBit: l 最高SPI时钟频率: ...

  4. 痞子衡嵌入式:串行NOR Flash的DQS信号功能简介

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是串行NOR Flash的DQS信号功能. 串行NOR Flash在嵌入式里的应用相当广泛,既可用作数据存储也可以用作代码(XiP)存储, ...

  5. 痞子衡嵌入式:飞思卡尔i.MX RTyyyy系列MCU硬件那些事(2.2)- 在串行NOR Flash XIP调试原理

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RTyyyy系列EVK在串行NOR Flash调试的原理. 本文是i.MXRT硬件那些事系列第二篇的续集,在第二篇首集 ...

  6. 玩转X-CTR100 l STM32F4 l W25Q64 SPI串行FLASH存储

    我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ]      本文介绍X-CTR100控制器 板载FLA ...

  7. 第24章 SPI—读写串行FLASH—零死角玩转STM32-F429系列

    第24章     SPI—读写串行FLASH 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/ ...

  8. STM32学习笔记——SPI串行通讯(向原子哥学习)

    一.SPI  简介 SPI是 Serial Peripheral interface 的缩写,就是串行外围设备接口.SPI 接口主要应用在  EEPROM, FLASH,实时时钟,AD 转换器,还有数 ...

  9. SPI—读写串行 FLASH

    SPI协议简介SPI 协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串行外围设备接口,是一种高速全双工的通信总线.它被广泛地使用在 ADC. LCD ...

随机推荐

  1. ListView中RadioButton实现单项选择

    1:FragmentHack5.java public class FragmentHack5 extends Fragment { View view; ListView lvCountries; ...

  2. LeetCode_Set Matrix Zeroes

    Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place. 很挫的一个想 ...

  3. VS2012 快捷键 VS Resharper 设置

    原文 http://www.cnblogs.com/skyangell/archive/2013/03/24/2979835.html 一直用Resharper插件,最近发现Ctrl+E,C快捷见被R ...

  4. mutate 转换

    zjtest7-frontend:/usr/local/logstash-2.3.4/config# cat geoip.conf input {stdin {} } filter { geoip { ...

  5. Centos中安装code blocks

    CentOS下面安装Codeblocks不像Ubuntu下面那样轻松,可以直接在软件中心安装.这里好多信赖我们要自己安装,也不是很麻烦. 1.先安装gcc和gcc++,这个可以直接安装 # yum i ...

  6. c++之 printf 打印内容

    该代码全部在Visual Studio 2015中编写,有关VS2015的安装流程后期在写相关的博文 首先让我们来输出一下hello, world! 1.首先新建一个main.cpp的文件,然后在该文 ...

  7. Traceroute原理介绍

    一.路由追踪 路由跟踪,就是获取从主机A到达目标主机B这个过程中所有需要经过的路由设备的转发接口IP. 二.ICMP协议 Internet控制报文协议(internet control message ...

  8. POJ3260:The Fewest Coins(混合背包)

    Description Farmer John has gone to town to buy some farm supplies. Being a very efficient man, he a ...

  9. POJ 2524 并查集

    Ubiquitous Religions Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 23580 Accepted: 1160 ...

  10. JS 点击复制Copy插件--Zero Clipboard

    写博客就是一周工作中遇到哪些问题,一个优点就是能够进行一个总结,另外一个优点就是下次遇到相同的问题即使那你记不住,也能够翻看你的博客攻克了.相同也能够帮到别人遇到与你一样问题的人.或者别人有比你更好的 ...