You are on page 1of 11

[01] TrueStudio 9.

1 for STM32(Arm Cortex-M)

1. TrueStudio 9.1 for STM32(Arm Cortex-M)


TrueStudio는 이클립스 기반의 Cortex-M 계열의 유료 컴파일러로 출발하였으나, 2017년 ST마이크로익렉트로닉스
(STMIcroelectronics, ST)사에 인수된 이후로 ST사의 마이컴에 대해 무료로 제공되기 시작 하였습니다.
ST사에 인수 후 9.0 및 9.1 버전이 릴리즈 되었으며, ST사의 마이컴만을 지원합니다.

1.1 프로그램 설치하기


TrueStudio는 윈도우즈와 리눅스 버전을 제공합니다. atollic(www.atollic.com) 홈페이지를 방문하여 다운로드를 받을 수 있
습니다. 홈페이지의 "TRUESTUDIO"->"DOWNLOAD"를 선택하면 Windows 설치 버전과 Linux 설치버전을 선택하는 화면에서 OS를 선
택하면 e-mail과 몇가지 정보를 입력하면 다운로드가 시작됩니다.

1.1.1 Windows용 TrueStudio 설치


다운로드 받은 설치프로램에 따라 설치가 그리 어렵지 않기 때문에 여기에서는 생략합니다.

1.1.2 Linux용(우분투 16.04 Desktop) TrueStudio 설치


리눅스용 패키지는 압축파일로 배포가 됩니다. 먼저 다음과 같이 압축파일을 해제합니다.
$ tar -xvf Atollic_TrueSTUDIO_for_STM32_linux_x86_64_v9.1.0_20181011-1241.tar.gz

압축 해제된 후 디렉토리로 이동을 한 후에 다음과 같이 설치를 합니다.


$ cd Atollic_TrueSTUDIO_for_STM32_9.1.0_installer && sudo ./install.sh

* 설치를 하기 위해서는 반드시 루트 권한으로 실행이 가능해야 합니다.

기본 디렉토리에 설치를 했을 경우, 다음과 같이 유저 홈 디렉토리에 있는 .bashrc 파일에 PATH를 추가 합니다.


...
export PATH=/opt/Atollic_TrueSTUDIO_for_STM32_9.1.0/ide:$PATH
...

다음과 같이 TrueStudio를 실행합니다.


$ TrueSTUDIO

2. 프로젝트 만들기
TrueStudio를 통해 프로젝트 생성시에 크게 2가지 방법으로 프로젝트를 생성할 수 있습니다. 첫 번째는 TrueStduio의
.cproject와 같이 TrueStudio의 XML 프로젝트 파일을 통해 프로젝트를 관리하는 방법(TrueStudio의 IDE를 통해 관리가 됩니
다.)과 MakeFile을 통해 관리하는 방법이 있습니다. 둘 다 장단점을 갖고 있지만, 주로 MakeFile을 통해 관리하는 방법을 사용
합니다. MakeFile을 사용하게 되면 GCC 컴파일러로 쉽게 빌드를 할 수 있습니다.
TrueStudio의 프로젝트는 C언어만을 지원하는 프로젝트와 C/C++ 모두를 지원하는 프로젝트를 생성할 수 있는데, 여기에서는
C/C++ 모두를 지원하는 프로젝트를 사용합니다.

2.1 TrueStudio 프로젝트 만들기


TrueStudio에서 프로젝트는 다음과 같은 절차로 프로젝트를 만들 수 있습니다.

메뉴에서 File->New->C/C++ Project를 선택합니다.


"Templates for New C/C++ Project" 다이얼로그박스에서 "C++ Managed Build"를 선택한 후에 NEXT를 선택합니다.
"C++ Project" 다이얼로그 박스에서 프로젝트 이름과 "Executable"항목에서 "Embedded C++ Project"를 선택한 후에
NEXT를 선택합니다.
"TrueSTUDIO" 다이얼로그 박스에서 STM32 MCU를 선택 한 후에 FINISH를 누르거나 계속 NEXT를 선택한 후에 마지막에
FINISH를 선택합니다.

2.2 TrueStudio Makefile 프로젝트 만들기


TrueStudio에서 프로젝트는 다음과 같은 절차로 프로젝트를 만들 수 있습니다.

메뉴에서 File->New->C/C++ Project를 선택합니다.


"Templates for New C/C++ Project" 다이얼로그박스에서 "C++ Managed Build"를 선택한 후에 NEXT를 선택합니다.
"C++ Project" 다이얼로그 박스에서 프로젝트 이름과 "Makefile Project"항목에서 "Embedded C++ Project"를 선택한
후에 NEXT를 선택합니다.
"TrueSTUDIO" 다이얼로그 박스에서 STM32 MCU를 선택 한 후에 FINISH를 누르거나 계속 NEXT를 선택한 후에 마지막에
FINISH를 선택합니다.

2.3 TrueStudio 프로젝트 파일


2.1과 2.2에서 프로젝트를 생성하면 2개의 파일이 생성 됩니다. 첫 번째는 .project 파일과 .cproject 파일입니다. Atollic
StrueStudio에서는 .project나 .cproject 파일 모두에서 열 수 있습니다. 2개의 파일은 항상 같은 디렉토리에 존재 합니다.

