/*
 * spi_flash.c
 *
 *  Created on: 2024年12月4日
 *      Author: yongchaoz
 */
#include "platform.h"
#include "hal_headfile.h"
#include "brom_func.h"
#include "spi_flash.h"

#define FLASH_OP_SPI    DEV_SPI0
#define EN25QXX_CS_H(); { \
	while(!(FLASH_OP_SPI->STA & DEV_SPIn_STA_TX_EMPTY)); \
	FLASH_OP_SPI->CTL &= ~DEV_SPIn_CTL_SPI_CS_NSSLOW;\
}

#define EN25QXX_CS_L();    FLASH_OP_SPI->CTL |=  DEV_SPIn_CTL_SPI_CS_NSSLOW;

/**
* @brief      	SPI初始化
* @details		None
* @param[in]	None
* @return		None
* @note			不对外调用 \n
* 				此函数需要在 #NOR_deinit 函数后调用
*/
void SPI_Flash_Init(void)
{
	SpiInitTypeDef spi_cfg;
	spi_cfg.clockSource = CMU_Clock_OSC_XTAL;
	spi_cfg.prescaler = CMU_Clk_Div_12;
	spi_cfg.receiveThreshold = 8;
	spi_cfg.transmitThreshold =8;
	spi_cfg.useRxDMA = DISABLE;
	spi_cfg.useTxDMA = DISABLE;
	hal_spi_init(SPI_0,&spi_cfg);
}
/**
* @brief      	向flash读写一个byte
* @details		None
* @param[in]	None
* @return		None
* @note			不对外调用。在不清楚原理情况，建议不修改。 \n
*/
uint8_t Flash_RW_Byte(uint8_t value)
{
	uint8_t revalue;
	while(!(FLASH_OP_SPI->STA & DEV_SPIn_STA_TX_EMPTY)){;}
	FLASH_OP_SPI->TX_DATA = value;
	while(FLASH_OP_SPI->STA & DEV_SPIn_STA_RX_EMPTY){;}
	revalue =  FLASH_OP_SPI->RX_DATA;
	return revalue;
}

/**
* @brief      	读取EN25QXX的状态寄存器
* @details		None
* @param[in]	None
* @return		状态寄存器的值
* @note			BIT7  6  5   4   3  2   1   0 \n
*         		  SPR RV TB	BP2 BP1 BP0 WEL BUSY \n
* 				SPR:默认0,状态寄存器保护位,配合WP使用 \n
* 	    		TB,BP2,BP1,BP0:FLASH区域写保护设置 \n
* 	    		WEL:写使能锁定 \n
* 	    		BUSY:忙标记位(1,忙;0,空闲) \n
*/
uint8_t EN25QXX_ReadSR(void)
{
    uint8_t byte=0;

    EN25QXX_CS_L();
	Flash_RW_Byte(EN25XX_ReadStatusReg);
	byte = Flash_RW_Byte(0xff);
    EN25QXX_CS_H();
    return byte;
}

/**
* @brief      	EN25QXX写使能
* @details		None
* @param[in]	None
* @return		None
* @note			None
*/
void EN25QXX_WriteEnable(void)
{
    EN25QXX_CS_L();
    Flash_RW_Byte(EN25XX_WriteEnable);
    EN25QXX_CS_H();
}

/**
* @brief      	等待flash空闲
* @details		None
* @param[in]	None
* @return		None
* @note			None
*/
void EN25QXX_WaitBusy(void)
{
    while((EN25QXX_ReadSR()&0x01)==0x01);
}


/**
* @brief     	 芯片擦除一个Sector 4K
* @details		None
* @param[in]	Sector地址
* @return		None
* @note			None
*/
void EN25QXX_EraseSector(uint32_t addr)
{

	EN25QXX_WriteEnable();
	EN25QXX_CS_L();
	Flash_RW_Byte(EN25XX_SectorErase);
    Flash_RW_Byte((uint8_t)((addr)>>16));
    Flash_RW_Byte((uint8_t)((addr)>>8));
    Flash_RW_Byte((uint8_t)addr);
	EN25QXX_CS_H();

	EN25QXX_WaitBusy();
}



/**
* @brief      	读取flash id
* @details		manufacturer id + memory type + memory density
* @param[in]	None
* @return		flash id
* @note			不对外调用。在不清楚原理情况，建议不修改。 \n
*/
uint32_t Flash_ReadID(void)
{
    uint32_t RDID = 0, manufacturer_id = 0, memory_type = 0, memory_density = 0;

    EN25QXX_CS_L();
    Flash_RW_Byte(0x9F);
    manufacturer_id = Flash_RW_Byte(0xff);
    memory_type = Flash_RW_Byte(0xff);
    memory_density = Flash_RW_Byte(0xff);
    EN25QXX_CS_H();
    RDID = (manufacturer_id << 16) | (memory_type << 8) | memory_density;
    return RDID;
}

