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

STM32 SPI调试 外部RAM FM25L04B - 4Kb 3V SPI F-RAM----------512*8bit 存储器地址范围00000H~1FFH,共4Kb(512* 8)bit, FM25V20A - 2MbitF-RAM (Upto 40MHz)--------(256K * 8) 存储器地址范围00000H~3FFFFH,共2Mbit (256k * 8)bit, 其中256k即为 256 * 1024 = 262144 个byte(0x4 00 00,因此存储器最后字节为0x3 ff ff)... 阅读详情
AI摘要

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


【本文发布于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个数据
FRAM铁电存储器FM25W256与FM24CLxx系列 | 跨平台SPI/I2C驱动移植与数据存取实战 本文详细解析了FRAM铁电存储器FM25W256与FM24CLxx系列的技术特点,包括近乎无限的擦写次数和微秒级写入速度。通过SPI/I2C驱动移植与数据存取实战,提供了跨平台开发的关键技巧和常见问题解决方案,适用于需要频繁记录数据的智能电表、工业控制等场景。 阅读详情

相关推荐

基于STM32L4XX、HAL库的FM25W256铁电存储器 驱动程序设计

FM25W256是一款256Kbit(32KB)的串行FRAM(铁电随机存取存储器),具有SPI接口。FRAM结合了RAM的速度和EEPROM的非易失性,适合需要频繁写入和低功耗的应用。FM25W256通过SPI接口与STM32L4XX微控制器通信。: 主输出从输入,连接到STM32的MOSI引脚。: 主输入从输出,连接到STM32的MISO引脚。: SPI时钟线,连接到STM32的SCK引脚。: 片选信号,连接到STM32的GPIO引脚。: 电源(3.3V)。

zhusl6688的博客 900

STM32H750VB读写FM24CL16铁电存储器

STM32H750VB读写FM24CL16铁电存储器,原来一直用stm 32f103硬件I2C总线读写FM24CL16铁电存储器,效果还不错,读写也非常稳定,将原来的程序移植到Stm32h750 VB的芯片上,发现原来的函数都没法用,这是一个痛苦的过程:(, ...

devicenet的博客 4589

AT24C16实例程序

这个是EPROM的读写程序,用51单片机读的 这个还有串口发出来显示

stm32初始化FM25W256

1.WREN-在任何写操作之前发出,会导致内部写锁存被设置,状态寄存器中一个标志位,称为WEL,表示锁存的状态。任何写操作会自动清除写锁存。 2.WRSR-允许用户向状态寄存器写一个字节,在WRSR写之前,/WP必须高位或者不动。 在发送WRSR之前,必须发送一个WERN命令来启动写操作,执行WRSR后会清除写锁存。 写状态寄存器: } FM25W256的写保护状态寄存器 WREN:0000 0110b; //写使能命令 WRSR:0000 0001b; //...

Krysdong 3013

铁电存储器FM25xx驱动程序(15单片机)

本资源主要是以stc15w60s2为开发平台,进行铁电读取与擦写实验,适用于数据的快速存储与高擦写次数的研究。

基于verilog的 IIC(AT24C16)读写测试程序

1、基于IIC协议,采用verilog编写AT24C16驱动程序。 2、实现功能:在AT24C16的地址0~99之间顺序写入数据0~99,然后在读取出来,读取的数据通过串口调试助手显示出来。 3、测试平台Quartus 17.1

STM32-HAL库06-硬件IIC驱动FM24CL16B非易失存储器

STM32F407VGT6硬件IIC驱动FM24CL16B

qq_45854134的博客 1808

fram.rar_STM32 FRAM存储器_stm32 fram_stm32读取fram_铁电FRAM驱动_铁电存储器

stm32f103驱动铁电存储器,测试程序,OK

FRAM铁电存储器FM25W256与FM24CLxx系列 | SPI/I2C双总线驱动移植与数据存取实战

本文详细介绍了FRAM铁电存储器FM25W256与FM24CLxx系列在嵌入式开发中的应用,包括SPI/I2C双总线驱动移植与数据存取实战。通过硬件设计要点、驱动移植优化及高级应用技巧,帮助开发者高效利用FRAM的非易失存储特性,提升系统性能与可靠性。

weixin_29158413的博客 400

pytorchDataLoader中调整数据长度不一致问题(lstm等)

数据长度不一致 用pytorch做rnn的时候,如果输入数据不一样长,可以用两种方式解决。 一种是自定义collate方法, #自定义collate_fn dataloader.DataLoader(dataset,4,True,collate_fn=my_collate) 然后里面写数据和标签载入方式即可 def my_collate(batch): data = [item[0] for item in batch] target = [item[1] for item in batc

