STM32学习笔记之存储器映射(原理篇)

news2025/4/1 15:48:23

📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨
📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】
📢:文章若有幸对你有帮助,可点赞 👍 收藏 ⭐不迷路🙉
📢:内容若有错误,敬请留言 📝指正!原创文,转载注明出处

文章目录

  • 什么是存储器映射呢?
  • 为什么叫存储器映射,而不是寄存器映射呢?
  • 存储器映射实现
  • 什么是寄存器映射?
  • 寄存器映射实现
  • 为什么要设置存储器映射?
  • stm32单片机地址总线访问大小是4G,是不是意味着内存大小也是4G?


什么是存储器映射呢?

存储器本身不具备地址,所以把芯片内核所预先设定好的地址分配给寄存器,就是存储器映射。因为stm32的地址线是32位,也就是2的32次方,正好是对应4G的虚拟存储空间。把内核厂商(也就是ARM公司)定义的这个虚拟空间与芯片厂商(这里是ST)芯片内部外设进行对应,也就是给存储器分配地址,即存储器映射。4个G的地址这么大,用不完没关系,可以保留。

为什么叫存储器映射,而不是寄存器映射呢?

在 STM32 单片机中,“存储器映射” 是指将不同的物理存储区域(如内部闪存、SRAM、外设寄存器等)和一些逻辑存储区域(如系统保留区域等)按照一定的规则,映射到一个统一的地址空间中,使得 CPU 可以通过访问这个统一地址空间中的不同地址来访问不同的物理或逻辑存储区域。因此存储器映射包含寄存器映射。

存储器映射实现

请查看存储器映射关系在代码中是如何体现的。下图是我项目中的 stm32f4xx.h 文件的部分代码。

#define FLASH_BASE            ((uint32_t)0x08000000) /*!< FLASH(up to 1 MB) base address in the alias region                         */
#define CCMDATARAM_BASE       ((uint32_t)0x10000000) /*!< CCM(core coupled memory) data RAM(64 KB) base address in the alias region  */
#define SRAM1_BASE            ((uint32_t)0x20000000) /*!< SRAM1(112 KB) base address in the alias region                             */
#define SRAM2_BASE            ((uint32_t)0x2001C000) /*!< SRAM2(16 KB) base address in the alias region                              */
#define SRAM3_BASE            ((uint32_t)0x20020000) /*!< SRAM3(64 KB) base address in the alias region                              */
#define PERIPH_BASE           ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region                                */
#define BKPSRAM_BASE          ((uint32_t)0x40024000) /*!< Backup SRAM(4 KB) base address in the alias region                         */

#if defined (STM32F40_41xxx)
#define FSMC_R_BASE           ((uint32_t)0xA0000000) /*!< FSMC registers base address                                                */
#endif /* STM32F40_41xxx */

#if defined (STM32F427_437xx) || defined (STM32F429_439xx)
#define FMC_R_BASE            ((uint32_t)0xA0000000) /*!< FMC registers base address                                                 */
#endif /* STM32F427_437xx ||  STM32F429_439xx */

#define CCMDATARAM_BB_BASE    ((uint32_t)0x12000000) /*!< CCM(core coupled memory) data RAM(64 KB) base address in the bit-band region  */
#define SRAM1_BB_BASE         ((uint32_t)0x22000000) /*!< SRAM1(112 KB) base address in the bit-band region                             */
#define SRAM2_BB_BASE         ((uint32_t)0x2201C000) /*!< SRAM2(16 KB) base address in the bit-band region                              */
#define SRAM3_BB_BASE         ((uint32_t)0x22400000) /*!< SRAM3(64 KB) base address in the bit-band region                              */
#define PERIPH_BB_BASE        ((uint32_t)0x42000000) /*!< Peripheral base address in the bit-band region                                */
#define BKPSRAM_BB_BASE       ((uint32_t)0x42024000) /*!< Backup SRAM(4 KB) base address in the bit-band region
/*!< Peripheral memory map */
#define APB1PERIPH_BASE       PERIPH_BASE
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x00010000)
#define AHB1PERIPH_BASE       (PERIPH_BASE + 0x00020000)
#define AHB2PERIPH_BASE       (PERIPH_BASE + 0x10000000)

