NANO130_H2Press/User/spi_FRam.c

362 lines
8.5 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_fram.c
* Version : V1.00
* Programmer(s) : Qian Xianghong
*********************************************************************************************************
*/
#include "includes.h"
// 铁电操作命令码
#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()
{
/* Set SPI0 multi-function pins */
/* Set SPI1 multi-function pins */
SYS->PE_L_MFP &= ~(SYS_PE_L_MFP_PE1_MFP_Msk | SYS_PE_L_MFP_PE2_MFP_Msk | SYS_PE_L_MFP_PE3_MFP_Msk | SYS_PE_L_MFP_PE4_MFP_Msk);
SYS->PE_L_MFP |= (SYS_PE_L_MFP_PE1_MFP_SPI0_SS0 | SYS_PE_L_MFP_PE2_MFP_SPI0_SCLK | SYS_PE_L_MFP_PE3_MFP_SPI0_MISO0 | SYS_PE_L_MFP_PE4_MFP_SPI0_MOSI0);
// 允许外设时钟
CLK_EnableModuleClock(SPI0_MODULE);
}
void FRAM_Open()
{
/*---------------------------------------------------------------------------------------------------------*/
/* Init SPI */
/*---------------------------------------------------------------------------------------------------------*/
/* Configure SPI0 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(SPI0, SPI_MASTER, SPI_MODE_0, 8, 36000000ul);
/* Disable the automatic hardware slave selection function. */
SPI_DisableAutoSS(SPI0);
SPI_SET_MSB_FIRST(SPI0);
/* Set TX FIFO threshold, enable TX FIFO threshold interrupt and RX FIFO time-out interrupt */
SPI_EnableFIFO(SPI0, 1, 1);
}
void FRAM_ReadID()
{
uint8_t i;
SPI_SET_SS0_LOW(SPI0);
SPI_WRITE_TX0(SPI0, FRAM_OP_RDID);
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SPI_READ_RX0(SPI0);
printf("\nFRAM ID is: ");
for(i = 0; i < 9; i++)
{
SPI_WRITE_TX0(SPI0, 0); // 提供CLK
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
printf(" %02X", SPI_READ_RX0(SPI0));
}
printf("\n");
SPI_SET_SS0_HIGH(SPI0);
}
uint8_t FRAM_WriteEN()
{
uint8_t SR = 0x00;
SPI_SET_SS0_LOW(SPI0);
// Write Enabled
SPI_WRITE_TX0(SPI0, FRAM_OP_WREN);
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SPI_READ_RX0(SPI0);
SPI_SET_SS0_HIGH(SPI0);
// Read SR
SPI_SET_SS0_LOW(SPI0);
SPI_WRITE_TX0(SPI0, FRAM_OP_RDSR);
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SPI_READ_RX0(SPI0);
SPI_WRITE_TX0(SPI0, 0); // 提供CLK
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SR = SPI_READ_RX0(SPI0);
SPI_SET_SS0_HIGH(SPI0);
// 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;
SPI_SET_SS0_LOW(SPI0);
// Write Enabled
SPI_WRITE_TX0(SPI0, FRAM_OP_WRDI);
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SPI_READ_RX0(SPI0);
SPI_SET_SS0_HIGH(SPI0);
// Read SR
SPI_SET_SS0_LOW(SPI0);
SPI_WRITE_TX0(SPI0, FRAM_OP_RDSR);
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SPI_READ_RX0(SPI0);
SPI_WRITE_TX0(SPI0, 0); // 提供CLK
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SR = SPI_READ_RX0(SPI0);
SPI_SET_SS0_HIGH(SPI0);
// 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();
SPI_SET_SS0_LOW(SPI0);
// Write
SPI_WRITE_TX0(SPI0, FRAM_OP_WRITE);
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SPI_READ_RX0(SPI0);
// address high byte
SPI_WRITE_TX0(SPI0, Addr >> 8);
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SPI_READ_RX0(SPI0);
// address low byte
SPI_WRITE_TX0(SPI0, Addr & 0xFF);
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SPI_READ_RX0(SPI0);
// data
for(i = 0; i < nbytes && Addr + i < FRAM_SIZE; i++)
{
SPI_WRITE_TX0(SPI0, buf[i]);
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SPI_READ_RX0(SPI0);
}
SPI_SET_SS0_HIGH(SPI0);
__enable_irq();
return i;
}
uint16_t FRAM_BufferRead(uint32_t Addr, uint8_t *buf, uint32_t nbytes)
{
uint16_t i;
__disable_irq();
SPI_SET_SS0_LOW(SPI0);
// Read
SPI_WRITE_TX0(SPI0, FRAM_OP_READ);
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SPI_READ_RX0(SPI0);
// address high byte
SPI_WRITE_TX0(SPI0, Addr >> 8);
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SPI_READ_RX0(SPI0);
// address low byte
SPI_WRITE_TX0(SPI0, Addr & 0xFF);
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SPI_READ_RX0(SPI0);
// data
for(i = 0; i < nbytes && Addr + i < FRAM_SIZE; i++)
{
SPI_WRITE_TX0(SPI0, 0); // 提供CLK
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
buf[i] = SPI_READ_RX0(SPI0);
}
SPI_SET_SS0_HIGH(SPI0);
__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();
SPI_SET_SS0_LOW(SPI0);
// Read
SPI_WRITE_TX0(SPI0, FRAM_OP_READ);
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SPI_READ_RX0(SPI0);
// address high byte
SPI_WRITE_TX0(SPI0, Addr >> 8);
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SPI_READ_RX0(SPI0);
// address low byte
SPI_WRITE_TX0(SPI0, Addr & 0xFF);
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
SPI_READ_RX0(SPI0);
// data
for(i = 0; i < nbytes && Addr + i < FRAM_SIZE; i++)
{
SPI_WRITE_TX0(SPI0, 0); // 提供CLK
while(SPI_GET_RX_FIFO_EMPTY_FLAG(SPI0));
if(buf[i] != SPI_READ_RX0(SPI0))
{
ret = FALSE;
break;
}
}
SPI_SET_SS0_HIGH(SPI0);
__enable_irq();
return ret;
}
void FRAM_Sleep(uint8_t sleep)
{
SPI_SET_SS0_LOW(SPI0);
// Chip erase
if(sleep)
SPI_WRITE_TX0(SPI0, FRAM_OP_SLEEP);
else
SPI_WRITE_TX0(SPI0, 0);
SPI_SET_SS0_HIGH(SPI0);
}
// 从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;
}