2.3.1 .project
TrueStudio의 프로젝트 파일로써 프로젝트 이름이 포함되어 있습니다.

2.3.2 .cproject
TrueStudio에서 소스 파일 및 빌드관련한 정보를 포함하고 있습니다. 빌드시스템을 atollic를 사용할지 MakeFile을 사용할지
에 대한 정보는 다음과 같이 .cproject XML 파일의 다음 항목에서 확인을 할 수 있습니다.

Atollic 프로젝트
...
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="attolic_project.com.atollic.truestudio.exe.887755257" name="Executable"
projectType="com.atollic.truestudio.exe"/>
</storageModule>
...

Makefile 프로젝트
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="make.null.639095045" name="make"/>
</storageModule>

3. 프로젝트 설정 변경하기
프로젝트 설정에서 TrueStudio 프로젝트와 MakeFile의 사용에 대해 설정하는 방법이 공통적인 것도 있고 다른 것들도 있습니
다. 프로젝트 설정은 "Project Explorer"에서 먼저 프로젝트를 선택 한 후에 메뉴의 "Project"->"Properties"를 선택하면 됩
니다.
여기에서 중요한 몇가지에 대해서만 설명을 합니다.

3.1 "C/C++ Build"->"Environment"


프로젝트 파일 내에서 여러개의 "Configuration"을 설정할 수 있습니다. 보통은 "Debug"와 "Release"와 같은 구성을 만들 수
있습니다. MakeFile를 사용할 때 여러개의 타겟(Target)을 만들때에도 유용하게 사용됩니다. 이에 대한 예제는 뒤에서 다시 설
명을 하겠습니다.

3.2 "C/C++ General"->"Paths and Symbols"


TrueStudio 프로젝트 파일을 사용할 때만 설정이고 Makefile을 사용할 때에는 Makefile 내에서 합니다. C/C++의 소스를 추가
로 작성시에 컴파일러가 추가로 찾을 include 디렉토리와 Source 디렉토리를 추가 할 수 있습니다.

3.3 "C/C++ General"->"Paths and Symbols"


TrueStudio 프로젝트를 생성하면 디버그 장비 설정이 되어 있지 않습니다.(Makefile도 공통입니다.) "New"를 선택한 후에 추
가를 하면 됩니다. 이에 대한 예제는 뒤에서 다시 설명을 하겠습니다.

3.4 Build Configuartion 관리


3.1에서 여러개의 빌드 환경을 추가하였다면 Proect->Manage Build Configuration을 통해 빌드하고자 하는 빌드 환경을 선택
할 수 있습니다.

4. Makefile를 통한 프로젝트 만들기 예제


"stm32_modulabs"라는 예제를 통해서 맨 처음 프로젝트를 어떻게 만드는지에 대해 설명합니다. 여기에서는 TrueStudio 9.1
버전을 사용하며, 다른 버전에서는 UI는 다를 수 있으나 기본적인 사항은 유사하므로, 다른 버전에서도 그리 어렵지는 않습니다.

4.1 프로젝트 만들기


2.2에서와 같이 Makefile용으로 프로젝트를 만듭니다. TrueStudio를 실행 한 후 다음과 같은 절차로 진행을 합니다.

메뉴 File->New->C/C++ Project를 선택합니다.


"Templates for New C/C++ Project"에서 "C++ Managed Build"를 선택한 후에 Next를 선택합니다.
"C++ Project"에서 Project name에 "stm32_modulabs"을 입력하고 "Use default location"은 언첵크(uncheck)를 선
택하여 예제를 생성할 디렉토리를 선택합니다. Project type에서는 "Makefile project"->"Embedded C++ Project"를
선택한 후에 Next를 선택합니다.
"TrueSTUDIO@ 하드웨어 구성"에서 "STM32H743ZI"를 선택합니다.
"TrueSTUDIO@ 소프트웨어 구성"에서 "tiny printf/sprintf/fprintf 사용(작은 코드 크기)"에 첵크되어 있는 것을 언첵
크(uncheck)를 하고 다른 사항은 수정하지 않고 Next를 선택합니다.
"TrueSTUDO@ 디버거 구성"에서는 기본상태(SEGGER J-LINK)"를 수정하지 않고 Next를 선택합니다.
"Select Configurations"에서 Finish를 선택하면 TrueStudio에서 빌드를 진행하고, Project Explorer에
"stm32_modulabs"가 보이면 됩니다.

위와 같이 빌드가 된 바이너리를 STM32H743ZI 보드에 다운로드를 하면 제대로 실행이 됩니다.

4.2 프로젝트에 여러 보드 지원하기


보통은 하나의 프로젝트가 하나의 보드를 지원하는 형태가 많습니다. 그러나 한 개의 프로젝트에 여러 보드를 지원하게도 작성
을 할 수 있습니다. 우리 임베디드랩에서는 STM32F401CC를 사용한 STEVAL-FCU001V1보드와 STM32H743ZI를 사용한 NUCLEO-
H743ZI 보드 2 종류가 있습니다. 하나의 프로젝트에서 2개의 보드를 지원하는 프로젝트 작성에 대해 설명을 하겠습니다. 2개의
보드를 하나의 프로젝트에서 빌드를 하기 위해서는 TrueStudio에서 지원하는 Project Configuration의 기능을 이용하여 작성
을 합니다.
불행스럽게도 MakeFile을 통해 관리되는 프로젝트에서는 적용이 되지 않습니다.

