FRAM铁电存储器FM25W256 | FM24CL04B | FM24CL16B编程实现读写存取数据

本文详细介绍了FRAM存储器通过SPI与I2C接口进行读写操作的方法,包括电路设计、SPI配置及命令解析,并提供了STM32与ESP8266平台上的具体实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


【本文发布于https://blog.youkuaiyun.com/Stack_/article/details/116353030,未经许可不得转载,转载须注明出处】


FM25W256


一、电路

在这里插入图片描述



二、配置SPI(GD32F303)

@ 优快云 Tyrion.Mon
/**
  * @brief  初始化SPI1
  * @note   SPI1_NSS -- PB12
  *         SPI1_SCK -- PB13
  *         SPI1_MI  -- PB14
  *         SPI1_MO  -- PB15
  * @param  None
  * @retval None
  * @author PWH     @ 优快云 Tyrion.Mon
  * @date   2021/3
  */
void SPI1_Init(void)
{
	RCU->RCU_APB1EN.Bits.SPI1EN = 1;			//
	
	/* SCK复用输出 */
	Gd32f30x_Gpio_Init(GPIO_PB13, GPIO_MODE_OUT_50MHZ, GPIO_CTL_AF_PP);
	/* MI上拉输入 */
	Gd32f30x_Gpio_Init(GPIO_PB14, GPIO_MODE_IN, GPIO_CTL_IPU);
	/* MO复用输出 */
	Gd32f30x_Gpio_Init(GPIO_PB15, GPIO_MODE_OUT_50MHZ, GPIO_CTL_AF_PP);
	
	/* SPI1 */
	//1:主机模式
	SPI1->SPI_CTL0.Bits.MSTMOD = 1;
	//0: 2 线单向传输模式
	SPI1->SPI_CTL0.Bits.BDEN = 0;
	//0:全双工模式(当 BDEN 清零时)
	SPI1->SPI_CTL0.Bits.RO = 0;
	//0: 8 位数据帧格式
	SPI1->SPI_CTL0.Bits.FF16 = 0;
	//1: NSS 软件模式, NSS 电平取决于 SWNSS 位
	SPI1->SPI_CTL0.Bits.SWNSSEN = 1;
	SPI1->SPI_CTL0.Bits.SWNSS = 1;
	//SPI1时钟来源:APB1   psc=001 : 4分频  FRAM spi最高20M
	SPI1->SPI_CTL0.Bits.PSC = 1;
	//0:先发送最高有效位
	SPI1->SPI_CTL0.Bits.LF = 0;
	//1: SPI 为空闲状态时, CLK 引脚拉低,此时fram spi工作在mode0
	SPI1->SPI_CTL0.Bits.CKPL = 0;
	//0:在第一个时钟跳变沿采集第一个数据
	SPI1->SPI_CTL0.Bits.CKPH = 0;
	//1: RBNE 中断使能。当 RBNE 置位时,产生中断。
//	SPI1->SPI_CTL1.Bits.RBNEIE = 1;
	//1: SPI 设备使能
	SPI1->SPI_CTL0.Bits.SPIEN = 1;
}



三、命令字

在这里插入图片描述

所有写操作前都必须先发送WREN以使能写操作。

@ 优快云 Tyrion.Mon
/**
  * @brief  使能/使能写操作
  * @note   
  * @param  ENABLE 允许;DISABLE 禁止
  * @retval None
  * @author PWH @ 优快云 Tyrion.Mon
  * @date   2021/3
  */
static void FRAM_WriteEnable(uint8_t EN_DISEN)
{
	FRAM_Select(CS_ENABLE);
	if (EN_DISEN == ENABLE)
		SPIx_SendData(SPI1, WREN);	//使能写操作(WREN操作码使WEL置位,允许写操作)
	else
		SPIx_SendData(SPI1, WRDI);
	FRAM_Select(CS_DISABLE);
}



四、读写

读写状态寄存器

