2020-07-08 12:13 AM
Hi, I have the below code where I trigger the UART DMA and write to a buffer, and in the while loop I simply do a read from the buffer 1st element:
MX_UART7_Init();
Uartret = HAL_UART_Receive_DMA(&huart7, uartbuf, 300);
while(1){
if(Uartret == HAL_OK)
{
timeBuf[0] = uartbuf[0];
}
}
here is the uartbuf:
however if I remover the read line the 00s are will with values which I am expected.
Is there a way to read from dma on the fly ?
2020-07-08 12:51 AM
Its an unusual use of DMA. Usually you wait for DMA (half-)completion interrupts/callbacks indicating that DMA is (half-)done.
But, using __HAL_DMA_GET_COUNTER(huart->hdmarx) you can get the current index into filled DMA buffer.
I met this once in the wild: https://github.com/yoneken/rosserial_stm32/blob/master/src/ros_lib/STM32Hardware.h
There, read() is a polling read reading from a cyclic DMA buffer.
Your buffer looks like NMEA telegrams. They come usually at a slow bitrate and have limited but variable lengths.
In that case, I used single char interrupt-driven read HAL_UART_Receive_IT( &huart1, &ch, 1 ); and assembled whole lines (telegrams) in the HAL_UART_RxCpltCallback completion handler which I sent to a telegram parser.
2020-07-08 02:12 AM
I also recommend using only interrupts for a slow protocols, but I also would clearly separate UART from NMEA and make all processing, including the line assembling, a task of NMEA parser.
2020-07-08 02:18 AM
If i use HAL_UART_Receive() with a long timeout instead will it block other interrupt ? as in the code I didnt see any __disable_irq() they only use __HAL_UNLOCK.
2020-07-08 02:47 AM
No, it will not block other interrupts. But the problem is variable length of telegrams. What buffer size do you want to HAL_UART_Receive call with? HAL_UART_Receive does only return when the buffer is full.
Therefore the char by char approach.
As an alternative, the is an UART idle interrupt. for details, see https://github.com/MaJerle/stm32-usart-uart-dma-rx-tx.
2020-07-08 12:20 PM
This is a valid need, if you use DMA in a rolling buffer fed by USART RX and you want to avoid interrupt and just size the buffer large enough to read with time slice method (the best polling method for USART RX)
2020-07-08 02:32 PM
Which STM32?
There's nothing unusual in it. Even Tilen Majerle uses exactly this (reading from circular-DMA buffer based on NDTR) in the code you've linked to above. That's how DMA is supposed to be used as receiving interfaces' FIFO, except in the Cube/HAL realm.
Using Cube/HAL also probably results in a slow code enough to cover the problem that NDTR counts the peripheral-side transactions, not the finished transfers, at least in the dual-port DMA (F2/F4/F7).
JW
2020-07-08 03:35 PM
Caching becomes an issue for CM7 implementation
Describing transient memory buffers as volatile is important for compiler/optimizer issues.
My suggested method is to use uint16_t buffers, where you mark the memory (0xFFFF patterns) before you hand it to the DMA unit so you can see where it has been, and can simply sweep the buffer at a convenient interval. The depth of the buffer, and the sweep period being predicated on the maximum data rate.
2020-07-08 06:15 PM
stm32f73x, if i make a loop to read I can see more zeros.
2020-07-08 09:33 PM
Where do you see zeros? In the debugger? Isn't that a debugger artefact, i.e. does the program in processor see those zeros? Isn't there some other process running which would write them?
Write a minimal program, which only starts the USART DMA and then goes to an infinite loop (i.e. does nothing), observe. Instead of continuously transmitting device, connect UART to PC and transmit into it manually, character by character, and observe.
JW