how to debug UART with DMA

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
lock attach
Attachments are accessible only for community members.
LeYu_281131
Level 3
Level 3

Hi my name is YS.

I have a problem about DMA with UART(just my opinion).

I programmed PSoC5LP to communication with two external PC.

but two external PC could send message simultaneously to PSoC5LP.

so, I configured UART with DMA, to reduce CPU load and get message without missing Data.

I tested with two CYKIT-050,

one kit configured as TX(send TX with two output pin)

another kit configured as RX(has DMA with UART)

It works well first several times,

but after the several times, DMA won't work(this also my opinion).

and I have no idea how to solve this problem.

If someone know, Please let me know.

I attached my project file, please refer that.

Thank you.

0 Likes
1 Solution
lock attach
Attachments are accessible only for community members.

YS,

I've made some changes to your Design01 project.

In general,  I removed your DMA_RX_B_DmaRelease() and re-Init_DMA_RX() calls.

I changed them to CyDmaChSetRequest() to terminate the TDs and CyDmaChEnable() to re-enable the DMA channel.

I ran the new project for over an hour with no stops in the Debug output.  Previously, it would sop after less than 20 seconds.

Len

Len
"Engineering is an Art. The Art of Compromise."

View solution in original post

0 Likes
5 Replies
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

YS,

I've downloaded your workspace.  I'm going to try out your projects.   I have to make some changes to fit my kits.

I do have some questions:

  1. How are the Rxs and the Txs hooked up between the two PSoCs?
  2. It appears in Test_TX that the output string is sent ONLY when the SW on Port 6.1 sees a rising edge. Is this correct?
  3. The output from Design01 is suppose to occur every 5.6us (67/12MHz).  Is this correct?
  4. What is the purpose of Counter_B in Design01?
  5. It would appear that Rx_1 to UART_1 in Test_TX is not used.  Is this correct?
  6. It would appear that Rx_1 to UART_Main in  Design01 is not used.  Is this correct?

If 2. is correct, then there is no guarantee that data will be available to either UART_A or UART_B in Design01.  In this case you will receive "[A=]" and "[B=]" responses.

If 3. is correct you have a data bottleneck.  If ALL the data is sent from Text_TX and received by Design01 UARTs that is 67 characters.  This will take 5.82ms to transmit from the PSoC running the Test_TX project.

Add the "[A=" and "]\n\r" and that makes it 73 characters total.  At 115200 kbps it will take 6.34ms to transmit to the debug port from the Design01 project.

You might want to reconsider your Counter_A timeout to be longer.

I found some additional curiosities in your code.

Your function:

void Init_DMA_TX()

{

    uint8 DMA_TX_Chan;

    uint8 DMA_TX_TD[1];

    DMA_TX_Chan = DMA_TX_A_DmaInitialize(DMA_TX_BYTES_PER_BURST, DMA_TX_REQUEST_PER_BURST, HI16(DMA_TX_SRC_BASE), HI16(DMA_TX_DST_BASE)); //

    DMA_TX_TD[0] = CyDmaTdAllocate();

    CyDmaTdSetConfiguration(DMA_TX_TD[0], 1, DMA_TX_TD[0], DMA_TX_A__TD_TERMOUT_EN ); //

    CyDmaTdSetAddress(DMA_TX_TD[0], LO16((uint32)&UART_Main_RXDATA_REG), LO16((uint32)&UART_A_TXDATA_REG)); //

    CyDmaChSetInitialTd(DMA_TX_Chan, DMA_TX_TD[0]);

    CyDmaChEnable(DMA_TX_Chan, 1);

   

    DMA_TX_Chan = DMA_TX_B_DmaInitialize(DMA_TX_BYTES_PER_BURST, DMA_TX_REQUEST_PER_BURST, HI16(DMA_TX_SRC_BASE), HI16(DMA_TX_DST_BASE)); //

    DMA_TX_TD[0] = CyDmaTdAllocate();

    CyDmaTdSetConfiguration(DMA_TX_TD[0], 1, DMA_TX_TD[0], DMA_TX_B__TD_TERMOUT_EN ); //

    CyDmaTdSetAddress(DMA_TX_TD[0], LO16((uint32)&UART_Main_RXDATA_REG), LO16((uint32)&UART_B_TXDATA_REG)); //

    CyDmaChSetInitialTd(DMA_TX_Chan, DMA_TX_TD[0]);

    CyDmaChEnable(DMA_TX_Chan, 1);

}

