UART RX DMA on MPC5645S

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

UART RX DMA on MPC5645S

1,263 Views
thomashuettenho
Contributor I

Hi.

In our project we receive data via UART (linflexd1). For this functionality, the MQX UART driver with interrupts is used. With a baud rate of 115200, the 4 byte RX buffer is overflowing , before the RX interrupt can copy the data.

To work around this limitation, I'm using UART RX DMA for receiving the data without using interrupts.

For testing purposes I configured the eDMA to do 4 major iterations, one byte each and generate an end-of-major loop interrupt afterwards. This basically works fine.

However, in about half of the transfers, additional bytes with the value of Zero are copied by the DMA engine. For example, sending 4 bytes "abcd" might be "a", "b", "c", 0x0, "d" in the DMA destination buffer. Sometimes its one Zero byte, sometimes two. Also the position is different each time. The Zero byte also occurs, if no end-of-major loop interrupt is configured. I already did a measurement of the RX line with an oscilloscope/logic analyzer: there are no additional bytes on the wire, which would explain this behaviour.

It seems to me, that sometimes a DMA transfer is triggered, when no new data is in the UART RX FIFO. Thus, a byte with the value zero is transfered.

Has anyone experience with UART RX DMA transfers and/or got it working reliable?

I can also supply the configuration of UART, DMAMUX and eDMA if this helps.

Thanks.

With best regards,

Thomas Huettenhofer

0 Kudos
2 Replies

750 Views
soledad
NXP Employee
NXP Employee

Hi,

UART driver updated to use the eDMA was introduced in MQX 4.1.0, it is for TWR-VF65GS10.  However this driver is not fully tested on Kinetis and even not documented in IO user guide. I would suggest you write your own driver for MQX.

 

Our customer implemented the UART with DMA at register programming level. I think it is very help to you. You can ported to MQX 4.0

Please refer to the following link.

https://community.nxp.com/message/584042?commentID=584042#comment-584042 

 

Have a great day,
Soledad

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

0 Kudos

750 Views
thomashuettenho
Contributor I

I'd like to add the configuration of linflexd1 as UART and DMA setup. Maybe this helps, analysing my problem.

Partially this is code from the MQX UART driver, which I extended for testing purposes, partially it is taken from sample code and/or own libraries.

The DMA transfer is working, but I get additional bytes (sometimes) with the value zero in the destination buffer.

Any help is appreciated.

Thanks in advance.

