UART 송수신은 blocking 방식을 쓰거나 인터럽트를 이용한 nonblocking 방식을 사용할 수 있다. Blocking 방식은 UART 송수신이 완료될 때까지 다른 작업을 할 수 없는 반면에 nonblocking 방식을 사용하면 UART 송수신을 메인 루틴과 독립적으로 사용할 수 있기 때문에 리얼타임을 보장하는 데 도움이 된다. UART DMA는 기본적으로 nonblocking의 일종이면서 인터럽트 발생의 횟수를 줄여서 더 리얼타임성을 높일 수 있다.
본 포스팅에서는 STM32103 MCU에서 UART DMA를 사용하는 방법을 설명한다.
Hardware Configuration
이전 포스팅에서와 같이 하드웨어 환경은 WIZnet WIZ145SR을 사용한다.
UART DMA를 사용하기 위한 포트는 UART4 를 사용할 것이다.
STM32CubeIDE에서 “Pinout & Configuration”을 선택한 후, 다음과 같이 설정한다.
- “Configuration”->”DMA Setting”에서 “Add” 버튼을 클릭해서 UART_TX를 선택한다.
- “Mode” 는 “Normal”을 선택한다. “Normal” 모드는 DMA TX/RX를 한번만 수행한다. 사용자의 개입없이 무한 반복이 필요한 경우라면 “Circular”를 선택하면 된다. 여기서는 “Normal” 모드를 사용할 것이다.
- “NVIC Settings”에서 “UART4 global interrupt”가 “Enabled” 되어 있는 지 확인한다.
- “UART4 global interrupt”가 “Enabled”되어 있지 않으면 DMA operation은 다음 명령을 내려도 수행되지 않는다.
Coding
위와 같이 하드웨어 설정을 한 후에 “Generate Code”를 하면, main.c에 “MX_DMA_Init()”이 추가된 것을 확인할 수 있다.
다음은 while() 문 내에서 1초 단위로 HAL_UART_Transmit_DMA를 호출하도록 구성한다.
UART1은 DMA를 사용하지 않고 Data를 송신하고 UART4는 DMA를 사용해서 Data를 송신한다.
HAL_UART_Transmit_DMA()를 호출하는 것으로 DMA 송신을 위한 코딩은 끝났다.
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(onesecondElapsed)
{
onesecondElapsed = 0;
count++; // increment count
memset(msg, 0, 200);
sprintf((char *)msg, "UART1,[%d],%s\r\n", count, message);
HAL_UART_Transmit(&huart1, msg, strlen((const char*)msg), 20);
memset(dma_buf, 0, 200);
sprintf((char *)dma_buf, "UART4 DMA,[%d],%s\r\n", count, message);
HAL_UART_Transmit_DMA(&huart4, dma_buf, strlen((const char*)dma_buf));
}
loopback_tcps(0, ethBuf0, 5000);
}
Build and Run
Build한 후에 STM32CubeProgrammer 로 생성된 바이너리를 다운로드 한다.
다음으로 STM32F103이 전송한 데이터를 수신하는 프로그램을 Putty를 실행한다.
여기까지의 전체 코드는 다음 링크에서 확인할 수 있다.
https://github.com/javakys/WIZ14xSR_Proj/releases/tag/Ver0.6
1 Comment