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

#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);
}