cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F407 DMA Transfer Peripheral to Peripheral

mogwaifactory
Associate II
Posted on November 19, 2015 at 18:32

Hello,

I'm wondering if it is possible like with the pic32 to initiate a DMA transfer from peripheral to peripheral. So far the documentation I've read specifies periph to memory, memory to periph, or memory to memory.

The idea is to forward every bytes from USART2_RX to USART6_TX and vice versa.

I'm currently doing it with interrupts, but I would like to lighten the MCU a little bit because it does a lot of things in background.

Should I use a small buffer in memory and do periph to mem, then mem to periph?

Thanks for your input.

Dan.

#stm32 #stm32f407 #uart #stm32f4

Note: this post was migrated and contained many threaded conversations, some content may be missing.
20 REPLIES 20
Posted on October 04, 2017 at 03:34

Unfortunately, I left on a trip soon after my post (I am writing this reply on the train now) so I wasn't able to post the DMA registers.

I don't see an attachment to your post. I would be interested in looking at the code and seeing what is different between my setup (I was using a modified HAL driver for my experiments in order to change the destination DMA address).

Posted on October 04, 2017 at 07:40

This is part of the truth.

The main thing in working with the periphery is the expectation of readiness, naturally on the hardware level. If you use DMA in memory-memory mode, then the waiting limit is replaced by the priority level. DMA will work at the first space speed, even if the receiver is an absolute brake.

However, if the speed of the receiver is higher than the source - the focus may turn out. For example, start DMA from the timer (does not require confirmation), take data from memory and write to the periphery. Or, to take data from a slow USART and write to a fast one, the slow USART should serve as the starting source.

But the reverse process is impossible, why the meaning of the solution is completely lost.
Posted on October 04, 2017 at 09:23

Indeed, there was no attachement. I've edited the previous post and added the attachment (cw.zip). Sorry.

Jan

[There was no attachment. Adding one, two appeared. I guess jive has been written in some sort of Cube too... 😉 )

Posted on October 05, 2017 at 01:05

You found a HAL bug! Congratulations!

In stm32f4xx_hal_dma.c:

static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
 ...
 /* Peripheral to Memory */
 if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
 {
 ...
 }
 ...
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

I don't have access to hardware on this trip, so I ran your code and mine in the simulator and saw that the source and destination buffer pointers were reversed. I have to get going, so I don't have time right now to figure out why the USART6 ->SRAM worked (if the buffers are reversed, it should have been broken also), but I'll investigate it later.

How do I go about reporting this to the proper authorities? Start a new thread?

Pity there isn't a GitHub repository that I could submit a pull request to...

Posted on October 05, 2017 at 10:41

That's just the comment lying (althought that deserves a fix too).

From STM32Cube_FW_F4_V1.0\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma.c:

static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
 /* Clear DBM bit */
 hdma->Instance->CR &= (uint32_t)(~DMA_SxCR_DBM);
 /* Configure DMA Stream data length */
 hdma->Instance->NDTR = DataLength;
 /* Peripheral to Memory */
 if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
 {
 /* Configure DMA Stream destination address */
 hdma->Instance->PAR = DstAddress;
 /* Configure DMA Stream source address */
 hdma->Instance->M0AR = SrcAddress;
 }
 /* Memory to Peripheral */
 else
 {
 /* Configure DMA Stream source address */
 hdma->Instance->PAR = SrcAddress;
 /* Configure DMA Stream destination address */
 hdma->Instance->M0AR = DstAddress;
 }
}
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Looks good to me. Not going to dig deeper.

JW

Posted on October 05, 2017 at 10:43

How do I go about reporting this to the proper authorities? Start a new thread?

Unless you are willing to pester a FAE or post a complaint through the web-based support, and then follow up - start a new thread and then hope.

JW

Posted on October 06, 2017 at 09:25