/*!< APB1 peripherals */
#define TIM2_BASE             (APB1PERIPH_BASE + 0x0000)
#define TIM3_BASE             (APB1PERIPH_BASE + 0x0400)
#define TIM4_BASE             (APB1PERIPH_BASE + 0x0800)
#define TIM5_BASE             (APB1PERIPH_BASE + 0x0C00)
#define TIM6_BASE             (APB1PERIPH_BASE + 0x1000)
#define TIM7_BASE             (APB1PERIPH_BASE + 0x1400)
#define TIM12_BASE            (APB1PERIPH_BASE + 0x1800)
#define TIM13_BASE            (APB1PERIPH_BASE + 0x1C00)
#define TIM14_BASE            (APB1PERIPH_BASE + 0x2000)
#define RTC_BASE              (APB1PERIPH_BASE + 0x2800)
#define WWDG_BASE             (APB1PERIPH_BASE + 0x2C00)
#define IWDG_BASE             (APB1PERIPH_BASE + 0x3000)
#define I2S2ext_BASE          (APB1PERIPH_BASE + 0x3400)
#define SPI2_BASE             (APB1PERIPH_BASE + 0x3800)
#define SPI3_BASE             (APB1PERIPH_BASE + 0x3C00)
#define I2S3ext_BASE          (APB1PERIPH_BASE + 0x4000)

什么是寄存器映射?

在存储器Block2这块区域,设计的是片上外设,它们以4个字节为一个单元,共32bit,那么每一个单元对应不同的功能,当我们控制这些单元时就可以驱动外设工作。我们可以找到每个单元的起始地址,然后通过C语言指针的操作方式来访问这些单元,如果每次都是通过这种地址的方式来访问,不仅不好记忆还容易出错,这是我们可以根据每个单元的功能不同,以功能为名给这个存储单元取一个别名,这个别名就是我们经常说的寄存器,这个给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。

寄存器映射实现

第一步:宏定义GPIO 口的基地址,AHB1PERIPH_BASE 依次累加 0x400的地址偏移量,就得到GPIOA~GPIOK的基地址。

#define GPIOA_BASE            (AHB1PERIPH_BASE + 0x0000)
#define GPIOB_BASE            (AHB1PERIPH_BASE + 0x0400)
#define GPIOC_BASE            (AHB1PERIPH_BASE + 0x0800)
#define GPIOD_BASE            (AHB1PERIPH_BASE + 0x0C00)
#define GPIOE_BASE            (AHB1PERIPH_BASE + 0x1000)
#define GPIOF_BASE            (AHB1PERIPH_BASE + 0x1400)
#define GPIOG_BASE            (AHB1PERIPH_BASE + 0x1800)
#define GPIOH_BASE            (AHB1PERIPH_BASE + 0x1C00)
#define GPIOI_BASE            (AHB1PERIPH_BASE + 0x2000)
#define GPIOJ_BASE            (AHB1PERIPH_BASE + 0x2400)
#define GPIOK_BASE            (AHB1PERIPH_BASE + 0x2800)

第二步:把这个GPIO的基地址通过加上(GPIO_TypeDef *)这步骚操作,来把地址强转成具有GPIO_TypeDef 性质的指针变量,并且用#define进行宏定义,实现取了个别名的效果。这就是寄存器的映射。

