본문 바로가기

카테고리 없음

STM32 HAL UART Receive

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으로 호출해 주어야 한다.