weixin_48174100的博客 7770

海思Hi3516DV300实战:从yolov5模型训练到Sort跟踪算法的完整部署流程

本文详细介绍了在海思Hi3516DV300芯片上部署YOLOv5目标检测与Sort多目标跟踪算法的完整流程。内容涵盖从特定场景数据训练YOLOv5模型、模型格式转换(PyTorch到ONNX再到Caffe),到利用海思NNIE引擎生成WK模型并进行端侧集成与优化的全链路实战经验,旨在解决嵌入式设备上实时人流量统计等实际应用挑战。

weixin_29034963的博客 337

告别EEPROM!用FRAM铁电存储器FM25W256/24CLxx做数据存储,实测读写速度与寿命对比

本文深入探讨了FRAM铁电存储器在嵌入式系统中的高效应用,重点对比了FM25W256和FM24CLxx系列与传统EEPROM的性能差异。通过实测数据展示了FRAM近乎无限的擦写次数(10^12次)、150ns的快速写入速度以及超低功耗特性,为工业控制、物联网设备等场景提供了更优的存储解决方案。文章还详细介绍了SPI/I2C接口配置、驱动优化和典型应用案例。

weixin_30752699的博客 507

8.5/Q1,Charls最新高分文章解读!

8 257名受试者中,672人(8.14%)在9年内发生过卒中。在调整的多因素cox回归模型中,TyG和ABSI仍然是卒中的预测因素,TyG的HR为1.25(95%CI:1.06~1.47),ABSI的HR为1.33(95%CI:1.06~1.68)。TyG和ABSI联合诊断效能最高(AUC:0.579,95%CI:0.553~0.597),而TyG(AUC:0.566,95%CI:0.544~0.587)和ABSI(AUC:0.533,95%CI:0.524~0.597)的诊断效能最低。

gsky_sci的博客 1015

FRAM铁电存储器FM25W256与FM24CLxx系列 | 基于GD32/ESP32/STM32的SPI与I2C驱动移植与实战

本文详细解析了FRAM铁电存储器FM25W256(SPI接口)与FM24CLxx系列(I2C接口)的核心特性与选型对比。针对嵌入式开发中EEPROM写寿命不足、Flash速度慢等痛点,提供了基于GD32、STM32及ESP32平台的通用驱动框架设计、实战移植步骤与避坑指南,并展示了如何利用FRAM构建可靠的参数存储系统,帮助开发者快速上手这一高性能非易失存储方案。

weixin_29159441的博客 226

别再死记硬背了!用‘小乌龟’实战图解ROS1核心指令(rosnode/rostopic/rosparam保姆级手册)

本文通过经典的turtlesim乌龟仿真器,以可视化实战方式讲解ROS1核心指令(rosnode/rostopic/rosparam),帮助初学者摆脱死记硬背,在操控乌龟的过程中轻松掌握节点管理、话题通信和参数设置等ROS1核心概念。

weixin_28731223的博客 370

机器学习实战1-四种算法对比对客户信用卡还款情况进行预测与模型评估

大家好,我是微学AI,今天给大家带来一个机器学习实战案例:利用机器学习的四种算法对比对客户信用卡还款情况进行分类。信用卡又叫贷记卡,是由商业银行或信用卡公司对信用合格的消费者发行的信用证明。现在的年轻人,特别是80后,90后甚至00后到喜欢超前消费,每个人名下多多少少都有至少一张信用卡,有些人由于过度超前消费,导致下个月无法还款导致的逾期,这样会对个人征信产生影响,今天我们就来分析分析具有哪些特性的人会有信用卡逾期的可能。

微学AI的博客 4710

Cypress Semiconductor Chip Selection Guide|FRAM, USB Controller & PSoC Programmable SoC Overview

摘要:本文介绍了Cypress Semiconductor(现属Infineon)的主流产品系列及其应用场景。其核心产品包括:1) FRAM铁电存储器(FM系列),具有近乎无限的写入寿命和低功耗特性,适用于工业仪器和传感器节点;2) USB控制器(EZ-USB系列),如CY7C68013A(USB2.0)和CYUSB3014(USB3.0),广泛用于高速数据桥接和FPGA通信;3) PSoC可编程片上系统(如CY8C5868AXI-LP035),集成MCU与可配置模拟/数字模块,适合混合信号采集。文章还提供

