ARM固件开发(LPC1768通过SPI接口快速读写flash,型号W25Q64FV)

一、外部Flash的硬件接口

ARM固件开发(LPC1768通过SPI接口快速读写flash,型号W25Q64FV)_第1张图片

 

ARM固件开发(LPC1768通过SPI接口快速读写flash,型号W25Q64FV)_第2张图片

 

 二、固件程序设计

2.1SPI接口初始化

/* Layer specfication ---------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------
--
-- This layer for W25Q64FV SPI flash
-- 2013 04 22 Liu Jie:
--                    Update.
-- 2013 04 25 Liu Jie:
--                    Update the init function
-------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------*/

#include "spi_port.h"


/* Macro defines for SSP SR register */
#define SSP_SR_TFE      ((uint32_t)(1<<0)) /** SSP status TX FIFO Empty bit */
#define SSP_SR_TNF      ((uint32_t)(1<<1)) /** SSP status TX FIFO not full bit */
#define SSP_SR_RNE      ((uint32_t)(1<<2)) /** SSP status RX FIFO not empty bit */
#define SSP_SR_RFF      ((uint32_t)(1<<3)) /** SSP status RX FIFO full bit */
#define SSP_SR_BSY      ((uint32_t)(1<<4)) /** SSP status SSP Busy bit */
#define SSP_SR_BITMASK    ((uint32_t)(0x1F)) /** SSP SR bit mask */

/**
  * @brief  Initializes the SSP0.
  *
  * @param  None
  * @retval None 
  */
void SPI_Init (void) 
{
//        INT32U Div_Freq;
        INT32U frequence = 12000000;

//LPC175X-6X
#if 1
    /* Enable SSPI0 block */
    LPC_SC->PCONP |= (1 << 21);

    /* Configure other SSP pins: SCK, MISO, MOSI */
    LPC_PINCON->PINSEL0 &= ~(3UL << 30);
    LPC_PINCON->PINSEL0 |=  (2UL << 30);          /* P0.15: SCK0 */
    LPC_PINCON->PINSEL1 &= ~((3UL<<2) | (3UL<<4));
    LPC_PINCON->PINSEL1 |=  ((2UL<<2) | (2UL<<4));    /* P0.17: MISO0, P0.18: MOSI0 */

    /* 8bit, SPI frame format, CPOL=0, CPHA=0, SCR=0 */  
    LPC_SSP0->CR0 = (0x07 << 0) |     /* data width: 8bit*/
                    (0x00 << 4) |     /* frame format: SPI */
                    (0x00 << 6) |     /* CPOL: low level */
                    (0x00 << 7) |     /* CPHA: first edge */
                    (0x00 << 8);      /* SCR = 0 */

    /* Enable SSP0 as a master */
    LPC_SSP0->CR1 = (0x00 << 0) |   /* Normal mode */
                    (0x01 << 1) |   /* Enable SSP0 */
                    (0x00 << 2) |   /* Master */
                    (0x00 << 3);    /* slave output disabled */

    /* Configure SSP0 clock rate to 400kHz (100MHz/250) */
    SPI_ConfigClockRate (FPCLK/frequence);
#endif

//LPC177X-8X
#if 0    

    LPC_SC->PCONP |= (0x1 << 21);                                   /* 开启SSP0外设                 */
    LPC_IOCON->P0_15 &= ~0x07;
    LPC_IOCON->P0_15 |=  0x02;                                      /* SSP CLK                      */
    //LPC_IOCON->P0_16 &= ~0x07;    
    //LPC_IOCON->P0_16 |=  0x02;                                    /* SSP SSEL                     */
    LPC_IOCON->P0_17 &= ~0x07;
    LPC_IOCON->P0_17 |=  0x02;                                      /* SSP MISO                     */
    LPC_IOCON->P0_18 &= ~0x07;    
    LPC_IOCON->P0_18 |=  0x02;                                      /* SSP MOSI                     */


    //In Master mode, this register must be an even number greater than or equal to 8
    Div_Freq = (FPCLK/frequence/2)&0xfe;
  LPC_SSP0->CPSR = 2;
    LPC_SSP0->CR0 &= 0xffffff00;    
  LPC_SSP0->CR0 = 0x07 << 0 |                                         /* 数据长度为8位                */
                  0x00 << 4 |                                         /* 帧格式为SPI                  */
                  0x00 << 6 |                                         /* CPOL为0                      */
                  0x00 << 7 |                                         /* CPHA为0                      */
                  (Div_Freq-1) << 8;                                  /* 串行时钟速率为7              */
    LPC_SSP0->CR1 |= (1<<1);
#endif    
}

