들어가며
주변 장치 드라이버는 두 가지 방식의 프로그래밍 모델을 제공합니다. 한 가지는 레지스터에 직접 접근하는 방식(Direct Register Access Model, DRA)이고 다른 한 가지는 소프트웨어 드라이버 모델입니다. 두 모델은 각각 장단점을 가지고 있으며 개발자는 상황에 맞게 개발 모델을 선택해야 합니다.
레지스터 직접 접근(DRA) 모델
DRA 모델은 제어하고자 하는 주변 장치(Peripherals) 레지스터에 직접 접근하여 개발하는 방식입니다. 레지스터에 접근하기 위해서는 레지스터 주소 값이 정의된 매크로를 이용합니다. 매크로에 정의된 주소 값은 개발하려는 칩마다 다를 수 있어 맞는 헤더 파일을 코드에 포함시킬 필요가 있습니다. 그렇다면 그 헤더 파일은 어디에 있는 걸까요?
헤더 파일은 TivaWare 패키지에 포함된 inc
폴더에서 찾아볼 수 있습니다. 예를 들어 타겟 칩이 TM4C123GH6PM이라면 tm4c123gh6pm.h
라는 파일을 찾아서 코드에 포함해야 합니다.
// 헤더 파일
#include "inc/tm4c123gh6pm.h"
// GPIO PF4 활성화
void Switch_Init(void)
{
volatile unsigned long delay;
SYSCTL_RCGC2_R |= 0x00000020;
delay = SYSCTL_RCGC2_R; // RCGC 레지스터 설정 후 적용까지 3 clock의 지연 시간이 필요함
// 이 코드를 추가함으로 인해서 지연 시간을 벌 수 있음
// delay 변수가 코드에서 사용되는 것은 아님
GPIO_PORTF_AMSEL_R &= ~0x10;
GPIO_PORTF_PCTL_R &= ~0x000F0000;
GPIO_PORTF_DIR_R &= ~0x10;
GPIO_PORTF_AFSEL_R &= ~0x10;
GPIO_PORTF_DEN_R |= 0x10;
GPIO_PORTF_PUR_R |= 0x10;
}
매크로는 아래와 같은 양식으로 작성되어 있습니다.
- 모듈 이름 / 레지스터 이름 / 비트 필드 이름(옵션) / 접미사
가장 먼저 오는 것이 시스템을 나눌 수 있는 큰 단위의 모듈명입니다. SYSCTL, GPIO, ADC, TIMER 등이 이에 해당합니다. 그다음에 이어지는 것은 각 모듈의 세부 기능을 나누는 레지스터 이름입니다. 실행 모드(Run mode)에서 각 모듈에 클럭 전달 여부를 설정하기 위한 RCGC 레지스터나 GPIO 데이터에 접근하기 위한 GPIODATA 등을 말합니다. 비트 필드(bit field)는 레지스터 주소에 있는 비트 위치를 가리키는 이름입니다. 이것은 매크로의 목적에 따라 있을 수도 없을 수도 있습니다. 마지막으로 붙는 접미사는 해당 매크로가 어떤 역할을 하는지 나타내는 것으로 아래와 같은 의미를 가집니다.
_R
로 끝나는 매크로는 레지스터 주소를 의미합니다._M
로 끝나는 매크로는 멀티 비트 필드 레지스터의 마스크를 의미합니다._S
로 끝나는 매크로는 시프트 값을 의미합니다.- 매크로 이름에 별 다른 접미사(suffix)가 없다면 일반적인 값을 의미합니다.
이러한 양식을 파악해둔다면 코드를 보다가 처음 보는 레지스터를 만나더라도 그것이 어떤 역할을 하는지 어느 정도 알 수 있을 것입니다. 그리고 데이터 시트에서 해당 레지스터를 찾아보기에도 수월할 거리고 생각합니다. 그 반대의 경우도 마찬가지고요.
그럼 DRA 방식으로 개발을 하면 어떤 장단점이 있을까요? 소프트웨어 드라이버 모델로 똑같은 동작을 하는 코드를 작성했을 때와 비교하면 다음과 같은 장점이 있습니다.
- 바이너리 파일 크기가 작다.
- 필요한 동작만 하게 되므로 빠르고 효율적으로 동작할 수 있다.
반대로 단점은 아래와 같습니다.
- 능숙한 개발을 위해서는 충분한 지식이 필요하다.
- 레지스터 이름부터 시작해서 활성화하는 순서, 각 레지스터의 비트 필드까지 잘 파악하고 있어야 한다.
DRA 모델은 컴퓨터 자원을 최소한으로 사용할 수 있는 대신 개발자의 노력이 필요하다는 것으로 정리해볼 수 있겠습니다. 그리고 제가 생각하는 장점을 한 가지 덧붙이자면, DRA 방식으로 개발을 익히게 되면 시스템 내부에서 어떤 동작을 하는지 구체적으로 알 수 있습니다. 따라서 MCU 공부를 하는 입장에서는 DRA 방식이 시스템을 이해하는데 도움이 되지 않을까 싶습니다.
소프트웨어 드라이버 모델
소프트웨어 드라이버 모델은 제공되는 API(Application Programming Interface)를 이용해서 주변 장치를 제어하는 방식을 말합니다. 이미 만들어져 있는 함수를 이용해서 장치를 제어하기 때문에 레지스터 설정에 관한 깊은 이해가 없어도 되며 쉽고 빠르게 개발할 수 있습니다.
반면, API는 범용으로 사용될 수 있도록 만들어져 있기 때문에 MCU를 효율적으로 제어하고 싶은 입장에서는 불필요한 자원을 소모할 수 있는 단점이 있습니다. 소프트웨어 드라이버 모델의 장단점은 DRA 모델이 가지는 장단점을 거꾸로 생각하시면 되겠습니다.
소프트웨어 드라이버 모델로 개발을 하기 위해서는 아래 예시 코드와 같이 헤더 파일을 포함시켜야 합니다. 레지스터 주소 값을 담고 있는 inc/hw_memmap.h
파일과 각 모듈을 제어할 수 있는 함수가 선언되어 있는 헤더 파일 (예: driverlib/gpio.h
)말이지요. 이 파일들은 모두 TivaWare 패키지에 포함되어 있습니다.
// 헤더 파일
#include "inc/hw_memmap.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
// GPIO PF3 활성화
int main(void)
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF)){}
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_3);
// ...
}
위 코드를 살펴보면 DRA 모델과는 다르게 단 3줄의 코드로 GPIO 핀을 활성화시켰습니다. 게다가 코드의 내용도 알아보기 쉬워서 다른 핀도 설정하고자 할 때 큰 어려움 없이 해낼 수 있을 것 같습니다. 만약 DRA 방식이었다면 데이터 시트를 보며 각 레지스터의 비트 필드를 확인해가며 필요한 값을 set 혹은 clear 해야만 했을 것입니다. 거기에 다른 비트에 영향이 가지 않도록 비트 AND나 OR 연산을 하면서 말이지요. 확실히 소프트웨어 드라이버 모델이 편하게 개발할 수 있음을 알 수 있습니다.
두 모델을 융합하기
각 프로그래밍 모델의 특징을 살펴보았는데요, 딱히 어느 방법이 좋다고 단정하기는 어렵습니다. 개발을 진행하는 입장에서 보다 맞는 방법을 선택하는 게 맞겠지요. 다행인 것은 한 가지 방법만으로 개발해야 하는 것은 아니라는 사실입니다.
예를 들어 시스템 성능에 구애받지 않는 초기화 과정에서는 소프트웨어 드라이버 모델을 사용합니다. 그리고 매우 짧은 시간에 작업을 처리해야 하는 부분에서는 DRA 모델로 개발할 수도 있습니다. UART 통신이나 ADC 데이터의 수신 처리 등 가능한 한 실시간으로 처리해야 하는 작업은 레지스터에 직접 접근하는데 효율을 높이는 방식입니다.
결국 어느 모델을 사용할 것인지는 개발자의 선택에 달린 문제라고 생각합니다. MCU의 자원을 극한으로 아껴가며 개발해야 한다면 고민할 여지가 없겠습니다. 하지만 그런 경우는 흔하지 않을뿐더러 더 강력한 MCU를 선택하고 개발을 쉽게 해 나가는 방법도 있으니까요. 만약 공부를 목적으로 하고 있다면 이 글 중간에서 말했듯이 DRA 모델을 따라가 보는 것을 권해드립니다.
'연구 노트 > Embedded' 카테고리의 다른 글
CCS 프로젝트 include 경로 설정 (4) | 2020.11.18 |
---|---|
[Modulabs] 2020년 임베디드랩 시즌1 마지막 프로젝트 (0) | 2020.11.13 |
[TM4C] TI사에서 제공하는 예제 프로젝트 추가하기 (0) | 2020.10.19 |
[TM4C] Code Composer Studio 프로젝트 만들기 (0) | 2020.10.19 |
[TM4C] Texas Instruments의 IDE, Code Composer Studio 설치하기 (0) | 2020.10.06 |