You set DMA_TX_Chan twice.   You also set DMA_TX_TD[0] twice.  In effect, only the second DMA_TX_Chan and DMA_TX_TD[0] is in effect.

Additionally the variables DMA_TX_Chan and DMA_TX_TD[1] are local vars in a function.  These variables will be usually placed on the stack and lost once the function returns to the calling function.   To preserve these variables when the function returns either pull these variables out of the function and use as globals for the module or use the static keyword in front or the declaration.

I recommend the following changes:

void Init_DMA_TX()

{

    static uint8 DMA_TX_Chan[2];

    static uint8 DMA_TX_TD[2];

/* Use DMA_TX_Chan[0] and DMA_TX_TD[0] elements */

    DMA_TX_Chan[0] = DMA_TX_A_DmaInitialize(DMA_TX_BYTES_PER_BURST, DMA_TX_REQUEST_PER_BURST, HI16(DMA_TX_SRC_BASE), HI16(DMA_TX_DST_BASE)); //

    DMA_TX_TD[0] = CyDmaTdAllocate();

    CyDmaTdSetConfiguration(DMA_TX_TD[0], 1, DMA_TX_TD[0], DMA_TX_A__TD_TERMOUT_EN ); //

    CyDmaTdSetAddress(DMA_TX_TD[0], LO16((uint32)&UART_Main_RXDATA_REG), LO16((uint32)&UART_A_TXDATA_REG)); //

    CyDmaChSetInitialTd(DMA_TX_Chan[0], DMA_TX_TD[0]);

    CyDmaChEnable(DMA_TX_Chan[0], 1);

  

/* Use DMA_TX_Chan[1] and DMA_TX_TD[1] elements */

    DMA_TX_Chan[1] = DMA_TX_B_DmaInitialize(DMA_TX_BYTES_PER_BURST, DMA_TX_REQUEST_PER_BURST, HI16(DMA_TX_SRC_BASE), HI16(DMA_TX_DST_BASE)); //

    DMA_TX_TD[1] = CyDmaTdAllocate();

    CyDmaTdSetConfiguration(DMA_TX_TD[1], 1, DMA_TX_TD[1], DMA_TX_B__TD_TERMOUT_EN ); //

    CyDmaTdSetAddress(DMA_TX_TD[1], LO16((uint32)&UART_Main_RXDATA_REG), LO16((uint32)&UART_B_TXDATA_REG)); //

    CyDmaChSetInitialTd(DMA_TX_Chan[1], DMA_TX_TD[1]);

    CyDmaChEnable(DMA_TX_Chan[1], 1);

}

I found the same basic issues for Init_DMA_RX() function.   I recommend the following changes:

void Init_DMA_RX()

