STM32存储左右互搏 I2C总线读写FRAM MB85RC1M
STM32存储左右互搏 I2C总线读写FRAM MB85RC1M
在较低容量存储领域,除了EEPROM的使用,还有铁电存储器FRAM的使用,相对于EEPROM, 同样是非易失性存储单元,FRAM支持更高的访问速度, 其主要优点为没有EEPROM持续写操作跨页地址需要变换的要求,没有写之后的延时等待要求。MB85RC1M是128K Byte(1M bit)的FRAM,能够按字节进行写入且没有写入等待时间。其管脚功能兼容相应容量的EEPOM:

这里介绍STM32访问FRAM MB85RC1M的例程。采用STM32CUBEIDE开发平台,以STM32F401CCU6芯片为例,通过STM32 I2C硬件电路实现读写操作,通过USB虚拟串口进行控制。
STM32工程配置
首先建立基本工程并设置时钟:



配置硬件I2C接口,STM32F401CCU6的I2C快速模式只支持400KHz速率:


然后配置USB虚拟串口:



保存并生成初始工程代码:

STM32工程代码
USB虚拟串口的使用参考:STM32 USB VCOM和HID的区别,配置及Echo功能实现(HAL)
这里的测试逻辑比较简单,当USB虚拟串口收到任何数据时,STM32在内部对MB85RC1M写入从USB虚拟串口收到的数据,然后再回读出来,通过USB虚拟串口发送出去。
USB接收数据的代码:

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{/* USER CODE BEGIN 6 */extern uint8_t cmd;extern uint8_t * RData;extern uint32_t RDataLen;RData = Buf;RDataLen = *Len;cmd = 1;USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);USBD_CDC_ReceivePacket(&hUsbDeviceFS);return (USBD_OK);/* USER CODE END 6 */
}
MB85RC1M的设备默认访问地址为0xA0, MB85RC1M的存储单元地址访问略为特殊,17位地址分为两部分,最高位的1位放置于I2C设备默认访问地址的第1位,I2C设备默认访问地址第0位仍然为读写控制位,由于采用硬件I2C控制,库函数自行通过识别调用的是发送还是接收函数对第0位进行发送前设置,因此,不管是调用库函数的I2C写操作还是读操作,提供的地址相同。17位地址的低16位通过在发送设备地址后的作为跟随的第一,二个字节发送。
建立MB85RC1M.h库头文件
#ifndef INC_MB85RC1M_H_
#define INC_MB85RC1M_H_#include "main.h"void MB85RC1M_Write(uint32_t addr, uint8_t * data, uint32_t len);
void MB85RC1M_Read(uint32_t addr, uint8_t * data, uint32_t len);#endif
建立MB85RC1M.c库源文件:
#include "MB85RC1M.h"
#include <string.h>extern I2C_HandleTypeDef hi2c1;
extern uint8_t MB85RC1M_Default_I2C_Addr ;
void MB85RC1M_Write(uint32_t addr, uint8_t * data, uint32_t len)
{uint8_t MB85RC1M_I2C_Addr;MB85RC1M_I2C_Addr = MB85RC1M_Default_I2C_Addr | ((addr>>16)<<1); //highest 1-bit access address placed into I2C addressuint8_t TD[len+2];TD[0] = (addr & 0xFF00)>>8; //high 8-bit access address placed into I2C first dataTD[1] =addr & 0x00FF; //low 8-bit access address placed into I2C first datamemcpy(TD+2, data, len);HAL_I2C_Master_Transmit(&hi2c1, MB85RC1M_I2C_Addr, TD, len+2, 2700); //Write data
}void MB85RC1M_Read(uint32_t addr, uint8_t * data, uint32_t len)
{uint8_t MB85RC1M_I2C_Addr;MB85RC1M_I2C_Addr = MB85RC1M_Default_I2C_Addr | ((addr>>16)<<1); //highest 1-bit access address placed into I2C addressuint8_t RA[2];RA[0] = (addr & 0xFF00)>>8; //high 8-bit access address placed into I2C first dataRA[1] =addr & 0x00FF; //low 8-bit access address placed into I2C first dataHAL_I2C_Master_Transmit(&hi2c1, MB85RC1M_I2C_Addr, &RA[0], 2, 2700); //Write address for readHAL_I2C_Master_Receive(&hi2c1, MB85RC1M_I2C_Addr, data, len, 2700); //Read data}
完成的main.c文件代码如下:
/* USER CODE BEGIN Header */
/********************************************************************************* @file : main.c* @brief : Main program body******************************************************************************* @attention** Copyright (c) 2023 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
//Written by Pegasus Yu in 2023
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usb_device.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "MB85RC1M.h"
#include <string.h>
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len);
/* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;/* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t cmd=0; //for status control
uint8_t * RData; //USB rx data pointer
uint32_t RDataLen; //USB rx data length
uint8_t * TData; //USB tx data pointer
uint32_t TDataLen; //USB tx data lengthuint8_t MB85RC1M_Default_I2C_Addr = 0xA0; //Pin A2=A1=0uint32_t MB85RC1M_Access_Addr = 0; //FRAM MB85RC1M access address (17-bit)/* USER CODE END 0 *//*** @brief The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_I2C1_Init();MX_USB_DEVICE_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){if(cmd==1){cmd=0;MB85RC1M_Access_Addr = 0; //Set FRAM access address hereMB85RC1M_Write(MB85RC1M_Access_Addr, RData, RDataLen); //Write dataTDataLen = RDataLen;uint8_t TD[TDataLen];TData = TD;MB85RC1M_Read(MB85RC1M_Access_Addr, TData, TDataLen); //Read dataCDC_Transmit_FS(TData, TDataLen);}/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Configure the main internal regulator output voltage*/__HAL_RCC_PWR_CLK_ENABLE();__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLM = 25;RCC_OscInitStruct.PLL.PLLN = 336;RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;RCC_OscInitStruct.PLL.PLLQ = 7;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK){Error_Handler();}
}/*** @brief I2C1 Initialization Function* @param None* @retval None*/
static void MX_I2C1_Init(void)
{/* USER CODE BEGIN I2C1_Init 0 *//* USER CODE END I2C1_Init 0 *//* USER CODE BEGIN I2C1_Init 1 *//* USER CODE END I2C1_Init 1 */hi2c1.Instance = I2C1;hi2c1.Init.ClockSpeed = 400000;hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;hi2c1.Init.OwnAddress1 = 0;hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;hi2c1.Init.OwnAddress2 = 0;hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;if (HAL_I2C_Init(&hi2c1) != HAL_OK){Error_Handler();}/* USER CODE BEGIN I2C1_Init 2 *//* USER CODE END I2C1_Init 2 */}/*** @brief GPIO Initialization Function* @param None* @retval None*/
static void MX_GPIO_Init(void)
{
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 *//* GPIO Ports Clock Enable */__HAL_RCC_GPIOH_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @brief This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#ifdef USE_FULL_ASSERT
/*** @brief Reports the name of the source file and the source line number* where the assert_param error has occurred.* @param file: pointer to the source file name* @param line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
STM32范例测试
上述范例的测试效果如下:

STM32例程下载
STM32F401CCU6 I2C总线读写FRAM MB85RC1M例程
–End–
相关文章:
STM32存储左右互搏 I2C总线读写FRAM MB85RC1M
STM32存储左右互搏 I2C总线读写FRAM MB85RC1M 在较低容量存储领域,除了EEPROM的使用,还有铁电存储器FRAM的使用,相对于EEPROM, 同样是非易失性存储单元,FRAM支持更高的访问速度, 其主要优点为没有EEPROM持续写操作跨页…...
1340. 跳跃游戏 V;2039. 网络空闲的时刻;2767. 将字符串分割为最少的美丽子字符串
1340. 跳跃游戏 V 核心思想:动态规划记忆化搜索。定义dfs(i),表示从i开始最多可以访问多少个下标,然后统计往左跳和往右边跳的最大值,思路其实比较简单,但是代码我感觉还是不太好想。 2039. 网络空闲的时刻 核心思想…...
ElementUI之CUD+表单验证
目录 前言: 增删改查 表单验证 前言: 继上篇博客来写我们的增删改以及表单验证 增删改查 首先先定义接口 数据样式,我们可以去elementUI官网去copy我们喜欢的样式 <!-- 编辑窗体 --><el-dialog :title"title" :visib…...
Linux:nginx---web文件服务器
我这里使用的是centos7系统 nginx源码包安装 Linux:nginx基础搭建(源码包)_鲍海超-GNUBHCkalitarro的博客-CSDN博客https://blog.csdn.net/w14768855/article/details/131445878?ops_request_misc%257B%2522request%255Fid%2522%253A%25221…...
go 端口转发 代理V2 --chatGPT
问:broker(localPort, targetPort), 实现远程访问localPort的http代理转发到目标机器 gpt: 要实现一个简单的 HTTP 代理服务器,你可以使用 Go 的 net/http 包来处理 HTTP 请求和响应。以下是一个示例,演示如何创建一个 HTTP 代理服务器将本地…...
idea环境下如何打包可运行jar?
工作中有时候偶尔写一些工具类、小程序,可是java程序员制作一个可运行jar实在折腾,利用idea开发环境,可以快速打包自己的可运行jar。具体怎么操作呢? 创建一个空白的java项目并完成自己的程序开发 完成java代码: /**…...
基于FFmpeg的Android播放器
基于FFmpeg的Android播放器 文章目录 基于FFmpeg的Android播放器1. 前言2. 编译相关组件库3. 解码器4. 解码流程5. 音频输出6. 视频输出(需要优化) 1. 前言 FFmpeg是一个最有名的开源的编解码库,实现了通常的编解码逻辑。它还能够根据平台特…...
osgPBR(十五)镜面IBL--查看不同级别的HDR环境贴图
首先,设置可以使用Mipmap,启用三线性过滤,设置最大级别和最小级别 osg::ref_ptr<osg::TextureCubeMap> tcm new osg::TextureCubeMap; tcm->setTextureSize(128, 128);tcm->setFilter(osg::Texture::MIN_FILTER, osg::Texture:…...
Docker的学习记录
Docker是一个被广泛使用的开源容器引擎,基于Go语言,遵从Apache2.0协议开源。 docker的三个概念:容器、镜像和仓库。 镜像(Image):镜像是Docker中的一个模板。通过 Docker镜像 来创建 Docker容器ÿ…...
Android Jetpack组件架构:ViewModel的原理
Android Jetpack组件架构:ViewModel的原理 导言 本篇文章是关于介绍ViewModel的,由于ViewModel的使用还是挺简单的,这里就不再介绍其的基本应用,我们主要来分析ViewModel的原理。 ViewModel的生命周期 众所周知,一般…...
数据分析(python)学习笔记1.0
《利用Python进行数据分析》(原书第2版) 《利用Python进行数据分析》(原书第2版) 《利用Python进行数据分析》(原书第2版) 社区和会议 除了网络搜索,科学、数据相关的Python邮件列表对于解决问题也非常有帮助。可以看看下列邮件列表: pydata:与数据分析和pandas相…...
SW免安装的toolbox只读问题
把SOLIDWORKSDATA 整体复制到另外的目录,然后这里设置目录位置。不然原始位置有只读属性...
nodejs在pdf中绘制表格
需求 之前我已经了解过如何在pdf模板中填写字段了 nodejs根据pdf模板填入中文数据并生成新的pdf文件https://blog.csdn.net/ArmadaDK/article/details/132456324 但是当我具体使用的时候,我发现我的模板里面有表格,表格的长度是不固定的,所…...
使用不同尺寸的传感器拍照时,怎么保证拍出同样视场范围的照片?
1、问题背景 使用竞品机做图像效果对比时,我们通常都会要求拍摄的照片要视场范围一致,这样才具有可比性。之前我会考虑用同样焦距、同样分辨率的设备去拍照对比就可以了,觉得相机的视场范围只由镜头焦距来决定。 但如果对于不同尺寸的传感器…...
01-工具篇-windows与linux文件共享
一般来说绝大部分PC上装的系统均是windows,为了开发linux程序,会在PC上安装一个Vmware的虚拟机,在虚拟机上安装ubuntu18.04,由于windows上的代码查看软件、浏览器,通信软件更全,我们想只用ubuntu进行编译&a…...
医疗实施-住院流程详解
住院就诊流程详解 1.病人入院登记2.病人进入病区3.医生操作病人4.医嘱录入与审核执行5. 医嘱收费前在对应业务系统的操作5.1.药物医嘱5.2.检查检验医嘱5.3.手术医嘱 6.住院医嘱费用的产生7. 医嘱收费后在对应业务系统的操作8. 病人出院 这篇文章是基于我的文章《医疗实施-住院就…...
本地连接服务器 jupyter notebook
本地连接服务器 jupyter notebook 一、前提工作二、服务器操作三、Windows 操作 一、前提工作 准备一台Linux云服务器新建一个用户,并切换到此用户安装 Anaconda 二、服务器操作 远程服务器上安装和配置 Jupyter Notebook: pip3 install jupyter接着…...
Android 使用Kotlin封装RecyclerView
文章目录 1.概述2.运行效果图3.代码实现3.1 扩展RecyclerView 3.2 扩展Adapter3.3 RecyclerView装饰绘制3.3.1 以图片实现分割线3.3.2 画网格线3.3.3空白的分割线3.3.4 不同方向上的分割线 3.4 使用方法 1.概述 在一个开源项目上看到了一个Android Kotlin版的RecyclerView封装…...
WPF 实现点击按钮跳转页面功能
方法1. 配置环境 首先添加prism依赖项,配置好所有文件。需要配置的有两个文件:App.xaml.cs和App.xaml App.xaml.cs using System.Data; using System.Linq; using System.Threading.Tasks; using System.Windows;namespace PrismDemo {/// <summa…...
关于http网络通信数据包封装的过程
当我们谈论网络通信时,数据在从源到目的地传输的过程中会通过多层网络协议。在每一层,都会添加一些头信息(和有时尾信息)来帮助处理和传输数据。这个过程被称为"封装"(Encapsulation)。简单来说&…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
