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

📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨
📢:不妨浏览一下我的博客主页【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.mzph.cn/web/73470.shtml

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

相关文章

mapbox V3 新特性,添加三维球鹰眼图控件

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️mapbox-gl-globe-minimap 三维球体鹰眼…

MySQL-调优策略-SQL语句

引言 架构调优&#xff0c;在系统设计时首先需要充分考虑业务的实际情况&#xff0c;是否可以把不适合数据库做的事情放到数据仓库、搜索引擎或者缓存中去做&#xff1b;然后考虑写的并发量有多大&#xff0c;是否需要采用分布式&#xff1b;最后考虑读的压力是否很大&#xf…

6502电气集中联锁道岔控制电路的工作过程

6502电气集中联锁道岔控制电路的工作过程主要包括选择进路、转换道岔、锁闭进路、开放信号和解锁进路等环节&#xff0c;以下是其具体工作过程模拟&#xff1a; 选择进路&#xff1a; 按压按钮&#xff1a;操作人员在控制台上按压进路两端的按钮&#xff0c;如始端按钮和终端按…

DS足球监控【比分直播】监控,钉钉实现自动提醒

文章目录 目标网站分析详细分析提醒工具代码截图成功提示对爬虫、逆向感兴趣的同学可以查看文章,一对一小班教学:https://blog.csdn.net/weixin_35770067/article/details/142514698 目标网站分析 https://live.dszuqiu.com/监控目标:实现固定时间内对比分监控,实现自动下单…

基于ssm的医院预约挂号系统

一、系统架构 前端&#xff1a;jsp | bootstrap | jquery | css | ajax 后端&#xff1a;spring | springmvc | mybatis 环境&#xff1a;jdk1.8 | mysql | maven | tomcat 二、代码及数据 三、功能介绍 01. 注册 02. 登录 03. 首页 04. 医院挂号 05. …

华为OD机试A卷 - 快递业务站 计算快递主站点(C++ Java JavaScript Python )

最新华为OD机试 真题目录:点击查看目录 华为OD面试真题精选:点击立即查看 题目描述 快递业务范围有 N 个站点,A 站点与 B 站点可以中转快递,则认为 A-B 站可达, 如果 A-B 可达,B-C 可达,则 A-C 可达。 现在给 N 个站点编号 0、1、…n-1,用 s[i][j]表示 i-j 是否可…

三维动态规划-LeetCode3418. 机器人可以获得的最大金币数

太爽了&#xff01;做完这道题&#xff0c;让我感觉就像是斩杀了一条大龙&#xff01;历时72天&#xff0c;分3次花掉30小时。终获突破&#xff01; 零、题目 3418. 机器人可以获得的最大金币数 给你一个 m x n 的网格。一个机器人从网格的左上角 (0, 0) 出发&#xff0c;目…

相生、相克、乘侮、复杂病机及对应的脏腑功能联系

一、五行相生关系&#xff08;母子关系&#xff09; 五行生序脏腑关系生理表现举例木生火肝&#xff08;木&#xff09;滋养心&#xff08;火&#xff09;肝血充足则心血旺盛火生土心&#xff08;火&#xff09;温煦脾&#xff08;土&#xff09;心阳充足则脾胃运化功能正常土…

Ubuntu22.04搭建freeradius操作说明

Ubuntu22.04搭建freeradius操作说明 更新依赖库 sudo apt update sudo apt install build-essential sudo apt install libtalloc-dev sudo apt install libssl-dev 按照freeradius sudo apt install freeradius 修改freeradius配置 文件路径如下 /etc/freeradius/3.…

es中安装ik分词器

在线安装ik插件&#xff08;较慢&#xff09; docker exec -it es /bin/bash ./bin/es-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.12.1/elasticsearch-analysis-ik-7.12.1.zip 看到报错了&#xff0c;我访问一下。就是没有了…

最大字段和问题 C++(穷举、分治法、动态规划)

