본문 바로가기

뭐라도 만들어보자!!( 프로젝트 )/임베디드

1. 임베디드 실습 : 전체적인 그림

반응형

 진짜 코드를 작성하기에 앞서서 작성한 코드가 어떻게 보드에 올라가서 동작하는 지 알 필요가 있다. 그래야 이 실습이 보다 유익하고 의미있어질 것이다. 과정은 다음과 같다.

  1. 소스 코드를 작성한다.(주로 C 내지는 C++을 이용하여 작성한다.)
  2. 작성한 코드를 컴파일하여 오브젝트 파일을 만든다.
  3. 오브젝트 파일들을 링킹하여 실행가능한 형태로 만든다. (ELF 파일 형태로)
  4. ELF 파일을 다시 바이너리 이미지로 변환한다.
  5. 바이너리 이미지를 JTAG 등을 사용하여 보드 위에 올린다.

1. 코드를 작성한다.

 너무 당연한 말이지만 보드를 동작시키기 위해서는 소스 코드를 작성해야 한다. 소스 코드는 컴퓨터를 동작시키기 위한 명령어의 집합이다. 그렇다면 컴퓨터(내지는 마이크로컨트롤러)는 어떻게 코드를 이해하는 가 ? 우리가 사용하는 언어인 C, C++, Phython 등 프로그래밍 언어를 컴퓨터는 바로 이해할 수 없다. 그렇기에 특수한 프로그램(컴파일러)을 이용하여 컴퓨터가 알아들을 수 있는 형태로 변환한다. 변환된 코드를 살펴보면 0, 1로 이루어진 명령어들의 집합임을 알 수 있다. 

 변환된 명령어들은 당연하지만 특정한 규칙을 따르고 있다.  'a = a + 3'이라는 코드를 어떠한 32-bit MCU에서 동작할 수 있게 컴파일하였다고 가정하자. 그러면 아마도 인스트럭션(Instruction, MCU 동작의 최소 단위)의 길이가 32 bit로 이루어진 바이너리 파일을 받을 수 있을 것이다. MCU는 오직 정해진 바이너리 형태의 파일만을 제대로 읽을 수 있다.

 Okay, 그러면 MCU가 바이너리 형태의 파일만을 읽고 동작할 수 있다는 것을 알았다. 그러면 도대체 어떻게 MCU는 이 바이너리 파일을 읽고 동작하는 가? 프로그램 실행 구조를 인터넷에 검색해 보면 이렇게 나온다.

  1. Fetch : 다음에 실행할 명령어를 주기억 장치로부터 읽어들임
  2. Decode : 명령어를 디코딩
  3. Operand : 피연산자를 주기억 장치로부터 읽어옴
  4. Excute : 명령어를 실행

 MCU 안에는 다양한 종류의 레지스터(Register)들이 있는데, 이 중 PC라 불리는 레지스터는 다음에 실행할 명령어의 주소를 저장하고 있다. 해당 명령어에 위치한 주소에서 인스트럭션을 가져오고(이 역시 다른 레지스터에 저장된다) 명령어 부분을 읽어 어떤 종류의 동작을 해야하는 지 판단한다. 명령어 종류에 따라서 필요한 피연산자의 종류가 달라지기에 명령어의 종류를 파악한 뒤에 피연산자를 메모리로 부터, 혹은 값 그대로 로드 내지는 사용하게 된다. 최종적으로 명령어가 물리적으로 실행된다. 

 

FDE cycle

 

2. 컴파일

 앞서서 말했지만 C, C++와 같이 사람이 사용하는 프로그래밍 언어를 MCU는 이해하지 못한다. MCU가 이해할 수 있는 형태로 코드를 바꾸어줄 필요가 있는 데 이 때 사용되는 것이 컴파일러이다. 컴파일러를 이용하여 MCU가 이해할 수 있는 형태로 바꾸어주는 것을 컴파일링이라고 한다.

 

3, 4 . 링킹 + 바이너리 파일로의 변환

 링킹이란 열거 개의 코드와 데이터를 모아서 연결하여 메모리에 로드될 수 있고 실행될 수 있는 한 갱의 파일로 만드는 작업을 의미한다. 이 때 필요한 것이 링커 스크립트인데, 타깃에서의 메모리 섹션의 서술을 담은 파일이다. .ld 확장자로 식별된다. 링커스크립트는 일종의 설계도면으로 프로그램이 시작될 때 어디에서 시작되는 지, 어느 메모리에 저장되는 지 등을 담고 있다. (링커 스크립트를 제대로 작성하지 않으면 당연하지만 프로그램이 제대로 실행되지 않는다. 링커 스크립트도 데이터 시트를 보며 작성할 필요가 있다.) 만들어진 실행가능한 파일을 다시 바이너리 파일로 변환할 것이다. ELF 파일에는 불필요한 부분들이 포함되어 있는 데, 이를 바이너리 포맷으로 변환하여 제거해 준다.

 

5. 타깃에 프로그램을 올린다.

 말그대로 다 만들어진 실행파일을 타깃 보드에 이식한다. 보통 JTAG/SWD 인터페이스와 상호작용하게 된다. 내부적으로타깃보드를 초기화하고 프로그램을 실행하게 되는 데, 전용 프로그램이 알아서 해준다. 보통은 MCU에 프로그램을 올리기 위해서 JTAG/SWD Debugger를 따로 사야하는 경우도 있는데, NUCLEO-F103RB 보드는 이미 디버거가 결합되어 있는 형태여서 USB 선만 있으면 바로 포팅과 디버깅이 가능하다. 

 

 사실 2번부터 5번까지 일들을 STM32CubeIDE에서 자동으로 해주기 때문에 몰라도 실습을 하는데는 큰 문제는 없다. 그래도 숨겨진 과정들을 알고 실습을 진행하는 것과 단순하게 코드만 따라치는 것에는 큰 차이가 존재한다. 다음 실습에서는 전체적인 프로젝트 구조에 대해서 다루고, 링커 스크립트와 코드를 작성해볼 것이다.

 

 

반응형