/*
*********************************************************************************************************
*                                       IAR Development Kits
*                                              on the
*
*                                    M451
*
* Filename      : spi_fram.c
* Version       : V1.00
* Programmer(s) : Qian Xianghong
*********************************************************************************************************
*/

#include  "includes.h"

// 片选
#define FRAM_CS_LOW()		LL_GPIO_ResetOutputPin(GPIOD, LL_GPIO_PIN_7)
#define FRAM_CS_HIGH()		LL_GPIO_SetOutputPin(GPIOD, LL_GPIO_PIN_7)

// 铁电操作命令码
#define FRAM_OP_WREN	0x06	// Set write enable latch
#define FRAM_OP_WRDI	0x04	// Reset write enable latch
#define FRAM_OP_RDSR	0x05	// Read Status Register
#define FRAM_OP_WRSR	0x01	// Write Status Register
#define FRAM_OP_READ	0x03	// Read memory data
#define FRAM_OP_FSTRD	0x0B	// Fast read memory data
#define FRAM_OP_WRITE	0x02	// Write memory data
#define FRAM_OP_SLEEP	0xB9	// Enter sleep mode
#define FRAM_OP_RDID	0x9F	// Read device ID

// 铁电状态寄存器（SR)写允许(WEL)标志位
#define FRAM_WEL_Pos	1
#define FRAM_WEL_Msk	(0x01 << FRAM_WEL_Pos)

void FRAM_Init()
{
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
  
  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
  /**SPI3 GPIO Configuration  
  PB3 (JTDO-TRACESWO)   ------> SPI3_SCK
  PB4 (NJTRST)   ------> SPI3_MISO
  PB5   ------> SPI3_MOSI 
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_3|LL_GPIO_PIN_4|LL_GPIO_PIN_5;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_6;
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOD);

  LL_GPIO_SetOutputPin(GPIOD, LL_GPIO_PIN_7);

  GPIO_InitStruct.Pin = LL_GPIO_PIN_7;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  LL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}

void FRAM_Open()
{
  LL_SPI_InitTypeDef SPI_InitStruct = {0};

  /* Peripheral clock enable */
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI3);

  /* SPI3 parameter configuration*/
  SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
  SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
  SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
  SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
  SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;
  SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
  SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2;
  SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
  SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
  SPI_InitStruct.CRCPoly = 7;
  LL_SPI_Init(SPI3, &SPI_InitStruct);
  LL_SPI_SetStandard(SPI3, LL_SPI_PROTOCOL_MOTOROLA);
  LL_SPI_EnableNSSPulseMgt(SPI3);
  
  LL_SPI_SetRxFIFOThreshold(SPI3, LL_SPI_RX_FIFO_TH_QUARTER);
  LL_SPI_Enable(SPI3);

	// 读出ID：测试通信是否正常
	FRAM_ReadID();
}

void FRAM_ReadID()
{
	uint8_t i;

	__disable_irq();
	
 	FRAM_CS_LOW();
	
	*(__IO uint8_t *)&SPI3->DR = FRAM_OP_RDID;
	while(!(SPI3->SR & SPI_SR_RXNE));
	*(__IO uint8_t *)&SPI3->DR;
	
	printf("\nFRAM ID is: ");
	for(i = 0; i < 9; i++)
	{
		*(__IO uint8_t *)&SPI3->DR = 0;	// 提供CLK
		while(!(SPI3->SR & SPI_SR_RXNE));
		printf(" %02X", *(__IO uint8_t *)&SPI3->DR);
	}
	printf("\n");
	
	FRAM_CS_HIGH();

	__enable_irq();
}

uint8_t FRAM_WriteEN()
{
	uint8_t SR = 0x00;
	
	FRAM_CS_LOW();

	// Write Enabled
	*(__IO uint8_t *)&SPI3->DR = FRAM_OP_WREN;
	while(!(SPI3->SR & SPI_SR_RXNE));
	*(__IO uint8_t *)&SPI3->DR;

	FRAM_CS_HIGH();
	
	// Read SR
	FRAM_CS_LOW();
	
	*(__IO uint8_t *)&SPI3->DR = FRAM_OP_RDSR;
	while(!(SPI3->SR & SPI_SR_RXNE));
	*(__IO uint8_t *)&SPI3->DR;
	
	*(__IO uint8_t *)&SPI3->DR = 0;	// 提供CLK
	while(!(SPI3->SR & SPI_SR_RXNE));
	SR = *(__IO uint8_t *)&SPI3->DR;
	
	FRAM_CS_HIGH();
	
	// Check WEL
	if(SR & FRAM_WEL_Msk)
		return 1;
	printf("\nFRam write enable failed\n");
	return 0;
}