@ 优快云 Tyrion.Mon
/**
  * @brief  读状态寄存器数据
  * @note   
  * @param  NONE
  * @retval 状态寄存器值 
  * @author PWH@ 优快云 Tyrion.Mon
  * @date   2021/3
  */
static uint8_t FRAM_ReadSR(void)
{
	uint8_t ret;
	FRAM_Select(CS_ENABLE);
	SPIx_SendData(SPI1, RDSR);
	ret = SPIx_SendData(SPI1, 0x00);
	FRAM_Select(CS_DISABLE);
	return ret;
}

/**
  * @brief  写状态寄存器
  * @note   
  * @param  状态寄存器值
  * @retval NONE
  * @author PWH @ 优快云 Tyrion.Mon
  * @date   2021/3
  */
static void FRAM_WriteSR(uint8_t val)
{
	FRAM_WriteEnable(ENABLE);	//写SR前需要使能写操作
	
	FRAM_Select(CS_ENABLE);
	SPIx_SendData(SPI1, WRSR);
	SPIx_SendData(SPI1, val);
	FRAM_Select(CS_DISABLE);
}

读写存储块

/**
  * @brief  FRAM
  * @note   
  * @param  None
  * @retval None
  * @author PWH@ 优快云 Tyrion.Mon
  * @date   2021/3
  */
uint16_t FRAM_Write(uint16_t AddrOffset, uint8_t *Data, uint16_t DataLen)
{
	if ((!DataLen) || (AddrOffset > FRAM_ADDR_MAX) || ((AddrOffset + DataLen - 1) > FRAM_ADDR_MAX))
		return 0;
	
	FRAM_WriteSR(0x80);			//写SR寄存器,所有存储块取消写保护
	
	FRAM_WriteEnable(ENABLE);	//写存储块前需要使能写操作

	FRAM_Select(CS_ENABLE);
	
	SPIx_SendData(SPI1, WRITE);								//写指令
	SPIx_SendData(SPI1, (AddrOffset >> 8) & 0x00ff);		//写入起始地址高字节
	SPIx_SendData(SPI1, AddrOffset & 0x00ff);				//写入起始地址低字节
	
	do {
		SPIx_SendData(SPI1, *Data++);
	} while (--DataLen);
	
	FRAM_Select(CS_DISABLE);
	
	FRAM_WriteSR(0x8C);			//写SR寄存器,所有存储块使能写保护

	return 1;
}

/**
  * @brief  FRAM
  * @note   
  * @param  None
  * @retval Noned
  * @author PWH @ 优快云 Tyrion.Mon
  * @date   2021/3
  */
uint16_t FRAM_Read(uint16_t AddrOffset, uint8_t *Data, uint16_t DataLen)
{
	if ((!DataLen) || (AddrOffset > FRAM_ADDR_MAX) || ((AddrOffset + DataLen - 1) > FRAM_ADDR_MAX))
		return 0;
	
	FRAM_Select(CS_ENABLE);
	
	SPIx_SendData(SPI1, READ);								//读指令
	SPIx_SendData(SPI1, (AddrOffset >> 8) & 0x00ff);		//写入起始地址高字节
	SPIx_SendData(SPI1, AddrOffset & 0x00ff);				//写入起始地址低字节
	
	do {
		*Data++ = SPIx_SendData(SPI1, 0x00);
	} while (--DataLen);
	
	FRAM_Select(CS_DISABLE);
	
	return 1;
}




FM24CL04B/FM24CL16B


一、电路


在这里插入图片描述

/*
 * FM24CL04B
 * 1    0    1    0    A2    A1    A0    R/W
 *
 * A2 A1 已硬件拉低, A0作页选择
 *
 * FM24CL16B
 * 1    0    1    0    A2    A1    A0    R/W
 *
 * 外部无地址选择引脚,A2 A1 A0作页选择
 *
 */

二、I2C驱动 (软 – ESP8266)

@ 优快云 Tyrion.Mon

#define I2C_MASTER_SCL_PIN			GPIO_Pin_5
#define I2C_MASTER_SCL_NUM			GPIO_NUM_5
#define I2C_MASTER_SCL_MODE			GPIO_MODE_OUTPUT_OD