#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB               ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC               ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD               ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIOE               ((GPIO_TypeDef *) GPIOE_BASE)
#define GPIOF               ((GPIO_TypeDef *) GPIOF_BASE)
#define GPIOG               ((GPIO_TypeDef *) GPIOG_BASE)
#define GPIOH               ((GPIO_TypeDef *) GPIOH_BASE)
#define GPIOI               ((GPIO_TypeDef *) GPIOI_BASE)
#define GPIOJ               ((GPIO_TypeDef *) GPIOJ_BASE)
#define GPIOK               ((GPIO_TypeDef *) GPIOK_BASE)

GPIO_TypeDef结构体的声明:

typedef struct
{
  __IO uint32_t MODER;    /*!< GPIO port mode register,               Address offset: 0x00      */
  __IO uint32_t OTYPER;   /*!< GPIO port output type register,        Address offset: 0x04      */
  __IO uint32_t OSPEEDR;  /*!< GPIO port output speed register,       Address offset: 0x08      */
  __IO uint32_t PUPDR;    /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */
  __IO uint32_t IDR;      /*!< GPIO port input data register,         Address offset: 0x10      */
  __IO uint32_t ODR;      /*!< GPIO port output data register,        Address offset: 0x14      */
  __IO uint16_t BSRRL;    /*!< GPIO port bit set/reset low register,  Address offset: 0x18      */
  __IO uint16_t BSRRH;    /*!< GPIO port bit set/reset high register, Address offset: 0x1A      */
  __IO uint32_t LCKR;     /*!< GPIO port configuration lock register, Address offset: 0x1C      */
  __IO uint32_t AFR[2];   /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
} GPIO_TypeDef;

为什么要设置存储器映射?

之所以这样做,有以下几个原因:

  • 统一访问接口:CPU通过地址总线访问内存和外设等不同部件时,采用统一的存储器映射方式,就可以使用相同的指令和操作来进行数据的读写。例如,无论是访问内部SRAM中的数据,还是向外设寄存器写入控制命令,都可以通过对相应地址的操作来完成,无需为不同的部件设计不同的访问指令和接口,简化了硬件设计和软件开发的复杂度。
  • 灵活的资源分配:存储器映射可以根据不同的应用需求,灵活地将地址空间分配给各种不同的存储介质和外设。例如,在设计一个具体的产品时,可以根据实际需要,将一部分地址空间分配给外部扩展的大容量Flash存储器用于存储程序和数据,将另一部分地址空间分配给特定的外设,如网络控制器、SD卡控制器等,使系统能够高效地利用各种资源,满足不同的功能需求。
  • 方便系统扩展:当需要对系统进行扩展时,无论是增加新的存储设备还是添加新的外设,都可以通过合理地分配存储器映射地址来实现。新的设备可以很容易地集成到现有的系统中,只需将其映射到未使用的地址空间,并编写相应的驱动程序来访问这些地址即可,而无需对整个系统的架构进行大规模的修改。

stm32单片机地址总线访问大小是4G,是不是意味着内存大小也是4G?

STM32单片机地址总线访问大小是4G,但这并不意味着其内存大小就是4G。

地址总线的宽度决定了CPU可以访问的地址空间范围。STM32单片机基于ARM Cortex - M内核,其具有32位地址总线,所以理论上可访问的地址空间为(2^{32})= 4G字节。然而,这4G的地址空间是包括了多个部分的,不仅仅是内存(RAM和ROM),还包括以下部分:

  • 片上外设寄存器空间:用于访问各种片上外设,如GPIO、USART、SPI等外设的控制寄存器。每个外设都有其特定的地址范围,通过地址总线来访问这些寄存器以实现对外设的控制和数据传输。
  • 外部设备扩展空间:如果单片机扩展了外部的Flash、RAM、FPGA等设备,这些设备也会占用一定的地址空间,与片上资源共同构成整个可寻址的4G空间。
  • 系统保留区域:一些地址范围可能被保留用于特定的系统功能或未来扩展,并不对应实际的物理存储或外设。

