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개의 댓글

답글 남기기

Avatar placeholder

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

ko_KRKorean