uint8_t FRAM_WriteDI()
{
	uint8_t SR = 0xFF;
	
	FRAM_CS_LOW();

	// Write Enabled
	*(__IO uint8_t *)&SPI3->DR = FRAM_OP_WRDI;
	while(!(SPI3->SR & SPI_SR_RXNE));
	*(__IO uint8_t *)&SPI3->DR;

	FRAM_CS_HIGH();
	
	// Read SR
	FRAM_CS_LOW();

	*(__IO uint8_t *)&SPI3->DR = FRAM_OP_RDSR;
	while(!(SPI3->SR & SPI_SR_RXNE));
	*(__IO uint8_t *)&SPI3->DR;
	
	*(__IO uint8_t *)&SPI3->DR = 0;	// 提供CLK
	while(!(SPI3->SR & SPI_SR_RXNE));
	SR = *(__IO uint8_t *)&SPI3->DR;

	FRAM_CS_HIGH();
	
	// Check WEL
	if(SR & FRAM_WEL_Msk)
	{
		printf("\nWrite disable failed\n");
		return 0;
	}
	return 1;
}

uint16_t FRAM_BufferWrite(uint32_t Addr, uint8_t *buf, uint32_t nbytes)
{
	uint16_t i;

	__disable_irq();
	
	FRAM_WriteEN();
	
	FRAM_CS_LOW();
	
	// Write
	*(__IO uint8_t *)&SPI3->DR = FRAM_OP_WRITE;
	while(!(SPI3->SR & SPI_SR_RXNE));
	*(__IO uint8_t *)&SPI3->DR;
	// address high byte
	*(__IO uint8_t *)&SPI3->DR = Addr >> 8;
	while(!(SPI3->SR & SPI_SR_RXNE));
	*(__IO uint8_t *)&SPI3->DR;
	// address low byte
	*(__IO uint8_t *)&SPI3->DR = Addr & 0xFF;
	while(!(SPI3->SR & SPI_SR_RXNE));
	*(__IO uint8_t *)&SPI3->DR;
	// data
	for(i = 0; i < nbytes && Addr + i < FRAM_SIZE; i++)
	{
		*(__IO uint8_t *)&SPI3->DR = buf[i];
		while(!(SPI3->SR & SPI_SR_RXNE));
		*(__IO uint8_t *)&SPI3->DR;
	}
	
	FRAM_CS_HIGH();

	__enable_irq();
	
	return i;
}

uint16_t FRAM_BufferRead(uint32_t Addr, uint8_t *buf, uint32_t nbytes)
{
	uint16_t i;

	__disable_irq();

	FRAM_CS_LOW();
	
	// Read
	*(__IO uint8_t *)&SPI3->DR = FRAM_OP_READ;
	while(!(SPI3->SR & SPI_SR_RXNE));
	*(__IO uint8_t *)&SPI3->DR;
	// address high byte
	*(__IO uint8_t *)&SPI3->DR = Addr >> 8;
	while(!(SPI3->SR & SPI_SR_RXNE));
	*(__IO uint8_t *)&SPI3->DR;
	// address low byte
	*(__IO uint8_t *)&SPI3->DR = Addr & 0xFF;
	while(!(SPI3->SR & SPI_SR_RXNE));
	*(__IO uint8_t *)&SPI3->DR;
	// data
	for(i = 0; i < nbytes && Addr + i < FRAM_SIZE; i++)
	{
		*(__IO uint8_t *)&SPI3->DR = 0; // 提供CLK
		while(!(SPI3->SR & SPI_SR_RXNE));
		buf[i] = *(__IO uint8_t *)&SPI3->DR;
	}
	
	FRAM_CS_HIGH();
	
	__enable_irq();
	
	return i;
}

uint32_t FRAM_BufferVerify(uint32_t Addr, uint8_t *buf, uint32_t nbytes)
{
	uint32_t ret = TRUE;
	uint16_t i;

	__disable_irq();

	FRAM_CS_LOW();
	
	// Read
	*(__IO uint8_t *)&SPI3->DR = FRAM_OP_READ;
	while(!(SPI3->SR & SPI_SR_RXNE));
	*(__IO uint8_t *)&SPI3->DR;
	// address high byte
	*(__IO uint8_t *)&SPI3->DR = Addr >> 8;
	while(!(SPI3->SR & SPI_SR_RXNE));
	*(__IO uint8_t *)&SPI3->DR;
	// address low byte
	*(__IO uint8_t *)&SPI3->DR = Addr & 0xFF;
	while(!(SPI3->SR & SPI_SR_RXNE));
	*(__IO uint8_t *)&SPI3->DR;
	// data
	for(i = 0; i < nbytes && Addr + i < FRAM_SIZE; i++)
	{
		*(__IO uint8_t *)&SPI3->DR = 0; // 提供CLK
		while(!(SPI3->SR & SPI_SR_RXNE));
		if(buf[i] != *(__IO uint8_t *)&SPI3->DR)
		{
			ret = FALSE;
			break;
		}
	}
	
	FRAM_CS_HIGH();

	__enable_irq();
	
	return ret;
}