Well, this is embarrassing. I'm going to post this for a laugh and a warning about tunnel-thinking and getting sloppy with the scientific method.

As background, I use DMA transmit for many things, but until this experiment, DMA receive for nothing. So all my thinking up until this point was geared towards DMA transmit. DMA transmit is always memory-to-peripheral, so in my (mistaken) mind, the peripheral data register was the 'bad guy' that needed to be changed (yes, I know, it makes no sense in retrospect). So I started my experiment by copying the:

HAL_UART_Receive_DMA(UART_HandleTypeDef* huart, uint8_t* pData, uint16_t Size)

function code, then renaming it and adding a parameter:

HAL_GPIO_Receive_DMA(UART_HandleTypeDef* huart, uint8_t* pData, uint16_t Size, uint8_t* Destination)

Yes, I know. It makes no sense. pData is already the destination. But I saw this function inside HAL_UART_Receive_DMA:

HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);

And for some reason (probably because of all the DMA Transmit destinations being a peripheral register), I thought I needed to change it to:

HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)Destination, *(uint32_t*)tmp, Size);

So I called the new HAL_GPIO_Receive_DMA function and predictably, nothing happened because the transfer was totally backwards, trying to receive data from my destination GPIO port.

Normally, this wouldn't be a big deal if I had used this function as my 'positive control' (in the experiment):

HAL_GPIO_Receive_DMA(&huart6, Buffer, 1, Some_SRAM_Buffer);

It would have failed and I would have known something was wrong with the function. However, my brain said 'Since the new GPIO Receive DMA function is just a slightly modified copy of the old HAL_UART_Receive_DMA function, you can just use the original function for your 'positive control'.' So my 'positive control' (sending data from USART6 to SRAM) was:

HAL_UART_Receive_DMA(&huart6, Some_SRAM_Buffer, 1);

which of course worked fine because it was a proper USART6 to SRAM DMA pipe.

Looking back, I think I must have been on drugs to make so many amateur mistakes. I don't have access to hardware for the next two days, but now my DMA registers match Jan's in the simulator and I think it will work fine.

Much thanks to Jan for keeping me from falsely discarding a very useful tool from my toolkit.

Posted on October 07, 2017 at 17:29

Confirmed. This works. I have edited my previous incorrect post.

Rostyslav S
Associate II
Posted on November 22, 2017 at 15:34

Implemented the same using STM32Cube.

I am working on the same task to forward data between two UARTs using DMA. In my case two devices are connected to central device via UARTs. Central device acts like a bridge between them.

In my case, DMA was enabled for UART4_RX with Peripheral to memory direction. Mode is set to Circular, priority high.

The same settings applies to UART5_RX DMA. See screenshot below.0690X00000608wHQAQ.png

UART4 and UART5 are configured as 115200bits/s, 8bit word length, no parity and one stop bit.

In source code I have added two lines of code:

HAL_UART_Receive_DMA(&huart4, (uint8_t *) &(USART5->TDR), 1);

HAL_UART_Receive_DMA(&huart5, (uint8_t *) &(USART4->TDR), 1);

This task appeared to be easier than I expected, so I am double checking if everything is set upped correctly.

Questions:

- DMA is configured to transfer one byte from ingress UART4 register to egress UART5 register.

UART4 is configured as 8bit word length + 1 stop bit. So I assumed that stop bit will be validated and then skipped by UART controller and exactly 8bits will be placed in UART4 RDR register. Afterwards RDR content will be placed directly to UART5 TDR.

Right?

- There will be no data loss as when any byte arrives to UART it will be immediately forward to another UART.

Is it possible that DMA will not be able to serve next request if previous DMA transfer is in progress?

Posted on November 22, 2017 at 21:39

Is it possible that DMA will not be able to serve next request if previous DMA transfer is in progress?

If the receiving USART's baudrate is higher than the transmitting one, then DMA will simply shovel the incoming bytes onto the still working USART and they will get lost.

JW