#define I2C_MASTER_SDA_PIN			GPIO_Pin_4
#define I2C_MASTER_SDA_NUM			GPIO_NUM_4
#define I2C_MASTER_SDA_MODE			GPIO_MODE_OUTPUT_OD

#define I2C_MASTER_SCL_CLR() 		gpio_set_level(I2C_MASTER_SCL_NUM, 0)//i2c scl
#define I2C_MASTER_SCL_SET() 		gpio_set_level(I2C_MASTER_SCL_NUM, 1)

#define I2C_MASTER_SDA_CLR() 		gpio_set_level(I2C_MASTER_SDA_NUM, 0)//i2c sda
#define I2C_MASTER_SDA_SET() 		gpio_set_level(I2C_MASTER_SDA_NUM, 1)


//延时
void I2C_Master_delay(void)
{
	uint8_t t = 1;
	while (t--);
}
//SDA配置为输出
void I2C_Master_SDA_PIN_OUTPUT(void)
{
#if 0
	gpio_config_t gpio_cfg = {
		.pin_bit_mask = I2C_MASTER_SDA_PIN,
		.mode = GPIO_MODE_OUTPUT_OD,
		.pull_up_en = 0,
		.pull_down_en = 0,
		.intr_type = GPIO_INTR_DISABLE,
	};
	gpio_config(&gpio_cfg);
#else
	gpio_set_direction(I2C_MASTER_SDA_NUM, GPIO_MODE_OUTPUT_OD);
#endif
}
//SDA配置为输入
void I2C_Master_SDA_PIN_INPUT(void)
{
#if 0
	gpio_config_t gpio_cfg = {
		.pin_bit_mask = I2C_MASTER_SDA_PIN,
		.mode = GPIO_MODE_INPUT,
		.pull_up_en = 0,
		.pull_down_en = 0,
		.intr_type = GPIO_INTR_DISABLE,
	};
	gpio_config(&gpio_cfg);
#else
	gpio_set_direction(I2C_MASTER_SDA_NUM, GPIO_MODE_INPUT);
#endif
}
//读取SDA输入电平
uint8_t I2C_Master_SDA_PIN_GET(void)
{
	return gpio_get_level(I2C_MASTER_SDA_NUM);
}
//起始信号
void I2C_Master_Start(void)
{
	I2C_Master_SDA_PIN_OUTPUT();
	I2C_MASTER_SDA_SET();
	I2C_MASTER_SCL_SET();
	I2C_Master_delay();
	I2C_MASTER_SDA_CLR();
	I2C_Master_delay();
	I2C_MASTER_SCL_CLR();
	I2C_Master_delay();
}
//结束信号
void I2C_Master_Stop(void)
{
	I2C_Master_SDA_PIN_OUTPUT();
	I2C_MASTER_SDA_CLR();
	I2C_MASTER_SCL_SET();
	I2C_Master_delay();
	I2C_MASTER_SDA_SET();
}
//发送ack
void I2C_Master_Ack(void)
{
	I2C_Master_SDA_PIN_OUTPUT();
	I2C_MASTER_SDA_CLR();
	I2C_MASTER_SCL_SET();
	I2C_Master_delay();
	I2C_MASTER_SCL_CLR();
	I2C_Master_delay();
}
//发送nack
void I2C_Master_NAck(void)
{
	I2C_Master_SDA_PIN_OUTPUT();
	I2C_MASTER_SDA_SET();
	I2C_MASTER_SCL_SET();
	I2C_Master_delay();
	I2C_MASTER_SCL_CLR();
	I2C_Master_delay();
}
//等待信号响应
uint8_t I2C_Master_WaitAck(void) //测数据信号的电平
{
	uint8_t ack;
	I2C_Master_SDA_PIN_INPUT();
	//I2C_MASTER_SDA_SET();
	//I2C_Master_delay();
	I2C_MASTER_SCL_SET();
	ack = I2C_Master_SDA_PIN_GET();
	I2C_Master_delay();
	I2C_MASTER_SCL_CLR();
	I2C_Master_delay();
	return ack;
}
//写入一个字节
void I2C_Master_Send_Byte(uint8_t dat)
{
	uint8_t i;
	I2C_Master_SDA_PIN_OUTPUT();
	for(i = 0; i < 8; i++)
	{
		if(dat & 0x80)//将dat的8位从最高位依次写入
		{
			I2C_MASTER_SDA_SET();
        }
		else
		{
			I2C_MASTER_SDA_CLR();
        }
		I2C_Master_delay();
		I2C_MASTER_SCL_SET();
		I2C_Master_delay();
		I2C_MASTER_SCL_CLR();//将时钟信号设置为低电平
		dat <<= 1;
    }
}
//写入一个字节
void I2C_Master_Send_1Byte(uint8_t slave_addr, uint8_t reg_address, uint8_t dat)
{

	I2C_Master_Start();
	I2C_Master_Send_Byte(slave_addr);
	I2C_Master_WaitAck();
	I2C_Master_Send_Byte(reg_address);
	I2C_Master_WaitAck();
	I2C_Master_Send_Byte(dat);
	I2C_Master_WaitAck();
	I2C_Master_Stop();
}
//写入n个字节
void I2C_Master_Send_Bytes(uint8_t slave_addr, uint8_t reg_address, uint8_t *dat, uint16_t len)
{
	uint16_t i = 0;

	I2C_Master_Start();
	I2C_Master_Send_Byte(slave_addr);
	I2C_Master_WaitAck();
	I2C_Master_Send_Byte(reg_address);
	I2C_Master_WaitAck();

	for (i = 0; i < len; i++)
	{
		I2C_Master_Send_Byte(dat[i++]);
		I2C_Master_WaitAck();
	}

	I2C_Master_Stop();
}
//读一个字节
void I2C_Master_Read_Byte(uint8_t *dat)
{
	uint8_t i;
	*dat = 0;
	I2C_Master_SDA_PIN_INPUT();
	for(i = 0; i < 8; i++)
	{
		I2C_MASTER_SCL_SET();
		I2C_Master_delay();
		*dat <<= 1;
		if (I2C_Master_SDA_PIN_GET())
			*dat |= 0x01;
		I2C_MASTER_SCL_CLR();
		I2C_Master_delay();
    }
}
void I2C_Master_Init(void)
{
	gpio_config_t gpio_cfg;

	gpio_cfg.pin_bit_mask = I2C_MASTER_SCL_PIN | I2C_MASTER_SDA_PIN;
	gpio_cfg.mode = I2C_MASTER_SCL_MODE;
	gpio_cfg.pull_up_en = 0;
	gpio_cfg.pull_down_en = 0;
	gpio_cfg.intr_type = GPIO_INTR_DISABLE;
	gpio_config(&gpio_cfg);

	I2C_MASTER_SCL_SET();
	I2C_MASTER_SDA_SET();
}
#define FRAM_FM24CL04B						0	//4K bit / 512字节
#define FRAM_FM24CL16B						1	//16K bit / 2K字节

