/*
*********************************************************************************************************
*                                       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; // 放在扩展内存

// 多项式为x16+x15+x2+1,LSB顺序
uint16_t do_crc_16(unsigned short crc_reg, uint8_t *message, int16_t len)
{
    int16_t i, j;
    uint16_t current;
       
    for (i = 0; i < len; i++)
    {
        current = message[i];
        for (j = 0; j < 8; j++)
        {
            if ((crc_reg ^ current) & 0x0001)
                crc_reg = (crc_reg >> 1) ^ 0xA001;
            else
                crc_reg >>= 1;
            current >>= 1;
        }
    }
    return crc_reg;
}

void SFlash_Init()
{
}

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;
	uint32_t priMask;

	priMask = __get_PRIMASK();
	__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();

	if(!priMask)
		__enable_irq();
}

uint8_t SFlash_UnlockBPR()
{
	uint32_t priMask;

	priMask = __get_PRIMASK();
	__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();
	
	if(!priMask)
		__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;
	uint32_t priMask;

	priMask = __get_PRIMASK();
	__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();

	if(!priMask)
		__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;
	uint32_t priMask;

	for(j = 0; j < SFLASH_ERASE_SIZE; j += SFLASH_PAGE_SIZE)
	{
		priMask = __get_PRIMASK();
		__disable_irq();
		SFlash_WriteEN();
		i += SFlash_PageProgram(Addr + j, buf + j);
		if(!priMask)
			__enable_irq();
	}
	
	return i;
}

uint32_t SFlash_BufferWrite(uint32_t Addr, uint8_t *buf, uint32_t nbytes)
{
	uint32_t count, offset;
	uint32_t priMask;
	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)
			 {
				 // 擦除本页
				priMask = __get_PRIMASK();
				__disable_irq();	
				 SFlash_WriteEN();
				 SFlash_PageErase(Addr);
				if(!priMask)
					__enable_irq();
			}
			 
			 // 修改数据
			 memcpy(SFlash_wtBuf + offset, buf, count);
			 
			 // 写入本页数据
			priMask = __get_PRIMASK();
			__disable_irq();			 
			SFlash_WriteEN();
			 SFlash_PageProgram(Addr, SFlash_wtBuf);
			if(!priMask)
				__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;
}
