【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系列芯片上,只需修改相应引脚即可。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值