4.2.1 보드 타겟 만들기
두개의 보드는 서로 다르기 때문에 각각의 보드에 따라 서로 다른 빌드가 되어야 합니다. 그럼므로 두개의 보드를 구별하기 위
해 TARGET_BOARD라는 환경 변수에 보드이름을 할당합니다.
TARGET_BOARD=STEVAL_FCU001V1
TARGET_BOARD=STEVAL_STM32H743ZI

위와 같이 정해졌으면 "Manage Build Configurations"에 두개의 타겟 Configuration을 다음과 같이 추가를 합니다.

메뉴에서 Project->Properties를 선택한 후, "Properties for stm32_modulabs" 다이얼로그 박스에서 "C/C++


Build"를 선택하면, 오른쪽에 있는 "C/C++" Build"화면에서 "Manage Configurations" 버튼이 활성화 됩니다.
"Manage Configurations" 버튼을 누르면 "stm32_modulabs: Manage Configurations" 다이얼로그가 실행됩니다. 이 다
이얼로그에 있는 "New" 버튼을 눌러 4개의 Configurations를 추가합니다.
"Create New Configuration"에서 Name과 Description은 다음과 같이 주며, Copy settings from에서는 "Existing
configuration" "Debug" 상태에서 다음과 같이 4번을 추가 합니다.

1. Name : STEVAL_FCU001V1-DEBUG, Description : STM32F401CC


2. Name : STEVAL_FCU001V1-RELEASE, Description : STM32F401CC
3. Name : NUCLEO_H743ZI-DEBUG, Description :STM32H743ZI
4. Name : NUCLEO_H743ZI-RELEASE, Description :STM32H743ZI

위와 같이 4개의 Configuration이 추가되어 있으면 "stm32_modulabs: Manage Configurations"에는 5개의


Configuration이 보이게 됩니다. 이 중에 "Debug"는 Delete를 한 후에 OK를 선택합니다.
"Properties for stm32_modulabs" 다이얼로그 박스에서 "C/C++ Build"의 >를 누르면 서브메뉴가 펼쳐집니다. 오른쪽
화면의 Configuration에는 "NUCLEO-H743ZI-DEBUG" 부터 "Mutiple Configurations"까지 6개의 항목을 선택할 수 있습
니다. 맨 처음 "Mutiple Configurations"를 선택한 후 NUCELO-H743ZI-xxx와 같이 2개의 보드를 선택합니다. 그리고
왼쪽에 있는 "C/C++ Build"의 서브메뉴 "Environment"를 선택합니다. "Environment"를 선택하면 오른쪽 화면에
"Environment variables to set"가 보이고 아래에 몇 개의 환경 변수가 설정되어 있는 것을 볼 수 있습니다. "Add" 번
튼을 눌러 다음과 같이 추가를 합니다.

Name : TARGET_BOARD
Value : NUCLEO_H743ZI

"Configuration"에서 다른 Configuration을 선택한 후 다시 "Mutiple configurations"를 선택하면 "Select


configuations"화면이 실행됩니다. 이번에는 STEVAL-FCU001V1-xxx와 같이 2개의 보드를 선택합니다. 그리고 위에서와
같이 ADD 버튼을 통해 환경변수에 다음과 같이 추가를 합니다.
Name : TARGET_BOARD
Value : STEVAL_FCU001V1

이번에는 "Multiple configurations"에서 Configuration에서 DEBUG라 붙은 2개를 선택한 후 다음과 같은 환경 변수를


추가합니다.

Name : DEBUG
Value : 1

이번에는 "Multiple configurations"에서 Configuration에서 RELEASE라 붙은 2개를 선택한 후 다음과 같은 환경 변수


를 추가합니다.

Name : DEBUG
Value : 0

위와 같이 설정이 제대로 되었는지는 Configuration에서 각각을 선택한 후에 환경변수를 확인하면 됩니다.

4.2.2 보드 타겟별 빌드하기


보드별 빌드를 하기 위해서는 메뉴 Project->Manage Configurations를 선택하면 "stm32_modulabs: Manage
Configurations" 다이얼로그 박스가 실행됩니다. 빌드하고자 하는 Configuration을 선택한 후 "Set Active"를 선택하면 해당
Configuration이 Active가 됩니다.
그리고 메뉴 Project->Build Project를 선택하면 빌드가 됩니다. 아직까지는 다른 작업을 하지 않았기 때문에 4개의
Configuration에 대해 같은 바이너리가 생성됩니다.

4.3 Makefile 작성하기


Makefile은 GNU make 유틸리티의 스크립트 언어로 작성이 됩니다. 리눅스 쉘프로그래밍에 대한 경험이 있다면 좀 더 쉽게 접
근을 할 수 있으나 경험이 없다면 접근이 쉽지 않습니다. 보통은 기본으로 생성된 Makefile을 사용하더라도 보통 개발을 하게되
면 소스 추가나 패스 추가 등을 위해서라도 기본 스크립트 언어에 대해서 이해가 있어야 합니다.
이 예제에서 작성된 Makefile은 기본 생성된 Makefile과는 상이하며, TrueStudio의 윈도우즈 버전 및 리눅스 버전과, GCC를
지원하기 위해 별도로 작성이 되었습니다.

