0

I have a known serial stream format that I am capturing via the DMA. It has header and footer bytes. But sometimes the MCU starts capturing in the middle of the stream and then the sync is out because the DMA is looking for a set number of bytes. I have read of people using circular buffers, but I have struggled to grasp this concept.

Instead, I was thinking of disabling the DMA and enabling the a serial interrupt at the start up of the MCU. Then cycle through each byte that is captured by the interrupt to find the start byte. Then, once I have found the start byte, disable the serial interrupt capturing and enable the DMA to take over the capturing of the stream.

Does this sound feasible? Thanks for any input.

I am using STM32 HAL libs with the new STM32 IDE that includes STM32 CubeMX.

Dylan144GT
  • 93
  • 1
  • 8
  • `DMA is looking for a set number of bytes` DMA is not looking for anything. As you do not understand the basics - I advice to drop the async way of handling and stick with single threaded – 0___________ May 27 '19 at 09:26
  • @P__J__ You are correct, DMA is not looking for anything. But the USART itself may have character recognition and its corresponding interrupt. Another extended feature might be configurable timeout. – KIIV May 27 '19 at 12:23
  • @P__J__, yes, I understand that the DMA itself is not looking for a number of bites. It is one of the definitions that is required when setting u the USART for DMA because it needs to know how much space to reserve in the memory bank. – Dylan144GT May 27 '19 at 13:43
  • Yes, I do know the time between each packet - it is consistent and there is enough time between each packet to ensure that the time out would not allow the interrupt to take data from the next packet. My packet duration is 3ms and the packet is updated every 9ms. So I could set a timeout of 4ms. This was a solution that I wanted to implement but I could not find out how to set a timeout. Would you know? – Dylan144GT May 27 '19 at 13:54
  • Really briefly: CR2 register for enabling it, RTOR for setting the timeout and `USART_ITConfig(USART1,USART_IT_RTO,ENABLE);` for enabling interrupt + some handling – KIIV May 27 '19 at 22:00

2 Answers2

0

If I understand your reference to circular buffers correctly, the concept is simple. You have a large buffer with a write pointer and a read pointer. The write function writes data into the buffer from the write pointer onward, taking care that once it reaches the end of the buffer, it wraps around and dumps the data at the beginning of the buffer and onward. Then you need a reader function that reads the data from the read pointer onward, and again, taking care of wrap around at the end of the buffer.

Both the read and write pointers start at the beginning of the buffer. The two conditions that you have to check are: 1) When the read pointer is at the same location as the write pointer, there is nothing (more) to read. 2) When the write pointer increments and runs into the read pointer location, you have a buffer overflow condition. This should never happen, so either you must use a larger buffer, or have the reader task runs more frequently, or you start throwing things out.

So in your scenario, the DMA just dumps data, and your reader task looks for the header bytes and processes the data until it finds the footer bytes.

0

As the protocol has idle gaps between packets, you can use the idle interrupt feature of the UART to synchronize the receiver.

Enable the UART interrupt, simply start receiving with DMA, and set UARTx->CR1 |= USART_CR1_IDLEIE. Whenever the idle interrupt is triggered, look at the DMA channel, if it's still running, stop the transfer and discard the input buffer (as this means that the receive was started in the middle of the packet) and start receiving the next packet.

  • I have been trying to get this to work, but to no avail. Please could you give me some guidance? Do I enable the uart interrupt with HAL_UART_Receive_IT(&huartx, buffer, buffer_size) and then enable the idle line interrupt with __HAL_UART_ENABLE_IT(&huartx, UART_IT_IDLE)? Then where do I stipulate the interrupt handling? – Dylan144GT Jun 02 '19 at 18:41
  • You can use the DMA receive function as it is, and enable the idle interrupt either directly writing `CR1` or `__HAL_UART_ENABLE_IT`, they are the same. Do not call `HAL_UART_Receive_IT`, since you are not receiving with interrupt, but with DMA. Then write your own UART interrupt handler, which aborts and restarts the DMA transfer. – followed Monica to Codidact Jun 03 '19 at 09:49
  • Okay, I have enabled the UART interrupt, started the DMA and enabled the idle detect interrupt flag. Can you please explain to me how I setup my own interrupt handler? I have tried to do this in the main loop, but this seems counter intuitive. I have been spoilt with HAL interrupt handlers, but have no idea how to set up my own. Could you refer me to a source, because I have searched Google with no luck! Thanks again for your help! – Dylan144GT Jun 06 '19 at 20:44
  • Would I put it in `void USART1_IRQHandler(void)` in `stm32l4xx_it.c`? – Dylan144GT Jun 06 '19 at 21:34
  • Yes, that's the function that gets called whenever the UART generates an interrupt. You can enable the interrupt and set it's priority before you enter the main loop. In order to avoid locking issues with HAL, you might want to just set a flag in the interrupt handler, and abort the transfer in the main loop. Thinking about it, you can as well drop the idea with the UART idle interrupt altogether, check the `IDLE` bit in the UART status register directly from the main loop, and abort the transfer there if there is a partially received packet. – followed Monica to Codidact Jun 07 '19 at 08:42
  • *I have been spoilt with HAL interrupt handlers* They might seem convenient first, but they have serious limitations. HAL uses only a very limited subset of what the hardware can do. That combined with the [ridiculous amount of overhead](https://stackoverflow.com/questions/56440516/stm32-spi-slow-compute) makes it impossible to use for any serious work. – followed Monica to Codidact Jun 07 '19 at 08:43