---
# System prepended metadata

title: '[STM32 UART] - Polling/ Interrupt/ DMA research'

---

## [STM32 UART] - Polling/ Interrupt/ DMA research
**Board:** NUCLEO-F072RB
**IDE:** STM32CubeIDE
**UART Pin:** PA10(RX), PA9(TX)
**USB to UART converter:** Prolific PL2303
**Serial Port APP:** Serial Port Utility

![image](https://hackmd.io/_uploads/Ske0-sbSYA.png)
Connection Diagram

![image](https://hackmd.io/_uploads/S1pwi-St0.png)
pin define

![image](https://hackmd.io/_uploads/HJzXnbrYC.png)
I use this Software to read/write UART data

![image](https://hackmd.io/_uploads/SJ23nbBKA.png)
configure PA10 as UART RX, PA9 as UART TX

![image](https://hackmd.io/_uploads/BkxNTWBYA.png)
Configure UART1 Mode as Asynchronous

![image](https://hackmd.io/_uploads/SJA_abSFR.png)
UART HAL API
**stm32f0xx_hal_uart.h:** you can see polling/ interrupt/ DMA tx&rx API

**@Polling: (Blocking)**
HAL_UART_Transmit()
HAL_UART_Receive()

**@Interrupt: (Non Blocking)**
HAL_UART_Transmit_IT()
HAL_UART_Receive_IT()

**@DMA: (Non Blocking)**
HAL_UART_Transmit_DMA()
HAL_UART_Receive_DMA()

---

### [UART Polling]
![image](https://hackmd.io/_uploads/HJUIbMrYA.png)
```c=
/* 
 * Receive data from 'Serial Port Utility' and transmit the same data back
 */
uint8_t arrTx[6];//TX buffer with a length of 6 bytes
uint8_t arrRx[6];//RX buffer with a length of 6 bytes

while(1)
{
    memset(arrRx, 0, sizeof(arrRx));
    HAL_UART_Receive(&huart1, arrRx, sizeof(arrRx), 5000);
    /* Receive data from 'Serial Port Utility'
     * 5000: Timeout 5 seconds. 
     * If the recieved data length is less than sizeof(arrRx), 
     * HAL_UART_Receive() will block until a 5-second timeout
     */
    
    memcpy(arrTx, arrRx, sizeof(arrTx));
    //Copy RX data to TX data
    HAL_UART_Transmit(&huart1, arrTx, sizeof(arrTx), 1000);
    //Transmit data to 'Serial Port Utility'
}
```
{%youtube plEEu-R_4Q4 %}
![image](https://hackmd.io/_uploads/rJEZRfBYR.png)
If you don’t send any data to the STM32, you will see 6 bytes of data with 0x00 transmitted from the STM32 every 5 seconds.

![image](https://hackmd.io/_uploads/HJWICfStC.png)
When you send 6 bytes of data to the STM32, you will immediately see it transmit the same 6 bytes of data back.

![image](https://hackmd.io/_uploads/S1ZoRfrKC.png)
If you send fewer than 6 bytes, you will need to wait 5 seconds to see the data transmitted back.

![image](https://hackmd.io/_uploads/ry5e1mBKA.png)
If you send more than 6 bytes to the STM32, you will immediately see it transmit the data, but the data will be truncated.

---
### [UART Interrupt]
![image](https://hackmd.io/_uploads/r1jyITwt0.png)
Need to enable UART interrupt 

![image](https://hackmd.io/_uploads/S1w8TWtFR.png)
![image](https://hackmd.io/_uploads/rkniAWFKR.png)
In stm32f0xx_hal_uart.h, the third parameter of HAL_UART_R_IT() is 'Size', which specifies the number of bytes to receive before triggering the HAL_UART_RxCpltCallback() callback function. This means that the callback will only be invoked when the specified amount of data(i.e., 'Size' bytes)has been received. If fewer bytes are received, the callback will not be triggered.

If the UART data being received has a fixed length, you can set 'Size' to this fixed length. For example, if you are expecting 10 bytes of data, you would set 'Size' to 10. However, if the length of the data is variable or unkown, it is advisable to set 'Size' to 1. This way, the callback will be triggered for every byte received, allowing you to check and process the data incrementally as it arrives.

In this example code, I will send variable-length data, with the first byte indicating the data length and the remaining bytes containing the data.
ex: **"02 11 22"**
**"0x02":** data lenth is 2 bytes
**"0x11 0x22":** 2 bytes of data 
```c=
uint8_t arrTx[6];
uint8_t arrRx[6];
uint8_t rxIdx = 0;
uint8_t rxLen = 0;
bool isRxDone = false;

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (USART1 == huart->Instance) {
        if (0 == rxIdx) {
            //The first byte represents the data length, so store it in 'rxLen'
            rxLen = arrRx[0];
            rxIdx++;
        }
        else if (rxLen == rxIdx || sizeof(arrRx) <= rxIdx) {
            /*When the data reception is compelte or if the 'arrRx' buffers is full, 
            set the 'isRxDone' flag, reset 'rxIdx', 
            and prepare to process the 'arrRx' buffer in the main while(1) loop
            */
            isRxDone = true;
            rxIdx = 0;
            return;
        }
        else {
            rxIdx++;
        }

        HAL_UART_Receive_IT(&huart1, arrRx + rxIdx, 1);
        /*Call HAL_UART_Receive_IT() to continue receiving data,
          'rxIdx' will indicate the next position to store the received data
        */
    }
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_USART1_UART_Init();

    HAL_UART_Receive_IT(&huart1, arrRx, 1);
    /*Before entering the main while(1) loop, you need to call 
      HAL_UART_Receive_IT(). If data is received, the 
      HAL_UART_RxCpltCallback() will be called.
    */
    while (1)
    {
        if (isRxDone) {
            isRxDone = false;
            memcpy(arrTx, arrRx + 1, rxLen);
            //Copy the received data to the transmit buffer, but skip the first byte 'rxLen'
            rxLen = (sizeof(arrTx) < rxLen) ? sizeof(arrTx) : rxLen;
            //
            HAL_UART_Transmit_IT(&huart1, arrTx, rxLen);
            memset(arrRx, 0, sizeof(arrRx));
            HAL_UART_Receive_IT(&huart1, arrRx, 1);
        }
    }
}

```


---
### [UART DMA]
TODO