4.3.1 리눅스와 윈도우즈의 차이점


윈도우즈와 리눅스는 쉘이름부터 패스를 구별하는 문자가 다르기 때문에 Makefile에서는 윈도우즈에서 실행되는지 리눅스에서
실행되는지를 알아야 합니다. 또한, 리눅스의 경우 TrueStudio에서 컴파일하는지 GCC로 컴파일하는지에 대해서도 알아야 합니
다.
다행스럽게 윈도우즈와 리눅스의 구별은 환경변수 PATH로부터 윈도우즈 패스를 통해 구별을 하는데 문제는 윈도우즈 패스명이
대소문자에 따라 정상 동작을 하지 않을 수 있습니다.(윈도우즈는 파일의 대소문자를 구별하지 않습니다.) 다음과 같이
"C:\Windows\System32"라는 문자가 PATH에 존재하면 윈도우즈 환경으로 설정합니다.
# -----------------------------------------------------------------------------
# Atollic Compiler or GCC
ifeq ("$(TRUESTUDIO_BUILD)", "1")
# -----------------------------------------------------------------------------
# Windows or Linux
ifneq (,$(findstring C:\Windows\System32, $(PATH)))
GCC_PREFIX := arm-atollic-eabi
CC = arm-atollic-eabi-gcc
CXX = arm-atollic-eabi-g++
OBJCOPY = arm-atollic-eabi-objcopy
SIZE = arm-atollic-eabi-size
MKDIR_CMD = mkdir
MKDIR_FROM_CHAR =/
MKDIR_TO_CHAR =\\
MKDIR_OPTION = 2> NUL || echo off

OS_NAME = WINDOWS
SHELL = cmd
else
GCC_PREFIX := arm-atollic-eabi
CC = arm-atollic-eabi-gcc
CXX = arm-atollic-eabi-g++
OBJCOPY = arm-atollic-eabi-objcopy
SIZE = arm-atollic-eabi-size
MKDIR_CMD = mkdir -p
MKDIR_FROM_CHAR = \
MKDIR_TO_CHAR = /
MKDIR_OPTION = 2> /dev/null

OS_NAME = LINUX
SHELL = /bin/sh
endif
else
GCC_PREFIX := arm-none-eabi
CC = ./toolchain/gcc-arm-none-eabi-6-2017-q2-update/bin/arm-none-eabi-gcc
CXX = ./toolchain/gcc-arm-none-eabi-6-2017-q2-update/bin/arm-none-eabi-g++
OBJCOPY = ./toolchain/gcc-arm-none-eabi-6-2017-q2-update/bin/arm-none-eabi-objcopy
SIZE = ./toolchain/gcc-arm-none-eabi-6-2017-q2-update/bin/arm-none-eabi-size
MKDIR_CMD = mkdir -p
MKDIR_FROM_CHAR = \
MKDIR_TO_CHAR = /
MKDIR_OPTION = 2> /dev/null

OS_NAME = LINUX
SHELL = /bin/sh
endif

* 만약 윈도우즈를 제대로 인식하지 못하면 윈도우즈의 CMD창을 열어 PATH를 실행하여 "C:\Windows\System32"라는 문자열이
다르게 되어 있으면 해당 문자열로 변경을 합니다.
* 리눅스에서 TrueStudio 빌드인지 GCC 빌드인지에 대해서는 TrueStudio의 환경변수 "TRUESTUDIO_BUILD" 변수에 1을 설정합
니다. GCC일때는 정의를 하지 않습니다.

4.3.2 GCC 컴파일러 옵션


이 예제에서는 ST의 다양한 칩을 지원을 하도록 작성이 되었습니다. 보드별 빌드를 위해 다음과 같이 컴파일 옵션과 ST사의
HAL 라이브러리의 헤더 패스를 정의 하였습니다.

STEVAL_FCU001V1
ifeq ("$(TARGET_BOARD)", "STEVAL_FCU001V1")
TARGET_MCU += -mcpu=cortex-m4
TARGET_FPU += -mfpu=fpv4-sp-d16
TARGET_INSTRUCTION += -mthumb -mhard-float
TARGET_C_EXTRA += -ffunction-sections -fdata-sections -specs=nano.specs
TARGET_CXX_EXTRA += -fno-threadsafe-statics -ffunction-sections -fdata-sections -fno-exceptions -fno-
rtti
TARGET_A_EXTRA += -specs=nano.specs -x assembler-with-cpp

TARGET_HAL_DEFINITION += -D"STM32F4XX" -D"STM32F40XX" -D"STM32F401xC"


TARGET_MODEL_DEFINITION += -D$(TARGET_BOARD) -DUART_DEBUG_PORT=1 -DSUPPORT_DEBUG_OUTPUT -
DUART_DEBUG_OUTPUT -DDEBUG_STRING_LEVEL_ERROR
TARGET_MODEL_DEFINITION += -DUSE_USB_CDC_DEVICE -DUSE_USB_FS
TARGET_MODEL_DEFINITION += -DTIM2_REMOTE_CONTROL -DMOTOR_DC -UMOTOR_ESC

