铁电存储器FM25CL64B简介及其驱动编写(基于STM32 hal库)

news2025/2/24 3:27:36

铁电存储器FM25CL64B简介及其驱动编写(基于STM32 hal库)

文章目录

  • 铁电存储器FM25CL64B简介及其驱动编写(基于STM32 hal库)
  • 前言
  • 一、FM25CL64B简介
  • 二、驱动代码
    • 1.头文件
    • 2.c文件
  • 总结


前言

FM25CL64B是赛普拉斯cypress出品的一款铁电存储器,这种存储器最大的优势是可以像RAM一样随机存储,和按字节写入,也可以像ROM一样掉电仍然可以保存数据,是一种相当优秀的新型存储器,但是容量不能做得很大,只适合保存一些重要数据。


一、FM25CL64B简介

FM25CL64B是一个串行F-RAM存储器。存储器阵列在逻辑上组织为8192×8位,并使用行业标准串行外围接口(SPI)总线进行访问。F-RAM的功能操作类似于串行闪存和串行EEPROM。FM25CL64B与具有相同引脚的串行闪存或EEPROM的主要区别在于F-RAM的卓越写入性能、高耐久性和低功耗。

①通信协议:
FM25CL64B可以由微控制器驱动,其SPI外围设备以以下两种模式之一运行,支持MSB格式,当通过将CS引脚设置为低电平来选择设备时,
设备会根据SCK引脚的状态检测SPI模式。
■ SPI Mode 0 (CPOL = 0, CPHA = 0)
■ SPI Mode 3 (CPOL = 1, CPHA = 1)

②数据读写:
■控制码:总线主控器可以向FM25CL64B发出六个操作码命令,这些操作码控制存储器执行的功能。
在这里插入图片描述
■读写状态寄存器:FM25CL64B的写保护功能是多层的,通过状态寄存器启用,状态寄存器位0和4-6固定为“0”;这些比特都不能被修改。位0是不必要的,因为F-RAM是实时写入的,从不繁忙,所以它读取为“0”。BP1和BP0控制软件写保护功能,是非易失性位。WEL标志表示写入启用锁存器的状态。尝试直接将WEL位写入状态寄存器对其状态没有影响。该位分别通过WREN和WRDI命令进行内部设置和清除。
初始化时候一般需要对状态寄存器写入0x00操作,但回读不一定0x00,回读为0x02为可写入。
在这里插入图片描述

