/* ********************************************************************************************************* * 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; }