/**
  * @brief  Configure SSP0 clock rate.
  *
  * @param  SPI_CLOCKRATE: Specifies the SPI clock rate.
  *         The value should be SPI_CLOCKRATE_LOW or SPI_CLOCKRATE_HIGH.
  * @retval None 
  *
  * SSP0_CLK = CCLK / SPI_CLOCKRATE
  */
void SPI_ConfigClockRate (INT32U SPI_CLOCKRATE)
{
    /* CPSR must be an even value between 2 and 254 */
    LPC_SSP0->CPSR = (SPI_CLOCKRATE & 0xFE);    
}
/**
  * @brief  Send one byte via MOSI and simutaniously receive one byte via MISO.
  *
  * @param  data: Specifies the byte to be sent out.
  * @retval Returned byte.
  *
  * Note: Each time send out one byte at MOSI, Rx FIFO will receive one byte. 
  */
INT8U SPI_SendByte (INT8U dat)
{
    /* Put the data on the FIFO */
    LPC_SSP0->DR = dat;
    /* Wait for sending to complete */
    while (LPC_SSP0->SR & SSP_SR_BSY);
    /* Return the received value */              
    return (LPC_SSP0->DR);                        
}

/**
  * @brief  Receive one byte via MISO.
  *
  * @param  None.
  * @retval Returned received byte.
  */
INT8U SPI_RecvByte (void)
{
    /* Send 0xFF to provide clock for MISO to receive one byte */
    return SPI_SendByte (0xFF);
}
/*
* function send byte
*/
INT8U SPI_SwapByte(INT8U dat){
      return SPI_SendByte(dat);
}
/* --------------------------------- End Of File ------------------------------ */

 

导出函数

#ifndef __SPI_PORT_H
#define __SPI_PORT_H

#include "includes.h"                     /* LPC17xx Definitions */

/* Public functions */
extern void    SPI_Init               (void);
extern void    SPI_Init16Bit          (void);
extern void    SPI_ConfigClockRate    (INT32U  SPI_CLOCKRATE);

//8  bit
extern INT8U   SPI_SendByte           (INT8U   dat);
extern INT8U   SPI_RecvByte           (void);
extern INT8U   SPI_SwapByte           (INT8U   dat);
//16 bit
extern INT16U  SPI_SendBytes          (INT16U  dat);
extern INT16U  SPI_RecvBytes          (void);
extern INT16U  SPI_SwapBytes          (INT16U  dat);

#endif  // __LPC17xx_SPI_H
/* --------------------------------- End Of File ------------------------------ */

 

2.2Flash读写控制

/* Layer specfication ---------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------
--
-- This layer for W25Q64FV SPI flash
-- 2013 04 22 Liu Jie:
--                    Update.
-- 2013 04 25 Liu Jie:
--                    Update the init function
-------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------*/

#include "memory_flash.h"

#if     KIT_SPI_FLASH_EN
/* Layer specfication ---------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------
--
-- This layer for Hard define
--
   W25Q64 organized into 32768 pages of 256-bytes each. Up to 256 bytes can be programmed at a time.
     Pages can be erased in groups of 16(4kb sector erase)
     SPI clock frequencies of up to 104MHz are supported allowing equivalent clock rates of 208 MHz for
     dual I/O and 416MHz for quad I/O when using the fast read dual/quad I/O and QPI instructions.
     
     Address Presentation
     >>>8M bytes --------------------------- address: 0x000000~0x7fffff
       Block [0~127] : 64Kb
       .............each Block > sectors[0~15] : 4Kb
       .......................................each sector > 4Kb
     
     >>>SFDP Register ---------------------- address: 0x000000~0x0000ff
     >>>Security Register1~3 --------------- address: 0x000000~0x0000ff
     
     Function Presentation
     >>>Power on -> Reset(66h+99h) -> Device initialization-> Standard spi/ Dual spi/quad spi/operations -><-
        enable QPI(38h)/disable QPI(ffh)
            
     Registers
        busy : S0
-------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------*/

#define SPIFLASH_SEC_SIZE 0x1000
#define SPIFLASH_WE      0x06//write enable
#define SPIFLASH_SR      0x50//volatile SR write enable
#define SPIFLASH_WD      0x04//write disable
#define SPIFLASH_RSR1    0x05//read status register 1
#define SPIFLASH_RSR2    0x35//read status register 2
#define SPIFLASH_WSR     0x01//write status register
#define SPIFLASH_PP      0x02//page program
#define SPIFLASH_SE4     0x20//sector erase 4KB
#define SPIFLASH_BE32    0x52//block erase 32KB
#define SPIFLASH_BE64    0xd8//block erase 64KB
#define SPIFLASH_CE      0xc7//0x60 chip erase
#define SPIFLASH_EPS     0x75//erase/program suspend
#define SPIFLASH_EPR     0x7a//erase/program resume
#define SPIFLASH_PD      0xb9//power down
#define SPIFLASH_RD      0x03//read data
#define SPIFLASH_FR      0x0b//fast read
#define SPIFLASH_RPD     0xab//release powerdown /ID
#define SPIFLASH_MID     0x90//manufacture/device ID
#define SPIFLASH_JID     0x9f//JEDEC ID
#define SPIFLASH_RUID    0x4b//read unique ID
#define SPIFLASH_RSFR    0x5a//read SFDP register
#define SPIFLASH_ESR     0x44//erase security registers
#define SPIFLASH_PSR     0x42//program security registers
#define SPIFLASH_RSR     0x48//read security registers
#define SPIFLASH_EQPI    0x38//enable QPI
#define SPIFLASH_ERST    0x66//enable reset
#define SPIFLASH_RST     0x99//reset

