ShipCentralControl/Anjiehui7_DTU/User/spi_Flash.c

520 lines
11 KiB
C
Raw 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"
// 片选
#define SFLASH_CS_LOW() LL_GPIO_ResetOutputPin(GPIOC, LL_GPIO_PIN_4)
#define SFLASH_CS_HIGH() LL_GPIO_SetOutputPin(GPIOC, LL_GPIO_PIN_4)
// 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_Open()
{
// 分配扩展内存
// SFlash_rdBuf = SRAM_Alloc(SFLASH_ERASE_SIZE);
// SFlash_wtBuf = SRAM_Alloc(SFLASH_ERASE_SIZE);
// LL_SPI_SetRxFIFOThreshold(SPI1, LL_SPI_RX_FIFO_TH_QUARTER);
LL_SPI_Enable(SPI1);
// 读出ID测试通信是否正常
SFlash_ReadID();
}
void SFlash_ReadID()
{
uint8_t i;
__disable_irq();
SFLASH_CS_LOW();
*(__IO uint8_t *)&SPI1->DR = SFLASH_OP_RDID;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
PRINTF("\r\nFlash ID is: ");
for(i = 0; i < 3; i++)
{
*(__IO uint8_t *)&SPI1->DR = 0; // 提供CLK
while(!(SPI1->SR & SPI_SR_RXNE));
PRINTF("%02X ", *(__IO uint8_t *)&SPI1->DR);
}
PRINTF("\r\n");
SFLASH_CS_HIGH();
__enable_irq();
}
uint8_t SFlash_UnlockBPR()
{
__disable_irq();
SFlash_WriteEN();
SFLASH_CS_LOW();
// Write Enabled
*(__IO uint8_t *)&SPI1->DR = SFLASH_OP_ULBPR;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
SFLASH_CS_HIGH();
__enable_irq();
return 1;
}
uint8_t SFlash_WriteEN()
{
uint8_t SR = 0x00;
SFLASH_CS_LOW();
// Write Enabled
*(__IO uint8_t *)&SPI1->DR = SFLASH_OP_WREN;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
SFLASH_CS_HIGH();
// Read SR
SFLASH_CS_LOW();
*(__IO uint8_t *)&SPI1->DR = SFLASH_OP_RDSR;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
*(__IO uint8_t *)&SPI1->DR = 0; // 提供CLK
while(!(SPI1->SR & SPI_SR_RXNE));
SR = *(__IO uint8_t *)&SPI1->DR;
SFLASH_CS_HIGH();
// Check WEL
if(SR & SFLASH_WEL_Msk)
return 1;
PRINTF("\r\nWrite enable failed\r\n");
return 0;
}
uint8_t SFlash_WriteDI()
{
uint8_t SR = 0xFF;
SFLASH_CS_LOW();
// Write Enabled
*(__IO uint8_t *)&SPI1->DR = SFLASH_OP_WRDI;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
SFLASH_CS_HIGH();
// Read SR
SFLASH_CS_LOW();
*(__IO uint8_t *)&SPI1->DR = SFLASH_OP_RDSR;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
*(__IO uint8_t *)&SPI1->DR = 0; // 提供CLK
while(!(SPI1->SR & SPI_SR_RXNE));
SR = *(__IO uint8_t *)&SPI1->DR;
SFLASH_CS_HIGH();
// Check WEL
if(SR & SFLASH_WEL_Msk)
{
PRINTF("\r\nWrite disable failed\r\n");
return 0;
}
return 1;
}
uint32_t SFlash_BufferRead(uint32_t Addr, uint8_t *buf, uint32_t nbytes)
{
uint32_t i;
__disable_irq();
SFLASH_CS_LOW();
// Read
*(__IO uint8_t *)&SPI1->DR = SFLASH_OP_READ;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
// address highest byte
*(__IO uint8_t *)&SPI1->DR = (Addr >> 16) & 0xFF;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
// address high byte
*(__IO uint8_t *)&SPI1->DR = (Addr >> 8) & 0xFF;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
// address low byte
*(__IO uint8_t *)&SPI1->DR = Addr & 0xFF;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
// data
for(i = 0; i < nbytes && Addr + i < SFLASH_SIZE; i++)
{
*(__IO uint8_t *)&SPI1->DR = 0; // 提供CLK
while(!(SPI1->SR & SPI_SR_RXNE));
buf[i] = *(__IO uint8_t *)&SPI1->DR;
}
SFLASH_CS_HIGH();
__enable_irq();
return i;
}
void SFlash_PageErase(uint32_t Addr)
{
uint8_t SR = 0xFF;
SFLASH_CS_LOW();
// Sector erase
*(__IO uint8_t *)&SPI1->DR = SFLASH_OP_PE;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
// address highest byte
*(__IO uint8_t *)&SPI1->DR = (Addr >> 16) & 0xFF;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
// address high byte
*(__IO uint8_t *)&SPI1->DR = (Addr >> 8) & 0xFF;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
// address low byte
*(__IO uint8_t *)&SPI1->DR = Addr & 0xFF;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
SFLASH_CS_HIGH();
// Read SR
do
{
SFLASH_CS_LOW();
*(__IO uint8_t *)&SPI1->DR = SFLASH_OP_RDSR;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
*(__IO uint8_t *)&SPI1->DR = 0; // 提供CLK
while(!(SPI1->SR & SPI_SR_RXNE));
SR = *(__IO uint8_t *)&SPI1->DR;
SFLASH_CS_HIGH();
} while(SR & SFLASH_BUSY_Msk);
}
void SFlash_SectorErase(uint32_t Addr)
{
uint8_t SR = 0xFF;
SFLASH_CS_LOW();
// Sector erase
*(__IO uint8_t *)&SPI1->DR = SFLASH_OP_SE;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
// address highest byte
*(__IO uint8_t *)&SPI1->DR = (Addr >> 16) & 0xFF;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
// address high byte
*(__IO uint8_t *)&SPI1->DR = (Addr >> 8) & 0xFF;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
// address low byte
*(__IO uint8_t *)&SPI1->DR = Addr & 0xFF;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
SFLASH_CS_HIGH();
// Read SR
do
{
SFLASH_CS_LOW();
*(__IO uint8_t *)&SPI1->DR = SFLASH_OP_RDSR;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
*(__IO uint8_t *)&SPI1->DR = 0; // 提供CLK
while(!(SPI1->SR & SPI_SR_RXNE));
SR = *(__IO uint8_t *)&SPI1->DR;
SFLASH_CS_HIGH();
} while(SR & SFLASH_BUSY_Msk);
}
void SFlash_ChipErase()
{
uint8_t SR = 0xFF;
SFLASH_CS_LOW();
// Chip erase
*(__IO uint8_t *)&SPI1->DR = SFLASH_OP_CE;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
SFLASH_CS_HIGH();
// Read SR
do
{
SFLASH_CS_LOW();
*(__IO uint8_t *)&SPI1->DR = SFLASH_OP_RDSR;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
*(__IO uint8_t *)&SPI1->DR = 0; // 提供CLK
while(!(SPI1->SR & SPI_SR_RXNE));
SR = *(__IO uint8_t *)&SPI1->DR;
SFLASH_CS_HIGH();
} while(SR & SFLASH_BUSY_Msk);
}
uint16_t SFlash_PageProgram(uint32_t Addr, uint8_t *buf)
{
uint8_t SR = 0xFF;
uint16_t i;
SFLASH_CS_LOW();
// Page grogram
*(__IO uint8_t *)&SPI1->DR = SFLASH_OP_PP;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
// address highest byte
*(__IO uint8_t *)&SPI1->DR = (Addr >> 16) & 0xFF;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
// address high byte
*(__IO uint8_t *)&SPI1->DR = (Addr >> 8) & 0xFF;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
// address low byte
*(__IO uint8_t *)&SPI1->DR = Addr & 0xFF;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
// data
for(i = 0; i < SFLASH_PAGE_SIZE && Addr + i < SFLASH_SIZE; i++)
{
*(__IO uint8_t *)&SPI1->DR = buf[i];
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
}
SFLASH_CS_HIGH();
// Read SR
do
{
SFLASH_CS_LOW();
*(__IO uint8_t *)&SPI1->DR = SFLASH_OP_RDSR;
while(!(SPI1->SR & SPI_SR_RXNE));
*(__IO uint8_t *)&SPI1->DR;
*(__IO uint8_t *)&SPI1->DR = 0; // 提供CLK
while(!(SPI1->SR & SPI_SR_RXNE));
SR = *(__IO uint8_t *)&SPI1->DR;
SFLASH_CS_HIGH();
} 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;
static uint8_t FF[SFLASH_ERASE_SIZE];
static uint8_t first = 1;
if(first)
{
first = 0;
memset(FF, 0xFF, SFLASH_ERASE_SIZE);
}
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)
{
// 如果目标区域为全FF不需要擦除
if(memcmp(SFlash_wtBuf + offset, FF, 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;
}
// 从SFlash读取记录前面2个字节为标志0x55AA最后两个字节为crc
uint32_t SFlash_LoadInfo(uint32_t Addr, uint8_t *buf, uint32_t nbytes)
{
if(SFlash_BufferRead(Addr, buf, nbytes) == nbytes && Byte2IntS(buf, 0) == 0x55AA && do_crc_16(0, buf, nbytes) == 0)
return 1;
memset(buf, 0, nbytes);
return 0;
}
// 保存记录到SFlash中前面2个字节为标志0x55AA最后两个字节为crc
uint32_t SFlash_SaveInfo(uint32_t Addr, uint8_t *buf, uint32_t nbytes)
{
Int2ByteS(buf, 0, 0x55AA);
Int2ByteS(buf, nbytes - 2, do_crc_16(0, buf, nbytes - 2));
return SFlash_BufferWrite(Addr, buf, nbytes);
}