cancel
Showing results for 
Search instead for 
Did you mean: 

Issues getting DMA's to work reliably with USART1 and LPUART

vd
Associate III

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.

0693W00000NrnUcQAJ.pngBelow 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.

1 ACCEPTED SOLUTION

Accepted Solutions
gbm
Lead III

Abandon HAL, use interrupts and two big circular buffers - it's much easier to do it that way than to use DMA for your task.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

View solution in original post

6 REPLIES 6
gbm
Lead III

Abandon HAL, use interrupts and two big circular buffers - it's much easier to do it that way than to use DMA for your task.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
vd
Associate III

I thought for baud rates of 1 MHz and above, the recommended way is to use DMA's. Could you please shed some light on this: The HAL uses interrupts for RX and TX too, why do you suggest abandoning it?

I'd also like some feedback on what I have done above and why it isn't working.

Yeah, I'd probably lean to DMA too. It helped on an STM32L072 based design.

There I used DMA to create a circular ring buffer for the receive, it reduced loading, and increased robustness.

Didn't use interrupts, or HAL, ST's solution is just too cluttered and cumbersome.

Sorry, I not going to unravel broken code.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

I'd like the idea of using dma's without interrupts too. Would you mind sharing such an example or snippet if you have one? - Also, the cubemx tends to generate code with interrupts enabled for the dma's, and it's greyed out causing unable to disable it.

Do you disable the interrupts in the main and then go about implementing your own code/driver to do the above without interrupts?

Never mind, figured out how to disable them. But if you have some examples, I'd be great if you could share them. Cheers.

vd
Associate III

Did this and worked like magic. I also realized the interrupt handlers generated by cubemx are massive. Cheers.