You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
179 lines
6.3 KiB
179 lines
6.3 KiB
6 years ago
|
#include "spi_flash.h"
|
||
|
|
||
|
#define FLASH_CMD_READID 0x9f
|
||
|
#define FLASH_DUMMY_BYTE 0xA5
|
||
|
#define FLASH_CMD_WREN 0x06 /* Write enable instruction */
|
||
|
#define FLASH_CMD_SE 0xD8 /* Sector Erase instruction */
|
||
|
#define FLASH_CMD_RDSR 0x05 /* Read Status Register instruction */
|
||
|
#define FLASH_CMD_WRITE 0x02 /* Write to Memory instruction */
|
||
|
#define FLASH_CMD_READ 0x03 /* Read from Memory instruction */
|
||
|
|
||
|
#define FLASH_WIP_FLAG 0x01 /* Write In Progress (WIP) flag */
|
||
|
unsigned int spi_flash_read_id(spi_t spi)
|
||
|
{
|
||
|
unsigned int id = 0xffffff;
|
||
|
uint8_t tx[4] = {FLASH_CMD_READID, FLASH_DUMMY_BYTE, FLASH_DUMMY_BYTE, FLASH_DUMMY_BYTE};
|
||
|
uint8_t rx[4] = {0};
|
||
|
|
||
|
spi_transfer(spi, tx, rx, sizeof tx);
|
||
|
id = (rx[1] << 16) | (rx[2] << 8) | rx[3];
|
||
|
|
||
|
return (id);
|
||
|
}
|
||
|
|
||
|
void spi_flash_enable_write(spi_t spi)
|
||
|
{
|
||
|
spi_send_byte(spi, FLASH_CMD_WREN);
|
||
|
}
|
||
|
|
||
|
static void wait_for_write_end(spi_t spi)
|
||
|
{
|
||
|
uint8_t flashstatus = 0;
|
||
|
|
||
|
/*!< Send "Read Status Register" instruction */
|
||
|
spi_cs(spi, SPI_CS_LOW);
|
||
|
spi_txrx(spi, FLASH_CMD_RDSR);
|
||
|
|
||
|
/*!< 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 = spi_txrx(spi, FLASH_DUMMY_BYTE);
|
||
|
} while ((flashstatus & FLASH_WIP_FLAG) != 0); /* Write in progress */
|
||
|
spi_cs(spi, SPI_CS_HIGH);
|
||
|
}
|
||
|
|
||
|
int spi_flash_erase_sector(spi_t spi, unsigned int SectorAddr)
|
||
|
{
|
||
|
uint8_t cmd[4] = {FLASH_CMD_SE};
|
||
|
/*!< Send write enable instruction */
|
||
|
spi_flash_enable_write(spi);
|
||
|
|
||
|
/*!< Sector Erase */
|
||
|
/*!< Send SectorAddr high nibble address byte */
|
||
|
cmd[1] = (SectorAddr & 0xFF0000) >> 16;
|
||
|
/*!< Send SectorAddr medium nibble address byte */
|
||
|
cmd[2] = (SectorAddr & 0xFF00) >> 8;
|
||
|
/*!< Send SectorAddr low nibble address byte */
|
||
|
cmd[3] = SectorAddr & 0xFF;
|
||
|
spi_transfer(spi, cmd, 0, sizeof cmd);
|
||
|
|
||
|
/*!< Wait the end of Flash writing */
|
||
|
wait_for_write_end(spi);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void spi_flash_write_page(spi_t spi, unsigned int WriteAddr, const uint8_t* pBuffer, uint16_t NumByteToWrite)
|
||
|
{
|
||
|
/*!< Enable the write access to the FLASH */
|
||
|
spi_flash_enable_write(spi);
|
||
|
|
||
|
/*!< Select the FLASH: Chip Select low */
|
||
|
spi_cs(spi, SPI_CS_LOW);
|
||
|
/*!< Send "Write to Memory " instruction */
|
||
|
spi_txrx(spi, FLASH_CMD_WRITE);
|
||
|
/*!< Send WriteAddr high nibble address byte to write to */
|
||
|
spi_txrx(spi, (WriteAddr & 0xFF0000) >> 16);
|
||
|
/*!< Send WriteAddr medium nibble address byte to write to */
|
||
|
spi_txrx(spi, (WriteAddr & 0xFF00) >> 8);
|
||
|
/*!< Send WriteAddr low nibble address byte to write to */
|
||
|
spi_txrx(spi, WriteAddr & 0xFF);
|
||
|
|
||
|
/*!< while there is data to be written on the FLASH */
|
||
|
while (NumByteToWrite--) {
|
||
|
/*!< Send the current byte */
|
||
|
spi_txrx(spi, *pBuffer);
|
||
|
/*!< Point on the next byte to be written */
|
||
|
pBuffer++;
|
||
|
}
|
||
|
|
||
|
/*!< Deselect the FLASH: Chip Select high */
|
||
|
spi_cs(spi, SPI_CS_HIGH);
|
||
|
|
||
|
/*!< Wait the end of Flash writing */
|
||
|
wait_for_write_end(spi);
|
||
|
}
|
||
|
|
||
|
void spi_flash_write(spi_t spi, uint32_t WriteAddr, const uint8_t* pBuffer, uint16_t NumByteToWrite)
|
||
|
{
|
||
|
uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
|
||
|
|
||
|
Addr = WriteAddr % TARGET_SPI_FLASH_PAGE_SIZE;
|
||
|
count = TARGET_SPI_FLASH_PAGE_SIZE - Addr;
|
||
|
NumOfPage = NumByteToWrite / TARGET_SPI_FLASH_PAGE_SIZE;
|
||
|
NumOfSingle = NumByteToWrite % TARGET_SPI_FLASH_PAGE_SIZE;
|
||
|
|
||
|
if (Addr == 0) { /*!< WriteAddr is sFLASH_PAGESIZE aligned */
|
||
|
if (NumOfPage == 0) { /*!< NumByteToWrite < sFLASH_PAGESIZE */
|
||
|
spi_flash_write_page(spi, WriteAddr, pBuffer, NumByteToWrite);
|
||
|
} else { /*!< NumByteToWrite > sFLASH_PAGESIZE */
|
||
|
while (NumOfPage--) {
|
||
|
spi_flash_write_page(spi, WriteAddr, pBuffer, TARGET_SPI_FLASH_PAGE_SIZE);
|
||
|
WriteAddr += TARGET_SPI_FLASH_PAGE_SIZE;
|
||
|
pBuffer += TARGET_SPI_FLASH_PAGE_SIZE;
|
||
|
}
|
||
|
|
||
|
spi_flash_write_page(spi, WriteAddr, pBuffer, NumOfSingle);
|
||
|
}
|
||
|
} else { /*!< WriteAddr is not sFLASH_PAGESIZE aligned */
|
||
|
if (NumOfPage == 0) { /*!< NumByteToWrite < sFLASH_PAGESIZE */
|
||
|
if (NumOfSingle > count) { /*!< (NumByteToWrite + WriteAddr) > sFLASH_PAGESIZE */
|
||
|
temp = NumOfSingle - count;
|
||
|
|
||
|
spi_flash_write_page(spi, WriteAddr, pBuffer, count);
|
||
|
WriteAddr += count;
|
||
|
pBuffer += count;
|
||
|
|
||
|
spi_flash_write_page(spi, WriteAddr, pBuffer, temp);
|
||
|
} else {
|
||
|
spi_flash_write_page(spi, WriteAddr, pBuffer, NumByteToWrite);
|
||
|
}
|
||
|
} else { /*!< NumByteToWrite > sFLASH_PAGESIZE */
|
||
|
NumByteToWrite -= count;
|
||
|
NumOfPage = NumByteToWrite / TARGET_SPI_FLASH_PAGE_SIZE;
|
||
|
NumOfSingle = NumByteToWrite % TARGET_SPI_FLASH_PAGE_SIZE;
|
||
|
|
||
|
spi_flash_write_page(spi, WriteAddr, pBuffer, count);
|
||
|
WriteAddr += count;
|
||
|
pBuffer += count;
|
||
|
|
||
|
while (NumOfPage--) {
|
||
|
spi_flash_write_page(spi, WriteAddr, pBuffer, TARGET_SPI_FLASH_PAGE_SIZE);
|
||
|
WriteAddr += TARGET_SPI_FLASH_PAGE_SIZE;
|
||
|
pBuffer += TARGET_SPI_FLASH_PAGE_SIZE;
|
||
|
}
|
||
|
|
||
|
if (NumOfSingle != 0) {
|
||
|
spi_flash_write_page(spi, WriteAddr, pBuffer, NumOfSingle);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void spi_flash_read(spi_t spi, unsigned int ReadAddr, uint8_t* pBuffer, uint16_t NumByteToRead)
|
||
|
{
|
||
|
/*!< Select the FLASH: Chip Select low */
|
||
|
spi_cs(spi, SPI_CS_LOW);
|
||
|
|
||
|
/*!< Send "Read from Memory " instruction */
|
||
|
spi_txrx(spi, FLASH_CMD_READ);
|
||
|
|
||
|
/*!< Send ReadAddr high nibble address byte to read from */
|
||
|
spi_txrx(spi, (ReadAddr & 0xFF0000) >> 16);
|
||
|
/*!< Send ReadAddr medium nibble address byte to read from */
|
||
|
spi_txrx(spi, (ReadAddr& 0xFF00) >> 8);
|
||
|
/*!< Send ReadAddr low nibble address byte to read from */
|
||
|
spi_txrx(spi, ReadAddr & 0xFF);
|
||
|
|
||
|
while (NumByteToRead--) {/*!< while there is data to be read */
|
||
|
/*!< Read a byte from the FLASH */
|
||
|
*pBuffer = spi_txrx(spi, FLASH_DUMMY_BYTE);
|
||
|
/*!< Point to the next location where the byte read will be saved */
|
||
|
pBuffer++;
|
||
|
}
|
||
|
|
||
|
/*!< Deselect the FLASH: Chip Select high */
|
||
|
spi_cs(spi, SPI_CS_HIGH);
|
||
|
}
|
||
|
|