/**
* @brief     	读取FLASH
* @details		在指定地址开始读取指定长度的数据
* @param[in]	pBuffer			读取数据存储区
* @param[in]	ReadAddr 			开始读取的地址(24bit)
* @param[in]	NumByteToRead		要读取的字节数(最大65535)
* @return		None
* @note			None
*/
void EN25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)
{
    uint16_t i;
    EN25QXX_CS_L();
    Flash_RW_Byte(EN25XX_ReadData);
    Flash_RW_Byte((uint8_t)((ReadAddr)>>16));
    Flash_RW_Byte((uint8_t)((ReadAddr)>>8));
    Flash_RW_Byte((uint8_t)ReadAddr);
    for(i=0;i<NumByteToRead;i++)
    {
        pBuffer[i]=Flash_RW_Byte(0XFF);
    }
    EN25QXX_CS_H();
}



/**
* @brief     	SPI在一页内写入少于256个字节的数据
* @details		在指定地址开始写入最大256字节的数据
* @param[in]	pBuffer			被写入数据存储区
* @param[in]	ReadAddr 			开始写入的地址(24bit)
* @param[in]	NumByteToRead		要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!
* @return		None
* @note			None
*/
void EN25QXX_WritePage(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
    uint16_t i;
    EN25QXX_WriteEnable();
    EN25QXX_CS_L();
    Flash_RW_Byte(EN25XX_PageProgram);
    Flash_RW_Byte((uint8_t)((WriteAddr)>>16));
    Flash_RW_Byte((uint8_t)((WriteAddr)>>8));
    Flash_RW_Byte((uint8_t)WriteAddr);
    for(i=0;i<NumByteToWrite;i++)
    {
        Flash_RW_Byte(pBuffer[i]);
    }
    EN25QXX_CS_H();
    EN25QXX_WaitBusy();
}



/**
* @brief        保存当前数据的flash空间
* @details      注意该函数需要运行在ram空间上，flash写的过程中，CPU的NOR不能访问FLASH。

* @param[in]    flash_addr：flash地址
* @param[in]    buff：缓存地址
* @param[in]    len：长度
* @return       none
* @note
*/
__ILM uint32_t save_flash(uint32_t flash_addr,uint8_t* buff,uint32_t len)
{
   uint32_t chip_id;
   cpu_mstatus_alloc();
   //GIE_DISABLE();
   DEV_NORC->CTL |= DEV_NORC_CTL_NOR_WAIT_MASK;
   while (DEV_NORC->SOFT_STA_f.BUS_IDLE == 0);
   // 先切时钟，避免后续直接高频切低频时，SPI通信错误
   DEV_CMU->SPInCLK[0] = DEV_CMU_SPInCLK_DIV_4 | DEV_CMU_SPInCLK_SEL_OSC_XTAL;
   DEV_CMU->CLKEN0_f.SPI0 = 1;
   for (int i = 0; i < 100; i++)
   {
	  asm volatile("nop");
   }
   brom_sf_init(0);
   chip_id = brom_sf_read_id();
   brom_sf_erase_area(flash_addr,len);//clear flash
   brom_sf_write_bytes(flash_addr, (uint8_t *)buff,len);// save data to flash
   brom_sf_deinit(0);
   DEV_NORC->CTL &= ~DEV_NORC_CTL_NOR_WAIT_MASK;
   //GIE_ENABLE();
   return chip_id;
}
/**
* @brief        从flash中读取指定位置的数据到内存
* @details      none

* @param[in]    flash_addr：flash地址
* @param[in]    buff：缓存地址
* @param[in]    len：长度
* @return       none
* @note
*/
uint32_t read_flash(uint32_t flash_addr,uint8_t* buff,uint32_t len)
{
	brom_memcpy((uint8_t*)buff,(uint8_t*)((flash_addr&0xFFFFFF)+0x48000000),len);
	return 0;
}
/**
* @brief        flash读写例程
* @details      none
* @param[in]    none
* @return       none
* @note
*/
#if 0
void flash_write_read(void)
{
	static uint8_t spi_test_buff[5]={0,1,2,3,4};
	static uint8_t read_test_buff[5]={0,0,0,0,0};
    debug("user_100ms_handler\r\n");
	uint32_t id = save_flash((uint32_t)(1004*1024 & 0x00FFFFFF),spi_test_buff,5);
	debug("id:%x\r\n",id);
	read_flash(1024*1024,read_test_buff,5);
	for(uint8_t i=0;i<5;i++)
	{
		debug("read_test_buff[%d]=%d\r\n",i,read_test_buff[i]);
	}
}
#endif

