503 lines
11 KiB
C
503 lines
11 KiB
C
/*
|
||
*********************************************************************************************************
|
||
* IAR Development Kits
|
||
* on the
|
||
*
|
||
* M451
|
||
*
|
||
* Filename : spi_flash.c
|
||
* Version : V1.00
|
||
* Programmer(s) : Qian Xianghong
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
#include "includes.h"
|
||
|
||
// Flash操作命令码
|
||
#define SFLASH_OP_WREN 0x06 // Write Enable
|
||
#define SFLASH_OP_WRDI 0x04 // Write Disable
|
||
#define SFLASH_OP_RDSR 0x05 // Read Status Register
|
||
#define SFLASH_OP_WRSR 0x01 // Write Status Register
|
||
#define SFLASH_OP_READ 0x03 // Read Memory
|
||
#define SFLASH_OP_FSTRD 0x0B // Read Memory at Higher Speed
|
||
#define SFLASH_OP_PP 0x02 // Page Program
|
||
#define SFLASH_OP_DPD 0xB9 // Deep Power-down Mode
|
||
#define SFLASH_OP_RDID 0x9F // JEDEC-ID Read
|
||
#define SFLASH_OP_PE 0x81 // Erase 256 Bytes of Memory Array
|
||
#define SFLASH_OP_SE 0x20 // Erase 4 KBytes of Memory Array
|
||
#define SFLASH_OP_CE 0xC7 // Erase Full Array
|
||
#define SFLASH_OP_ULBPR 0x98 // Global Block Protection Unlock
|
||
|
||
// Flash状态寄存器(SR)写允许(WEL)标志位
|
||
#define SFLASH_WEL_Pos 1
|
||
#define SFLASH_WEL_Msk (0x01 << SFLASH_WEL_Pos)
|
||
|
||
// Flash状态寄存器(SR)Busy标志位
|
||
#define SFLASH_BUSY_Pos 0
|
||
#define SFLASH_BUSY_Msk (0x01 << SFLASH_BUSY_Pos)
|
||
|
||
// 写Flash缓冲
|
||
uint8_t SFlash_wtBuf[SFLASH_ERASE_SIZE];
|
||
//uint8_t *SFlash_wtBuf; // 放在扩展内存
|
||
|
||
// 读Flash全局缓冲
|
||
uint8_t SFlash_rdBuf[SFLASH_ERASE_SIZE];
|
||
//uint8_t *SFlash_rdBuf; // 放在扩展内存
|
||
|
||
void SFlash_Init()
|
||
{
|
||
SYS->PC_H_MFP &= ~(SYS_PC_H_MFP_PC8_MFP_Msk | SYS_PC_H_MFP_PC9_MFP_Msk | SYS_PC_H_MFP_PC10_MFP_Msk | SYS_PC_H_MFP_PC11_MFP_Msk);
|
||
SYS->PC_H_MFP |= (SYS_PC_H_MFP_PC8_MFP_SPI1_SS0 | SYS_PC_H_MFP_PC9_MFP_SPI1_SCLK | SYS_PC_H_MFP_PC10_MFP_SPI1_MISO0 | SYS_PC_H_MFP_PC11_MFP_SPI1_MOSI0);
|
||
|
||
// 允许外设时钟
|
||
CLK_EnableModuleClock(SPI1_MODULE);
|
||
}
|
||
|
||
void SFlash_Open()
|
||
{
|
||
// 分配扩展内存
|
||
// SFlash_rdBuf = SRAM_Alloc(SFLASH_ERASE_SIZE);
|
||
// SFlash_wtBuf = SRAM_Alloc(SFLASH_ERASE_SIZE);
|
||
|
||
/*---------------------------------------------------------------------------------------------------------*/
|
||
/* Init SPI */
|
||
/*---------------------------------------------------------------------------------------------------------*/
|
||
/* Configure SPI1 as a master, SPI clock rate 36 MHz,
|
||
clock idle low, 8-bit transaction, drive output on falling clock edge and latch input on rising edge. */
|
||
SPI_Open(SPI1, SPI_MASTER, SPI_MODE_0, 8, 36000000ul);
|
||
|
||
/* Disable the automatic hardware slave selection function. */
|
||
SPI_DisableAutoSS(SPI1);
|
||
SPI_SET_MSB_FIRST(SPI1);
|
||
|
||
/* Set TX FIFO threshold, enable TX FIFO threshold interrupt and RX FIFO time-out interrupt */
|
||
SPI_EnableFIFO(SPI1, 1, 1);
|
||
}
|
||
|
||
void SFlash_ReadID()
|
||
{
|
||
uint8_t i;
|
||
|
||
__disable_irq();
|
||
|
||
SPI_SET_SS0_LOW(SPI1);
|
||
|
||
SPI_WRITE_TX0(SPI1, SFLASH_OP_RDID);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
|
||
printf("\nFlash ID is: ");
|
||
for(i = 0; i < 3; i++)
|
||
{
|
||
SPI_WRITE_TX0(SPI1, 0); // 提供CLK
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
printf(" %02X", SPI_READ_RX0(SPI1));
|
||
}
|
||
printf("\n");
|
||
|
||
SPI_SET_SS0_HIGH(SPI1);
|
||
|
||
__enable_irq();
|
||
}
|
||
|
||
uint8_t SFlash_UnlockBPR()
|
||
{
|
||
__disable_irq();
|
||
|
||
SFlash_WriteEN();
|
||
|
||
SPI_SET_SS0_LOW(SPI1);
|
||
|
||
// Write Enabled
|
||
SPI_WRITE_TX0(SPI1, SFLASH_OP_ULBPR);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
|
||
SPI_SET_SS0_HIGH(SPI1);
|
||
|
||
__enable_irq();
|
||
|
||
return 1;
|
||
}
|
||
|
||
uint8_t SFlash_WriteEN()
|
||
{
|
||
uint8_t SR = 0x00;
|
||
|
||
SPI_SET_SS0_LOW(SPI1);
|
||
|
||
// Write Enabled
|
||
SPI_WRITE_TX0(SPI1, SFLASH_OP_WREN);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
|
||
SPI_SET_SS0_HIGH(SPI1);
|
||
|
||
// Read SR
|
||
SPI_SET_SS0_LOW(SPI1);
|
||
|
||
SPI_WRITE_TX0(SPI1, SFLASH_OP_RDSR);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
|
||
SPI_WRITE_TX0(SPI1, 0); // 提供CLK
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SR = SPI_READ_RX0(SPI1);
|
||
|
||
SPI_SET_SS0_HIGH(SPI1);
|
||
|
||
// Check WEL
|
||
if(SR & SFLASH_WEL_Msk)
|
||
return 1;
|
||
printf("\nWrite enable failed\n");
|
||
return 0;
|
||
}
|
||
|
||
uint8_t SFlash_WriteDI()
|
||
{
|
||
uint8_t SR = 0xFF;
|
||
|
||
SPI_SET_SS0_LOW(SPI1);
|
||
|
||
// Write Enabled
|
||
SPI_WRITE_TX0(SPI1, SFLASH_OP_WRDI);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
|
||
SPI_SET_SS0_HIGH(SPI1);
|
||
|
||
// Read SR
|
||
SPI_SET_SS0_LOW(SPI1);
|
||
|
||
SPI_WRITE_TX0(SPI1, SFLASH_OP_RDSR);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
|
||
SPI_WRITE_TX0(SPI1, 0); // 提供CLK
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SR = SPI_READ_RX0(SPI1);
|
||
|
||
SPI_SET_SS0_HIGH(SPI1);
|
||
|
||
// Check WEL
|
||
if(SR & SFLASH_WEL_Msk)
|
||
{
|
||
printf("\nWrite disable failed\n");
|
||
return 0;
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
uint32_t SFlash_BufferRead(uint32_t Addr, uint8_t *buf, uint32_t nbytes)
|
||
{
|
||
uint32_t i;
|
||
|
||
__disable_irq();
|
||
|
||
SPI_SET_SS0_LOW(SPI1);
|
||
|
||
// Read
|
||
SPI_WRITE_TX0(SPI1, SFLASH_OP_READ);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
// address highest byte
|
||
SPI_WRITE_TX0(SPI1, (Addr >> 16) & 0xFF);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
// address high byte
|
||
SPI_WRITE_TX0(SPI1, (Addr >> 8) & 0xFF);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
// address low byte
|
||
SPI_WRITE_TX0(SPI1, Addr & 0xFF);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
// data
|
||
for(i = 0; i < nbytes && Addr + i < SFLASH_SIZE; i++)
|
||
{
|
||
SPI_WRITE_TX0(SPI1, 0); // 提供CLK
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
buf[i] = SPI_READ_RX0(SPI1);
|
||
}
|
||
|
||
SPI_SET_SS0_HIGH(SPI1);
|
||
|
||
__enable_irq();
|
||
|
||
return i;
|
||
}
|
||
|
||
void SFlash_PageErase(uint32_t Addr)
|
||
{
|
||
uint8_t SR = 0xFF;
|
||
|
||
SPI_SET_SS0_LOW(SPI1);
|
||
|
||
// Sector erase
|
||
SPI_WRITE_TX0(SPI1, SFLASH_OP_PE);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
// address highest byte
|
||
SPI_WRITE_TX0(SPI1, (Addr >> 16) & 0xFF);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
// address high byte
|
||
SPI_WRITE_TX0(SPI1, (Addr >> 8) & 0xFF);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
// address low byte
|
||
SPI_WRITE_TX0(SPI1, Addr & 0xFF);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
|
||
SPI_SET_SS0_HIGH(SPI1);
|
||
|
||
// Read SR
|
||
do
|
||
{
|
||
SPI_SET_SS0_LOW(SPI1);
|
||
|
||
SPI_WRITE_TX0(SPI1, SFLASH_OP_RDSR);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
|
||
SPI_WRITE_TX0(SPI1, 0); // 提供CLK
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SR = SPI_READ_RX0(SPI1);
|
||
|
||
SPI_SET_SS0_HIGH(SPI1);
|
||
} while(SR & SFLASH_BUSY_Msk);
|
||
}
|
||
|
||
void SFlash_SectorErase(uint32_t Addr)
|
||
{
|
||
uint8_t SR = 0xFF;
|
||
|
||
SPI_SET_SS0_LOW(SPI1);
|
||
|
||
// Sector erase
|
||
SPI_WRITE_TX0(SPI1, SFLASH_OP_SE);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
// address highest byte
|
||
SPI_WRITE_TX0(SPI1, (Addr >> 16) & 0xFF);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
// address high byte
|
||
SPI_WRITE_TX0(SPI1, (Addr >> 8) & 0xFF);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
// address low byte
|
||
SPI_WRITE_TX0(SPI1, Addr & 0xFF);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
|
||
SPI_SET_SS0_HIGH(SPI1);
|
||
|
||
// Read SR
|
||
do
|
||
{
|
||
SPI_SET_SS0_LOW(SPI1);
|
||
|
||
SPI_WRITE_TX0(SPI1, SFLASH_OP_RDSR);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
|
||
SPI_WRITE_TX0(SPI1, 0); // 提供CLK
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SR = SPI_READ_RX0(SPI1);
|
||
|
||
SPI_SET_SS0_HIGH(SPI1);
|
||
} while(SR & SFLASH_BUSY_Msk);
|
||
}
|
||
|
||
void SFlash_ChipErase()
|
||
{
|
||
uint8_t SR = 0xFF;
|
||
|
||
SPI_SET_SS0_LOW(SPI1);
|
||
|
||
// Chip erase
|
||
SPI_WRITE_TX0(SPI1, SFLASH_OP_CE);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
|
||
SPI_SET_SS0_HIGH(SPI1);
|
||
|
||
// Read SR
|
||
do
|
||
{
|
||
SPI_SET_SS0_LOW(SPI1);
|
||
|
||
SPI_WRITE_TX0(SPI1, SFLASH_OP_RDSR);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
|
||
SPI_WRITE_TX0(SPI1, 0); // 提供CLK
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SR = SPI_READ_RX0(SPI1);
|
||
|
||
SPI_SET_SS0_HIGH(SPI1);
|
||
} while(SR & SFLASH_BUSY_Msk);
|
||
}
|
||
|
||
uint16_t SFlash_PageProgram(uint32_t Addr, uint8_t *buf)
|
||
{
|
||
uint8_t SR = 0xFF;
|
||
uint16_t i;
|
||
|
||
SPI_SET_SS0_LOW(SPI1);
|
||
|
||
// Page grogram
|
||
SPI_WRITE_TX0(SPI1, SFLASH_OP_PP);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
// address highest byte
|
||
SPI_WRITE_TX0(SPI1, (Addr >> 16) & 0xFF);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
// address high byte
|
||
SPI_WRITE_TX0(SPI1, (Addr >> 8) & 0xFF);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
// address low byte
|
||
SPI_WRITE_TX0(SPI1, Addr & 0xFF);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
// data
|
||
for(i = 0; i < SFLASH_PAGE_SIZE && Addr + i < SFLASH_SIZE; i++)
|
||
{
|
||
SPI_WRITE_TX0(SPI1, buf[i]);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
}
|
||
|
||
SPI_SET_SS0_HIGH(SPI1);
|
||
|
||
// Read SR
|
||
do
|
||
{
|
||
SPI_SET_SS0_LOW(SPI1);
|
||
|
||
SPI_WRITE_TX0(SPI1, SFLASH_OP_RDSR);
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SPI_READ_RX0(SPI1);
|
||
|
||
SPI_WRITE_TX0(SPI1, 0); // 提供CLK
|
||
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI1));
|
||
SR = SPI_READ_RX0(SPI1);
|
||
|
||
SPI_SET_SS0_HIGH(SPI1);
|
||
} while(SR & SFLASH_BUSY_Msk);
|
||
|
||
return i;
|
||
}
|
||
|
||
uint16_t SFlash_SectorProgram(uint32_t Addr, uint8_t *buf)
|
||
{
|
||
uint16_t i = 0;
|
||
uint16_t j;
|
||
|
||
for(j = 0; j < SFLASH_ERASE_SIZE; j += SFLASH_PAGE_SIZE)
|
||
{
|
||
__disable_irq();
|
||
SFlash_WriteEN();
|
||
i += SFlash_PageProgram(Addr + j, buf + j);
|
||
__enable_irq();
|
||
}
|
||
|
||
return i;
|
||
}
|
||
|
||
uint32_t SFlash_BufferWrite(uint32_t Addr, uint8_t *buf, uint32_t nbytes)
|
||
{
|
||
uint32_t count, offset;
|
||
|
||
while(nbytes > 0)
|
||
{
|
||
// 计算页内偏移(只有第一页有可能非0)
|
||
offset = Addr % SFLASH_ERASE_SIZE;
|
||
|
||
// 计算一页内写入字节数
|
||
count = SFLASH_ERASE_SIZE - offset;
|
||
if(count > nbytes)
|
||
count = nbytes;
|
||
|
||
// 页对齐
|
||
Addr -= offset;
|
||
// 读本页内数据
|
||
SFlash_BufferRead(Addr, SFlash_wtBuf, SFLASH_ERASE_SIZE);
|
||
// 如果数据一致,不用写
|
||
if(memcmp(SFlash_wtBuf + offset, buf, count) != 0)
|
||
{
|
||
// 擦除本页
|
||
__disable_irq();
|
||
SFlash_WriteEN();
|
||
SFlash_PageErase(Addr);
|
||
__enable_irq();
|
||
|
||
// 修改数据
|
||
memcpy(SFlash_wtBuf + offset, buf, count);
|
||
|
||
// 写入本页数据
|
||
__disable_irq();
|
||
SFlash_WriteEN();
|
||
SFlash_PageProgram(Addr, SFlash_wtBuf);
|
||
__enable_irq();
|
||
}
|
||
|
||
// 计算下一页
|
||
Addr += SFLASH_ERASE_SIZE;
|
||
buf += count;
|
||
nbytes -= count;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
uint32_t SFlash_BufferVerify(uint32_t Addr, uint8_t *buf, uint32_t nbytes)
|
||
{
|
||
uint32_t data_len;
|
||
|
||
while(nbytes > 0)
|
||
{
|
||
if(nbytes > SFLASH_ERASE_SIZE)
|
||
data_len = SFLASH_ERASE_SIZE;
|
||
else
|
||
data_len = nbytes;
|
||
|
||
SFlash_BufferRead(Addr, SFlash_wtBuf, data_len);
|
||
if(memcmp(SFlash_wtBuf, buf, data_len) != 0)
|
||
return FALSE;
|
||
|
||
// 计算下一页
|
||
Addr += data_len;
|
||
buf += data_len;
|
||
nbytes -= data_len;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
uint16_t do_sflash_crc(unsigned long base_addr, long len)
|
||
{
|
||
unsigned short crc = 0;
|
||
unsigned short data_len;
|
||
|
||
while(len > 0)
|
||
{
|
||
if(len > SFLASH_ERASE_SIZE)
|
||
data_len = SFLASH_ERASE_SIZE;
|
||
else
|
||
data_len = len;
|
||
|
||
SFlash_BufferRead(base_addr, SFlash_rdBuf, data_len);
|
||
crc = do_crc_16(crc, SFlash_rdBuf, data_len);
|
||
|
||
base_addr += data_len;
|
||
len -= data_len;
|
||
}
|
||
|
||
return crc;
|
||
}
|