FRAM学习及使用
一、FM24CL16B-G芯片介绍
FM24CL16B-GTR是采用先进铁电工艺的16K位非易失性存储器,铁电随机存取存储器或F-RAM是非易失性的,并且类似于RAM执行读取和写入,它提供了151年的可靠数据保留,同时消除了EEPROM和其他非易失性存储器引起的复杂性、开销和系统级可靠性问题,接下来一起看看FM24CL16B-GTR型号存储芯片的详细介绍:
与EEPROM不同,FM24CL16B以总线速度执行写入操作,没有发生写入延迟。每个字节成功传输到设备后,数据会立即写入内存阵列,下一个总线周期可以在不需要数据轮询的情况下开始。此外,与其他非易失性存储器相比,该产品提供了实质性的写入耐久性。
F-RAM在写入期间表现出比EEPROM低得多的功率,因为写入操作不需要写入电路的内部提升电源电压,FM24CL16B能够支持1014个读/写周期,即比EEPROM多1亿倍的写周期,这些功能使FM24CL16B成为需要频警或快速写入的,非易失性存储器应用的理想选择.
FM24CL16B是串行F-RAM存储器,采用IIC接口协议进行操作。存储器阵列逻辑上组织为2,048 × 8位(即最多存储2k字节的数据),在使用上将这2048个字节的地址分成8个页,每个页可存储256字节数据。
FM24CL16B引脚定义如下:
FM24CL16B设备从机地址如下:
二、FRAM代码实例
头文件:
/*
* fm24cl16b.h
*
* Created on: 2021年1月28日
* Author: Ted
*/
#ifndef INC_HARDWARE_FM24CL16B_H_
#define INC_HARDWARE_FM24CL16B_H_
#include <stdint.h>
#include "main.h"
#include "gpio.h"
#define FM24CL16B_SDA_PORT GPIOC
#define FM24CL16B_SDA_PIN LL_GPIO_PIN_13
#define FM24CL16B_SCL_HIGH LL_GPIO_SetOutputPin(GPIOC,LL_GPIO_PIN_12)
#define FM24CL16B_SCL_LOW LL_GPIO_ResetOutputPin(GPIOC,LL_GPIO_PIN_12)
#define FM24CL16B_SDA_HIGH LL_GPIO_SetOutputPin(GPIOC,LL_GPIO_PIN_13)
#define FM24CL16B_SDA_LOW LL_GPIO_ResetOutputPin(GPIOC,LL_GPIO_PIN_13)
#define FM24CL16B_SDA_READ LL_GPIO_IsInputPinSet(GPIOC,LL_GPIO_PIN_13)
#define FM24CL16B_SLAVEID 0xA0
#define FM24CL16B_READ_BIT 0x01
#define FM24CL16B_WRITE_BIT 0x00
#define FM24CL16B_PAGE_READ(page) (FM24CL16B_SLAVEID | (page << 1) | FM24CL16B_READ_BIT)
#define FM24CL16B_PAGE_WRITE(page) (FM24CL16B_SLAVEID | (page << 1) | FM24CL16B_WRITE_BIT)
void FM24CL16B_IIC_Init();
void FM24CL16B_IIC_Start();
void FM24CL16B_IIC_Stop();
void FM24CL16B_IIC_ACK();
void FM24CL16B_IIC_NOACK();
/**
* desc:等待IIC应答
* return:
* 0:应答成功; 1:应答失败
*/
int8_t FM24CL16B_IIC_Wait_ACK();
/**
* desc:IIC读取数据
* return:
* IIC读取到的值
*/
uint8_t FM24CL16B_IIC_Read();
/**
* desc:IIC写数据
* params:
* data:需要通过IIC发送的数据
*/
void FM24CL16B_IIC_Write(uint8_t data);
/**
* desc:FM24CL16B写入1个字节
* params:
* page:需要写入数据的页地址:0~7,一共8页
* addr:需要写入数据的段地址:0~255,一共256个地址段
* writeData:需要写入的字节数据
* return:
* 0:写入成功;-1:应答失败
*/
int8_t FM24CL16B_WriteByte(uint8_t page, uint8_t addr, uint8_t writeData);
/**
* desc:FM24CL16B读取1个字节
* params:
* page:需要读取数据的页地址:0~7,一共8页
* addr:需要读取数据的段地址:0~255,一共256个地址段
* writeData:返回读取到的字节数据
* return:
* 0:写入成功;-1:应答失败
*/
int8_t FM24CL16B_ReadByte(uint8_t page, uint8_t addr, uint8_t *readData);
/**
* desc:FM24CL16B写入多个字节
* params:
* page:需要写入数据的页地址:0~7,一共8页
* addr:需要写入数据的段地址:0~255,一共256个地址段
* writeBuff:需要写入的字节数据
* len:需要写入的数据长度
* return:
* 0:写入成功;-1:应答失败
*/
int8_t FM24CL16B_WriteBytes(uint8_t page, uint8_t addr, uint8_t *writeBuff, uint8_t len);
/**
* desc:FM24CL16B读取多个字节
* params:
* page:需要读取数据的页地址:0~7,一共8页
* addr:需要读取数据的段地址:0~255,一共256个地址段
* readBuff:返回读取到的字节数据
* len:需要读取的数据长度
* return:
* 0:写入成功;-1:应答失败
*/
int8_t FM24CL16B_ReadBytes(uint8_t page, uint8_t addr, uint8_t *readBuff, uint8_t len);
#endif /* INC_HARDWARE_FM24CL16B_H_ */
源文件:
/*
* fm24cl16b.c
*
* Created on: 2021年1月28日
* Author: Ted
*/
#include "hardware/fm24cl16b.h"
#include "hardware/timer.h"
#include "hardware/serial.h"
static void FM24CL16B_SDA_IN()
{
LL_GPIO_SetPinMode(FM24CL16B_SDA_PORT, FM24CL16B_SDA_PIN, LL_GPIO_MODE_INPUT);
LL_GPIO_SetPinPull(FM24CL16B_SDA_PORT, FM24CL16B_SDA_PIN, LL_GPIO_PULL_UP);
}
static void FM24CL16B_SDA_OUT()
{
LL_GPIO_SetPinMode(FM24CL16B_SDA_PORT,FM24CL16B_SDA_PIN,LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinOutputType(FM24CL16B_SDA_PORT,FM24CL16B_SDA_PIN,LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinPull(FM24CL16B_SDA_PORT,FM24CL16B_SDA_PIN,LL_GPIO_PULL_UP);
LL_GPIO_SetPinSpeed(FM24CL16B_SDA_PORT,FM24CL16B_SDA_PIN,LL_GPIO_SPEED_FREQ_LOW);
}
void FM24CL16B_IIC_Init()
{
FM24CL16B_SDA_OUT();
FM24CL16B_SDA_HIGH;
FM24CL16B_SCL_HIGH;
}
void FM24CL16B_IIC_Start()
{
FM24CL16B_SDA_OUT();
FM24CL16B_SDA_HIGH;
delay_us(1);
FM24CL16B_SCL_HIGH;
delay_us(5);
FM24CL16B_SDA_LOW;
delay_us(5);
FM24CL16B_SCL_LOW;
}
void FM24CL16B_IIC_Stop()
{
FM24CL16B_SDA_OUT();
FM24CL16B_SDA_LOW;
FM24CL16B_SCL_LOW;
delay_us(6);
FM24CL16B_SDA_HIGH;
FM24CL16B_SCL_HIGH;
delay_us(6);
}
void FM24CL16B_IIC_ACK()
{
FM24CL16B_SCL_LOW;
FM24CL16B_SDA_OUT();
FM24CL16B_SCL_HIGH;
delay_us(5);
FM24CL16B_SCL_HIGH;
delay_us(5);
FM24CL16B_SCL_LOW;
}
void FM24CL16B_IIC_NOACK()
{
FM24CL16B_SCL_LOW;
FM24CL16B_SDA_OUT();
FM24CL16B_SDA_HIGH;
delay_us(5);
FM24CL16B_SCL_HIGH;
delay_us(5);
FM24CL16B_SCL_LOW;
}
int8_t FM24CL16B_IIC_Wait_ACK()
{
FM24CL16B_SDA_IN();
FM24CL16B_SDA_HIGH;
FM24CL16B_SCL_LOW;
delay_us(2);
FM24CL16B_SCL_HIGH;
delay_us(2);
if(FM24CL16B_SDA_READ)
{
FM24CL16B_IIC_Stop();
return 1;
}
FM24CL16B_SCL_LOW;
return 0;
}
uint8_t FM24CL16B_IIC_Read()
{
uint8_t data=0;
FM24CL16B_SDA_IN();
FM24CL16B_SCL_LOW;
delay_us(2);
for(uint8_t i=0;i<8;i++)
{
FM24CL16B_SCL_HIGH;
delay_us(2);
data<<=1;
if(FM24CL16B_SDA_READ)
{
data|=0x01;
}
FM24CL16B_SCL_LOW;
delay_us(2);
}
return data;
}
void FM24CL16B_IIC_Write(uint8_t data)
{
FM24CL16B_SDA_OUT();
FM24CL16B_SCL_LOW;
for(uint8_t i=0;i<8;i++)
{
if(data & 0x80)
{
FM24CL16B_SDA_HIGH;
}
else
{
FM24CL16B_SDA_LOW;
}
data<<=1;
delay_us(4);
FM24CL16B_SCL_HIGH;
delay_us(4);
FM24CL16B_SCL_LOW;
delay_us(4);
}
//数据位拉高,等待应答
FM24CL16B_SDA_HIGH;
}
/**
* desc:FM24CL16B写入1个字节
* params:
* page:需要写入数据的页地址:0~7,一共8页
* addr:需要写入数据的段地址:0~255,一共256个地址段
* writeData:需要写入的字节数据
* return:
* 0:写入成功;-1:应答失败
*/
int8_t FM24CL16B_WriteByte(uint8_t page, uint8_t addr, uint8_t writeData)
{
FM24CL16B_IIC_Start();
FM24CL16B_IIC_Write(FM24CL16B_PAGE_WRITE(page));
if(FM24CL16B_IIC_Wait_ACK()!=0) return -1;
FM24CL16B_IIC_Write(addr);
if(FM24CL16B_IIC_Wait_ACK()!=0) return -1;
FM24CL16B_IIC_Write(writeData);
if(FM24CL16B_IIC_Wait_ACK()!=0) return -1;
FM24CL16B_IIC_Stop();
return 0;
}
/**
* desc:FM24CL16B读取1个字节
* params:
* page:需要读取数据的页地址:0~7,一共8页
* addr:需要读取数据的段地址:0~255,一共256个地址段
* writeData:返回读取到的字节数据
* return:
* 0:写入成功;-1:应答失败
*/
int8_t FM24CL16B_ReadByte(uint8_t page, uint8_t addr, uint8_t *readData)
{
FM24CL16B_IIC_Start();
FM24CL16B_IIC_Write(FM24CL16B_PAGE_WRITE(page));
if(FM24CL16B_IIC_Wait_ACK()!=0) return -1;
FM24CL16B_IIC_Write(addr);
if(FM24CL16B_IIC_Wait_ACK()!=0) return -1;
FM24CL16B_IIC_Start();
FM24CL16B_IIC_Write(FM24CL16B_PAGE_READ(page));
if(FM24CL16B_IIC_Wait_ACK()!=0) return -1;
*readData = FM24CL16B_IIC_Read();
FM24CL16B_IIC_NOACK();
FM24CL16B_IIC_Stop();
return 0;
}
/**
* desc:FM24CL16B写入多个字节
* params:
* page:需要写入数据的页地址:0~7,一共8页
* addr:需要写入数据的段地址:0~255,一共256个地址段
* writeBuff:需要写入的字节数据
* len:需要写入的数据长度
* return:
* 0:写入成功;-1:应答失败
*/
int8_t FM24CL16B_WriteBytes(uint8_t page, uint8_t addr, uint8_t *writeBuff, uint8_t len)
{
//char msg[16];
//sprintf(msg, "%02X %02X %02X %02X\n",writeBuff[0], writeBuff[1], writeBuff[2], writeBuff[3]);
Serial_User_Print((char*)writeBuff);
FM24CL16B_IIC_Start();
FM24CL16B_IIC_Write(FM24CL16B_PAGE_WRITE(page));
if(FM24CL16B_IIC_Wait_ACK()!=0) {
Serial_User_Print("写page无应答");
return -1;
}
FM24CL16B_IIC_Write(addr);
if(FM24CL16B_IIC_Wait_ACK()!=0)
{
Serial_User_Print("写addr无应答");
return -1;
}
for(uint8_t i=0;i<len;i++)
{
FM24CL16B_IIC_Write(writeBuff[i]);
if(FM24CL16B_IIC_Wait_ACK()!=0)
{
Serial_User_Print("写数据无应答");
return -1;
}
}
FM24CL16B_IIC_Stop();
return 0;
}
/**
* desc:FM24CL16B读取多个字节
* params:
* page:需要读取数据的页地址:0~7,一共8页
* addr:需要读取数据的段地址:0~255,一共256个地址段
* readBuff:返回读取到的字节数据
* len:需要读取的数据长度
* return:
* 0:写入成功;-1:应答失败
*/
int8_t FM24CL16B_ReadBytes(uint8_t page, uint8_t addr, uint8_t *readBuff, uint8_t len)
{
FM24CL16B_IIC_Start();
FM24CL16B_IIC_Write(FM24CL16B_PAGE_WRITE(page));
if(FM24CL16B_IIC_Wait_ACK()!=0)
{
Serial_User_Print("write page no answer");
return -1;
}
FM24CL16B_IIC_Write(addr);
if(FM24CL16B_IIC_Wait_ACK()!=0)
{
Serial_User_Print("write addr no answer");
return -1;
}
FM24CL16B_IIC_Start();
FM24CL16B_IIC_Write(FM24CL16B_PAGE_READ(page));
if(FM24CL16B_IIC_Wait_ACK()!=0)
{
Serial_User_Print("read pageno answer");
return -1;
}
for(uint8_t i=0;i<len;i++)
{
readBuff[i] = FM24CL16B_IIC_Read();
if(i == len-1)
{
FM24CL16B_IIC_NOACK();
}
else
{
FM24CL16B_IIC_ACK();
}
}
Serial_User_Print(readBuff);
FM24CL16B_IIC_Stop();
return 0;
}
注:该代码可直接移植到stmf405系列芯片上,只需修改相应引脚即可。