【随笔记】FRAM 铁电随机存储器(MB85RC04VPNF)
参考资料
器件规格书: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
通过以下方式实现区分命令与普通的数据读写操作
- 该芯片通过保留地址的方式来实现设备ID的获取功能.
- 通过将真实的器件地址作为保留器件地址的数据,来获取指定芯片的设备ID。
按上述步骤:
- 发起起始信号之后,发送保留从机地址 0xF8(所有设备都会给出应答信号)。
- 得到应答信号之后,发一次本芯片的器件地址 0x52 << 1(只有0x52设备会给出应答信号)。
- 得到应答信号之后,重新再发起起始信号,发送目标从机地址 0xF9(告诉 0x52 设备要读取设备ID)。
- 得到应答信号之后,即可连续读取三个字节的数据(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;
}