您现在的位置是:首页 >技术教程 >嵌入式软件开发必备知识—存储器和寄存器器映射(重要)网站首页技术教程

嵌入式软件开发必备知识—存储器和寄存器器映射(重要)

无限嚣张(菜菜) 2024-08-28 00:01:03
简介嵌入式软件开发必备知识—存储器和寄存器器映射(重要)

 一、存储器映射

        存储器映射是一种计算机内存管理技术,它将计算机存储器的一部分映射到处理器的地址空间。这样,处理器就可以直接访问内存中映射的地址,而不需要进行复杂的寻址计算。存储器映射可以用于访问计算机的物理内存、设备寄存器、硬件设备等。在存储器映射中,不同的地址被映射到不同的实际内存位置或硬件设备,这样可以简化对内存的管理和操作。

        存储器是可以存储数据的设备,本身是没有地址信息的,对存储器分配地址的过程称为存储器映射。

先复习一点知识:

        1  Byte  =  8  bit(位)
        1  Kilobyte  (KB)  =  1,024  Bytes
        1  Megabyte  (MB)  =  1,024  KB
        1  Gigabyte  (GB)  =  1,024  M
        1  Terabyte  (TB)  =  1,024  G

我们所说的单片机的的内存大小是说的是字节,而不是位。

        假设一个某个芯片有19根地址线:A0-A18,数据线是:D0-D15(16位,两个字节),他所能访问的地址的标号数就是2^19字节,512 KB个地址,512K*2 = 1024bit = 1M.接下来,我们对其存储器进行映射。

地址范围0-512K
映射10-512K(0x0-0x80000)
映射21-512K(0x0-0x80000)
映射3100k-612K
映射3512K-1024K

存储器功能的划分(F1为例)

ST将4GB(2^32)地址空间分成8个块

ST的4GB的地址空间可以分成8个块,每个块为512MB。

具体分配如下:

1. 块0(Code(FLASH)):    0x00000000 ~ 0x1FFFFFFF(主要用于存储代码)
2. 块1(SRAM):                      0x20000000 ~ 0x3FFFFFFF
3. 块2(片上外设):                  0x40000000 ~ 0x5FFFFFFF(最重要)
4. 块3(FSMC Bank1&2): 0x60000000 ~ 0x7FFFFFFF
5. 块4(FSMC Bank3&4):      0x80000000 ~ 0x9FFFFFFF
6. 块5(FSMC寄存器):            0xA0000000 ~ 0xBFFFFFFF
7. 块6(没用到):                  0xC0000000 ~ 0xDFFFFFFF
8. 块7(Cortex M3内部外设):0xE0000000 ~ 0xFFFFFFFF

每个块都有512MB的地址空间,可以用来存放不同的程序、数据以及内核代码等。这种分块的方式方便操作系统和应用程序进行内存管理,提高系统的稳定性与性能。

二、寄存器映射(重要)

        寄存器是单片机内部一种特殊的内存,可以实现对单片机各个功能的控制。 

        简单来说:寄存器就是单片机内部的控制机构。

什么叫做寄存器映射?

        寄存器是特殊的存储器,给寄存器地址命名的过程,就叫做寄存器映射。

例如我们一个寄存器的地址是0x4001080C,我们给寄存器命名叫做GPIOA_ODR(寄存器名字),这个过程就叫做寄存器映射。

如何直接操作寄存器

*(unsigned int*)(0x4001080C) = 0XFFFF;

即GPIOA_ODR所有的位都是1,即PA0-PA15都是1。

定义一个名字后再操作

# define GPIO_ODR *(unsigned int *)(0X4001080C)

GPIO_ODR = 0XFFFF;

三、寄存器映射计算

问题一:寄存器地址怎么寻找并计算呢?

问题二:如何映射?

解决一

        为了方便编写代码及使用,我们寄存器地址分为三个部分:

1、总线基地址(BUS_BASE_ADDR)

2、外设基于总线基地址的偏移量(PERIPH_OFFSET)

3、寄存器相对与外设基地址的偏移量(REG_OFFSET)

寄存器地址=BUS_BASE_ADDR+PERIPH_OFFSET+REG_OFFSET

以F1为例,我们的总线基地址如下

总线基地址偏移量
APB10X4000 00000
APB20X4001 00000X1 0000
AHB0X4001 8000

0X1 8000

APB1总线的基地址,也叫做外设的基地址(PERIPH_BASE)

此表的偏移量:是相对外设的基地址。

GPIO外设基地址及偏移量

所属总线外设基地址偏移量

APB2

0X4001 0000

GPIOA0X4001 08000X0800
GPIOB0X4001 0C000X0C00
GPIOC0X4001 10000X1000
GPIOD0X4001 14000X1400
GPIOE0X4001 18000X1800
GPIOF0X4001 1C000X1C00
GPIOG0X4001 20000X2000

此表的偏移量:是相对APB2外设基地址(APB2 PERIPH_OFFSET)偏移量

GPIO外设基地址及偏移量

所属总线所属外设寄存器地址偏移量

APB2

0X4001 0000

GPIO

0X4001 0800

GPIOA_CRL0X4001 08000X00
GPIOA_CRH0X4001 08040X04
GPIOA_IDR0X4001 08080X08
GPIOA_ODR0X4001 080C0X0C
GPIOA_BSRR0X4001 08100X10
GPIO_BRR0X4001 08140X14
GPIO_LCKR0X4001 08180X18

GPIO_ODR寄存器地址计算过程:

1.获取外设挂在哪个总线上面?查:系统结构图

2.获取总线的基地址,APB2总线基地址是:0X4001 0000

3.获取外设地址偏移量,GPIOA相对APB2总线偏移量是:0X800

4.获取寄存器地址偏移量,ODR相对GPIOA外设基地址的偏移量是0X0C。

寄存器地址=BUS_BASE_ADDR+PERIPH_OFFSET+REG_OFFSET

GPIO_ODR = 0X4001 0000+0X800+0X0C=0X4001 080C

解决二:

使用结构体可以很方便的实现对寄存器的映射

typdef struct

{

        _IO uint32_t CRL;

        _IO uint32_t CRH;

        _IO uint32_t IDR;

        _IO uint32_t ODR;

        _IO uint32_t BSRR;

        _IO uint32_t LCKR;

}GPIO_TypeDef;

整体映射:

# define GPIOA ((GPIO_TypeDef*)GPIOA_BASE)

取里边的地址:

&GPIOA->CRL:  0X4001 0800

&GPIOA->CRH:0X4001 0804

&GPIOA->IDR:  0x40010808

&GPIOA->ODR:0X4001 080C

实际应用:

GPIO->ODR= 0XFFFF;

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。