参考资料

器件规格书:https://atta.szlcsc.com/upload/public/pdf/source/20131104/1457706659695.pdf
I2C总线规范:https://community.nxp.com/pwmxy87654/attachments/pwmxy87654/nxp-designs/931/1/UM10204.pdf
第一次接触这种 FRAM 铁电随机存储芯片,发现有几点有意思的知识点,顺带记录一下,数据读写的操作就没啥记录的了。

芯片简介

FRAM 优点:
集结 RAM 的高读写速度但掉电数据丢失和 ROM 掉电仍可报错数据但读写速度很慢的优点。

FRAM 缺点:
访问次数有限(100亿次),超出后不再具有非易失性(即掉电丢失数据),但仍可作为 RAM 使用。

器件地址

高地址为表示方法

这颗芯片的容量有 512 字节,可以通过 I2C 指定地址来读写数据。由于 4KB 的内存地址超出了一个字节所能表示的范围(0-255),该器件采用 7bit 器件地址的最低位作为内存地址的高有效位,即可完整描述(0-511)。这样可以避免使用两个字节来表示内存地址,有效提升读写效率。

在这里插入图片描述

两个从机器件地址

但这样也带来了一个小弊端,该芯片会占用 I2C 总线的两个地址:(A2=0,A1=1,A8=0/1)
0x52 = 1010 010、0x53 = 1010 011

在这里插入图片描述

设备ID

通过以下方式实现区分命令与普通的数据读写操作

  1. 该芯片通过保留地址的方式来实现设备ID的获取功能.
  2. 通过将真实的器件地址作为保留器件地址的数据,来获取指定芯片的设备ID。

【随笔记】FRAM 铁电随机存储器(MB85RC04VPNF)-小白菜博客
在这里插入图片描述

按上述步骤:

  1. 发起起始信号之后,发送保留从机地址 0xF8(所有设备都会给出应答信号)。
  2. 得到应答信号之后,发一次本芯片的器件地址 0x52 << 1(只有0x52设备会给出应答信号)。
  3. 得到应答信号之后,重新再发起起始信号,发送目标从机地址 0xF9(告诉 0x52 设备要读取设备ID)。
  4. 得到应答信号之后,即可连续读取三个字节的数据(0x52 设备会给出应答信号,并输出三个字节数据)。

上述 0xF8、0xF9 是包含了读写位,移除读写位得到 7bit 地址为 0x7C(1111 100),对应下方I2C标准规范(P16):

在这里插入图片描述

同样 I2C 标准规范也制定了读取设备 ID 的流程(P20):

在这里插入图片描述

实测的数据波形

下面解析的地址数据,包含了读写位:
在这里插入图片描述

对应的 Linux 应用层获取的代码:

bool get_pidmid(unsigned short *pid, unsigned short *mid)
{
	struct i2c_msg msgs[2];
	unsigned char val[3] = {0};
	struct i2c_rdwr_ioctl_data i2c_data;
	std::unique_lock<std::mutex> lock(mutex);
	
	memset(&msgs, 0x00, sizeof(msgs));
	memset(&i2c_data, 0x00, sizeof(struct i2c_rdwr_ioctl_data));
	
	i2c_data.nmsgs = 2;
	i2c_data.msgs = msgs;
	
	char data = saddr << 1;
	i2c_data.msgs[0].buf = &data;
    i2c_data.msgs[0].len = 1;
    i2c_data.msgs[0].addr = 0xF8 >> 1;
    i2c_data.msgs[0].flags = 0;

	i2c_data.msgs[1].buf = (char*)val;
    i2c_data.msgs[1].len = 3;
    i2c_data.msgs[1].addr = 0xF9 >> 1;
    i2c_data.msgs[1].flags = 1;
	
    if (ioctl(fd, I2C_RDWR, (unsigned long)&i2c_data) < 0){
        return false;
    }
	
	*pid = val[2] | ((val[1]&0x0F) << 8);
	*mid = (val[0] << 4) | ((val[1]&0xF0) >> 4);
	return true;
}