#define FRAM_FM24CLxx						FRAM_FM24CL16B

#define FRAM_I2C_ADDR						0xA0
#if (FRAM_FM24CLxx == FRAM_FM24CL04B)	//2pages x 256bytes
	#define FRAM_PAGE_MAX						2
	#define FRAM_PAGE_BYTES_MAX					256
	#define FRAM_DATA_ADDR_END					0x1FF
#elif (FRAM_FM24CLxx == FRAM_FM24CL16B)	//8pages x 256bytes
	#define FRAM_PAGE_MAX						8
	#define FRAM_PAGE_BYTES_MAX					256
	#define FRAM_DATA_ADDR_END					0x7FF
#endif

/**
  * @名称: FRAM_WriteBytes
  * @描述: FM24CL04B 同一页写入多个字节	256字节x2页
  * @参数:
  * @参数:
  * @日期:2023
  * @返回: bool
  **/
bool FRAM_WriteBytes(uint8_t *pBytes, uint32_t framStartAddress, uint32_t dataLenght)
{
	uint8_t page;

	if (framStartAddress > FRAM_DATA_ADDR_END) return false;

	page = framStartAddress >> 8;
	if ((page + 1) > FRAM_PAGE_MAX) return false;

	I2C_Master_Start();

	I2C_Master_Send_Byte(FRAM_I2C_ADDR | ((page << 1) & 0x0E) | 0x00);
	I2C_Master_WaitAck();
	I2C_Master_Send_Byte(0xFF & framStartAddress);
	I2C_Master_WaitAck();

	for (uint32_t i = 0; i < dataLenght; i++)
	{
		I2C_Master_Send_Byte(pBytes[i]);
		I2C_Master_WaitAck();
	}

	I2C_Master_Stop();

	return true;
}

