NANO130_H2Press/User/spi_Flash.c

503 lines
11 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
*********************************************************************************************************
* 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;
}