■写数据:
1、在写入数据之前需要先发送8位写使能操作码(0x02),写使能是单向操作,芯片没有回应。
2、接下来的8位是地址码的高8位(低5位有效,由于本芯片是8K字节,也就是说,地址码的有效位是5+8=13位,所以本区段 只有低5位有效位。对于容量不同的芯片来说,有效位数不一样。
3、第3个8位,是地址码的低8位,均有效。
4、第4个8位,是数据位。具体时序如下
在这里插入图片描述
■读数据:
读数据和写数据时序一样,只不过先发送读操作码(0x03),接下来两个字节是13位地址码,然后从机返回对应地址的数据。具体时序如下
在这里插入图片描述

二、驱动代码

1.头文件

代码如下(示例):

#ifndef __FRAM_H__
#define __FRAM_H__


#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdint.h>

#include "spi_bsp.h"

//Status register   X:be meaningless,0:default value
//  BIT7      BIT6      BIT5      BIT4      BIT3      BIT2      BIT1      BIT0
//  WPEN      X(0)      X(0)      X(0)      BP1       BP0       WEL       X(0)
//  WEL:      1 is write enable, 0 is prohibit write
//  BP0,BP1:  block protection
//  WPEN:

#define FM25CL64_WREN_INST   0x06   //write enable(set WRSR bit),Before writing operations (WRSR and WRITE), this command must be issued first
#define FM25CL64_WRDI_INST   0x04   //write disable(clear WRSR bit),This operation will prohibit write operations (WRSR and WRITE), and even sending (WRSR and WRITE) thereafter will be invalid
#define FM25CL64_RDSR_INST   0x05   //read Status register
#define FM25CL64_WRSR_INST   0x01   //write Status register
#define FM25CL64_WRITE_INST  0x02   //write
#define FM25CL64_READ_INST   0x03   //read
#define FM25CL64_STATUS_REG  0x00
#define FM25CL64_INIT_INST   0x09

#define State       0x0200  //write data to Status register

//片选CS
#define FM25_Enable()   HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10, GPIO_PIN_RESET); 
#define FM25_Disable()  HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10, GPIO_PIN_SET);

extern uint8_t fm25testdata[];  //spi read value

extern uint8_t fm25_bsp_Init();
extern uint8_t Read_FM25CL64_Byte(uint16_t addre);
extern uint8_t Write_FM25CL64_Byte(uint16_t addre, uint8_t dat);
extern uint8_t Read_FM25CL64_nByte(uint16_t addre, uint8_t *buff, uint16_t len);
extern void Write_FM25CL64_nByte(uint16_t addre, uint8_t *buff, uint16_t len);


#endif

2.c文件

代码如下(示例):

#include "fm25_bsp.h"
//测试数据
uint8_t fm25testdata[100] =
{
    0x11, 0x00, 0x1D, 0x02, 0x6B, 0xE0, 0x0E, 0x0F, 0xBC, 0x00,
    0x22, 0xF0, 0xAC, 0x3F, 0x0A, 0x0A, 0x07, 0x02, 0x65, 0x40,
    0x33, 0x45, 0xEF, 0x0F, 0x11, 0x00, 0xFE, 0x00, 0xEC, 0x1B,
    0x44, 0x8A, 0x10, 0x11, 0x25, 0xC3, 0x19, 0x02, 0x6F, 0x63,
    0x55, 0x34, 0x01, 0x12, 0x6B, 0xFA, 0xFE, 0xF0, 0xAC, 0x0A,
    0x66, 0xFE, 0x66, 0x7A, 0x44, 0x8A, 0x10, 0x11, 0x25, 0xE0,
    0x77, 0xDA, 0x77, 0xF0, 0x55, 0x34, 0x01, 0x12, 0x6B, 0x0A,
    0x88, 0x01, 0x88, 0x71, 0x66, 0xFE, 0x66, 0x7A, 0x1B, 0x00,
    0x99, 0x86, 0x99, 0x93, 0x77, 0xDA, 0x77, 0xF0, 0x2F, 0xC3,
    0xAA, 0x0E, 0xAA, 0xFE, 0x88, 0x01, 0x88, 0x71, 0x0B, 0xFA,
};

//1. read Status register
static uint8_t ReadState();
//2. ?????
static uint8_t Check_Start();
//3. ???
static void WriteEnable();
//4. ???
static void WriteState();


uint8_t fm25_bsp_Init()
{
//先对状态寄存器写入解锁,读出状态是否解锁写保护
    WriteState();
    if (ReadState() != 0x02)
    {
        return E_NOT_OK;
    }

    return E_OK;
}

//1. ???
static uint8_t ReadState()
{
    uint8_t r;
    uint8_t Rxbyte = 0;

    WriteEnable();
    FM25_Enable();
    SPI_ReadWriteByte(SPI_2, FM25CL64_RDSR_INST, &Rxbyte);
    SPI_ReadWriteByte(SPI_2, 0x00, &Rxbyte);
    FM25_Disable();

    return (Rxbyte);
}

//2. check read state
static uint8_t Check_Start()
{
    uint8_t i = 0, r = 255;

    do
    {
        r = ReadState();
        i++;
    }
    while ((r & 0x01) && i < 254);
    if (i >= 254)
    {
        return 1;
    }

    return 0;
}

//3. Write Enable
static void WriteEnable()
{
    uint8_t r;
    uint8_t Rxbyte = 0;

    FM25_Enable();
    r = SPI_ReadWriteByte(SPI_2, FM25CL64_WREN_INST, &Rxbyte);
    FM25_Disable();
}

//4. Write Status register
void WriteState()
{
    uint8_t r;
    uint8_t Rxbyte = 0;

    WriteEnable();
    FM25_Enable();
    SPI_ReadWriteByte(SPI_2, FM25CL64_WRSR_INST, &Rxbyte);
    SPI_ReadWriteByte(SPI_2, FM25CL64_STATUS_REG, &Rxbyte);
    FM25_Disable();
    Check_Start();
}

//5. read a byte
uint8_t Read_FM25CL64_Byte(uint16_t addre)
{
    uint8_t r;
    uint8_t dat;
    uint8_t Rxbyte = 0;

    FM25_Enable();
    SPI_ReadWriteByte(SPI_2, FM25CL64_READ_INST, &Rxbyte);
    SPI_ReadWriteByte(SPI_2, (addre & 0xFF00) >> 8, &Rxbyte);
    SPI_ReadWriteByte(SPI_2, (addre & 0x00FF), &Rxbyte);
    SPI_ReadWriteByte(SPI_2, 0x00, &dat);
    FM25_Disable();

    return (dat);
}

//6. read n byte
uint8_t Read_FM25CL64_nByte(uint16_t addre, uint8_t *buff, uint16_t len)
{
    uint8_t r;
    uint8_t dat;
    uint8_t Rxbyte = 0;

    WriteEnable();
    FM25_Enable();
    SPI_ReadWriteByte(SPI_2, FM25CL64_READ_INST, &Rxbyte);
    SPI_ReadWriteByte(SPI_2, (addre & 0xFF00) >> 8, &Rxbyte);
    SPI_ReadWriteByte(SPI_2, (addre & 0x00FF), &Rxbyte);
    for (int i = 0; i < len; i++)
    {
        SPI_ReadWriteByte(SPI_2, 0x00, &buff[i]);
    }
    FM25_Disable();

    return (dat);
}
//7. Write a byte
uint8_t Write_FM25CL64_Byte(uint16_t addre, uint8_t dat)
{
    uint8_t r;
    uint8_t Rxbyte = 0;

    WriteEnable();
    FM25_Enable();
    SPI_ReadWriteByte(SPI_2, FM25CL64_WRITE_INST, &Rxbyte);
    SPI_ReadWriteByte(SPI_2, (addre & 0xFF00) >> 8, &Rxbyte);
    SPI_ReadWriteByte(SPI_2, (addre & 0x00FF), &Rxbyte);
    SPI_ReadWriteByte(SPI_2, dat, &Rxbyte);
    FM25_Disable();

    return (dat);
}


//8. Write n byte
void  Write_FM25CL64_nByte(uint16_t addre, uint8_t *buff, uint16_t len)
{
    uint8_t r;
    uint8_t Rxbyte = 0;

    WriteEnable();
    FM25_Enable();
    SPI_ReadWriteByte(SPI_2, FM25CL64_WRITE_INST, &Rxbyte);
    SPI_ReadWriteByte(SPI_2, (addre & 0xFF00) >> 8, &Rxbyte);
    SPI_ReadWriteByte(SPI_2, (addre & 0x00FF), &Rxbyte);
    for (int i = 0; i < len; i++)
    {
        SPI_ReadWriteByte(SPI_2, buff[i], &Rxbyte);
    }
    FM25_Disable();
}

SPI_ReadWriteByte()函数是自己实现的SPI的收发单字节函数,参数分别为SPI设备号、发送字节内容和接收返回字节的变量的地址。


总结

FM25CL64B的时序和代码驱动实现相对比较简单,唯一需要注意的是需要先通过状态寄存器解锁写保护,否则无法写入。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2280361.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于微信小程序的科创微应用平台设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

HarmonyOS Next 最强AI智能辅助编程工具 CodeGenie介绍

随着大模型的兴起&#xff0c;在智能编码领域首先获得了应用。 市面上从Microsoft Copilot到国内阿里通义&#xff0c;字节marscode等&#xff0c;都提供了copilot方式的智能编码工具。HarmonyOS Next作为诞生一年的新事物&#xff0c;由于代码量和文档迭代原因&#xff0c;在智…

WPF2-1在xaml为对象的属性赋值.md

1. AttributeValue方式 1.1. 简单属性赋值1.2. 对象属性赋值 2. 属性标签的方式给属性赋值3. 标签扩展 (Markup Extensions) 3.1. StaticResource3.2. Binding 3.2.1. 普通 Binding3.2.2. ElementName Binding3.2.3. RelativeSource Binding3.2.4. StaticResource Binding (带参…

Appium(四)

一、app页面元素定位 1、通过id定位元素: resrouce-id2、通过ClassName定位&#xff1a;classname3、通过AccessibilityId定位&#xff1a;content-desc4、通过AndroidUiAutomator定位5、通过xpath定位xpath、id、class、accessibility id、android uiautomatorUI AutomatorUI自…

Windows图形界面(GUI)-QT-C/C++ - Qt List Widget详解与应用

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 目录 QListWidget概述 使用场景 常见样式 QListWidget属性设置 显示方式 (Display) 交互行为 (Interaction) 高级功能 (Advanced) QListWidget常见操作 内容处理 增加项目 删除项目…

Oracle 创建并使用外部表

目录 一. 什么是外部表二. 创建外部表所在的文件夹对象三. 授予访问外部表文件夹的权限3.1 DBA用户授予普通用户访问外部表文件夹的权限3.2 授予Win10上的Oracle用户访问桌面文件夹的权限 四. 普通用户创建外部表五. 查询六. 删除 一. 什么是外部表 在 Oracle 数据库中&#x…

靠右行驶数学建模分析(2014MCM美赛A题)

笔记 题目 要求分析&#xff1a; 比较规则的性能&#xff0c;分为light和heavy两种情况&#xff0c;性能指的是 a.流量与安全 b. 速度限制等分析左侧驾驶分析智能系统 论文 参考论文 两类规则分析 靠右行驶&#xff08;第一条&#xff09;2. 无限制&#xff08;去掉了第一条…

Kafka 源码分析(一) 日志段

首先我们的 kafka 的消息本身是存储在日志段中的, 对应的源码是下面这段代码: class LogSegment private[log] (val log: FileRecords,val lazyOffsetIndex: LazyIndex[OffsetIndex],val lazyTimeIndex: LazyIndex[TimeIndex],val txnIndex: TransactionIndex,val baseOffset:…

【番外篇】实现排列组合算法(Java版)

一、说明 在牛客网的很多算法试题中&#xff0c;很多试题底层都是基于排列组合算法实现的&#xff0c;比如最优解、最大值等常见问题。排列组合算法有一定的难度&#xff0c;并不能用一般的多重嵌套循环解决&#xff0c;没有提前做针对性的学习和研究&#xff0c;考试时候肯定…

Linux - 线程池

线程池 什么是池? 池化技术的核心就是"提前准备并重复利用资源". 减少资源创建和销毁的成本. 那么线程池就是提前准备好一些线程, 当有任务来临时, 就可以直接交给这些线程运行, 当线程完成这些任务后, 并不会被销毁, 而是继续等待任务. 那么这些线程在程序运行过程…

【K8S系列】K8s 领域深度剖析:年度技术、工具与实战总结

引言 Kubernetes作为容器编排领域的行业标准&#xff0c;在过去一年里持续进化&#xff0c;深刻推动着云原生应用开发与部署模式的革新。本文我将深入总结在使用K8s特定技术领域的进展&#xff0c;分享在过去一年中相关技术工具及平台的使用体会&#xff0c;并展示基于K8s的技术…

C++《AVL树》

在之前的学习当中我们已经了解了二叉搜索树&#xff0c;并且我们知道二叉搜索树的查找效率是无法满足我们的要求&#xff0c;当二叉树为左或者右斜树查找的效率就很低下了&#xff0c;那么这本篇当中我们就要来学习对二叉搜索树进行优化的二叉树——AVL树。在此会先来了解AVL树…

【MySQL】存储引擎有哪些?区别是什么?

频率难度60%⭐⭐⭐⭐ 这个问题其实难度并不是很大&#xff0c;只是涉及到的相关知识比较繁杂&#xff0c;比如事务、锁机制等等&#xff0c;都和存储引擎有关系。有时还会根据场景选择不同的存储引擎。 下面笔者将会根据几个部分尽可能地讲清楚 MySQL 中的存储引擎&#xff0…

王道数据结构day1

2.1线性表的定义和基本操作 1.线性表的定义 相同数据类型的数据元素的有限序列 位序(从1开始&#xff09; 表头元素&#xff0c;表尾元素 直接钱去&#xff0c;直接后继 2.线性表的基本操作 基本操作&#xff1a;创销&#xff0c;增删改查 优化插入&#xff1a; 查找

电梯系统的UML文档07

从这个类中得到的类图&#xff0c;构划出了软件的大部分设计。 系统结构视图提供软件和整个系统结构最复杂的也是最优雅的描述。和通常的软件系统相比&#xff0c;在分布式嵌入系统中了解系统组件如何协同工作是非常重要的。毕竟&#xff0c;每个类图仅仅是一个系统的静态设计…

数据恢复常见故障(五)晶振异常导致时钟Clock信号异常引发的硬盘故障

晶振是给固态硬盘“主控”芯片工作提供时钟信号的器件。 高温、高湿、撞件等都会引起晶振不起振&#xff0c;最终导致时钟信号异常。 如图是正常情况下的晶振波形。 晶振异常时&#xff0c;输出的波形&#xff0c;不起振。 由于晶振异常&#xff0c;无法提供时钟信号&#…

16.5万煤气柜柜位计故障分析

一、事故经过&#xff1a; 2015年8月1&#xff14;日20点45分&#xff0c;16.5万立煤气柜柜顶油封溢流口有大量油液溢出&#xff0c;此时雷达柜位计在计算机上示值为63.79米&#xff0c;由于接近傍晚天色较暗&#xff0c;岗位操作员并未及时发现这一异常状况。22点45分左右&…

ARM学习(42)CortexM3/M4 MPU配置

笔者之前学习过CortexR5的MPU配置,现在学习一下CortexM3/M4 MPU配置 1、背景介绍 笔者在工作中遇到NXP MPU在访问异常地址时,就会出现总线挂死,所以需要MPU抓住异常,就需要配置MPU。具体背景情况可以参考ARM学习(41)NXP MCU总线挂死,CPU could not be halted以及无法连…

STM32 FreeRTOS 任务挂起和恢复---实验

实验目标 学会vTaskSuspend( )、vTaskResume( ) 任务挂起与恢复相关API函数使用&#xff1a; start_task:用来创建其他的三个任务。 task1&#xff1a;实现LED1每500ms闪烁一次。 task2&#xff1a;实现LED2每500ms闪烁一次。 task3&#xff1a;判断按键按下逻辑&#xff0c;KE…

七.网络模型

最小(支撑)树问题 最小部分树求解&#xff1a; 破圈法&#xff1a;任取一圈&#xff0c;去掉圈中最长边&#xff0c;直到无圈&#xff1b; 加边法&#xff1a;取图G的n个孤立点&#xff5b;v1&#xff0c;v2&#xff0c;…&#xff0c; vn }作为一个支撑图&#xff0c;从最短…