DMA - UART clock sync on TWR - K65F 180M

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

DMA - UART clock sync on TWR - K65F 180M

430 Views
viveksrinivasan
Contributor I

Hi everyone,

 

I'm trying to use DMA for UART2 on TWR - K65F 180M. The reason is UART2 is readily available through the USB and easy to test.

 

I came across this example application low_power_dma_uart_demo, which tried to add the DMA to LPUART0. I did not test it as LPUART0 is not readily available on any connectors.

 

But I tried to make some changes to adapt the code to UART2. Below is my code.

 

int main (void)

{

    int i;

    uint32 reg_temp = 0;

    register uint16 sbr, brfa;

    uint8 temp;

    extern int periph_clk_khz;

    extern int mcg_clk_hz;

    int uartClock = periph_clk_khz;

   

    char TxBuf[26] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    char RxBuf[26];    

 

    // Enable DMA clocks

    SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;

    SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;    

  

    // Enable UART5, PORT clocks, and TX line

    SIM_SCGC4 |= SIM_SCGC4_UART2_MASK;

    SIM_SCGC5 |= SIM_SCGC5_PORTE_MASK;

    PORTE_PCR17 = PORT_PCR_MUX(0x3);

    PORTE_PCR16 = PORT_PCR_MUX(0x3);

   

    /* Make sure that the transmitter and receiver are disabled while we

     * change settings.

     */

    UART_C2_REG(TERM_PORT) &= ~(UART_C2_TE_MASK

  | UART_C2_RE_MASK );  

   

    /* Configure the UART for 8-bit mode, no parity */

    UART_C1_REG(TERM_PORT) = 0; /* We need all default settings, so entire register is cleared */

   

    /* Calculate baud settings */

    sbr = (uint16)((uartClock*1000)/(115200 * 16));

   

    /* Save off the current value of the UARTx_BDH except for the SBR field */

    temp = UART_BDH_REG(TERM_PORT) & ~(UART_BDH_SBR(0x1F));

   

    UART_BDH_REG(TERM_PORT) = temp |  UART_BDH_SBR(((sbr & 0x1F00) >> 8));

    UART_BDL_REG(TERM_PORT) = (uint8)(sbr & UART_BDL_SBR_MASK);

   

    /* Determine if a fractional divider is needed to get closer to the baud rate */

    brfa = (((uartClock*32000)/(115200 * 16)) - (sbr * 32));

   

    /* Save off the current value of the UARTx_C4 register except for the BRFA field */

    temp = UART_C4_REG(TERM_PORT) & ~(UART_C4_BRFA(0x1F));

   

    UART_C4_REG(TERM_PORT) = temp |  UART_C4_BRFA(brfa);

    

    // Set FIFO water marks (not used in default 'legacy' port configuration)

    UART_TWFIFO_REG(TERM_PORT) = UART_TWFIFO_TXWATER(0);

    UART_RWFIFO_REG(TERM_PORT) = UART_RWFIFO_RXWATER(1); 

   

    UART_C5_REG(TERM_PORT) |= UART_C5_TDMAS_MASK;                               // use DMA rather than interrupts for transmission

   

    /* Enable receiver and transmitter */

  UART_C2_REG(TERM_PORT) |= ( UART_C2_TE_MASK | UART_C2_RE_MASK | UART_C2_TIE_MASK | UART_C2_TCIE_MASK );

   

    //print_uart_regs();

   

    enable_irq(1);              //see table: 3-5 , page-85

    //enable_irq(35);

    enable_irq(36);

   

    // Enable Global Interrupts

    EnableInterrupts; 

 

    DMAMUX_CHCFG1 = 0x00;   

   

    DMA_TCD1_BITER_ELINKNO = 1;

    DMA_TCD1_CITER_ELINKNO = 1;

   

    // Source address

    DMA_TCD1_SADDR = (uint32_t)TxBuf; 

    DMA_TCD1_SOFF  = 1;                                                                 //Source increment (Source Address Signed Offset)

    DMA_TCD1_SLAST = 0;                                                   //Last Source Address Adjustment

   

    // Destination address

    DMA_TCD1_DADDR = (uint32_t) &UART2_D;                                             // Set Destination Address. Points to UART2 base

    DMA_TCD1_DOFF = 0;                                                                  //Do not increment destination address

    DMA_TCD1_DLASTSGA = 0x0;                                                            //Destination last address adjustment

 

 

   

    DMA_TCD1_ATTR  = (0 | DMA_ATTR_SSIZE(0) | DMA_ATTR_DSIZE(0));                       // transfer sizes always single bytes (000 - 8-bit)   

    DMA_TCD1_NBYTES_MLNO = sizeof(TxBuf);                                               //minor loop mapping is disabled; Number of bytes to be transferred in each service request of the channel

   

    DMA_TCD1_CSR = (DMA_CSR_INTMAJOR_MASK | DMA_CSR_DREQ_MASK);                         //The end-of-major loop interrupt is enabled (Check)

    DMAMUX_CHCFG1 = (DMAMUX_CHCFG_SOURCE(7)                                             // UART2-Tx is source 7              //refer page 103 of the datasheet

                        | DMAMUX_CHCFG_ENBL_MASK);                                      // enable the DMA channel request

   

    DMA_TCD1_CSR |= DMA_CSR_START_MASK;    

    DMA_SERQ |= 1;//DMA_SERQ_SERQ(1); 

    

    while(1);

}

 

When I run this code, I could just see the first byte on the terminal (In this case just 'A'). As you can see I'm trying to send 26 bytes through UART. After running the code I can see SADDR actually offset by 26 bytes which indicates that the DMA has transferred all 26 bytes but the UART is not fast enough to capture and send all 26 bytes. This could be because both DMA and UART are configured with different clock source (DMA-System Clock; UART2-Bus Clock).

65227_65227.pngpastedImage_0.png

65330_65330.pngpastedImage_1.png

 

The low_power_dma_uart_demo example confirms this with the following comment.

 

    ///////////////////////////////////////////////////////////////////////////

    // Switch the system clock to the IR Clock !!!

    //

    // NOTE:  Due to a rev 1.0 errata, the UART and DMA must be clocked from

    // sources that are approximately the same frequency.  Otherwise, the

    // DMA will finish before it is time. 

    ///////////////////////////////////////////////////////////////////////////

 

In which they try to use the IR clock to configure LPUART.

 

My question is how do I configure UART2 and DMA to use a clock source of same frequency? Could you please give me an example?

 

I did try the above code with slight modification for Memory to memory transfer and it works perfectly. So I believe if I make UART2 and DMA to use the same clock frequency this issue should be fixed.

 

I have also attached my sysinit.c file for your reference.

 

Any help is much appreciated. Thank you.

 

 

Regards,

Vivek

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

0 Kudos
1 Reply

231 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Vivek,

Thank you very much for your focus on Freescale Kinetis product. I'm glad to provide service for you.

According to the reference manual, you can see that the maximal frequency of the Core clock and Bus clock is different, one is 180 MHz, however another is 60 MHz(Fig 1)。

So if you want to get the same frequency of the both clock sources, I'd like to suggest that you have to follow through these procdures.

1. Make sure the frequency of the MCGOUTCLK <=60 MHz;2. The OUTDIV1 and OUTDIV2 should be same(Fig 2);

2015-08-21_10-19-45.jpg

                                                                              Fig 1

2015-08-21_10-28-12.jpg

                                                                                Fig 2

Hope it helps.
Have a great day,
Ping

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

0 Kudos