printf 디버깅은 가장 간단하면서, 다양한 임베디드 플랫폼에 공통적으로 사용할 수 있는 디버깅 방법이다.
현업에서도 많이 사용되는 디버깅 방법이다.

USART_printf라는 이름으로 프로젝트를 생성한다.

USART_printf 라는 프로젝트가 새로 생성된 것을 확인할 수 있다.

외부 클락(HSE, LSE)을 비활성화 해준다.

MUX로 PLLCLK를 선택해준다. HCLK가 64MHz가 되었는지 확인해준다.
STM32F103RB의 Schematic 이다.

PA2, PA3 을 USART로 쓸 수 있음을 확인할 수 있다.

추가적으로 User Manual을 보면, 어떤 조건하에 PC10, PC11을 USART3으로 쓸 수 있는 듯하다.

Pinout & Configuration에 가보면 이미 PA2,PA3가 USART 로 설정되어있음을 확인할 수 있다.
(프로젝트 생성시에 Initialize all peripherals with their default Mode 팝업에서 Yes를 선택해서 그렇다. CubeMX가 자동으로 모든 주변장치를 기본 값으로 세팅해놓은 것이다.)

Generate Code 해준다.
printf() 같은 함수에서 문자를 출력할 때, 내부적으로 putchar() 또는 fputc() 를 호출한다.
STM32같은 MCU의 경우 C언어의 표준 출력인 콘솔과 같은 개념이 존재하지 않는다.
따라서 표준 출력을 USART로 바꿔서 내 PC에서 이를 통신으로 받아 디버깅 해야한다.
printf()를USART통신으로 출력하기위해main.c에서 이 함수를 오버라이드(재정의) 해줘야한다.
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */
printf()를 쓰기위해 위와 같이 <stdio.h>를 #include 해준다.
#ifdef __GNUC__ // __GNUC__ 가 DEFINE되어있는 경우
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
// PUTCHAR_PROTOTYPE을 int __io_putchar(int ch) 로 치환하라
#else // 아니면
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
// PUTCHAR_PROTOTYPE을 int fputc(int ch, FILE *f)으로 치환하라
#endif
//if블럭 끝
PUTCHAR_PROTOTYPE //__GNUC__ 가 DEFINE되어있는 경우->int __io_putchar(int ch)
{
if (ch== '\n') // ch가 \n이면
HAL_UART_Transmit (&huart2, (uint8_t*) "\r", 1, 0xFFFF);
// uart2로 캐리지 리턴을 보내라
HAL_UART_Transmit (&huart2, (uint8_t*) &ch, 1, 0xFFFF);
// uart2로 ch를 전송한다. 전송 완료 전까지 0xFFFF 동안 기다린다.
// HAL_UART_Transmit 은 1Byte를 전송하므로 ch의 타입을 강제로uint8_t로 캐스팅 해준다
return ch;
}
그다음 위와같이 __io_putchar(int ch) 또는 fputc(int ch, FILE *f) 를 재정의 (Override) 해준다.
앞으로 디버깅을 위하여 프로젝트 생성시마다
#include <stdio.h>
로 <stdio.h>+ 를 include 해주고
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
사이에 위의 코드를 꼭 넣어주도록 하자.
이렇게하면 USART 통신을 사용하기위한 세팅은 끝이난다.
(지금부터는 printf 쓰면 표준 출력이아닌 USART2 데이터를 보내게된다)
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
printf("Hello World!\n");
HAL_Delay(1000);
}
/* USER CODE END 3 */
이렇게 1000ms 단위로 Hello World! 를 출력하도록 코드를 작성한다.
Run-Run으로 소스코드빌드및 보드에 코드를업로드` 한다.

보드에 정상적으로 코드가 업로드된 것을 확인할 수 있다.

Teraterm을 켜주고 개인 통신 설정에 맞게 옵션을 구성해준다.

성공 !
앞으로 이런식으로 디버깅을 진행하면 될 것 같다.