Setup of UART DMA on Channel 4
    
   #define BT_DMA_CHANNEL 4  

   EDMA.CR.B.ERCA = 1;        // Round Robin Channel Arbitration is enabled

   uint8_t channel = BT_DMA_CHANNEL; // use DMA channel 4 for UART RX
   uint8_t source = 33; // DMA MUX Source Number, See MPC5645S Reference Manual, page 645
   
   /* Configure DMA Channel Mux
    */
   DMAMUX.CHCONFIG[channel].R = 0;            /* Disable and clear mux channel */
   DMAMUX.CHCONFIG[channel].B.SOURCE = source;   /* Assign source with channel */
   
   /* Disable and clear EDMA for desired channel
    */
   EDMA.CERQ.B.CERQ = BT_DMA_CHANNEL;      // Clear enable DMA request
   EDMA.CEEI.B.CEEI = BT_DMA_CHANNEL;      // Clear enable error interrupt
   EDMA.CERR.B.CER  = BT_DMA_CHANNEL;      // Clear DMA error
   EDMA.CDNE.B.CDNE = BT_DMA_CHANNEL;      // Clear Done Status bit
   EDMA.CPR[channel].R = 0;      // Channel priority
  
   struct EDMA_TCD_STD_tag tcd_uart;
   
   memset((void*)&tcd_uart, 0, sizeof(tcd_uart));    // Clear structure
   
   // tcd configuration as described in MPC5645S Reference Manual, page 1032
   tcd_uart.SOFF = 0; // no source increment
   tcd_uart.SSIZE = 0; // size = 1byte
   tcd_uart.DOFF = 1; // byte-wise increment
   tcd_uart.DSIZE = 0; // byte-wise transfer
   tcd_uart.NBYTESu.B.NBYTES = 1; // minor loop transfer: 1 byte
   tcd_uart.D_REQ = 1; // Disable DMA after major iteration finished
   tcd_uart.INT_MAJ = 1; // Interrupt after major iteration count finished
   tcd_uart.START = 0; // Do not start manually

   // Write TCD for channel 4
   memcpy((void*)&EDMA.TCD[BT_DMA_CHANNEL], tcd, sizeof(struct EDMA_TCD_STD_tag));
   
   // Enable DMA RX interrupt for DMA channel 4
   _int_install_isr(MPXD20_INTC_EDMA_CHANNEL_0_VECTOR + BT_DMA_CHANNEL, bt_dma_rx_interrupt_handler, 0);
   _bsp_int_init(MPXD20_INTC_EDMA_CHANNEL_0_VECTOR + BT_DMA_CHANNEL, 4, 0, TRUE);
   
   // calculate source and destination addresses
   uint32_t src_addr = (uint32_t) ((char*) &linflexd_ptr->BDRM[3]);
   uint32_t dest_addr = (uint32_t)&s_bt_dma_buffer;
   
   uint16_t count = 4; // Major iteration counter: 4.
   // Set Source and Destination addresses, major iteration counter (count) and enable channel
   EDMA.CDNE.B.CDNE = channel;                // Clear DONE status
   EDMA.TCD[channel].SADDR = s_address;
   EDMA.TCD[channel].DADDR = d_address;
   EDMA.TCD[channel].BITER = count;
   EDMA.TCD[channel].CITER = count;
   EDMA.SERQ.B.SERQ = channel;                // Set enable DMA request
   DMAMUX.CHCONFIG[channel].B.ENBL = 1;        // Enable mux channel    

   
Initialisation of UART1

    uartcr = LINFLEXD_UARTCR_UART; // Enable UART Mode
    uartcr |= LINFLEXD_UARTCR_RFBM; // Enable FIFO mode for RX buffer (mandatory for DMA)
    uartcr |= LINFLEXD_UARTCR_WL0; // UART word length: 8bit

    linflexd_ptr = (VLINFLEXD_1_2_3_REG_STRUCT_PTR) io_info_ptr->LINFLEXD_PTR; // Cast linflexd ptr, as linflex 1,2 and 3 structure differs from linflex0

    // Save interrupt enable state - reconfigure may be done from polled or interrupt mode driver
    linier = linflexd_ptr->LINIER;
        
    /* Go into init mode */
    linflexd_ptr->LINCR1 = LINFLEXD_LINCR1_INIT;
    linflexd_ptr->LINCR1 = LINFLEXD_LINCR1_INIT;

    /* Select UART mode and set parameters */
    linflexd_ptr->UARTCR = LINFLEXD_UARTCR_UART;
    linflexd_ptr->UARTCR = uartcr;

    /* Calculate baud rate */
    lfdiv =  (io_info_ptr->INIT.CLOCK_SPEED*2/io_info_ptr->INIT.BAUD_RATE + 1)/2;
    linflexd_ptr->LINFBRR = lfdiv & 0xf;
    linflexd_ptr->LINIBRR = lfdiv>>4;

    /* Disable interrupts */
    linflexd_ptr->LINIER = 0;
    
    /* Enable Tx and Rx */
    uartcr |= LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN;
    linflexd_ptr->UARTCR = uartcr;
    
    // Enable DMA RX Interrupt
       linflexd_ptr->DMARXE = 0x0000ffff; // taken from sample code. Channels can't be enabled individually.
    
    /* Leave init mode */
    linflexd_ptr->LINCR1 &= ~LINFLEXD_LINCR1_INIT;

    /* Restore interrupt enable state */
    linflexd_ptr->LINIER = linier;      

0 Kudos