实际上,STM32单片机内部的内存(如SRAM和Flash)容量通常远小于4G。不同型号的STM32其内部SRAM一般在几十KB到几百KB之间,内部Flash存储器一般在几十KB到几MB之间。
在这里插入图片描述

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

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

相关文章

如何通过数据可视化提升管理效率

通过数据可视化提升管理效率的核心方法包括清晰展示关键指标、及时发现和解决问题、支持决策优化。其中&#xff0c;清晰展示关键指标尤为重要。通过数据可视化工具直观地呈现关键绩效指标&#xff08;KPI&#xff09;&#xff0c;管理者能快速、准确地理解业务现状&#xff0c…

数据结构:利用递推式计算next表

next 表是 KMP 算法的核心内容&#xff0c;下面介绍一种计算 next 表的方法&#xff1a;利用递推式计算 如图 6.3.1 所示&#xff0c;在某一趟匹配中&#xff0c;当对比到最后一个字符的时候&#xff0c;发现匹配失败&#xff08;s[i] ≠ t[j]&#xff09;。根据 BF 算法&…

每日算法-250326

83. 删除排序链表中的重复元素 题目描述 思路 使用快慢指针遍历排序链表。slow 指针指向当前不重复序列的最后一个节点&#xff0c;fast 指针用于向前遍历探索。当 fast 找到一个与 slow 指向的节点值不同的新节点时&#xff0c;就将 slow 的 next 指向 fast&#xff0c;然后 …

trino查询mysql报Unknown or incorrect time zone: ‘Asia/Shanghai‘

问题 trino查询mysql时报Error listing schemas for catalog mysql: java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.&#xff0c;trino的日志中看到Unknown or incorrect time zone…

java学习笔记7——面向对象

关键字&#xff1a;static 类变量 静态变量的内存解析&#xff1a; 相关代码&#xff1a; public class ChineseTest {public static void main(String[] args) {System.out.println(Chinese.nation); //null 没赋值前System.out.println(Chinese.nation); //中国 静态变量赋值…

C++三大特性之继承

1.继承的概念及定义 回忆封装 C Stack类设计和C设计Stack对比。封装更好&#xff1a;访问限定符类的数据和方法放在一起 -> 避免底层接口的暴露&#xff0c;数据更加的安全&#xff0c;程序的耦合性更高迭代器的设计&#xff0c;封装了容器底层结构&#xff0c;在不暴露底层…

解决Vmware 运行虚拟机Ubuntu22.04卡顿、终端打字延迟问题

亲测可用 打开虚拟机设置&#xff0c;关闭加速3D图形 &#xff08;应该是显卡驱动的问题&#xff0c;不知道那个版本的驱动不会出现这个问题&#xff0c;所以干脆把加速关了&#xff09;

ctfshow做题笔记—栈溢出—pwn73、pwn74