USB_DEVICE := CDC
USE_USB_DEVICE := USED
ifeq ("$(DEBUG)", "1")
TARGET := $(TARGET_BOARD)_DEBUG
BUILD_OPTION += -g -O0
TARGET_MODEL_DEFINITION += -DDEBUG_STRING_LEVEL_WARN -DDEBUG_STRING_LEVEL_DEBUG -
DDEBUG_STRING_LEVEL_FN_TRACE -DDEBUG_STRING_LEVEL_INFO -DDEBUG_STRING_LEVEL_DUMP
else
TARGET := $(TARGET_BOARD)_RELEASE
BUILD_OPTION += -O3
endif
# for HAL library & CMSIS
INCLUDE_DIR += -I./Drivers/F4_V1.21.0/CMSIS/Include
INCLUDE_DIR += -I./Drivers/F4_V1.21.0/CMSIS/Device/ST/STM32F4xx/Include
INCLUDE_DIR += -I./Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Inc
INCLUDE_DIR += -I./Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Inc/Legacy
endif

DISCOVERY_STM32F7
ifeq ("$(TARGET_BOARD)", "DISCOVERY_STM32F7")
TARGET_MCU += -mcpu=cortex-m7
TARGET_FPU += -mfpu=fpv5-sp-d16
TARGET_INSTRUCTION += -mthumb -mhard-float
TARGET_C_EXTRA += -ffunction-sections -fdata-sections -specs=nano.specs
TARGET_CXX_EXTRA += -fno-threadsafe-statics -ffunction-sections -fdata-sections -fno-exceptions -fno-
rtti
TARGET_A_EXTRA += -specs=nano.specs -x assembler-with-cpp

TARGET_HAL_DEFINITION += -D"STM32F746xx"
TARGET_MODEL_DEFINITION += -D$(TARGET_BOARD) -DUART_DEBUG_PORT=1 -DSUPPORT_DEBUG_OUTPUT -
DUART_DEBUG_OUTPUT -DDEBUG_STRING_LEVEL_ERROR
TARGET_MODEL_DEFINITION += -DUSE_USB_CDC_DEVICE -DUSE_USB_HS
TARGET_MODEL_DEFINITION +=

USB_DEVICE := CDC
USE_USB_DEVICE := USED
ifeq ("$(DEBUG)", "1")
TARGET := $(TARGET_BOARD)_DEBUG
BUILD_OPTION += -g -O0
TARGET_MODEL_DEFINITION += -DDEBUG_STRING_LEVEL_WARN -DDEBUG_STRING_LEVEL_DEBUG -
DDEBUG_STRING_LEVEL_FN_TRACE -DDEBUG_STRING_LEVEL_INFO -DDEBUG_STRING_LEVEL_DUMP
else
TARGET := $(TARGET_BOARD)_RELEASE
BUILD_OPTION += -O3
endif
# for HAL library & CMSIS
INCLUDE_DIR += -I./Drivers/F7_V1.11.0/CMSIS/Include
INCLUDE_DIR += -I./Drivers/F7_V1.11.0/CMSIS/Device/ST/STM32F4xx/Include
INCLUDE_DIR += -I./Drivers/F7_V1.11.0/STM32F4xx_HAL_Driver/Inc
INCLUDE_DIR += -I./Drivers/F7_V1.11.0/STM32F4xx_HAL_Driver/Inc/Legacy
endif

NUCLEO_H743ZI
ifeq ("$(TARGET_BOARD)", "NUCLEO_H743ZI")
TARGET_MCU += -mcpu=cortex-m7
TARGET_FPU += -mfpu=fpv5-sp-d16
TARGET_INSTRUCTION += -mthumb -mhard-float
TARGET_C_EXTRA += -ffunction-sections -fdata-sections -specs=nano.specs
TARGET_CXX_EXTRA += -fno-threadsafe-statics -ffunction-sections -fdata-sections -fno-exceptions -fno-
rtti
TARGET_A_EXTRA += -specs=nano.specs -x assembler-with-cpp

TARGET_HAL_DEFINITION += -D"STM32H7xx" -D"STM32H743xx"


TARGET_MODEL_DEFINITION += -D$(TARGET_BOARD) -DUART_DEBUG_PORT=1 -DSUPPORT_DEBUG_OUTPUT -
DUART_DEBUG_OUTPUT -DDEBUG_STRING_LEVEL_ERROR
TARGET_MODEL_DEFINITION += -D"USE_USB_FS"

USB_DEVICE := CDC
USE_USB_DEVICE := USED
ifeq ("$(DEBUG)", "1")
TARGET := $(TARGET_BOARD)_DEBUG
BUILD_OPTION += -g -O0
TARGET_MODEL_DEFINITION += -DDEBUG_STRING_LEVEL_WARN -DDEBUG_STRING_LEVEL_DEBUG -
DDEBUG_STRING_LEVEL_FN_TRACE -DDEBUG_STRING_LEVEL_INFO -DDEBUG_STRING_LEVEL_DUMP
else
TARGET := $(TARGET_BOARD)_RELEASE
BUILD_OPTION == -O3
endif