/**
  * @名称: FRAM_ReadBytes
  * @描述: FM24CL04B 同一页读多个字节	256字节x2页
  * @参数:
  * @参数:
  * @日期:2023
  * @返回: bool
  **/
bool FRAM_ReadBytes(uint8_t *pBytes, uint32_t framStartAddress, uint32_t dataLenght)
{
	uint8_t page;

	if (framStartAddress > FRAM_DATA_ADDR_END) return false;

	page = framStartAddress >> 8;
	if ((page + 1) > FRAM_PAGE_MAX) return false;

	I2C_Master_Start();

	I2C_Master_Send_Byte(FRAM_I2C_ADDR | ((page << 1) & 0x0E) | 0x00);
	I2C_Master_WaitAck();
	I2C_Master_Send_Byte(framStartAddress & 0xFF);
	I2C_Master_WaitAck();

	I2C_Master_Start();
	I2C_Master_Send_Byte(FRAM_I2C_ADDR | ((page << 1) & 0x0E) | 0x01);
	I2C_Master_WaitAck();
	do
	{
		I2C_Master_Read_Byte(pBytes);
		pBytes++;

		if (dataLenght == 1) {
			I2C_Master_NAck();
		}
		else {
			I2C_Master_Ack();
		}
	}while(--dataLenght);

	I2C_Master_Stop();

	return true;
}


读写示例:
uint8_t datArray[10];
FRAM_WriteBytes(datArray, 0, sizeof(datArray));		//写page0第0-9
FRAM_WriteBytes(datArray, 256, sizeof(datArray));	//写page1第0-9
FRAM_WriteBytes(datArray, 512, sizeof(datArray));	//写page2第0-9

FRAM_ReadBytes(datArray, 0, sizeof(datArray));		//读page0第0-9
FRAM_ReadBytes(datArray, 256, sizeof(datArray));	//读page1第0-9
FRAM_ReadBytes(datArray, 512, sizeof(datArray));	//读page2第0-9

三、I2C驱动 (硬 – STM32F103)


@ 优快云 Tyrion.Mon
/**
  * @名称: FRAM_Init
  * @描述: FRAM IO初始化  i2c配置
  * @参数: 
  * @参数: 
  * @日期:2019
  * @返回: bool
  **/
bool FRAM_Init(void)
{
	I2C_InitTypeDef   I2C_InitStruct;
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(FRAM_GPIO_CLK,ENABLE);
	RCC_APB1PeriphClockCmd(FRAM_I2C_CLK, ENABLE);
	
	I2C_InitStruct.I2C_ClockSpeed = 100000;	
	I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;	//该参数只有在 I2C 工作在快速模式(时钟工作频率高于 100KHz)下才有意义。
	I2C_InitStruct.I2C_OwnAddress1 = 0x75;
	I2C_InitStruct.I2C_Ack = I2C_Ack_Enable; 
	I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C_Init(I2C1, &I2C_InitStruct);
	I2C_Cmd(FRAM_I2C, ENABLE);
	
	GPIO_InitStruct.GPIO_Pin =  FRAM_SCL_PIN | FRAM_SDA_PIN;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;               
	GPIO_Init(FRAM_GPIO, &GPIO_InitStruct);
	GPIO_SetBits(FRAM_GPIO, FRAM_SCL_PIN);
	GPIO_SetBits(FRAM_GPIO, FRAM_SDA_PIN);
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;               //先把GPIO设为推挽输出并拉倒高电平再转设为复用开漏输出,这样可以有效解决I2C设备死锁的问题???
	GPIO_Init(FRAM_GPIO, &GPIO_InitStruct);

	return true;
}
/**
  * @名称: FRAM_WriteBytes
  * @描述: FM24CL04B 同一页写入多个字节	256字节x2页
  * @参数: 
  * @参数: 
  * @日期:2019
  * @返回: bool
  **/