void FRAM_Sleep(uint8_t sleep)
{
	FRAM_CS_LOW();

	// Chip erase
	if(sleep)
		*(__IO uint8_t *)&SPI3->DR = FRAM_OP_SLEEP;
	else
		*(__IO uint8_t *)&SPI3->DR = 0;

	FRAM_CS_HIGH();
}

// 从FRAM读取记录（前面2个字节为标志0x55AA，最后两个字节为crc）
uint32_t FRAM_LoadInfo(uint32_t Addr, uint8_t *buf, uint32_t nbytes)
{
	if(FRAM_BufferRead(Addr, buf, nbytes) == nbytes && Byte2IntS(buf, 0) == 0x55AA && do_crc_16(0, buf, nbytes) == 0)
		return 1;

	memset(buf, 0, nbytes);
	return 0;
}

// 保存记录到FRAM中（前面2个字节为标志0x55AA，最后两个字节为crc）
uint32_t FRAM_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 (FRAM_BufferWrite(Addr, buf, nbytes) == nbytes);
}

// 循环缓冲实现部分

// 因为当读写指针相同表示缓冲区满（浪费了一个数据空间），故需要多分配一个数据空间
void LoopBuff_Create(loopbuff_t *lpbuf, uint16_t itemSize, uint16_t maxItemCount, uint32_t info_base, uint32_t data_base)
{
	memset(&lpbuf->info, 0, sizeof(loopbuff_info_t));
	lpbuf->itemSize = itemSize;
	lpbuf->maxItemCount = maxItemCount;
	lpbuf->info_base = info_base;

//	if(info_base == 0)	// 分配扩展内存
//		lpbuf->data = SRAM_Alloc(itemSize * (maxItemCount + 1));
//	else				// 记录铁电或系统内存位置
		lpbuf->data_base = data_base;
}

void LoopBuff_Clear(loopbuff_t *lpbuf)
{
	lpbuf->info.rdPtr = lpbuf->info.wtPtr;
}

uint16_t LoopBuff_GetCount(loopbuff_t *lpbuf)
{
	if(lpbuf->info.rdPtr <= lpbuf->info.wtPtr)
		return lpbuf->info.wtPtr - lpbuf->info.rdPtr;
	return (lpbuf->maxItemCount + 1) - lpbuf->info.rdPtr + lpbuf->info.wtPtr;
}

uint16_t LoopBuff_GetNextPtr(loopbuff_t *lpbuf, uint16_t ptr)
{
	if(ptr == lpbuf->maxItemCount)
		return 0;
	return (ptr + 1);
}

void LoopBuff_PutItem(loopbuff_t *lpbuf, uint8_t *item)
{
	uint16_t nextPtr;
	
	// 移动写指针
	nextPtr = LoopBuff_GetNextPtr(lpbuf, lpbuf->info.wtPtr);
	
	// 如果队列未满
	if(nextPtr != lpbuf->info.rdPtr)
	{
		// 将新数据加到最后
		memmove(lpbuf->data + lpbuf->info.wtPtr * lpbuf->itemSize, item, lpbuf->itemSize);
		lpbuf->info.wtPtr = nextPtr;
	}
	else
	{
		// 如果队列已满，则丢弃最新数据
	}
}

void LoopBuff_RemoveItems(loopbuff_t *lpbuf, uint16_t count)
{
	while(lpbuf->info.rdPtr != lpbuf->info.wtPtr && count--)
		lpbuf->info.rdPtr = LoopBuff_GetNextPtr(lpbuf, lpbuf->info.rdPtr);
}

uint32_t LoopBuff_GetDataPos(loopbuff_t *lpbuf, uint16_t ptr)
{
	return lpbuf->data_base + lpbuf->itemSize * ptr;
}

uint8_t *LoopBuff_GetDataPtr(loopbuff_t *lpbuf, uint16_t ptr)
{
	return lpbuf->data + lpbuf->itemSize * ptr;
}