/*
** SPI controller register
*/
#define SPI_FLASH_CPHA      (0<<3)//1:Data is sampled on the second clock edge of the SCK
                            //0:Data is sampled on the first clock edge of SCK
#define SPI_FLASH_CPOL      (0<<4)//1:SCK is active low.
                            //0:SCK is active high.
#define SPI_FLASH_MSTR      (1<<5)//0:Slave mode. 1: Master mode.
#define SPI_FLASH_LSBF      (0<<6)//0:transferred MSB first. 1:LSB first.
#define SPI_FLASH_SPIE      (0<<7)//0: interrupts are inhibited. 
                            //1: interrupt is generated each time the SPIF or MODF
#define SPI_FLASH_BITS      (8<<8)//1000:8bits 1001:9 ~~ 1111:15 0000:16


INT16U  spi_flash_id_MID;
/* Layer specfication -------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------
--
-- This layer for spi hardware
--
-----------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------*/

/*
* function 
*/
void fun_waitbusy(void){
    SPI_FLASH_CS_LOW();
    SPI_FLASH_SWAPE(SPIFLASH_RSR1);
    while( SPI_FLASH_SWAPE(SPIFLASH_RSR1)&0x01);
    SPI_FLASH_CS_HIGH();
}
void fun_waitWEL(void){
    SPI_FLASH_CS_HIGH();
    SPI_FLASH_CS_LOW();
    SPI_FLASH_SWAPE(SPIFLASH_RSR1);
    while( SPI_FLASH_SWAPE(SPIFLASH_RSR1)&0x03);
    SPI_FLASH_CS_HIGH();
}
/*
* function 
*/
void fun_flashEraseSector(INT32U sos,INT32U eos){
    INT32U i,addr;
    if(sos>eos){ i=eos;eos=sos;sos=i;  }

    SPI_FLASH_CS_LOW();
    SPI_FLASH_SWAPE(SPIFLASH_SR);
    SPI_FLASH_CS_HIGH();
        
    while(sos<=eos){    
        SPI_FLASH_CS_LOW();
        SPI_FLASH_SWAPE(SPIFLASH_WE);
        SPI_FLASH_CS_HIGH();

        fun_waitbusy();    
        //address
        addr = sos++*SPIFLASH_SEC_SIZE;    
        SPI_FLASH_CS_LOW();
        SPI_FLASH_SWAPE(SPIFLASH_SE4     );
        SPI_FLASH_SWAPE((INT8U)(addr>>16));
        SPI_FLASH_SWAPE((INT8U)(addr>> 8));
        SPI_FLASH_SWAPE((INT8U)(addr>> 0));
        SPI_FLASH_CS_HIGH();
        fun_waitWEL();
    }  
}

