一、外部Flash的硬件接口
二、固件程序设计
2.1SPI接口初始化
/* Layer specfication --------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------- -- -- This layer for W25Q64FV SPI flash -- 2013 04 22 : -- Update. -- 2013 04 25 : -- 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 : -- Update. -- 2013 04 25 : -- 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<size;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;cnt<SPIFLASH_SEC_SIZE && size>0;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字节。
使用memchk指令测试flash内存,测试地址为0x00080000,测试大小为10K字节。
测试结果flash读写正常,读写速率为5099.60字节/秒,约5Kb/s,读写速率和SPI速率优化也有关联,不同的初始化配置速率表现不同。
优化测试单元以及修改SPI速率重新测试,SPI flash读取速率约250Kb/s,写入约170Kb/s,FRAM的读写速率均为21Kb/s左右,如下图: