버스 아키텍처

위는 간단한 STM32F030의 ‘버스 아키텍처’를 추상적으로 표현한 이미지이다.
이미지에서는 ‘Core’, ‘DMA’를 각각 마스터로 가지며, 슬레이브로 ‘Flash interface’, ‘SRAM’, ‘GPIO Ports …’, ‘AHB to APB bridge’를 가진다.
- Master
- Core
- DMA
- Slave
- Flash interface
- SRAM
- GPIO Ports …
- AHB to APB bridge
Master는 각자의 버스(System, DMA)를 통해서 Bus Matrix에 접근하게 되고, Bus Matrix는 내부적으로 ‘라운드 로빈’ 방식의 알고리즘을 통해서 마스터의 접근을 중재한다.
이때, 마스터는 ‘APB bus’에 연결된 ‘주변 장치’에 접근할 때, ‘AHB to APB 브릿지’를 거쳐야한다.
각각의 버스는 서로 다른 클록 소스에 연결되어 있다. 즉, 최대 속도에 차이가 있을 수 있다.
주변장치 메모리 매핑

위 이미지 처럼 각 버스에 대한 주소가 메모리에 매핑된다.
하지만, 이는 버스 자체가 메모리에 적재된다는 의미는 아니다. CPU에서 특정 버스를 통해 접근해야하는 ‘주변 장치(peripheral)’들의 레지스터 주소를 적절하게 배치한 구조를 의미한다.
위 이미지에서는 CPU가 GPIOA에 접근할 때, ‘AHB2’를 사용하기 때문에 위와 같은 주소에 배치된 것이다.
여담으로 CPU가 메모리에서 특정 ‘주변 기기’의 레지스터를 수정하는 것은 곧바로 해당하는 버스를 통해서 레지스터에 해당하는 ‘주변 기기’로 전달된다. 이는 ‘주변 기기’에서 메모리로 적재되는 과정또한 대부분 그러하다.

GPIO MODER resister 부분의 이미지 예시. 이처럼 레지스터로 존재한다.
HAL에서 추상화한 구조
HAL에서는 위의 설명에서 언급한 버스와 주변기기 매핑에 관한 것들을 모두 추상화 시켜서 제공한다.
예를들어 아래 코드를 살펴보자.
/* GPIO 핀 PA5 설정 */
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);HAL 구조체에 Pin, Mode 등등 다양한 멤버 설정을 하는 것을 볼 수 있다. 추상화된 구조체 ‘GPIO_InitStruct’를 정의하고 HAL_GPIO_Init 함수를 호출하여, 근본적으로 ‘GPIOA’의 레지스터를 초기화하는 식이다.
위 코드를 보다 깊게 이해하기 위해 아래 구조체를 살펴보자.
typedef struct {
volatile uint32_t MODER;
volatile uint32_t OTYPER;
volatile uint32_t OSPEEDR;
volatile uint32_t PUPDR;
volatile uint32_t IDR;
volatile uint32_t ODR;
volatile uint32_t BSRR;
volatile uint32_t LCKR;
volatile uint32_t AFR[2];
volatile uint32_t BRR;
} GPIO_TypeDef;이처럼 GPIO_TypeDef구조체는 각각의 레지스터의 크기에 맞게 정의된다. 이는 다시 아래와 같이 할당된다.
GPIO_TypeDef *GPIOA = 0x48000000;
GPIOA->MODER |= 0x400;
GPIOA->ODR |= 0x20;‘GPIOA’가 매핑된 주소인 ‘0x48000000’에 위치함으로써 추상화된 구조체를 통해 각 레지스터에 접근하여 보다 쉽게 값을 수정하고 읽을 수 있다.