目录 一、pwn73(愉快的尝试一下一把梭吧&#xff01;) 二、pwn74(噢&#xff1f;好像到现在为止还没有了解到one_gadget?) 前言&#xff1a; 抽空闲时间继续学习&#xff0c;记录了两道题&#xff0c;pwn74卡了几天哈哈。 一、pwn73(愉快的尝试一下一把梭吧&#xff01;) …

026-zstd

zstd 以下为Zstandard&#xff08;zstd&#xff09;压缩算法从原理到代码实现的技术调研报告&#xff0c;结合流程图、结构图及完整C代码实现&#xff1a; 一、核心原理与技术架构 1.1 算法原理 Zstd基于LZ77衍生算法与熵编码&#xff08;FSE/Huffman&#xff09;的混合架构&…

AF3 quat_to_rot函数解读

AlphaFold3 rigid_utils 模块的 quat_to_rot 函数的功能是把四元数转换为旋转矩阵,函数利用预定义的四元数到旋转矩阵的转换表 _QTR_MAT 来简化计算。 理解四元数到旋转矩阵的转换 源代码: _quat_elements = ["a", "b", "c", "d"]…

Elasticsearch 的搜索功能

Elasticsearch 的搜索功能 建议阅读顺序&#xff1a; Elasticsearch 入门Elasticsearch 搜索&#xff08;本文&#xff09; 1. 介绍 使用 Elasticsearch 最终目的是为了实现搜索功能&#xff0c;现在先将文档添加到索引中&#xff0c;接下来完成搜索的方法。 查询的分类&…

CSS+JS 堆叠图片动态交互切换

结合DeepSeek提供的代码&#xff0c;终于实现了堆叠两张图片动态循环切换&#xff0c;以下是代码&#xff1a; 通过绝对定位放了两张图片 <div class"col-lg-5" style"z-index: 40; position: relative;"><img src"images/banner_1.png&quo…

内存检查之Valgrind工具

内存检查之Valgrind工具 Author: Once Day Date: 2025年3月26日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章请查看专栏: Linux实践记录_Once-Day的博客-CSD…

强大的AI网站推荐(第四集)—— Gamma

网站&#xff1a;Gamma 号称&#xff1a;展示创意的新媒介 博主评价&#xff1a;快速展示创意&#xff0c;重点是展示&#xff0c;在几秒钟内快速生成幻灯片、网站、文档等内容 推荐指数&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x…

《熔化焊接与热切割作业》考试注意事项

考试前的准备 携带必要的证件和材料&#xff1a;考生需携带身份证、准考证等有效证件&#xff0c;以及考试所需的焊接工具、材料等。确保证件齐全&#xff0c;避免因证件问题影响考试。 提前检查焊接设备和工具&#xff1a;在考试前&#xff0c;考生应仔细检查焊接设备和工具是…

[unity 点击事件] 区域响应点击事件,排除子节点区域,Raycast Target 应用

当我打开一个二级弹窗后&#xff0c;希望可以通过点击弹窗以外的区域来关闭该弹窗。一开始我是在弹窗主节点上挂载了一个 button 组件&#xff0c;该 button 注册的点击事件中关闭该弹窗。在子节点&#xff08;一个背景图&#xff09;的image组件上启用 Raycast Target 选项&am…

鸿蒙生态全解析:应用适配分享

一、鸿蒙系统的技术底座与适配挑战 HarmonyOS NEXT 作为全场景分布式操作系统&#xff0c;通过统一的技术底座和声明式开发框架&#xff0c;实现了 "一次开发&#xff0c;多端部署" 的跨设备协同能力。其核心优势在于&#xff1a; 弹性部署架构&#xff1a;一套系统…

el-select 可搜索下拉框 在ios、ipad 无法唤出键盘,造成无法输入

下一篇&#xff1a;el-select 可搜索下拉框&#xff0c;选中选项后&#xff0c;希望立即失去焦点&#xff0c;收起键盘&#xff0c;执行其他逻辑 【效果图】&#xff1a;分组展示选项 >【去界面操作体验】 首先&#xff0c;通过 夸克浏览器的搜索: el-select 在 ipad 输入框…

Axure设计之中继器表格——拖动列调整位置教程(中继器)

一、原理介绍 实现表格列的拖动排序&#xff0c;主要依赖Axure的动态面板和中继器两大核心功能&#xff1a; 动态面板交互控制 将表格的列标题封装在动态面板中&#xff0c;通过拖拽事件&#xff08;开始、移动、结束&#xff09;捕捉用户操作 在拖拽过程中实时计算鼠标位置&…

基于大数据的各品牌手机销量数据可视化分析系统(源码+lw+部署文档+讲解),源码可白嫖!

摘要 时代在飞速进步&#xff0c;每个行业都在努力发展现在先进技术&#xff0c;通过这些先进的技术来提高自己的水平和优势&#xff0c;各品牌手机销量数据可视化分析系统当然不能排除在外。基于大数据的各品牌手机销量数据可视化分析系统是在实际应用和软件工程的开发原理之…