STM32F4 보드에서 C++ 기반 프로젝트를 시작할 때 필요한 초기 세팅 과정을 정리해 보았습니다. 이번 단계에서는 프로젝트 생성 → 기본 환경 설정 → ConsoleTask 구성 → 빌드 및 디버깅까지의 흐름을 설명합니다.
작업 범위
- 이 글에서는 다음과 같은 항목을 다룹니다.
- STM32CubeIDE를 이용한 프로젝트 생성
- Clock, Timer, Port 등 필수 Configuration
- ConsoleTask 설정 및 코드 적용
- 빌드 후 stlink 다운로드와 Putty를 통한 메시지 확인
1. Project 생성(자동 Pin 할당)
STM32CubeMX로 미리 작성해 둔 .ioc 파일을 이용하면 핀과 기본 설정이 자동으로 반영됩니다.
예제 .ioc 파일을 사용하려면 Download 메뉴에서 “TW100PCTest.ioc”를 이용하면 됩니다.
STM32CubeIDE에서 새로운 프로젝트를 만들 때 “STM Project from Existing STM32CubeMX Configuration File(.ioc)” 메뉴를 선택하면 됩니다.

- 원하는 Project Name을 입력 (예: TW100PCTest)
- Targeted Language를 C++로 지정 → 이 단계가 중요합니다. 기본값은 C 언어이기 때문에 반드시 C++로 바꿔줘야 이후 ConsoleTask 코드를 원활히 사용할 수 있습니다.

2. 기본 Configuration 살펴보기
Clock
- HSE: 12MHz (외부 클럭)
- PLL: 168MHz (메인 시스템 클럭)
- LSI: 32kHz (RTC용 내부 클럭)
Driver Selector
- I2C, RTC → HAL
- 나머지 → LL
- 조합을 사용합니다.
즉, 시간 관리나 통신 관련은 HAL로 간단히, 그 외에는 LL로 성능 최적화를 노리는 방식입니다.
3. ConsoleTask 구성
개발할 때 반드시 필요한 것이 디버깅 메시지 출력입니다. 이번 프로젝트에서는 USART6을 통해 Console 메시지를 보내도록 설정합니다.
- main.c → main.cpp 로 변경 (C++ 코드로 전환)
- stm32f4xx_it.c → stm32f4xx_it.cpp 로 변경 (인터럽트 코드도 C++화)
- 프로젝트 내에 Libraries 폴더 생성 후, twlabcpp-stm32f4-base 라이브러리를 추가

4. main.cpp 코드 적용
“ConsoleTask.h” 와 ConsoleTask 객체 추가
/* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include <ConsoleTask.h> /* USER CODE END Includes */ ... /* USER CODE BEGIN PV */ ConsoleTask CTask; __attribute__ ((section(".ccmram"))) volatile uint8_t consoleBuf[2048]; ...
ConsoleTask 객체 초기화 함수 정의
- 초기화 함수를 별도로 정의하고 implementation문은 main.cpp 내에 /* USER CODE … */ 블록 내에 둔다.
/* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_DMA_Init(void); static void MX_TIM2_Init(void); static void MX_SPI1_Init(void); static void MX_USART6_UART_Init(void); static void MX_I2C3_Init(void); static void MX_RTC_Init(void); /* USER CODE BEGIN PFP */ void InitConsoleTask(void); ... ... /* USER CODE BEGIN 4 */ /* * */ void InitConsoleTask(void) { CTask = ConsoleTask(USART6, DMA2, LL_DMA_STREAM_6, DMA2, LL_DMA_STREAM_1); CTask.setBufPtr((uint8_t *)consoleBuf); CTask.uart.DMARxEnable(); LL_USART_EnableIT_IDLE(USART6); CTask.PRINTF((char *)"\r\n\r\n"); CTask.PRINTF((char *)"=====================================\r\n"); CTask.PRINTF((char *)"Hello. This is TW100PCTest Application\r\n"); CTask.PRINTF((char *)"\r\nBuild Date: %s, %s\r\n", __DATE__, __TIME__); CTask.PRINTF((char *)"=====================================\r\n"); CTask.flushTxBuf(); }
main() 함수내에 적용
- MX_GPIO_Init(), MX_DMA_Init() 등 CubeMX 자동 초기화 함수 뒤에 InitConsoleTask(); 추가
/* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_TIM2_Init(); MX_SPI1_Init(); MX_USART6_UART_Init(); MX_I2C3_Init(); MX_RTC_Init(); /* USER CODE BEGIN 2 */ InitConsoleTask(); /* USER CODE END 2 */
- while 루프 안에서 CTask.run(); 호출 → 주기적으로 메시지 처리를 실행
/* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { CTask.run(); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
5. 인터럽트 핸들러 수정
- “ConsoleTask.h” 추가 및 ConsoleTask 객체를 extern으로 추가한다.
/* Includes ------------------------------------------------------------------*/ #include "main.h" #include "stm32f4xx_it.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include <ConsoleTask.h> /* USER CODE END Includes */ ... /* External variables --------------------------------------------------------*/ /* USER CODE BEGIN EV */ extern ConsoleTask CTask; /* USER CODE END EV */
- DMA와 USART6 인터럽트 발생 시 ConsoleTask의 핸들러로 제어를 넘겨줍니다.
/** * @brief This function handles DMA2 stream1 global interrupt. */ void DMA2_Stream1_IRQHandler(void) { /* USER CODE BEGIN DMA2_Stream1_IRQn 0 */ CTask.uart.RXDMAInterruptHandler(); /* USER CODE END DMA2_Stream1_IRQn 0 */ /* USER CODE BEGIN DMA2_Stream1_IRQn 1 */ /* USER CODE END DMA2_Stream1_IRQn 1 */ } ... /** * @brief This function handles DMA2 stream6 global interrupt. */ void DMA2_Stream6_IRQHandler(void) { /* USER CODE BEGIN DMA2_Stream6_IRQn 0 */ CTask.uart.TXDMAInterruptHandler(); /* USER CODE END DMA2_Stream6_IRQn 0 */ /* USER CODE BEGIN DMA2_Stream6_IRQn 1 */ /* USER CODE END DMA2_Stream6_IRQn 1 */ } ... /** * @brief This function handles USART6 global interrupt. */ void USART6_IRQHandler(void) { /* USER CODE BEGIN USART6_IRQn 0 */ CTask.uart.IDLEInterruptHandler(); /* USER CODE END USART6_IRQn 0 */ /* USER CODE BEGIN USART6_IRQn 1 */ /* USER CODE END USART6_IRQn 1 */ }
6. 빌드 및 실행
- Build Project 실행 → .hex와 .bin 파일 생성 확인
- stlink로 보드에 다운로드
- PC에서 Putty 실행 후 2 Mbps baudrate로 연결

- Reset 버튼 클릭 → 시작 메시지가 정상적으로 출력됨을 확인

마치며
- 이번 단계에서는 STM32F4 보드에서 C++ 기반 프로젝트 환경을 구축하고 ConsoleTask를 통한 기본 디버그 출력까지 확인했습니다.
- 다음 단계부터는 이 환경 위에서 실제 애플리케이션 기능을 확장해 나갈 수 있습니다
0개의 댓글