{

    static uint8 DMA_RX_Chan[2];

    static uint8 DMA_RX_TD[2];

   

/* Use DMA_RX_Chan[0] and DMA_RX_TD[0] elements */

    DMA_RX_Chan[0] = DMA_RX_A_DmaInitialize(DMA_RX_BYTES_PER_BURST, DMA_RX_REQUEST_PER_BURST, HI16(DMA_RX_SRC_BASE), HI16(DMA_RX_DST_BASE));

    DMA_RX_TD[0] = CyDmaTdAllocate();

    CyDmaTdSetConfiguration(DMA_RX_TD[0], 100, DMA_RX_TD[0], CY_DMA_TD_INC_DST_ADR);

    CyDmaTdSetAddress(DMA_RX_TD[0], LO16((uint32)UART_A_RXDATA_PTR), LO16((uint32)RXA_Buffer));

    CyDmaChSetInitialTd(DMA_RX_Chan[0], DMA_RX_TD[0]);

    CyDmaChEnable(DMA_RX_Chan[0], 0);

   

/* Use DMA_RX_Chan[1] and DMA_RX_TD[1] elements */

    DMA_RX_Chan[1] = DMA_RX_B_DmaInitialize(DMA_RX_BYTES_PER_BURST, DMA_RX_REQUEST_PER_BURST, HI16(DMA_RX_SRC_BASE), HI16(DMA_RX_DST_BASE)); //

    DMA_RX_TD[1] = CyDmaTdAllocate();

    CyDmaTdSetConfiguration(DMA_RX_TD[1], 100, DMA_RX_TD[1], CY_DMA_TD_INC_DST_ADR);

    CyDmaTdSetAddress(DMA_RX_TD[1], LO16((uint32)UART_B_RXDATA_PTR), LO16((uint32)RXB_Buffer)); //

    CyDmaChSetInitialTd(DMA_RX_Chan[1], DMA_RX_TD[0]);

    CyDmaChEnable(DMA_RX_Chan[1], 0);

}

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
lock attach
Attachments are accessible only for community members.
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

YS,

I have been able to reproduce what you are seeing.  With one exception:  I perform a memset() with ' ' (space char) instead of 0.

When you memset() to 0, this is why your output eventually gets to "[A=]" and "[B=]" because 0 is a string NULL terminator.

Attached is my Terminal output.

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Dear Len,

Thank you for your advice.

I think, Do not need my answer about your first reply.

because, you already tested and got same problem.

I think you understand very well.

1. DMA for TX

- I have a two PC that has UART.

- when PSoC get a data, Send the data to two PC simultaneously.

   so I put two DMA with UART_Main_RX.

- if you Have another solution with DMA, please let me know.

- It is not used with current Test(to test RX with DMA) but will use.

2. Counter purpose

- Counter is for "number of received data"

- if the Data Length is fixed, there is no issue.

   but the Length is variable in my system.

- so, I put the counter each DMA.

3. about my system.

- Send Data simultaneously, from Kit_A(include DMA) to two PC.

   Receive Data simultaneously, from two PC to Kit_A.

4. Method for Reset transition counter

- there is no API to reset transition counter of DMA channel.

   so, I put the DmaRelease and Init_DMA

- Do you have another method to reset transition counter after read data?

   the Data Length is not fixed, so I want to reset transition counter manually.

5. Do you have solve the problem?

- You already have same problem, push button several times, DMA may stop.

- Please share the solution or advice to solve the problem.

Thank you again.

YS

0 Likes
lock attach
Attachments are accessible only for community members.

YS,

I'm still working on your issue.  However, I have narrowed it down quite a bit.

Since when it 'fails' you are getting "[A=]" and "[B=]", this means that Counter_A and Counter_B are still counting.  That means the incoming data is being processed by UART_A and UART_B.

Therefore the issue with how the DMA is initialized OR how it is being handled in your DmaRelease().  For some reason it appears to no longer move the data from UART_Main's Rx to your Rx buffers.

If you're interested, I've modified your Test_TX project to use a psuedo-random trigger of your TX output stimulus.  This makes the issue occur quicker for diagnostic purposes.

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
lock attach
Attachments are accessible only for community members.

YS,

I've made some changes to your Design01 project.

In general,  I removed your DMA_RX_B_DmaRelease() and re-Init_DMA_RX() calls.

I changed them to CyDmaChSetRequest() to terminate the TDs and CyDmaChEnable() to re-enable the DMA channel.

I ran the new project for over an hour with no stops in the Debug output.  Previously, it would sop after less than 20 seconds.

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes