DMA problem with UART1

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

DMA problem with UART1

1,687 Views
albertopenasa
Contributor II

Hello everybody,

i need to transfer received data from UART1 to a buffer into the RAM on my K20 demoboard.

I encountered some problem managing the synchronization between UART1 and DAM channel 0: the DMA rightly reads the data from UART1_D  and writes it on the RAM, but write the same value more than once. My drivers seems not clean properly the UART S1 [RDRF], i tried to clear it inside the DMA 0 ISR, but nothing, no effect obtained.

 

Any idea?

 

Note: i attached the initialization code of the DMA.

 

Regards,

Alberto

Original Attachment has been moved to: dma.c.zip

Tags (3)
0 Kudos
Reply
6 Replies

1,083 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Alberto Penasa,

I have had a brief look through your question, however I'm still confused about this synchronization issue. Would you please explain this issue in detail again?

I'm looking forward your reply.

Have a nice day!

Ping

0 Kudos
Reply

1,083 Views
albertopenasa
Contributor II

Hi jeremyzhou,

thanks for your reply.

Just to give you a breaf idea on what i'm doing. I'm writing a driver that transmit and receive data to/from RS485. At this moment I implement just a test that transmits and receives 16 chars on the same K20: transmits on UART0 and receives on UART1 at 9600bps. The idea is to transfer the received data from UART1_D to a buffer (int8_t, 64 lenght) in the RAM using DMA channel 0. To do that I set the link between the UART1 and the DMA ch0, and I have defined the value of  the RX watermark (set to 1):

UART_C2_REG(uartch) |= UART_C2_RIE_MASK; //Enable RDRF interrupt or DMA transfer requests enabled
UART_C5_REG(uartch) |= UART_C5_RDMAS_MASK ; //Enable DMA
UART_RWFIFO_REG(uartch) = rx_wm; //RX Watermark Threshold

The results of the test:
when the UART1 receives the first byte, it correctly calls the DMA that transfers the data to the first location of the buffer in RAM. Unfortunatelly, the UART1 keep on  to call the DMA0 that writes the first byte in all the locations of the buffer. The baud rate of the UART is more slower than the transfer rate of the DMA, so I suppose: if the RDRF interrupt of the UART1 is not correctly cleared, the UART1 go on to call DMA0 and to transfer the same value more than once. So I try to understand if there is a way to manage correctly the calls to the DMA.

I hope I was clear enough. Thanks for your help.


Regards,

Alberto

0 Kudos
Reply

1,083 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Alberto Penasa,

I also agree with Mark that you may had mixed up the minor loop and major loop. I've attached a DMA deom code with the reply and please refer to it for details. So I'd like to suggest you'd better correct your code with the help of the attachment.
Have a great day,
Ping

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

1,083 Views
mjbcswitzerland
Specialist V

Alberto

You may have mixed up the minor and major loops. Also ensure that you don't leave registers like DMA_TCD0_NBYTES_MLNO unconfigured since they have random values otherwise.

Below is the rx configuration from the uTasker project. This allows DMA operation parallel on all available Kinetis UARTs (just Rx shown in half-buffer, full buffer interrupt modes or free-running circular buffer mode). Although not a problem with your single channel setup, you generally need to manage DMA channel priorities to avoid conflicts when working with multiple ones.

The complete project is available at KINETIS Project Code and it allows you to test the UART DMA operation in its Kinetis simulator to help save time learning and debugging. Send me an email if you would like to try it. The UART DMA driven driver has been used successfully in industrial projects using multiple > 1,5Mb/s UARTs in environments requiring high reliability communications.

Regards

Mark

if (pars->ucDMAConfig & UART_RX_DMA) {

    KINETIS_DMA_TDC *ptrDMA_TCD = (KINETIS_DMA_TDC *)eDMA_DESCRIPTORS;

    ptrDMA_TCD += UART_DMA_RX_CHANNEL[Channel];

    fnEnterInterrupt((irq_DMA0_ID + UART_DMA_RX_CHANNEL[Channel]), UART_DMA_RX_INT_PRIORITY[Channel], (void (*)(void))_uart_rx_dma_Interrupt[Channel]); // enter DMA interrupt handler

    uart_reg->UART_C5 |= UART_C5_RDMAS;                              // use DMA rather than interrupts for reception

    POWER_UP(6, SIM_SCGC6_DMAMUX0);                                  // enable DMA multiplexer 0

    *(unsigned char *)(DMAMUX0_BLOCK + UART_DMA_RX_CHANNEL[Channel]) = ((DMAMUX_CHCFG_SOURCE_UART0_RX + (2 * Channel)) | DMAMUX_CHCFG_ENBL); // connect UART rx to DMA channel

    ptrDMA_TCD->DMA_TCD_BITER_ELINK = ptrDMA_TCD->DMA_TCD_CITER_ELINK = pars->Rx_tx_sizes.RxQueueSize; // the length of the input buffer in use

    ptrDMA_TCD->DMA_TCD_SOFF = 0;                                    // source not increment

    ptrDMA_TCD->DMA_TCD_DOFF = 1;                                    // destination incremented

    ptrDMA_TCD->DMA_TCD_ATTR = (DMA_TCD_ATTR_DSIZE_8 | DMA_TCD_ATTR_SSIZE_8); // transfer sizes always single bytes

    ptrDMA_TCD->DMA_TCD_SADDR = (volatile unsigned long)&(uart_reg->UART_D); // source is the UART's data register

    ptrDMA_TCD->DMA_TCD_NBYTES_ML = 1;                               // each request starts a single transfer

    if (pars->ucDMAConfig & (UART_RX_DMA_HALF_BUFFER | UART_RX_DMA_FULL_BUFFER)) { // if operating in half-buffer or full buffer mode

        if (pars->ucDMAConfig & UART_RX_DMA_HALF_BUFFER) {

            ptrDMA_TCD->DMA_TCD_CSR = (DMA_TCD_CSR_INTMAJOR | DMA_TCD_CSR_INTHALF); // never disable and inform on half and full buffer

        }

        else {

            ptrDMA_TCD->DMA_TCD_CSR = (DMA_TCD_CSR_INTMAJOR);        // never disable and inform on full buffer

        }

    }

    else {

        ptrDMA_TCD->DMA_TCD_CSR = 0;

        usDMA_progress[Channel] = ptrDMA_TCD->DMA_TCD_BITER_ELINK;

    }

    ptrDMA_TCD->DMA_TCD_SLAST = 0;                                   // no change to address when the buffer has filled

    ptrDMA_TCD->DMA_TCD_DLASTSGA = (-pars->Rx_tx_sizes.RxQueueSize); // when the buffer has been filled set the destination back to the start of it

}

else {

    uart_reg->UART_C5 &= ~(UART_C5_RDMAS);                           // disable rx DMA so that rx interrupt mode can be used

}

1,083 Views
albertopenasa
Contributor II

Hi everybody,

now the system works. It takes the data from the UART1_D and puts them into the buffer in RAM. Just another problem (I hope), the DMA writes the single bytes twice into the buffer.

Regards and thanks for your help.

Alberto

0 Kudos
Reply

1,083 Views
Wlodek_D_
Senior Contributor II

Dear Alberto Penasa,

Thank you for your post, however please consider moving it to the right community place (e.g. Kinetis Microcontrollers ) for better visibility.

For details please see general advice https://community.freescale.com/docs/DOC-99909

Thank you for using Freescale Community.

Regards,

Wlodek_D.

0 Kudos
Reply