bool FRAM_WriteBytes(uint8_t framPage, uint8_t *pBytes, uint8_t framStartAddress, uint8_t dataLenght)
{
	if(framPage > 1 || !dataLenght) return false;
	if(framStartAddress + dataLenght > 256) return false;
	/* Send START condition */
	I2C_GenerateSTART(FRAM_I2C, ENABLE);
	/* Test on EV5 and clear it */
	while(I2C_CheckEvent(FRAM_I2C, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
	//EV5事件被检测到,发送设备地址
	I2C_Send7bitAddress(FRAM_I2C, 0xA0 | (FRAM_ADDRESS << 2) | (framPage << 1), I2C_Direction_Transmitter);
	/* Test on EV6 and clear it */
	while(I2C_CheckEvent(FRAM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) == ERROR);
	//EV6事件被检测到,发送要操作的存储单元地址
	I2C_SendData (FRAM_I2C, framStartAddress);
	/* Test on EV8 and clear it */
	while(I2C_CheckEvent(FRAM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED ) == ERROR);
	do
	{
		//EV8事件被检测到,发送要存储的数据
		I2C_SendData (FRAM_I2C, *pBytes++);
		/* Test on EV8 and clear it */
		while(I2C_CheckEvent(FRAM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED ) == ERROR);
	}while(--dataLenght);
	/* Send STOP condition */
	I2C_GenerateSTOP(FRAM_I2C, ENABLE);
	return true;
}

/**
  * @名称: FRAM_ReadBytes
  * @描述: FM24CL04B 同一页读多个字节	256字节x2页
  * @参数: 
  * @参数: 
  * @返回: bool
  **/
bool FRAM_ReadBytes(uint8_t framPage, uint8_t *pBytes, uint8_t framStartAddress, uint8_t dataLenght)
{
	if(framPage > 1 || !dataLenght) return false;
	if(framStartAddress + dataLenght > 256) return false;
	/* Send START condition */
	I2C_GenerateSTART(FRAM_I2C, ENABLE);
	/* Test on EV5 and clear it */
	while(I2C_CheckEvent(FRAM_I2C, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
	//EV5事件被检测到,发送设备地址
	I2C_Send7bitAddress(FRAM_I2C, 0xA0 | (FRAM_ADDRESS << 2) | (framPage << 1), I2C_Direction_Transmitter);
	/* Test on EV6 and clear it */
	while(I2C_CheckEvent(FRAM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) == ERROR);
	//EV6事件被检测到,发送要操作的存储单元地址
	I2C_SendData (FRAM_I2C, framStartAddress);
	/* Test on EV8 and clear it */
	while(I2C_CheckEvent(FRAM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED ) == ERROR);
	
	/* Send START condition */
	I2C_GenerateSTART(FRAM_I2C, ENABLE);
	/* Test on EV5 and clear it */
	while(I2C_CheckEvent(FRAM_I2C, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
	//EV5事件被检测到,发送设备地址
	I2C_Send7bitAddress(FRAM_I2C, 0xA0 | (FRAM_ADDRESS << 2) | (framPage << 1), I2C_Direction_Receiver);
	/* Test on EV6 and clear it */
	while(I2C_CheckEvent(FRAM_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ) == ERROR);
	
	do
	{
		if(dataLenght == 1)
		{
			I2C_AcknowledgeConfig (FRAM_I2C, DISABLE);
		}
		//EV7事件被检测到	
		while(I2C_CheckEvent(FRAM_I2C, I2C_EVENT_MASTER_BYTE_RECEIVED ) == ERROR);
		//EV8事件被检测到,发送要存储的数据
		*pBytes++ = I2C_ReceiveData (FRAM_I2C);
	}while(--dataLenght);
	/* Send STOP condition */
	I2C_GenerateSTOP(FRAM_I2C, ENABLE);
	I2C_AcknowledgeConfig (FRAM_I2C, ENABLE);
	return true;
}



读写示例:
uint8_t FRAM_ENERGY_BANK[10];
FRAM_ReadBytes(0, FRAM_ENERGY_BANK, 0x00, 10);	//读page0第0-9个数据
FRAM_ReadBytes(1, FRAM_ENERGY_BANK, 0x00, 10);	//读page1第0-9个数据

FRAM_WriteBytes(0, FRAM_ENERGY_BANK, 0x00, 10);	//写page0第0-9个数据
FRAM_WriteBytes(1, FRAM_ENERGY_BANK, 0x00, 10);	//写page1第0-9个数据
### FM24CL16B在RT-Thread操作系统上的使用方法 对于FM24CL16B随机存取存储器(FRAM),当其应用于RT-Thread操作系统时,主要通过I2C接口进行通信。为了使FM24CL16B能够在RT-Thread上正常工作,通常需要编写特定的驱动程序来初始化设备并提供读写功能。 #### 初始化过程 在RT-Thread环境下配置FM24CL16B之前,应先确保已经正确安装了支持I2C协议的相关库文件以及硬件连接无误。接着可以通过调用`rt_i2c_bus_device_register()`函数注册I2C总线,并设置对应的地址参数以便后续访问目标器件[^1]。 ```c #include <rtthread.h> #include <rtdevice.h> #include <board.h> /* 定义I2C总线名称 */ #define I2C_BUS_NAME "i2cbus" static struct rt_i2c_bus_device *i2c_dev; int fm24cl16b_init(void) { /* 获取指定名字的I2C总线对象 */ i2c_dev = (struct rt_i2c_bus_device *)rt_device_find(I2C_BUS_NAME); if (!i2c_dev) return -RT_ERROR; /* 注册I2C设备到系统中 */ rt_i2c_bus_device_register(i2c_dev, I2C_BUS_NAME); return RT_EOK; } ``` 此部分代码实现了对I2C总线资源的获取与注册操作,为下一步具体控制FM24CL16提供了基础环境准备。 #### 数据交互实现 完成上述准备工作之后,则可以利用标准API来进行数据传输动作。下面给出一段简单的例子用于展示如何向FRAM内部写入字节流以及从中读回相同长度的数据: ```c uint8_t write_data[] = {0x01, 0x02}; uint8_t read_data[2]; void fm24cl16b_write_read_test() { struct rt_i2c_msg msgs[2]; int ret; /* 构建消息结构体数组 */ msgs[0].addr = 0xA0 >> 1; // 设备地址右移一位去掉R/W位 msgs[0].flags = RT_I2C_WR; msgs[0].buf = &write_data[0]; // 写入起始位置指针 msgs[0].len = sizeof(write_data); msgs[1].addr = 0xA0 >> 1; msgs[1].flags = RT_I2C_RD; msgs[1].buf = read_data; // 读取缓冲区首地址 msgs[1].len = sizeof(read_data); /* 发送命令序列给I2C控制器执行 */ ret = rt_i2c_transfer(i2c_dev, msgs, 2); if(ret != 2){ /* 错误处理逻辑 */ } } ``` 这段示例展示了完整的写入和读取流程,包括构建消息队列、设定目标寄存器偏移量在内的细节均被涵盖进去。值得注意的是这里采用连续两次独立的消息传递方式分别完成了写入指令发送及随后的结果接收两个阶段的任务。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值