Skip to main content
Gordon Madden
Associate III
October 31, 2017
Solved

Receiving duplicate bytes in DMA output

  • October 31, 2017
  • 3 replies
  • 3696 views
Posted on October 31, 2017 at 21:32

My project involves sending packets of bytes out of the serial port using DMA. I am using an STM32F417 with DMA2 using USART3. DMA transmit buffer is set to The packets that stream the current head position (live) are 66 bytes and stream at 10Hz. Occasionally, longer packets of camera head moves that were previously recorded to flash are sent. This is where I started to notice problems in the DMA output.

00 00 00 00 00 00 00 00 00 00 00 00 00 00 15 23 56 89

00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 23 56 89

00 00 00 00 00 00 00 00 00 00 00 00 00 00 17 23 56 89

00 00 00 00 00 00 00 00 00 00 00 00 00 00 18 23 23 56 89

00 00 00 00 00 00 00 00 00 00 00 00 00 00 19 23 56 89

00 00 00 00 00 00 00 00 00 00 00 00 00 00 1A 23 56 89

00 00 00 00 00 00 00 00 00 00 00 00 00 00 1B 23 56 89

00 00 00 00 00 00 00 00 00 00 00 00 00 00 1C 23 56 89

The above packets are frames from a camera move and at frame 18 (which is hex, so that's frame 24), there is an extra byte inserted (in this case, an extra '23'). This happens every time the frame number is 0x

To check out the whole buffer, I filled the buffer with 398 sequential bytes. Here are the results.

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

10 11 12 13 14 15 16 17 18 19 19 1A 1B 1C 1D 1E 1F

20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F

30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F

40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F

50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F

60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F

70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F

80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F

90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F

A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF

B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF

C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF

D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF

E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF

F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

10 11 12 13 14 15 16 17 18 19 19 1A 1B 1C 1D 1E 1F

20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F

30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F

40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F

50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F

60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F

70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F

80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D

The numbers rolled over, which was expected, but the duplicate '19's were not expected.

The duplicate bytes were verified to not be in the transmit buffer before sending. The same is true with the packets above.

I'm not sure how to troubleshoot this because the programmer doesn't have access to internal buffers that the dma uses.

Any suggestions on what the problem may be or how to troubleshoot? Thanks!

#packets #dma #stm32f4 #duplicate

Note: this post was migrated and contained many threaded conversations, some content may be missing.
    This topic has been closed for replies.
    Best answer by Gordon Madden
    Posted on November 01, 2017 at 19:43

    Sorry everybody! It turned out to be the version of Hyperterminal that I was using.

    I set up the same test using just USART3 and got the same results (still using Hyperterminal), so that ruled out the DMA part of the problem.

    I ran the same tests (working backwards from USART only transfers) and had no problems with any of the packet transfers or tests using RealTerm3.

    Much thanks to those who contributed and to Jan, who nudged me in the right direction to look outside the system for some other cause.

    Just for reference, I was using version 5.1.2600.0 of HT from 2001. It's a free version that has been kicking around the office here for years, but I guess it's always good to re-evaluate your tools from time to time!

    Cheers!

    3 replies

    Tesla DeLorean
    Guru
    October 31, 2017
    Posted on October 31, 2017 at 21:49

    Don't know, are you modifying registers?

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Gordon Madden
    Associate III
    October 31, 2017
    Posted on October 31, 2017 at 22:17

    DMA registers? Just the enable/disable.

    I enable the DMA and have the transfer complete interrupt handler turn it off.

    waclawek.jan
    Super User
    October 31, 2017
    Posted on October 31, 2017 at 22:28

    You don't give us enough information but my crystal ball whispered: Camera? DMA2? He might be using DCMI, and then it might've been related to the DMA2 data corruption when managing AHB and APB peripherals in a concurrent way erratum.

    Or

    https://community.st.com/0D50X00009XkW5oSAF

    .

    JW

    Alan Chambers
    Associate III
    November 1, 2017
    Posted on November 01, 2017 at 11:19

    What is the relationship between the 400-byte DMA TX buffer and the 66-byte packets? Why not a multiple of 66? How are packets copied into the buffer? It would be easy to create off-by-one errors when concatenating packets. What triggers the start of a DMA transfer? Are you certain you are not overlapping transfers in some way? Can you make a minimal complete program that demonstrates the issue?

    Gordon Madden
    Associate III
    November 1, 2017
    Posted on November 01, 2017 at 16:51

    Good questions!

    There is no relationship between the streaming packets and transferred packets other than I wanted the buffer to be larger than the largest packet I would send. When transferring a move, I pack multiple frames into the buffer to minimize the number of transfers.

    How would a multiple of 66 help? The streaming packets are sent at a constant rate, 10Hz.

    Packets are copied one byte at a time and transferred to the buffer like this:

       dma2TxBuffer[ dma2WriteHead ] = inChar;

    The write head just moves along the buffer.

    DMA transfer is triggered by sending the number of bytes to transfer to this function:

       //------------------------------------------------------------------------------------

    void SetupDMA2Transmit( u32 transmitBytes )

    //------------------------------------------------------------------------------------

    {

        USART_ClearFlag(USART3, USART_FLAG_TC);    // clear transmission complete flag

        

        DMA1_Stream3->NDTR = transmitBytes;

        DMA1_Stream3->M0AR = (uint32_t)dma2TxBuffer;

        DMA_ITConfig(DMA1_Stream3,DMA_IT_TC, ENABLE);                        // Interrupt Configuration

        DMA_Cmd(DMA1_Stream3,ENABLE);

    }

    I check that the transfer DMA has been disabled (meaning that the previous transfer is complete) before starting a new transfer.

    I did make a function not related to the packet generating functions. It fills the transfer buffer with sequential bytes and then initiates the transfer. RESULT: the first byte is 0 and then they count up. At 0x19 (27th byte), the next byte is 0x19. it then continues to count up to 256 (max for byte), rolls over to 0 and continues to count up. When 0x19 is encountered again, it duplicates again.

    Compare that to sending a prerecorded move. While sending blocks of frames (18 bytes each), mostly filling the buffer, the 25th frame sent (which is in the second buffer-load), a single byte WITHIN that frame gets duplicated. There seems to be no correlation between position of the byte in the transfer buffer and anything else. But again, when that 25th packet transmits, that same byte is duplicated in the same position within the frame.

    So, I am getting the same type of behavior in packet and non-packet transfers, and they are consistent within themselves, but not to each other.

    Also, the streaming packets (66 bytes) do not have any duplicate bytes. I have been recording the output using hyperterminal and the streaming packets are fine over thousands of iterations.

    I hope this gives you some additional insight!

    Alan Chambers
    Associate III
    November 1, 2017
    Posted on November 01, 2017 at 17:46

    Are you certain that the data in the buffer does not include the duplicated bytes? Put a break point in and look at the memory. From your description, the 25th (0x19 == 25) addition of *something* leads to a glitch. You've done blocks of 1 and blocks of 18. What happens if you send blocks of 10 bytes each? 20 bytes each? What is the code doing that adds data to your TX buffer? I think a minimal example intended to demonstrate the issue is the way to go. I suspect you will have an Aha! moment while doing this. Pretty sure the DMA stuff just works.

    I am using DMA for UART TX of variable length packets. Every packet is treated as a separate transfer. There is no advantage to concatenating packets except that I would have fewer TC interrupts. The code would be more complicated. The packet data is memcpy'd into a holding buffer, and the transfers are queued. The TC interrupt does basically what your SetupDMA2Transmit() does with the item at the front of the queue, if there is one:

    // Called from ISR on TC and from thread mode on append packet.

    void UsartDriver::tx_isr()

    {

        DisableInterrupts di;

        // Prevent starting another DMA transfer if we are in the middle of one.

        if (DMA_GetCmdStatus(m_res.dma_tx.stream) != DISABLE)

        {

            return;

        }

        

        // Clean up now that the transfer is complete.

        if (DMA_GetITStatus(m_res.dma_tx.stream, m_res.dma_tx.tc_flag))

        {

            DMA_ClearITPendingBit(m_res.dma_tx.stream, m_res.dma_tx.tc_flag);

            const UsartData& dma = m_tx_queue.front();

            tx_remove(dma.length); // Moves get address in holding buffer.

            m_tx_queue.pop();

        }   

        // If there is more data pending, start another DMA transaction.

        if (m_tx_queue.size() > 0U)

        {

            const UsartData& dma = m_tx_queue.front();

               

            // Start the DMA transfer

            m_res.dma_tx.stream->M0AR = (uint32_t)dma.data;

            m_res.dma_tx.stream->NDTR = (uint32_t)dma.length;

            DMA_Cmd(m_res.dma_tx.stream, ENABLE);

        }

    }

    Gordon Madden
    Gordon MaddenAuthorBest answer
    Associate III
    November 1, 2017
    Posted on November 01, 2017 at 19:43

    Sorry everybody! It turned out to be the version of Hyperterminal that I was using.

    I set up the same test using just USART3 and got the same results (still using Hyperterminal), so that ruled out the DMA part of the problem.

    I ran the same tests (working backwards from USART only transfers) and had no problems with any of the packet transfers or tests using RealTerm3.

    Much thanks to those who contributed and to Jan, who nudged me in the right direction to look outside the system for some other cause.

    Just for reference, I was using version 5.1.2600.0 of HT from 2001. It's a free version that has been kicking around the office here for years, but I guess it's always good to re-evaluate your tools from time to time!

    Cheers!

    waclawek.jan
    Super User
    November 1, 2017
    Posted on November 01, 2017 at 20:01

    0690X000006048dQAA.jpg