FLASH读写----SPI

最近项目中用到FLASH作为数据存储,研究了下以SPI方式读写FLASH的基本方法与流程。

应用环境如下: 控制器     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);

}

}   

串口输出:



你可能感兴趣的:(STM32)