STM32의 Library가 Standard peripheral에서 HAL로 변경되면서 당황스러운 부분이 하나 있다.
바로 UART의 수신 시 받는 데이터 크기를 지정해야 한다는 것이다.
구글링으로 찾아 보면 일반적인 예제들은 이렇게 되어 있다.
volatile uint8_t uart_ch;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART3)
{
...
HAL_UART_Receive_IT( &huart3, (uint8_t*)&uart_ch, 1);
}
}
int main(void)
{
...
HAL_UART_Receive_IT( &huart3, (uint8_t*)&uart_ch, 1);
...
}
초기에 "HAL_UART_Receive_IT" 함수를 호출하고 콜백함수에서도 다시 호출해 주어야 한다.
RTOS를 적용했다면 별도의 Task를 만들어 주기적으로 "HAL_UART_Receive_IT"를 Polling하는 방식도 사용할 수 있다.
하지만 Standard peripheral 라이브러리를 쓰던 방식이 좋은 사람이라면 다음과 같은 방식을 취할 수 있다.
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
// HAL Driver 우회 코드
// HAL Driver의 UART RX 처리 방식이 고정 크기로 되어야 하므로 불편함.
// 이를 해결하기 위하여 SPL처럼 구현하고 HAL을 우회.
uint32_t tmp_flag = 0, tmp_it_source = 0;
/* 수신 이벤트 조사 */
tmp_flag = __HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE);
tmp_it_source = __HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_RXNE);
/* UART in mode Receiver ---------------------------------------------------*/
if ((tmp_flag != RESET) && (tmp_it_source != RESET)) {
/* 수신 레지스터에서 링버퍼로 한 바이트 복사 */
rx_buf[rx_i & RXBUF_MSK] = (uint8_t)(huart1.Instance->RDR & 0x00FF);
}
__HAL_UART_CLEAR_PEFLAG(&huart1); /* 이벤트 플래그 삭제 */
return; /* IRQ 핸들러 종료 */
// 아래 코드는 CubeMX 실행 시 자동 생성 되므로 삭제할 필요 없음.
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
int main(void)
{
...
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
while(1)
{
...
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
}
}
이 방식은 기존의 "USART1_IRQHandler"에서 "HAL_UART_IRQHandler"로 넘어가기 전에 데이터를 우회시키는 방법이다.
한가지 주의점은 STM의 CubeMX에서 Interrupt 방식을 설정해도 "USART1_IRQHandler"가 호출되지 않는다는 것이다. 이를 해결하기 위해"__HAL_UART_ENABLE_IT"를 Polling으로 호출해 주어야 한다.