|
MCU
|
STM32F746G DISCOVERY(ST)
|
|
IDE
|
Atollic(TrueSTUDIO), STM32CubeMX
|
|
목표
|
HAL driver를 사용하여 UART각 Polling, Interrupt mode 입출력 Test(Receive Overrun 방지)
|
- UART Firmware 작성시 아래와 같이 크게 세가지 모드로 구분 할 수 있음
- 각 mode별로 입출력 Test
1. Polling
2. Interrupt
3. DMA
이번 페이지에서는 Polling, Interrupt mode 사용
1. STM32CubeMX : UART-Polling 설정
- Configuration은 STM32F746 DISCOVERY - printf()를 이용하여 UART로 문자열 출력 참고
- ATOLLIC : main.c
- 터미널에서 Keyboard 입력을 받아 다시 Terminal로 출력 코드 작성
- 필요한 변수 선언
#define RX_MAX 1
uint8_t rcv_data[RX_MAX];
- while() 작성
while (1)
{
HAL_UART_Receive(&huart1, rcv_data, RX_MAX, 1000);
if(rcv_data[0]) {
printf("Rx OK = %c\r\n", rcv_data[0]);
rcv_data[0] = 0x00;
}
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_ORE)) {
printf("UART1 Overrun Error occurred.\r\n");
__HAL_UART_CLEAR_IT(&huart1,UART_CLEAR_OREF);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
- 위와 같이 작성하였지만 Keyboard 입력이 빠르지 않기 때문에 Overrun Error가 발생하지 않는다.
때문에 HAL_Delay만 추가 해서 Test
while (1)
{
HAL_Delay(50);
HAL_UART_Receive(&huart1, rcv_data, RX_MAX, 1000);
if(rcv_data[0]) {
printf("Rx OK = %c\r\n", rcv_data[0]);
rcv_data[0] = 0x00;
}
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_ORE)) {
printf("UART1 Overrun Error occurred.\r\n");
__HAL_UART_CLEAR_IT(&huart1,UART_CLEAR_OREF);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
- Delay 하나로, Keyboard 입력이 쌓임 - 바로 처리 하지 못하고 Delay - Overrun Error 발생함을 확인

2-1. STM32CubeMX : UART-Interrupt(1) 설정
- Configuration은 STM32F746 DISCOVERY - printf()를 이용하여 UART로 문자열 출력 참고
- USART1 NVIC enable 할 것
- ATOLLIC : main.c
- 터미널에서 Keyboard 입력을 받아 다시 Terminal로 출력 코드 작성
- 필요한 변수 및 callback() 작성
#define RX_MAX 1
uint8_t rcv_data[RX_MAX];
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if(huart->Instance == USART1)
{
HAL_UART_Receive_IT(&huart1, rcv_data, RX_MAX);
}
}
- while() 작성
/* Infinite loop */
/* USER CODE BEGIN WHILE */
HAL_UART_Receive_IT(&huart1, rcv_data, RX_MAX);
while (1)
{
if(rcv_data[0])
{
printf("Rx OK = %c\r\n", rcv_data[0]);
rcv_data[0] = 0x00;
}
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_ORE))
{
printf("UART1 Overrun Error occurred.\r\n");
__HAL_UART_CLEAR_IT(&huart1,UART_CLEAR_OREF);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
- 위와 같이 작성하였지만 Keyboard 입력이 빠르지 않기 때문에 Overrun Error가 발생하지 않는다.
때문에 HAL_Delay만 추가 해서 Test
/* Infinite loop */
/* USER CODE BEGIN WHILE */
HAL_UART_Receive_IT(&huart1, rcv_data, RX_MAX);
while (1)
{
HAL_Delay(50);
if(rcv_data[0])
{
printf("Rx OK = %c\r\n", rcv_data[0]);
rcv_data[0] = 0x00;
}
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_ORE))
{
printf("UART1 Overrun Error occurred.\r\n");
__HAL_UART_CLEAR_IT(&huart1,UART_CLEAR_OREF);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
- HAL_UART_Receive_IT()를 사용하였음에도 Overrun Error 발생

Q. printf()가 시간이 오래 걸리는데 printf()를 사용해서 문제가 발생하지 않았나? Delay가 너무 길다.
A. printf()를 사용하지 않아 문제가 발생하지 않았다 하더라도, Polling 방식과 마찬가지로, 내가 컨트롤 할 수 없는 Delay가 발생할때 Overrun Error 발생될 수 있음(데이터가 들어오면 처리 해야 하는데, delay 때문에 처리는 못하고 데이터가 또 들어오면 Overrun)
Q. HAL_UART_Receive_IT 버퍼 사이즈를 키우면 되지 않나?
A. 수신 사이즈 만큼의 데이터가 들어와야 인터럽트 발생되며 사이즈를 무한정 키울수도 없음.
수신 사이즈를 1000으로 키웠는데 999개가 들어온다면? 1001개가 들어온다면?
아래에 Overrun Error를 방지하기 위한 예제를 설명합니다.
2-2. STM32CubeMX : UART-Interrupt(2) 설정
- Configuration은 STM32F746 DISCOVERY - printf()를 이용하여 UART로 문자열 출력 참고
- USART1 NVIC enable 할 것
- ATOLLIC : main.c
- 터미널에서 Keyboard 입력을 받아 다시 Terminal로 출력 코드 작성
- main.c : main() 수정
/* Infinite loop */
/* USER CODE BEGIN WHILE */
HAL_UART_Receive_IT(&huart1, rcv_data, RX_MAX);
while (1)
{
HAL_Delay(50);
if(rcv_data[0])
{
printf("Rx OK = %c\r\n", rcv_data[0]);
rcv_data[0] = 0x00;
}
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_ORE))
{
printf("UART1 Overrun Error occurred.\r\n");
__HAL_UART_CLEAR_IT(&huart1,UART_CLEAR_OREF);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
- stm32f7xx_it.c : USART1_IRQHandler 생성됨
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
- stm32f7xx_it.c : USART1_IRQHandler 수정
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if((huart1.Instance->ISR & UART_FLAG_RXNE) != RESET)
{
rcv_data[0] = huart1.Instance->RDR;
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
위와 같이 rx 데이터가 들어올 때 바로 읽어야 Overrun Error 발생 하지 않음
※ UART Interrupt mode 추가 설명(꼭 읽고 가면 좋은)
- HAL_UART_Receive_IT()를 호출하면 UART 수신 인터럽트에 관한 설정을 자동으로 해주며, UART 수신 인터럽트 대기 상태가 됨(while()이나 다른 Timer 인터럽트에서 호출 하면 데이터를 잃어 버릴수 있음)
- HAL_UART_Receive_IT()에서 데이터 size가 고정되어 있는것이 아니라면 한 바이트씩 수신 추천
- UART 수신 인터럽트가 발생(데이터가 들어오면)하면 USARTx_IRQHandler() 실행됨
2-1. STM32CubeMX : UART-Interrupt(1) 추가 설명
- USARTx_IRQHandler()가 HAL_UART_IQRHandler() 호출하여 인터럽트 관련 처리를 수행함
(STM32CubeMX에서 USART1 NVIC enable 하면 자동 생성됨)
- HAL_UART_IQRHandler()의 수신 인터럽트에서 HAL_UART_RxCpltCallback() 호출
- HAL_UART_RxCpltCallback()는 weak로 선언 되어 있으며 사용자가 원하는대로 작성, 마지막에 HAL_UART_Receive_IT()를 호출하여 다시 UART 수신 인터럽트 대기 상태로 만들 것
2-2. STM32CubeMX : UART-Interrupt(2) 추가 설명
- 위 USARTx_IRQHandler()의 huart1.Instance->RDR 넣는 어레이는 링버퍼로 작성 권장(데이터 잃어 버리고 싶지 않으면)
'ST > STM32F746DIS' 카테고리의 다른 글
| STM32F746G DISCOVERY - TIMER (0) | 2025.04.19 |
|---|---|
| STM32F746G DISCOVERY - UART(DMA) (0) | 2025.04.19 |
| STM32F746G DISCOVERY - printf()를 이용하여 UART로 문자열 출력 (0) | 2025.04.19 |
| STM32F746G DISCOVERY - GPIO(EXTI) (0) | 2025.04.19 |
| STM32F746G DISCOVERY - GPIO (0) | 2025.04.19 |


























































