MS-DTU/MS-DTU-V1/User/spi_FRam.c

401 lines
9.4 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_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;
}