The ARM Memory map

Definitions:

  • AHB-Advanced high performance bus.
  • APB-Advanced peripheral bus.
  • AMBA-Advanced micro-controller bus architecture.

The memory map is a way to access peripherals and other micro-controller features via a memory write or read. The memory map on 32 bit ARM micro-controllers is 4GB (2^32 unsigned) and contiguous.

The reason it is this large is to allow room for expansion and not limit the micro-controller vendors. Examples include adding extra peripherals to a chip revision. The above definitions define buses on the ARM micro-controllers. If the APB is set to 0.5GB, the vendor only has to worry about the APB space but can add numerous peripherals to this bus.

The image below shows the memory map obtained from the data-sheet of the STM32F446RE,note the memory map may be different for different micro-controllers:

mmap

The 4GB memory map is split into eight 512MB sections. To link the memory map to the physcal chip we need the functional block diagram. The image below is part of the block diagram, which shows how the buses are connected to the CPU core:

func

Top section of block diagram

func2

Bottom section of block diagram

The bus matrix is the core of the whole system that controls which master(Cortex core,DMA,USB OTG) controls the slaves(AHB,flash and SRAM).

bus_matrix

By definition from the datasheet:The 32-bit multi-AHB bus matrix interconnects all the masters (CPU, DMAs, USB HS) and the slaves Flash memory, RAM, QuadSPI, FMC, AHB and APB peripherals and ensures a seamless and efficient operation even when several high-speed peripherals work simultaneously.

We shall focus on the GPIO as an example of how the memory map works.

pinout

We would like to write to PB13 above maybe to turn on an led (Port B pin 13/ GPIO B pin 13). We thus look for GPIOB in the memory map

ahb

We can thus see GPIOB is addressable from 0x40020400-0x400207FF . That is great but how do we choose pin 13?

We thus turn from the datasheet to the technical reference manual(TRM).

gpio_registers

As from the above,each GPIO port has 10, 32 bit registers that just determine how the GPIO port works. Remember that this is on the STM32F446RE. It may be different on a different microcontroller even from the same vendor.

Now we turn to the GPIO register map:

gpio_map

We stop temporarily here and recall,

  • AHB1 location  starts at 0x4002 0000. We take this as our base  location(AHB1_BASE) as it is referenced from 0x0000 0000. This is absolute referencing.
  • GPIOB location starts at AHB1_BASE + 0x400, we shall call this GPIOB_BASE. This is relative referencing.

We can now reference GPIOB registers as offsets from GPIOB. Notice the Image above from the reference manual lists the registers as offsets so we can define GPIOB_MODER as GPIOB+0x0 as it is at offset 0.

CHECKING HOW THIS IS APPLIED IN A PRE-WRITTEN DRIVER LIBRARY

Notice that for different GPIOx, the offsets are the same from the base whether it is GPIOA or GPIOB. We can thus define a GPIO as a structure and reference it via a pointer. This is how it is defined in the STM32CUBEF4 drivers:

typedef struct
{
__IO uint32_t GPIOx_MODER;
__IO uint32_t GPIOx_OTYPER;
__IO uint32_t GPIOx_OSPEEDER;
__IO uint32_t GPIOx_IDR;
__IO uint32_t GPIOx_ODR;
__IO uint32_t GPIOx_BSRR;
__IO uint32_t GPIOx_LCKR;
__IO uint32_t GPIOx_AFRL;
} GPIO_TypeDef;

 

 

The __IO modifier is expanded as:

#ifdef __cplusplus
#define __I volatile
/*!<defines ’read only’ permissions */
#else
#define __I volatile const /*!<defines ’read only’ permissions */
#endif
#define __O volatile /*!<defines ’write only’ permissions */
#define __IO volatile /*!<defines ’read / write’ permissions */

Due to the nature of structures in ANSI C, the structure elements are placed in contiguous memory locations in memory. The structure elements must have the same type. Thus the structure is a perfect data structure for this application.

I usually use eclipse to program arm microcontrollers. A good feature is that it allows one to transparently see macro expansions.

eclipse

We thus check GPIOB macro expansion:

eclipse2

Peripheral base is defined as:

#define PERIPH_BASE ((uint32_t)0x40000000)

The peripheral base can be seen in the memory map below. All peripherals are on the right block.

mmap

AHB1 is offset at 0x20000 from the peripheral base

#define AHB1PERIPH_BASE (PERIPH_BASE + 0x20000)

Remembering that GPIOB is offset at 0x400 from AHB1PERIPH_BASE

 

#define GPIOB_BASE (AHB1PERIPH_BASE + 0x0400)

 

 

Finally to link the struct defining the GPIOx egisters and the definitions above:

#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE)

 

 

GPIO B thus is macro expanded to:

  • GPIOB ((GPIO_TypeDef *) GPIOB_BASE)
  • GPIOB ((GPIO_TypeDef *) (AHB1PERIPH_BASE + 0x0400))
  • GPIOB ((GPIO_TypeDef *) ((PERIPH_BASE + 0x20000) + 0x0400))
  • GPIOB ((GPIO_TypeDef *) ((((uint32_t)0x40000000) + 0x20000) + 0x0400))
  • GPIOB ((GPIO_TypeDef *) ((0x40000000 + 0x20000) + 0x0400))

 

The U suffix after the memory locations such as 0x4000000U are to force the compiler to regard the literal as an unsigned integer. This makes the code more portable across compilers as the drivers are to be used with the customers preferred compiler which could be Keil from arm or the open source bare metal arm toolchain gcc-arm-none-eabi.

Pin 13 is defined as:

#define pin13 ((uint16_t)0x4000U)

 

To toggle a pin:

void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
/* Check the parameters */
assert_param(IS_GPIO_PIN(GPIO_Pin));
GPIOx->ODR ^= GPIO_Pin;
}

 

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s