STM32 튜토리얼 01 - 프로젝트 생성 및 디버깅하기
1. STM32 Cube IDE 설치하기
2. Workspace 생성 및 설정하기
2.1. Workspace 생성
- Workspace 설정 후 Launch 버튼을 누른다. 이때 경로는 무조건 영어로 설정한다.
- Impormation Center를 닫으면 빈 Workspcace가 나타난다.
- Workspace 안에선 여러 개의 프로젝트를 관리할 수 있다.
2.2. Text file Encoding 설정
- Window → Preferences → General → Workspace 클릭
- 오픈 소스를 활용할 때 한글이 존재하면 문제가 발생할 수 있으므로 Text file encoding을 항상 UTF-8로 설정한다.
2.3. Coding Style 설정
- C/C++ → Coding Style → Formatter → New 버튼 클릭
- 이름은 아무거나 적고, 베이스로 할 것을 GNU로 설정한다.
- Indentation → General settings에서 Tab policy는 Spaces only, Indentation size는 2로 변경한다.
- Braces → Brace positions에서 마지막 설정을 제외하고 모두 Next line으로 변경한다.
2.4. Launch Operation 설정
- Run/Debug → Launching → Launch Operation에서 Always launch the previously launched application으로 변경한다.
- 이후 Apply and Close 클릭
3. Project 생성 및 설정하기
3.1. Project 생성
- File → New → STM32 Project 클릭
- STM32F401RET6 선택 후 Next 클릭
- Project Name에 MCU 이름을 바탕으로 설정하고, Location에 Project Name을 뒤에 적는다. 자동으로 해당 폴더가 생성된다.
- Targeted Project Type을 Empty로 설정한다.
- 프로젝트를 생성하면 위와 같은 구조로 파일을 자동으로 생성한다.
- main 함수(
main.c
), 스타터 코드(startup_stm32f401retx.s
), 시스템 콜백 함수(syscalls.c, sysmem.c
), 링커 스크립트 파일(STM32F401RETX_FLASH.ld, STM32F401RETX_RAM.ld
)로 구성된다.
3.2. 파일 구성 변경하기
- 우선 위와 같이 파일 구조를 바꾸자
- 가장 위에 존재하는 stm32f401_fw 프로젝트에 src 폴더를 생성한다.
- stm32f401_fw
- src
- ap
- bsp
- ldscript
- STM32F401RETX_FLASH.ld
- STM32F401RETX_RAM.ld
- startup
- startup_stm32f401retx.s
- syscalls.c
- sysmem.c
- common
- hw
- lib
- main.c 파일을 삭제하고 위와 같이 폴더 및 파일을 구성한다. 폴더만 생성하고 파일은 새롭게 생성하지 않았다.
- stm32f401_fw
- src
- ap
- ap.c
- ap.h
- bsp
- ldscript
- STM32F401RETX_FLASH.ld
- STM32F401RETX_RAM.ld
- startup
- startup_stm32f401retx.s
- bsp.c
- bsp.h
- syscalls.c
- sysmem.c
- common
- def.h
- hw
- hw_def.h
- hw.c
- hw.h
- lib
- main.c
- main.h
- 각 폴더에 맞게 파일을 생성한다.
- 파일의 기본적인 구성은 끝났다.
4. 기본적인 코드 작성하기
-
ap.h
#ifndef SRC_AP_AP_H_ #define SRC_AP_AP_H_ #include "hw.h" void apInit(void); void apMain(void); #endif /* SRC_AP_AP_H_ */
-
ap.c
#include "ap.h" void apInit(void) { } void apMain(void) { while(1) { } }
ap.c
의apMain
함수에 무한 루프(while
)을 넣는 이유는main.c
의 내용을 간소화하기 위함이다.apMain
함수가 진짜 main이 될 예정이다. -
bsp.h
#ifndef SRC_BSP_BSP_H_ #define SRC_BSP_BSP_H_ #include "def.h" // common/def.h 가져오기 void bspInit(void); // 공동으로 사용하는 함수들 정리 void delay(uint32_t ms); // ms 단위로 시간 지연하는 함수 uint32_t millis(void); // ms 단위로 count 하는 함수 #endif /* SRC_BSP_BSP_H_ */
-
bsp.c
#include "bsp.h" void bspInit(void) { } void delay(uint32_t ms) { } uint32_t millis(void) { return 0; }
-
def.h
#ifndef SRC_COMMON_DEF_H_ #define SRC_COMMON_DEF_H_ #include <stdio.h> #include <stdint.h> #include <stdbool.h> #endif /* SRC_COMMON_DEF_H_ */
공통으로 사용할 것들을 작성한다. 전체적인 수정이 필요할 때 def.h에서 수정하면 전체가 바뀌도록 코드를 작성한다. 유지보수를 쉽게 할 수 있다.
-
hw_def.h
#ifndef SRC_HW_HW_DEF_H_ #define SRC_HW_HW_DEF_H_ // hw 폴더 내에서 공통적으로 사용하게 될 것을 작성한다. #include "def.h" #include "bsp.h" #endif /* SRC_HW_HW_DEF_H_ */
-
hw.h
#ifndef SRC_HW_HW_H_ #define SRC_HW_HW_H_ #include "hw_def.h" void hwInit(void); #endif /* SRC_HW_HW_H_ */
-
hw.c
#include "hw.h" void hwInit(void) { bspInit(); }
-
main.h
#ifndef SRC_MAIN_H_ #define SRC_MAIN_H_ #include "ap.h" #endif /* SRC_MAIN_H_ */
-
main.c
#include "main.h" int main(void) { hwInit(); apInit(); apMain(); return 0; }
5. Build 및 include 경로 설정하기
5.1. Build
- 첫 번째 방법은 위 카테고리를 활용하는 것이다. Project → Build Project 클릭
- 두 번째 방법은 Project Explorer를 활용하는 것이다. Project Explorer에서 프로젝트(stm32f401_fw)를 우클릭 한 후 Build Project를 클릭한다.
5.2. include 경로 설정
- build를 하게 되면 아래 Console 창에 결과가 나타난다. 위 사진을 보면 오류가 많이 발생한 것을 볼 수 있다. 이는 include 경로를 설정하지 않아 발생한 것이다.
- Project → Properties를 클릭한다.
- C/C++ Build → Settings → Tool Settings → MCU GCC Complier → Preprocessor를 클릭한다.
- Define symbols에 저장된 것을 모두 삭제한다.
- C/C++ Build → Settings → Tool Settings → MCU GCC Complier → include paths를 클릭한다.
- Include paths에 존재하는 것을 모두 삭제한다.
- Add 버튼을 클릭하여 코드를 작성한 모든 폴더의 경로를 추가한다.
5.3. Linker Script 경로 설정
- 위 과정에서 링커 스크립트 파일을 옮겼기 때문에 경로 설정을 추가로 진행해야 한다.
- C/C++ → Settings → Tool Settings → MCU GCC Linker → General을 클릭한다.
- Linker Script를
${workspace_loc:/${ProjName}/src/bsp/ldscript/STM32F401RETX_FLASH.ld}
로 변경한다. - 이후 빌드를 진행한다.
- 에러 없이 build 된 것을 확인할 수 있다.
- Console 오른쪽을 보면 Build Analyzer가 있다. build 진행 후 다양한 정보를 보여준다.
5.4. Build Analyzer
- Memory Regions는 메모리의 사용량을 보여준다.
- Memory Details는 각 메모리의 섹션을 보여준다.
.isr_vector
: FlASH의 시작 주소와 같다. 스타터 코드에 정의되어 있다..bss
: 전역 변수를 의미한다.._user_heap_stack
: 힙의 시작 주소를 의미한다.
6. 디버깅
6.1. Debug Configurations
- Run → Debug Configurations 클릭하기
- STM32 C/C++ Application을 더블 클릭하면 자동으로 프로젝트가 적용된다.
- Browse 버튼을 눌러 수동으로 프로젝트를 선택한다.
- Browse 버튼을 눌렀는데 프로젝트가 하나도 존재하지 않는다면? 프로젝트를 다시 build 한 후 확인해본다.
이후 Apply 버튼을 누르고 Debug 버튼을 클릭한다.
- 디버깅을 처음하게 되면 뜨는 창이다. 디버깅 시 프로그램 메뉴 구성이 변하는데 이것을 바꿀 거냐는 뜻이다. 체크 박스를 클릭하여 항상 바뀌도록 설정한다.
6.2. 디버깅 오류
- ST-LINK를 찾을 수 없다는 오류와 함께 디버깅이 되지 않는다.
- 펌웨어 업데이트가 필요하다는 것을 깨닫게 되었다. (오제이 튜브)
- STM을 노트북과 연결한 상태에서 ‘STM32 ST-LINK Utility’ 프로그램을 실행한다.
- Target → Connect 를 클릭하여 연결한다.
- ST-LINK → Firmware update 클릭
- Device Connect 버튼 클릭
- Device 정보가 뜨면, Yes 버튼을 클릭한다.
- 펌웨어가 업데이트 되었다.
- 이제 다시 STM32 Cube IDE로 돌아간다.
- build 후 디버깅을 시도하면 펌웨어 업데이트를 하라고 한다. 분명 ‘STM32 ST-LINK Utility’ 프로그램에서 업데이트를 진행하였지만 다시 해준다.
- 이후 다시 디버깅을 시도하면
hwInit
함수에서 브레이크 포인트가 걸린 것을 확인할 수 있다.