ICGOODFIND1的博客 261

【反卷积算法】Richardson-Lucy (RL) :通过不断迭代更新图像估计值

Richardson-Lucy(RL)反卷积算法:是一种基于最大似然估计(Maximum Likelihood Estimation, MLE)的图像去卷积方法,常用于去模糊和图像增强。通过不断地更新图像估计值,来最小化模糊图像和恢复图像之间的误差,逐步消除模糊,最终接近真实的原始图像,每次迭代都会根据当前估计的图像来修正下次迭代的结果。

📷 图像处理践行者 | 传统算法 · 深度学习 · 多模态 | 分享实战经验与技术洞见,探索从像素到智能的无限可能。 3038

fm24c16c语言程序,铁电存储器FM24C16的页面写和任意字节读汇编程序

下面给出FM24C16的页面写和任意字节读汇编子程序。程序经过应用验证,效果良好(为保证稳定性,可以在相应地方加入空语句以延时)。页面写子程序:PAGE-WR: ACALL START_BITMOV A,#10100000BMOV R7,#4ACALL SHFTO;SHFTO为送位子程序,以上3行送1010到FM24C16MOV A,#20HMOV R7,#3ACALL SHFTO;以上3行确定写...

weixin_39913807的博客 957

web渗透学习手册

依据多年的渗透测试项目经验及个人理解,对漏洞分类

渗透之路,攻防之间皆学问 1万+

openharmony之UniProton内核技术揭秘:鸿蒙面向工业控制领域的RTOS设计之道

UniProton是鸿蒙操作系统面向工业控制领域的轻量级实时操作系统(RTOS),专为资源受限的嵌入式设备设计。作为鸿蒙生态的重要组成部分,UniProton提供了高效的实时任务调度、内存管理和IPC机制,满足工业控制场景对实时性和可靠性的严格要求。想象一下,UniProton就像一个超级聪明的管家,管理着电子设备里所有的工作。让你的智能手表既能显示时间,又能接收消息让家里的扫地机器人既能避开障碍物,又能记住哪里已经打扫过了让工厂里的机器人手臂既能精确地抓取东西,又能快速地完成任务实时性强。

m0_67505153的博客 883

【FRAM存储模块的学习及使用】

文章介绍了FRAM的使用并给出了实例代码

weixin_49275308的博客 1768

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

STM32存储左右互搏 SPI总线读写FRAM MB85RS16

在中低容量存储领域,除了FLASH的使用,,还有铁电存储器FRAM的使用,相对于FLASH,FRAM写操作时不需要预擦除,所以执行写操作时可以达到更高的速度,其主要优点为没有FLASH持续写操作跨页地址需要变换的要求。相比于SRAM则具有非易失性, 因此价格方面会高一些。MB85RS16是2K Byte(16K bit)的FRAM,能够按字节进行写入且没有写入等待时间。

Pegasus的软件博客 1958

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

STM32存储左右互搏 SPI总线读写FRAM MB85RS2M

在中低容量存储领域,除了FLASH的使用,,还有铁电存储器FRAM的使用,相对于FLASH,FRAM写操作时不需要预擦除,所以执行写操作时可以达到更高的速度,其主要优点为没有FLASH持续写操作跨页地址需要变换的要求。相比于SRAM则具有非易失性, 因此价格方面会高一些。MB85RS2M是512K Byte(2M bit)的FRAM,能够按字节进行写入且没有写入等待时间。其管脚功能兼容FLASH:这里介绍STM32访问FRAM MB85RS2M的例程。

Pegasus的软件博客 2301

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

FM25V01铁电存储器驱动移植

最近在做毕设,为了兼容PIX的固件,硬件选用了PIX的FMUV5传感器组合: ICM20689 IST8310 MS5611 主控是STM32F407 其他的驱动都好移植 ICM20689 SPI读取 使用42M速度时会出错 改成4分频到21M后正常每1MS读取一次没问题 但是移植到FM25V01时出现了卡顿 和普通的W25QXX不一样,这个芯片在写数据前不需要擦除,尽管写,高达10^...

Kevincoooool 6934

DSP280049C初学(5)-基于IIC的FM24CL16B存储器的使用

DSP280049C初学(5)-基于IIC的FM24CL16B存储器的使用

qq_45854134的博客 1252
上一篇: TI公司16位ADC芯片 --- ADS1158 单端模式使用心得
下一篇: DIY一个USB集线器 --- FE1.1S
Tyrion.Mon
博客等级 码龄8年 251粉丝 53原创
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值