Issues getting DMA's to work reliably with USART1 and LPUART
- June 14, 2022
- 2 replies
- 3097 views
Brief: I am using cubemx to configure and generate code.
MCU: stm32wb55rgvx
firmware package name and version: FW_WB V1.13.3
Details:
I am working on a project where the stm must act as a bridge between the PC and the device under test (DUT). We use the newtmgr tool on the PC to transfer/upload the firmware on the DUT via the stm at baudrate of 1MHz. For this, we are using two uarts on the stm i.e. USART1 connected to the PC and LPUART1 connected to the DUT. All packets received from the PC must be relayed to the DUT and all packets/responses received from the DUT must be forwarded to the PC.
I have attached the .ioc file that shows how I have configured the two uarts to be used with DMA's. I'd like the DMA's to work in the following cyclic order since it's a request-response mechanism.
- Receive packet from the PC over USART1-RX
- Relay this packet to the DUT over LPUART1-TX
- Receive a response from the DUT on LPUART-RX
- Relay this packet to the PC over USART1-TX
With the above configuration, the transfer starts to work but stops after about 20%, as shown below image. You can also see on channel-2 i.e. (PC->STM), there's a massive delay of 3s introduced which could be breaking the upload process.
Below are code snippets implementing the bridge.
/**
* @brief Initialises the UART ports to receive data, called once in the main.
*/
void test_process_init() {
if (HAL_OK != HAL_UARTEx_ReceiveToIdle_DMA(pc.uart,
(uint8_t *)pc.buffer, sizeof(pc.buffer))){
Error_Handler();
}
if (HAL_OK != HAL_UARTEx_ReceiveToIdle_DMA(dut.uart,
(uint8_t *)dut.buffer, sizeof(dut.buffer))){
Error_Handler();
}
enter_boot_mode(); // puts dut in serial recovery mode
}The above is called once in the main on boot to initiate dma reception. The below code snippet shows how I managing/bridging the transfers.
UART_HandleTypeDef huart1;
UART_HandleTypeDef hlpuart1;
struct uart {
UART_HandleTypeDef *uart;
char buffer[1024];
volatile bool buffer_ready;
size_t length;
};
static struct uart pc= { .uart = &huart1, };
static struct uart dut= { .uart = &hlpuart1, };
/**
* @brief Special service to capture the following events (bridge the transfers)
* - RX line IDLE for 1 frame time
*/
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){
struct uart *rec_uart = &dut;
struct uart *tx_uart = &pc;
if (huart == pc.uart) {
rec_uart = &pc;
tx_uart = &dut;
}
HAL_StatusTypeDef status = HAL_UART_Transmit_DMA(tx_uart->uart, (uint8_t*)rec_uart->buffer, Size);
if(status != HAL_OK){
if(status == HAL_BUSY){
// do nothing
}else{
Error_Handler();
}
}
status = HAL_UARTEx_ReceiveToIdle_DMA(rec_uart->uart, (uint8_t *)rec_uart->buffer, sizeof(rec_uart->buffer));
if(status != HAL_OK){
if(status == HAL_BUSY){
// do nothing
}else{
Error_Handler();
}
}
}Any support in getting this to work reliably would be helpful. Cheers.