/* Layer specfication -------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------
--
-- This layer for flash application
--
-----------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------*/
/*
* function
*/
BOOLEAN spi_flash_ReadData(INT8U* pdest,INT32U addr,INT32U size)
{
    INT32U i;

    fun_waitbusy();    //2017.11.17

    SPI_FLASH_CS_LOW();
    SPI_FLASH_SWAPE(SPIFLASH_FR);
    SPI_FLASH_SWAPE((INT8U)(addr>>16)&0xff);
    SPI_FLASH_SWAPE((INT8U)(addr>> 8)&0xff);
    SPI_FLASH_SWAPE((INT8U)(addr>> 0)&0xff);
    SPI_FLASH_SWAPE(0xff);
    for(i=0;i){
        *(pdest+i) = SPI_FLASH_SWAPE(0xff);
    }
    SPI_FLASH_CS_HIGH();
    return TRUE;
}
/*
* function
*/
BOOLEAN spi_flash_WriteData(INT32U dest,INT8U* const psrc,INT32U size)
{
    INT32U cnt;
    INT8U  temp;
    INT8U* p=psrc;

    fun_waitbusy();//2017.11.17
    
    while(size > 0)
    {
        if(0 == dest%SPIFLASH_SEC_SIZE)
            fun_flashEraseSector(dest/SPIFLASH_SEC_SIZE,dest/SPIFLASH_SEC_SIZE);
        SPI_FLASH_CS_LOW();
        SPI_FLASH_SWAPE(SPIFLASH_RSR1);
        temp = SPI_FLASH_SWAPE(0xff);
        SPI_FLASH_CS_HIGH();
        SPI_FLASH_CS_LOW();
        SPI_FLASH_SWAPE(SPIFLASH_SR);
        SPI_FLASH_CS_HIGH();
        SPI_FLASH_CS_LOW();            
        SPI_FLASH_SWAPE(SPIFLASH_WSR);
        SPI_FLASH_SWAPE(0);//chip writeable     
        SPI_FLASH_CS_HIGH();                            
        for(cnt=0;cnt0;cnt++,dest++,size--){
            SPI_FLASH_CS_LOW();
            SPI_FLASH_SWAPE(SPIFLASH_WE);
            SPI_FLASH_CS_HIGH();
            SPI_FLASH_CS_LOW();
            SPI_FLASH_SWAPE(SPIFLASH_PP      );
            SPI_FLASH_SWAPE((INT8U)(dest>>16));
            SPI_FLASH_SWAPE((INT8U)(dest>> 8));
            SPI_FLASH_SWAPE((INT8U)(dest>> 0));
            SPI_FLASH_SWAPE(  *(p++)        );
            SPI_FLASH_CS_HIGH();
            fun_waitWEL();
        }
    }

    SPI_FLASH_CS_LOW();
    SPI_FLASH_SWAPE(SPIFLASH_WE);
    SPI_FLASH_CS_HIGH();        

    SPI_FLASH_CS_LOW();
    SPI_FLASH_SWAPE(SPIFLASH_SR);
    SPI_FLASH_CS_HIGH();            

    SPI_FLASH_CS_LOW();            
    SPI_FLASH_SWAPE(SPIFLASH_WSR);
    SPI_FLASH_SWAPE(temp);//    
    SPI_FLASH_CS_HIGH();            
    //
    return TRUE;
}
/*
* function erase data
* return Error code
* size = 256/512/1024/4096
SPIFLASH_SEC_SIZE
*/
BOOLEAN   spi_flash_EraseData        (INT32U addr,INT32U size)
{
    INT32U sos,eos;
    
    if( size == 0) return TRUE;
    
    //1.find the sector num
    sos = addr/SPIFLASH_SEC_SIZE;    
    //2.find the end of sector
    eos = (addr+size-1)/SPIFLASH_SEC_SIZE;
    //erase sector
    fun_flashEraseSector(sos,eos);
    
    return TRUE;
}

/* Layer specfication -------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------
--
-- This layer for initialization
--
-----------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------*/

/*
* function 
*/
INT32U spi_flashReadID(void)
{
    INT32U ID;
    SPI_FLASH_CS_LOW();
    SPI_FLASH_SWAPE(SPIFLASH_MID);
    SPI_FLASH_SWAPE(0x00);SPI_FLASH_SWAPE(0x00);SPI_FLASH_SWAPE(0x00);
    ID =  SPI_FLASH_SWAPE(0xff)<<8;   //manufacturer ID
    ID |= SPI_FLASH_SWAPE(0xff);      //Device ID
    SPI_FLASH_CS_HIGH();
    return ID;
}
void spi_flashReset(void)
{
    SPI_FLASH_CS_LOW();
    SPI_FLASH_SWAPE(SPIFLASH_ERST);
    SPI_FLASH_SWAPE(SPIFLASH_RST);
    SPI_FLASH_CS_HIGH();
}
#endif //#if     KIT_SPI_FLASH_EN

 

三、Flash读写测试

查看flash逻辑配置地址0x00080000 到0x00880000,一共8M字节,flash最小单元256字节。

ARM固件开发(LPC1768通过SPI接口快速读写flash,型号W25Q64FV)_第3张图片

使用memchk指令测试flash内存,测试地址为0x00080000,测试大小为10K字节。

测试结果flash读写正常,读写速率为5099.60字节/秒,约5Kb/s,读写速率和SPI速率优化也有关联,不同的初始化配置速率表现不同。

ARM固件开发(LPC1768通过SPI接口快速读写flash,型号W25Q64FV)_第4张图片

 

优化测试单元以及修改SPI速率重新测试,SPI flash读取速率约250Kb/s,写入约170Kb/s,FRAM的读写速率均为21Kb/s左右,如下图:

ARM固件开发(LPC1768通过SPI接口快速读写flash,型号W25Q64FV)_第5张图片

 

 

你可能感兴趣的:(ARM固件开发(LPC1768通过SPI接口快速读写flash,型号W25Q64FV))