问题描述 给定由n个整数&#xff08;包含负整数&#xff09;组成的序列a1,a2,…,an&#xff0c;求该序列子段和的最大值。规定当所有整数均为负值时定义其最大子段和为0 穷举法 最简单的方法就是穷举法&#xff0c;用一个变量指示求和的开始位置&#xff0c;一个变量指示结束…

如何理解三极管截至区、放大区、饱和区

一、 三极管符号&#xff1a; NPN : PNP: 二、Vce、与Ic曲线图 1、截至区&#xff1a;ib很小的时候就是截至区。因为Ib很小的时候等价于Ub很小&#xff0c;Ub如果不足以达到0.7V PN结就不会导通&#xff0c;所以三极管就…

电脑上我的windows目录下,什么是可以删除的

在Windows系统目录&#xff08;通常是C:\Windows&#xff09;中&#xff0c;大部分文件和文件夹都是系统运行所必需的&#xff0c;随意删除可能导致系统崩溃或程序无法运行。不过&#xff0c;部分文件可以安全清理。以下是详细指南&#xff1a; 可安全清理的内容 临时文件&…

工作中遇到的spark SQL小问题:包含某个或某些字符的条件

今天又来总结工作中遇到的问题了&#xff0c;今天是SQL&#xff0c;spark引擎 需求描述&#xff0c;筛选渠道包含”线上化“的数据 也就是讨论where里面的这个筛选条件怎么写 一般起手都是 where QD like %线上化%‘ 学习了其他的写法: 1.INSTR函数 where INSTR(QD,&quo…

Git 命令操作完全指南

Git 是现代软件开发中不可或缺的分布式版本控制系统。它不仅能追踪代码变更&#xff0c;还能协调多人协作、管理项目历史。本文从核心概念入手&#xff0c;逐步深入讲解 Git 的基础与高级命令&#xff0c;结合实用场景&#xff0c;帮助您从入门到精通。 一、Git 核心概念 理解…

深入剖析带头循环双向链表的实现与应用

引言 场景描述 想象一个 环形地铁线路&#xff08;如深圳地铁11号线&#xff09;&#xff0c;这条线路首尾相连&#xff0c;列车可以顺时针或逆时针循环行驶。为了方便管理&#xff0c;地铁系统设置了一个 “虚拟调度中心”&#xff08;头节点&#xff09;&#xff0c;它不承…

DeepSeek Smallpond 在火山引擎 AI 数据湖的探索实践

资料来源&#xff1a;火山引擎-开发者社区 DeepSeek Smallpond 介绍 Smallpond 是一套由 DeepSeek 推出的 、针对 AI 领域&#xff0c;基于 Ray 和 DuckDB 实现的轻量级数据处理引擎&#xff0c;具有以下优点&#xff1a; 1.轻量级 2.高性能 3.支持规模大 4.无需运维 5.P…

Linux进程间的通信

进程间通信 1.进程间通信介绍2.匿名命名管道原理操作 1.进程间通信介绍 1.1 进程间通信目的&#xff1a;一个进程需要将他的数据发送给另一个进程&#xff0c;大家应该都多少接触过linux中的管道符"|"&#xff0c;这个符号就是用来多个命令执行&#xff0c;在Linux中…

直播预告 | TDgpt 智能体发布 时序数据库 TDengine 3.3.6 发布会即将开启

从海量监控数据&#xff0c;到工业、能源、交通等场景中实时更新的各类传感器数据&#xff0c;时序数据正在以指数级速度增长。而面对如此庞杂的数据&#xff0c;如何快速分析、自动发现问题、精准预测未来&#xff0c;成为企业数字化转型过程中的关键挑战。 TDengine 的答案是…

手撕FIO工具指南:从压测翻车到避坑实战

文章目录 手撕FIO工具指南&#xff1a;从压测翻车到避坑实战一、背景&#xff1a;一次FIO压测引发的惊魂夜二、FIO vs 其他IO工具&#xff1a;为何让人又爱又怕&#xff1f;三、安装指南&#xff1a;避开依赖地狱四、参数详解五、避坑指南&#xff1a;血泪经验总结六、安全压测…