# for HAL library & CMSIS


INCLUDE_DIR += -IDrivers/H7_V1.2.0/CMSIS/Include
INCLUDE_DIR += -IDrivers/H7_V1.2.0/CMSIS/Device/ST/STM32H7xx/Include
INCLUDE_DIR += -IDrivers/H7_V1.2.0/STM32H7xx_HAL_Driver/Inc
INCLUDE_DIR += -IDrivers/H7_V1.2.0/STM32H7xx_HAL_Driver/Inc/Legacy
endif
4.3.3 HAL Library Source 추가
기본적으로 모든 HAL Library를 추가해도 되지만 그렇게 하면 빌드 및 코드크기가 커지기 때문에 실제 사용하는 라이브러리만
을 추가합니다. 현재는 STEVAL_FCU001V1 보드에 대해서만 작업이 되었습니다. 현재 ST에서 릴리즈되는 HAL 라이브러리는 모두
C언어로 작성이 되었습니다. C++로 작성된 라이브러리는 "HAL_LIBRARY_CXX_SRC"에 추가를 하면 됩니다.

STEVAL_FCU001V1
ifeq ("$(TARGET_BOARD)", "STEVAL_FCU001V1")
# HAL Library Source
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c

ifeq ($(USE_USB_DEVICE),USED)
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pcd.c
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pcd_ex.c
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c
HAL_LIBRARY_C_SRC += Drivers/F4_V1.21.0/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c
endif
endif

4.3.4 Middle Ware 소스 추가


현재는 USB에 대해서만 추가가 되어 있는데 추후에는 FreeRTOS 등등의 미들웨어 소스가 추가 될 예정입니다. C++언어로 작성된
미들웨어는 "MIDDLEWARE_CXX_SRC"에 추가를 하면 됩니다.

# -----------------------------------------------------------------------------
# Middle Source

