[C] 纯文本查看 复制代码 #include "at32_spiflash.h"
#define flash_spi_cs_low() gpio_bits_reset(FLASH_SPI_CS_GPIO, FLASH_SPI_CS_PIN)
#define flash_spi_cs_high() gpio_bits_set(FLASH_SPI_CS_GPIO, FLASH_SPI_CS_PIN)
#define flash_dummy_byte 0xff
#define flah_page_size 256
#define flah_sector_size 0x1000
static uint8_t flash_spi_readbyte(void);
static uint8_t flash_spi_sendbyte(uint8_t byte);
static void flash_spi_writeenable(void);
static void flash_spi_erasesector(uint32_t sectoraddr);
static void flash_spi_waitforwriteend(void);
static void flash_spi_writepage(uint8_t* pbuffer, uint32_t writeaddr, uint16_t numbytetowrite);
static uint32_t flash_spi_getid(void);
uint32_t spi_flash_size = 0x1000000;
uint32_t spi_flash_sectorsize = flah_sector_size;
uint32_t device_id = 0;
uint8_t gtmpbuff[4096] = {0};
/**
* @brief Initializes the peripherals used by the SPI FLASH driver.
* @param None
* @retval None
*/
void flash_spi_init(void)
{
gpio_init_type GPIO_InitStructure;
spi_init_type SPI_InitStruct;
/*RCC Config*/
crm_periph_clock_enable(CRM_SPI1_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
/*Configure SPI SCK pin*/
GPIO_InitStructure.gpio_pins = FLASH_SPI_SCK_PIN;
GPIO_InitStructure.gpio_mode = GPIO_MODE_MUX;
GPIO_InitStructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(FLASH_SPI_SCK_GPIO, &GPIO_InitStructure);
/*Configure SPI MISO pin*/
GPIO_InitStructure.gpio_pins = FLASH_SPI_MISO_PIN;
gpio_init(FLASH_SPI_MISO_GPIO, &GPIO_InitStructure);
/*Configure SPI MOSI pin*/
GPIO_InitStructure.gpio_pins = FLASH_SPI_MOSI_PIN;
gpio_init(FLASH_SPI_MOSI_GPIO, &GPIO_InitStructure);
/*Configure SPI CS pin*/
GPIO_InitStructure.gpio_mode = GPIO_MODE_OUTPUT;
GPIO_InitStructure.gpio_pins = FLASH_SPI_CS_PIN;
gpio_init(FLASH_SPI_CS_GPIO, &GPIO_InitStructure);
/*Deselect FLASH*/
flash_spi_cs_high();
/*SPI Configuration*/
SPI_InitStruct.transmission_mode = SPI_TRANSMIT_FULL_DUPLEX;
SPI_InitStruct.master_slave_mode = SPI_MODE_MASTER;
SPI_InitStruct.mclk_freq_division = SPI_MCLK_DIV_4;
SPI_InitStruct.frame_bit_num = SPI_FRAME_8BIT;
SPI_InitStruct.first_bit_transmission = SPI_FIRST_BIT_MSB;
SPI_InitStruct.cs_mode_selection = SPI_CS_SOFTWARE_MODE;
SPI_InitStruct.clock_polarity = SPI_CLOCK_POLARITY_HIGH;
SPI_InitStruct.clock_phase = SPI_CLOCK_PHASE_2EDGE;
spi_init(FLASH_SPI, &SPI_InitStruct);
spi_crc_polynomial_set(FLASH_SPI, 7);
/*Enable SPI*/
spi_enable(FLASH_SPI, TRUE);
device_id = flash_spi_getid();
if ( device_id == 0xef16 )
{
spi_flash_size = 0x800000; /*8m byte*/
}else if ( device_id == 0xef17 )
{
spi_flash_size = 0x1000000; /*16m byte*/
}else
{
spi_flash_size = 0;
}
}
/**
* @brief Sends a byte through the SPI interface and return the byte received
* from the SPI bus.
* @param byte: byte to send.
* @retval The value of the received byte.
*/
static uint8_t flash_spi_sendbyte(uint8_t byte)
{
/*!< Loop while DR register in not emplty */
while (spi_i2s_flag_get(FLASH_SPI, SPI_I2S_TDBE_FLAG) == RESET);
/*!< Send byte through the SPI1 peripheral */
spi_i2s_data_transmit(FLASH_SPI, byte);
/*!< Wait to receive a byte */
while (spi_i2s_flag_get(FLASH_SPI, SPI_I2S_RDBF_FLAG) == RESET);
/*!< Return the byte read from the SPI bus */
return spi_i2s_data_receive(FLASH_SPI);
}
/**
* @brief Reads a byte from the SPI Flash.
* @note This function must be used only if the Start_Read_Sequence function
* has been previously called.
* @param None
* @retval Byte Read from the SPI Flash.
*/
static uint8_t flash_spi_readbyte(void)
{
return (flash_spi_sendbyte(flash_dummy_byte));
}
/**
* @brief Enables the write access to the FLASH.
* @param None
* @retval None
*/
static void flash_spi_writeenable(void)
{
/*!< Select the FLASH: Chip Select low */
flash_spi_cs_low();
/*!< Send "Write Enable" instruction */
flash_spi_sendbyte(FLASH_CMD_WREN);
/*!< Deselect the FLASH: Chip Select high */
flash_spi_cs_high();
}
/**
* @brief Polls the status of the Write In Progress (WIP) flag in the FLASH's
* status register and loop until write opertaion has completed.
* @param None
* @retval None
*/
static void flash_spi_waitforwriteend(void)
{
uint8_t flashstatus = 0;
/*!< Select the FLASH: Chip Select low */
flash_spi_cs_low();
/*!< Send "Read Status Register" instruction */
flash_spi_sendbyte(FLASH_CMD_READSTS);
/*!< Loop as long as the memory is busy with a write cycle */
do
{
/*!< Send a dummy byte to generate the clock needed by the FLASH
and put the value of the status register in FLASH_Status variable */
flashstatus = flash_spi_sendbyte(flash_dummy_byte);
}
while ((flashstatus & 0x1) == SET); /* Write in progress */
/*!< Deselect the FLASH: Chip Select high */
flash_spi_cs_high();
}
/**
* @brief Erases the specified FLASH sector.
* @param SectorAddr: address of the sector to erase.
* @retval None
*/
static void flash_spi_erasesector(uint32_t sectoraddr)
{
/*!< send write enable instruction */
flash_spi_writeenable();
/*!< sector erase */
/*!< select the flash: chip select low */
flash_spi_cs_low();
/*!< send sector erase instruction */
flash_spi_sendbyte(FLASH_CMD_ERASE_SECTOR);
/*!< send sectoraddr high nibble address byte */
flash_spi_sendbyte((sectoraddr & 0xff0000) >> 16);
/*!< send sectoraddr medium nibble address byte */
flash_spi_sendbyte((sectoraddr & 0xff00) >> 8);
/*!< send sectoraddr low nibble address byte */
flash_spi_sendbyte(sectoraddr & 0xff);
/*!< deselect the flash: chip select high */
flash_spi_cs_high();
/*!< wait the end of flash writing */
flash_spi_waitforwriteend();
}
/**
* @brief Writes more than one byte to the FLASH with a single WRITE cycle
* (Page WRITE sequence).
* @note The number of byte can't exceed the FLASH page size.
* @param pBuffer: pointer to the buffer containing the data to be written
* to the FLASH.
* @param WriteAddr: FLASH's internal address to write to.
* @param NumByteToWrite: number of bytes to write to the FLASH, must be equal
* or less than "sFLASH_PAGESIZE" value.
* @retval None
*/
static void flash_spi_writepage(uint8_t* pbuffer, uint32_t writeaddr, uint16_t numbytetowrite)
{
/*!< enable the write access to the flash */
flash_spi_writeenable();
/*!< select the flash: chip select low */
flash_spi_cs_low();
/*!< send "write to memory " instruction */
flash_spi_sendbyte(FLASH_CMD_WRITEPAGE);
/*!< send writeaddr high nibble address byte to write to */
flash_spi_sendbyte((writeaddr & 0xff0000) >> 16);
/*!< send writeaddr medium nibble address byte to write to */
flash_spi_sendbyte((writeaddr & 0xff00) >> 8);
/*!< send writeaddr low nibble address byte to write to */
flash_spi_sendbyte(writeaddr & 0xff);
/*!< while there is data to be written on the flash */
while (numbytetowrite--)
{
/*!< send the current byte */
flash_spi_sendbyte(*pbuffer);
/*!< point on the next byte to be written */
pbuffer++;
}
/*!< deselect the flash: chip select high */
flash_spi_cs_high();
/*!< wait the end of flash writing */
flash_spi_waitforwriteend();
}
/**
* @brief Writes block of data to the FLASH. In this function, the number of
* WRITE cycles are reduced, using Page WRITE sequence.
* @param pBuffer: pointer to the buffer containing the data to be written
* to the FLASH.
* @param WriteAddr: FLASH's internal address to write to.
* @param NumByteToWrite: number of bytes to write to the FLASH.
* @retval None
*/
void flash_spi_writebuffer(uint8_t* pbuffer, uint32_t writeaddr, uint16_t numbytetowrite)
{
uint16_t pager;
pager = flah_page_size - (writeaddr % flah_page_size);
if ( numbytetowrite <= pager )
{
pager = numbytetowrite;
}
while ( 1 )
{
flash_spi_writepage(pbuffer, writeaddr, pager);
if ( pager == numbytetowrite )
break;
else
{
pbuffer += pager;
writeaddr += pager;
numbytetowrite -= pager;
if ( numbytetowrite > flah_page_size )
pager = flah_page_size;
else
pager = numbytetowrite;
}
}
}
/**
* @brief Reads a block of data from the FLASH.
* @param pBuffer: pointer to the buffer that receives the data read from the FLASH.
* @param ReadAddr: FLASH's internal address to read from.
* @param NumByteToRead: number of bytes to read from the FLASH.
* @retval None
*/
void flash_spi_read(uint8_t* pbuffer, uint32_t readaddr, uint16_t numbytetoread)
{
/*!< select the flash: chip select low */
flash_spi_cs_low();
/*!< send "read from memory " instruction */
flash_spi_sendbyte(FLASH_CMD_READPAGE);
/*!< send readaddr high nibble address byte to read from */
flash_spi_sendbyte((readaddr & 0xff0000) >> 16);
/*!< send readaddr medium nibble address byte to read from */
flash_spi_sendbyte((readaddr& 0xff00) >> 8);
/*!< send readaddr low nibble address byte to read from */
flash_spi_sendbyte(readaddr & 0xff);
while (numbytetoread--) /*!< while there is data to be read */
{
/*!< read a byte from the flash */
*pbuffer = flash_spi_sendbyte(flash_dummy_byte);
/*!< point to the next location where the byte read will be saved */
pbuffer++;
}
/*!< deselect the flash: chip select high */
flash_spi_cs_high();
}
/**
* @brief Writes block of data to the FLASH. In this function, the number of
* WRITE cycles are reduced, using Page WRITE sequence.
* @param pBuffer: pointer to the buffer containing the data to be written
* to the FLASH.
* @param WriteAddr: FLASH's internal address to write to.
* @param NumByteToWrite: number of bytes to write to the FLASH.
* @retval None
*/
void flash_spi_write(uint8_t* pbuffer, uint32_t writeaddr, uint16_t numbytetowrite)
{
uint32_t cnt = 0;
uint32_t sectornum, sectoroffset, sectorremain;
sectornum = writeaddr / flah_sector_size;
sectoroffset = writeaddr % flah_sector_size;
sectorremain = flah_sector_size - sectoroffset;
if ( numbytetowrite <= sectorremain)
{
sectorremain = numbytetowrite;
}
while ( 1 )
{
/*read all sector data*/
flash_spi_read(gtmpbuff, sectornum * flah_sector_size, flah_sector_size);
/*check data is 0xff ?*/
for ( cnt = 0; cnt < sectorremain; cnt ++ )
{
if ( gtmpbuff[sectoroffset + cnt] != 0xff)
break;
}
if ( cnt < sectorremain ) /*need sector erase*/
{
flash_spi_erasesector(sectornum * flah_sector_size);
for ( cnt = 0; cnt < sectorremain; cnt ++ )
gtmpbuff[cnt + sectoroffset] = pbuffer[cnt];
flash_spi_writebuffer(gtmpbuff, sectornum * flah_sector_size, flah_sector_size);
}
else
{
flash_spi_writebuffer(pbuffer, writeaddr, sectorremain);
}
if ( sectorremain == numbytetowrite )
break;
else
{
sectornum ++;
sectoroffset = 0;
pbuffer += sectorremain;
writeaddr += sectorremain;
numbytetowrite -= sectorremain;
if ( numbytetowrite > flah_sector_size )
{
sectorremain = flah_sector_size;
}
else
{
sectorremain = numbytetowrite;
}
}
}
}
/**
* @brief Reads FLASH identification.
* @param None
* @retval FLASH identification
*/
uint32_t flash_spi_getid(void)
{
/*用户可根据不同flash采用不同的指令获取id*/
uint16_t flash_id = 0;
flash_spi_cs_low();
flash_spi_sendbyte(FLASH_GETID);
flash_spi_sendbyte(0x00);
flash_spi_sendbyte(0x00);
flash_spi_sendbyte(0x00);
flash_id |= flash_spi_readbyte() << 8;
flash_id |= flash_spi_readbyte();
flash_spi_cs_high();
return flash_id;
}
/**
* @brief Get FLASH SIZE.
* @param None
* @retval FLASH identification
*/
uint32_t flash_spi_getsize(void)
{
return spi_flash_size;
}
/**
* @brief Get FLASH Sector SIZE.
* @param None
* @retval FLASH identification
*/
uint32_t flash_spi_sectorsize(void)
{
return spi_flash_sectorsize; /*4k*/
}
/**
* @brief Get FLASH Page SIZE.
* @param None
* @retval FLASH identification
*/
uint32_t flash_spi_pagesize(void)
{
//return flah_page_size; /*256byte*/
return 4096; /*可根据代码配置usb buffer 一次可以接受多少数据, 最大4k*/
}
上面是总的程序,下面两个代码段是从上摘出来的
[C] 纯文本查看 复制代码 void flash_spi_writebuffer(uint8_t* pbuffer, uint32_t writeaddr, uint16_t numbytetowrite)
{
uint16_t pager;
pager = flah_page_size - (writeaddr % flah_page_size);
if ( numbytetowrite <= pager )
{
pager = numbytetowrite;
}
while ( 1 )
{
flash_spi_writepage(pbuffer, writeaddr, pager);
if ( pager == numbytetowrite )
break;
else
{
pbuffer += pager;
writeaddr += pager;
numbytetowrite -= pager;
if ( numbytetowrite > flah_page_size )
pager = flah_page_size;
else
pager = numbytetowrite;
}
}
}
第一段
[C] 纯文本查看 复制代码 void flash_spi_write(uint8_t* pbuffer, uint32_t writeaddr, uint16_t numbytetowrite)
{
uint32_t cnt = 0;
uint32_t sectornum, sectoroffset, sectorremain;
sectornum = writeaddr / flah_sector_size;
sectoroffset = writeaddr % flah_sector_size;
sectorremain = flah_sector_size - sectoroffset;
if ( numbytetowrite <= sectorremain)
{
sectorremain = numbytetowrite;
}
while ( 1 )
{
/*read all sector data*/
flash_spi_read(gtmpbuff, sectornum * flah_sector_size, flah_sector_size);
/*check data is 0xff ?*/
for ( cnt = 0; cnt < sectorremain; cnt ++ )
{
if ( gtmpbuff[sectoroffset + cnt] != 0xff)
break;
}
if ( cnt < sectorremain ) /*need sector erase*/
{
flash_spi_erasesector(sectornum * flah_sector_size);
for ( cnt = 0; cnt < sectorremain; cnt ++ )
gtmpbuff[cnt + sectoroffset] = pbuffer[cnt];
flash_spi_writebuffer(gtmpbuff, sectornum * flah_sector_size, flah_sector_size);
}
else
{
flash_spi_writebuffer(pbuffer, writeaddr, sectorremain);
}
if ( sectorremain == numbytetowrite )
break;
else
{
sectornum ++;
sectoroffset = 0;
pbuffer += sectorremain;
writeaddr += sectorremain;
numbytetowrite -= sectorremain;
if ( numbytetowrite > flah_sector_size )
{
sectorremain = flah_sector_size;
}
else
{
sectorremain = numbytetowrite;
}
}
}
}
第二段
spi flash 不是输入一个地址后一直写的话地址会自动增加嘛,为什么还要去区分是哪个扇区的呢?
|