# C Source of USB
ifeq ($(USB_DEVICE),CDC)
MIDDLEWARE_C_SRC += $(wildcard ./Middlewares/ST/STM32_USB_Device_Library/Core/Src/*.c)
MIDDLEWARE_C_SRC += $(wildcard ./Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/*.c)
MIDDLEWARE_C_SRC += $(wildcard ./src/drivers/usb/cdc/src/*.c)
INCLUDE_DIR += -I./Middlewares/ST/STM32_USB_Device_Library/Core/Inc
INCLUDE_DIR += -I./Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc
INCLUDE_DIR += -I./src/drivers/usb/cdc/inc
endif

ifeq ($(USB_DEVICE),BULK)
MIDDLEWARE_C_SRC += $(wildcard ./Middlewares/ST/STM32_USB_Device_Library/Core/Src/*.c)
MIDDLEWARE_C_SRC += $(wildcard ./Middlewares/ST/STM32_USB_Device_Library/Class/BULK/Src/*.c)
MIDDLEWARE_C_SRC += $(wildcard ./src/drivers/usb/bulk/src/*.c)
INCLUDE_DIR += -I./Middlewares/ST/STM32_USB_Device_Library/Core/Inc
INCLUDE_DIR += -I./Middlewares/ST/STM32_USB_Device_Library/Class/BULK/Inc
INCLUDE_DIR += -I./src/drivers/usb/bulk/inc
endif

4.3.5 보드별 소스 추가
보드에 관련된 소스는 공통적인 소스와 보드에 종속적인 소스로 구별해서 추가가 됩니다. C++ 소스는 DRIVERS_CXX_SRC
나 MODEL_CXX_SRC에 추가를 하면 됩니다.

# -----------------------------------------------------------------------------
# Common Driver Source
ifeq ($(USE_USB_DEVICE),USED)
DRIVERS_C_SRC += src/drivers/usb/usb_device.c
INCLUDE_DIR += -Isrc/drivers/usb/inc
endif

# C Source of common
DRIVERS_C_SRC += src/common/src/printf.c
DRIVERS_C_SRC += src/common/src/uart_debug.c
DRIVERS_C_SRC += src/common/src/scheduler.c

INCLUDE_DIR += -Isrc/common/inc

# -----------------------------------------------------------------------------
# Model Source

# "STEVAL_FCU001V1"
ifeq ("$(TARGET_BOARD)", "STEVAL_FCU001V1")
INCLUDE_DIR += -Isrc/model/$(TARGET_BOARD)/inc
INCLUDE_DIR += -Isrc/drivers/$(TARGET_BOARD)/inc

ASM_SRC += src/startup/$(TARGET_BOARD)/startup_stm32f401xc.s

MODEL_C_SRC += src/model/$(TARGET_BOARD)/src/stm32f4xx_hal_msp.c
MODEL_C_SRC += src/model/$(TARGET_BOARD)/src/stm32f4xx_it.c
MODEL_C_SRC += src/model/$(TARGET_BOARD)/src/system_stm32f4xx.c

# C Source of user driver


DRIVERS_C_SRC += src/drivers/$(TARGET_BOARD)/src/battery_gauge.c
DRIVERS_C_SRC += src/drivers/$(TARGET_BOARD)/src/blue_nrg_spi1.c
DRIVERS_C_SRC += src/drivers/$(TARGET_BOARD)/src/led.c
DRIVERS_C_SRC += src/drivers/$(TARGET_BOARD)/src/lis2mdl.c
DRIVERS_C_SRC += src/drivers/$(TARGET_BOARD)/src/lps22hd.c
DRIVERS_C_SRC += src/drivers/$(TARGET_BOARD)/src/lsm6dsl.c
DRIVERS_C_SRC += src/drivers/$(TARGET_BOARD)/src/motor.c
DRIVERS_C_SRC += src/drivers/$(TARGET_BOARD)/src/motor_ext_esc.c
DRIVERS_C_SRC += src/drivers/$(TARGET_BOARD)/src/remote_controller.c
DRIVERS_C_SRC += src/drivers/$(TARGET_BOARD)/src/sensor_spi2.c

MODEL_CXX_SRC +=
endif

4.3.6 기타
그 외 추가된 것은 빌드 관련되어 추가된 사항으로 특별하게 빌드에 문제가 되지 않는 한 변경되는 일이 거의 없습니다. C소스
및 C++ 소스는 아래와 같이 결국에는 C_SRC와 CXX_SRC로 정리가 됩니다.
C_SRC := $(HAL_LIBRARY_C_SRC) $(MIDDLEWARE_C_SRC) $(DRIVERS_C_SRC) $(MODEL_C_SRC)
CXX_SRC := $(HAL_LIBRARY_CXX_SRC) $(MIDDLEWARE_CXX_SRC) $(DRIVERS_CXX_SRC) $(MODEL_CXX_SRC)

모델용으로 작성된 C언어 파일을 "MODEL_C_SRC"에 추가하지 않고 "HAL_LIBRARY_C_SRC"에 추가해도 문제없이 빌드가 됩니다.
이는 논리적으로 구분을 해 놓은 것입니다. 다만 C 언어 파일을 MODEL_CXX_SRC와 같이 CXX에 추가를 하면 됩니다. C 언어는 C
언어 쪽에 C++ 언어는 C++ 언어쪽에 놓아야 합니다.

5. 빌드 및 디버깅
여기에서는 TrueStudio를 통해 빌드하는 방법과 GCC를 통해 빌드하는 방법에 대해 설명을 합니다.

5.1 빌드하기
5.1.1 TrueStudio 9.1에서 빌드하기
불행스럽게 Makefile을 통한 빌드시에는 TrueStudio의 "Manage Build Configuration"을 통해 빌드가 되지 않습니다. 그렇기
때문에 불편하지만 다음과 같이 환경변수를 수정하여 빌드를 합니다.
TrueStudio의 Project->Properties(Project Explorer의 프로젝트 명에서 마우스 오른쪽 버튼 선택시 팝업메뉴에서
Properties)를 선택합니다. Properties 다이얼로그박스의 왼쪽 메뉴에서 C/C++ Build->Environment(펼쳐져 있지 않으면 >를
선택하면 펼쳐집니다.)를 선택합니다. 그리고 오른쪽에 있는 다음 항목을 수정하여 빌드를 할 수 있습니다.

TARGET_BOARD

STEVAL_FCU001V1 : 우리 랩에서 사용하고 있는 ST사의 드론 플라이트 컨트롤러 입니다.


DISCOVERY_STM32F7 : ST사의 STM32F7 디스커버리 보드 입니다.
NUCLEO_H743ZI : 구매 예정인 뉴클레오 보드 입니다.

DEBUG

1 : 디버그 모드로 빌드를 합니다.


0 : 릴리즈 모드로 빌드를 합니다.

다른 보드나 릴리즈 모드 등으로 빌드를 하기 위해서는 위의 값을 변경하여 빌드를 합니다. 그 외의 값들은 변경하지 않습니다.
* 만약 Header 파일(.h)을 수정하였다면, TrueStudio의 Project->Clean Project를 실행 한 후에 TrueStudio의 Project-
>Rebuild Project를 해야 됩니다.(Makefile에서 헤더파일에 대한 종속성(dependency)이 설정되어 있지 않아서 발생하는 문제
입니다.)

5.1.2 GCC 빌드하기


GCC 빌드는 기본적으로 아래와 같이 3개의 쉘스크립트로 작성을 하였습니다.
$ build_f4.sh
$ build_f7.sh
$ build_h7.sh

위 스크립트를 사용하지 않고 직접 make 유틸리티로 다음과 같이 빌드를 할 수 있습니다.


$ make TRUESTUDIO_BUILD=0 TARGET_BOARD=STEVAL_FCU001V1 DEBUG=1
$ make TRUESTUDIO_BUILD=0 TARGET_BOARD=STEVAL_FCU001V1 DEBUG=0

clean은 다음과 같이 합니다.


$ make clean

5.2 디버깅하기
보드별 디버깅을 하기 위해서는 빌드시와 같이 여러개의 환경을 추가해서 디버깅이 TrueStudio의 버그인지 동작이 잘 되지 않
습니다. 아마도 TrueStudio의 프로젝트는 하나의 코어에 대해서 작성하도록 되어 있어 그런 문제가 발생하는 것 같습니다.
메뉴에서 Project->Properties를 선택한 후, Properties화면에서 "Run/Debug Setting"를 선택한 후 왼쪽에 추가된 설정이
있으면 삭제를 한 후에 New를 선택합니다. Select Config 다이얼로그 박스에서 "Embedded C/C++ Application"을 선택한 후
OK 버튼을 선택합니다.

5.2.1 Edit launch configuration properties - Main(탭)


이 탭에서는 C/C++ Application 항목만을 수정하고 다른 항목은 그대로 변경없이 사용을 합니다.

C/C++ Application
여기에는 elf파일을 추가하는 항목으로 Browse 버튼을 선택하여 elf파일을 선택합니다.(OUTPUT 디렉토리 밑에 .elf 파일이 생
성됩니다.)

5.2.2 Edit launch configuration properties - Debugger(탭)


자신이 갖고 있는 디버거 장비를 설정합니다. 특히 Device항목은 자신의 보드에 맞게 수정을 해야 합니다.

STEVAL_FCU001V1 : STM32F401CC
DISCOVERY_STM32F7 : STM32F746NG
NUCLEO_H743ZI : STM32H743Zi

5.2.3 Edit launch configuration properties - Startup_Scripts(탭)


JLINK의 경우, 만약 플래쉬 다운로드를 하고 싶지 않다면 스크립트 중간에 있는 다음 항목을 0으로 변경 합니다.
# Enable flash download
monitor flash download = 0

5.2.4 Edit launch configuration properties - Source, Common (탭)


TBD

5.2.5 디버깅 실행하기


메뉴의 Run->Debug를 선택하면 기본적으로 바이너리를 타겟보드에 다운로드 한 후에 main함수에서 브레이크(break)가 걸립니
다.
6. 신규 보드 추가하기
3개의 보드 이외에 신규보드를 추가하는 방법에 대해 설명을 합니다. 예를 들어 신규보드 NEW_BOARD를 추가하는 예를 듭니다.
먼저 TrueStudio를 통해 NEW_BOARD에 대한 C/C++ 프로젝트를 Makefile로 생성을 합니다.

6.1 Makefile
Makefile에서는 같은 코어를 사용한 보드가 있으면(cortex-m4나 coretex-m7) 추가하기가 쉬우나, 다른 코어를 사용했다면 다
음과 추가로 작성하는 일이 그리 쉽지는 않습니다.
먼저 Makefile에서 유사한 다른 보드의 설정을 복사합니다. 만약 DISCOVERY_STM32F와 유사한 보드라고 가정을 할 때, "ifeq
("$(TARGET_BOARD)", "DISCOVERY_STM32F7")"로 검색을 한 후에 각각을 복사하여 바로 밑에 추가를 합니다.
ifeq ("$(TARGET_BOARD)", "DISCOVERY_STM32F7")
...
endif

ifeq ("$(TARGET_BOARD)", "NEW_BOARD")


...
endif

코어가 다른 경우에는 다음과 같은 3개의 값을 참조로 만든 Makefile을 참조하여 수정을 합니다.


TARGET_MCU += -mcpu=cortex-m7
TARGET_FPU += -mfpu=fpv5-sp-d16
TARGET_INSTRUCTION += -mthumb -mhard-float

그리고 HAL 라이브러리를 사용하기 위해 참조로 만든 Makefile에 보면 칩에 대한 정의가 있습니다. 다음 항목을 적당한 값으로
변경을 합니다.
TARGET_HAL_DEFINITION += -D"STM32F746xx"

6.2 필수 Source하기
신규보드에 맞는 필수 파일을 추가해야 합니다.

6.2.1 ldscript
링크스크립트 파일은 참조로 만든 소스에 .ld로 생성되어 있습니다. 해당 파일을 다음과 같은 디렉토리를 생성한 후에 이름을
변경하여 추가를 합니다.
./ldscript/NEW_BOARD/NEW_BOARD_FLASH.ld

6.2.2 startup source


참조로 만든 소스에 보면 .s파일이 있습니다. 해당 파일을 다음과 같은 디렉토리에 복사를 합니다.
./src/startup/NEW_BOARD/startup_stm32xxxxx.s
* Makefile에서 ASM_SRC 항목에서 위의 이름으로 수정을 합니다.

6.2.3 model source 추가하기


HAL을 사용하기 위해서는 다음과 같은 형태의 파일 3개가 참조소스에 생성되어 있습니다. 3개의 파일을 다음의 디렉토리를 생
성한 후에 복사를 합니다.
./src/model/NEW_BOARD/src

stm32fxxx_hal_msp.c
stm32fxxx_it.c
system_stm32fxxx.c

* 참조로 생성한 main.c 함수에 있는 void SystemClock_Config(void) 함수는 위의 system_stm32fxxx.c 파일로 코드를 복사
합니다.

./src/model/NEW_BOARD/inc 디렉토리에는 다음과 같은 main.h 파일은 생성을 하고 stm32fxxx_hal_conf.h 파일은 참조로 만


든 소스에서 복사를 합니다.

main.h
stm32fxxx_hal_conf.h : ST의 HAL Configuration 설정 파일입니다.

You might also like