This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

UART and DMA interrupt

Other Parts Discussed in Thread: TM4C123GH6PGE

I use UART1 to transmit some bytes (max. 100) at 56700, 8,n,1


 UARTConfigSetExpClk(UART1_BASE,SysCtlClockGet(),57600,
       (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));
 
 UARTFIFOLevelSet(UART1_BASE,UART_FIFO_TX4_8, UART_FIFO_RX4_8);

I use DMA to do this.

I use interrupt from UART1 to intercept the end of trasmission with :

ulStatus = uDMAChannelModeGet(UDMA_UART1_TX | UDMA_PRI_SELECT);
  if (ulStatus == UDMA_MODE_STOP)

but this interrupt arrives before the bytes are completely spooled out....(with 100 bytes the interrupt arrives 3msec before bytes are completely out)

Someone can tell me how to intercept the effective end of bytes trasmission?

With this UART I would like to drive an half duplex channel and the interrupt change the channel from TX to RX before the bytes are complitely transmitted....how can I do?

 

I

  • Hi Lisa,

        Provide more info regarding your set-up. See this post below.

        Information to provide when asking for help

    -kel

  • You are right.....

    I'm using TM4C123GH6PGE on my board.

    I'm using UART1 configured as I wrote, in particular I 'm using pin PC5 for TX and PC4 for RX.

    I'm using DMA to transmit 100 bytes from txDataChar[]

    the DMA is configured as you can see below:

    UARTDMAEnable(UART1_BASE,UART_DMA_TX);
      uDMAChannelAssign(UDMA_CH23_UART1TX);

     uDMAChannelAttributeDisable(UDMA_UART1_TX, UDMA_ATTR_ALTSELECT |
            UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
     
      uDMAChannelControlSet (UDMA_UART1_TX | UDMA_PRI_SELECT,
             UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_4);

     uDMAChannelTransferSet(UDMA_UART1_TX  | UDMA_PRI_SELECT,
             UDMA_MODE_BASIC,
             &txDataChar[0],
             (void*)(UART1_BASE + UART_O_DR),        
             100);
     
     uDMAChannelEnable(UDMA_UART1_TX);

    Then I wait interrupt of end transmission but this interrupt arrives before all bytes have been transmitted.

    With this interrupt I would change channel direction from TX to RX but in this way I change the channel direction before end of transmission.

    I'm developing the SW with EWARM from IAR.

  • Hi Lisa,

        I just recently read your reply. 

        I have noticed, what you are trying to do is somehow similar to the udma_demo example. Compare your work to the udma_demo example. Do consider UART FIFO size.

        Also, regarding &txDataChar[0], I think only txDataChar will do. The array name itself is also a constant pointer variable. Correct me, if I am wrong.

        txDataChar = &txDataChar[0]

    -kel

  • Hi Markel!

    Yes, I'm trying to do somehow similar to udma_example and if I wouldn't have half duplex channel everything is good.

    About txDataChar or &txDataChar[0] are two equivalent way to write the same thing...but it isn't here the problem...

    AS you can see in the plot below,  the red trace is a GPIO pin that I put high at the start of trasmission and that I put low when the interrupt from end TX arrives and the yellow trace is UART1 TX pin

    This pin is used to commutate the channel from RX (GPIO pin low) to TX (GPIO pin high).

    Unfortunately the pin becomes low during the TX bytes channel spool and the channel become RX truncating the transmission of the remaining bytes...

    How is  possible to use DMA with half duplex channel?

     

     As you can see the interrupt arrives about 3msec. before the end of transmission...I'm using the UART at 57600, N,8,1...3 msec are about 16 bytes.

     

    Lisa

    Lisa

     

     

  • Hi Lisa56900,

    It sounds like you may be using the interrupt that signals that the data has traveled from the DMA to the UART FIFO. I believe you want to use the End of Transmission(EOT) interrupt instead.  This is covered in the Interrupt section of the UARTs section of the Data sheet. Let me know if I am incorrect about this and we can try to solve your problem.

    Sheldon

  • Hi Sheldon!

    In the data sheet you can read:

    "When a μDMA transfer is complete, the μDMA controller generates a completion interrupt on the

    interrupt vector of the peripheral. Therefore, if μDMA is used to transfer data for a peripheral and

    interrupts are used, then the interrupt handler for that peripheral must be designed to handle the

    μDMA transfer completion interrupt. ......

    When μDMA is enabled for a peripheral, the μDMA controller stops the normal transfer interrupts

    for a peripheral from reaching the interrupt controller (the interrupts are still reported in the peripheral's

    interrupt registers). Thus, when a large amount of data is transferred using μDMA, instead of receiving

    multiple interrupts from the peripheral as data flows, the interrupt controller receives only one interrupt

    when the transfer is complete."

    And then from UART chapter:

    "When DMA operation is enabled, the UART asserts a DMA request on

    the receive or transmit channel when the associated FIFO can transfer data. For the receive channel,

    a single transfer request is asserted whenever any data is in the receive FIFO. A burst transfer

    request is asserted whenever the amount of data in the receive FIFO is at or above the FIFO trigger

    level configured in the

    UARTIFLS

    register. For the transmit channel, a single transfer request is

    asserted whenever there is at least one empty location in the transmit FIFO. The burst request is

    asserted whenever the transmit FIFO contains fewer characters than the FIFO trigger level. The

    single and burst DMA transfer requests are handled automatically by the μDMA controller depending

    on how the DMA channel is configured."

    I tryed to configure UART channel also disabling UART FIFO with:

    HWREG(UART1_BASE + UART_O_LCRH) &= (~UART_LCRH_FEN);

    but the problem remains....

     

     

     

  • @ Lisa,

    Have followed your post - wish to applaud your grasp of - and attempt to comply - w/relevant data sheet guidance. 

    What you seek appears reasonable - while I do not have a solution @ this time - may I suggest some actions which may lead in that direction?

    Your 08:07 (past post), "...Red trace is a GPIO pin that I put high at the start of trasmission and that I put low when the interrupt from end TX arrives..."  Now that red, high to low transition appears to be the "end" of a one-byte transmission - not the end of your transmitted packet.  Is this correct?  And - if so - can you devise a means to detect when your entire transmission packet (multiple bytes) has completed?  (one way to do this may be to examine any/all interrupt activity upon packet completion)

    Suspect it may prove useful to reduce your packet size from 100 bytes to far smaller - say 8 bytes to start.  You want to ease & speed the discovery of just what is available to you - to identify or mark the end of packet transmission.  You may also experiment with holding these packets to integral multiples of the FIFO size - and to trying different methods to prevent the FIFO from "emptying" - until you've sent your entire packet...

  • I'm here and I'm ready to every suggests!!!!

    I think it is not possible for a microcontroller like this not to have the possibility to transmit and receive in a HALF DUPLEX channel with DMA!!!

    I'm sure that I'm wrong something!

    Lisa

  • Our earlier posts crossed - unclear if you've read/absorbed my (one up) posting...  (suggest that you start there - then read here - as/if needed)

    Your half-duplex "switch-over" requirement is mandatory when RS485 serial communication is employed in a multi-user system.  (beyond 2 users)  This is so as the RS485 drivers must "hold off" their transmit sides so that any "originating device" is not, "blocked" when it seeks to transmit upon the RS485 bus. 

    Now - this method works best when the MCU is able to quickly & efficiently "recognize" when its transmission packet has completed.  In the case of RS485 - the line drivers must be enabled prior to the transmission - and disabled very quickly upon completion - to prevent data collisions.

    If such "end of message" signaling is not automatically generated by your MCU - you may examine similar other MCUs - which do include this capability.  (one hopes - this may ease your "synthesis" of such a capability - should it not exist here)

    And - should this prove too difficult - if your packet size is constant - it should not be too difficult to launch a timer coincident with your start of transmission - and have this timer extinguish just after your final transmission byte has completed.  At timer's completion - you disable your line driver and/or set-up for receive...

  • Hi Lisa, we suffered the same issue you are facing.

    Our solution was to debug via JTAG and we realized that the interrupt with uDMA enabled triggers twice at Tx.

    The first one, with the behaviour you see, the second one, some ms later, when everything is transfered. Don't know why yet, but works.

    Our code in the interrupt is something like this:

    //Triggers twice
    	ui32Mode = uDMAChannelModeGet(7);
    
    	if (ui32Mode == UDMA_MODE_STOP) {
    
    #ifdef RS485
    
    		cnt_tx5_dma++;
    		if (cnt_tx5_dma>=2)
                    {
    			Enable_Tx_485(false);
    			cnt_tx5_dma=0;
    		}
    #endif
    }

    Hope this helps.

  • Lisa,

    I have talked with some other engineers and they tried this method and it should work. If you enable the transmit interrupt UART and set the EOT bit in UARTCTL, even with the DMA enabled you should get the interrupt at the EOT.

    So,

    1) Enable the Transmit Interrupt. (TXIM bit in UARTIM)

    2) Set the EOT bit in UARTCTL

    3) Setup your Interrupt handler to look if TXRIS has been set in UARTRIS. This will tell you when its an end of transmission.

    Hope this helps, 

    Sheldon

  • Stellaris Sheldon said:

    Lisa,

    I have talked with some other engineers and they tried this method and it should work. If you enable the transmit interrupt UART and set the EOT bit in UARTCTL, even with the DMA enabled you should get the interrupt at the EOT.

    So,

    1) Enable the Transmit Interrupt. (TXIM bit in UARTIM)

    2) Set the EOT bit in UARTCTL

    3) Setup your Interrupt handler to look if TXRIS has been set in UARTRIS. This will tell you when its an end of transmission.

    Hope this helps, 

    Sheldon

    And that in Tivaware code would be?

    EDIT:

    Just configuring UARTTxIntModeSet(UART5_BASE,UART_TXINT_MODE_EOT) works.

    Watch out the point 

    Stellaris Sheldon said:
    3) Setup your Interrupt handler to look if TXRIS has been set in UARTRIS

    if ((HWREG(UART5_BASE + UART_O_RIS) & UART_RIS_TXRIS) == UART_RIS_TXRIS)

    {

    //some code

    }

    since this could block your enable and therefore your RS485 bus!!!

  • @ Stellaris Sheldon,

    Your inside info - this topic - highly appreciated.  Below - detail w/in our LX4F manual - UARTCTL Reg:

    Devil in the detail here - and manual's use of, "after all transmitted data" may logically apply to a single byte - may it not?  This absence of clarity as to the define of, "all xmt'd data" derails many...

    Might you detail "just how" Register UARTCTL can "know/detect" when the final byte of a multi-byte (perhaps 100 bytes - in the example here) has been reached?  Might this be, (absence of byte-stream) "time triggered?"

    Further - does this same EOT bit "trigger" of TXRIS exist in the simpler, non-uDMA UART mode?

    Thanks much your time/attention...

  • @cb1_mobile,

    This works because the DMA should be filling the FiFo with data as the FiFo is pushing data into the serializer, meaning the serializer is not done transmitting data until The DMA and FiFo are empty. The description of the Transmit Interrupt in the data sheet:"Transmit (when condition defined in the TXIFLSEL bit in the UARTIFLS register is met, or if the EOT bit in UARTCTL is set, when the last bit of all transmitted data leaves the serializer)".

    If you were not using the uDMA the interrupt should trigger when the FiFo and serializer are empty. If you are also not using the FiFo, the Transmit interrupt should trigger after each byte.

    Sorry for the confusion,

    Sheldon

  • @ Stellaris Sheldon,

    Your rapid & detailed response - much appreciated.

    Still - the language, "all transmitted data" (from the MCU manual) is really insufficient.  It fails to detail and fully describe what, how - or even if - "all transmitted data" describes a single byte - or multi-byte serial packet.  I return to this as many posters - this forum and its predecessor - have run aground - this issue.

    And - the use/disuse of FIFO appears to alter this operation - adding yet more complexity. 

    Of course you, most cohorts did not write that MCU manual - and surely the tech writers know their stuff.  But the language employed has proved imprecise - and extends the development time/effort/agony of your user clients. (Lisa's quest here illustrates...) And that is not the best means to generate volume sales...

    As uDMA has come up - might you comment (or consult w/others) as to just when uDMA use w/UART (or other uDMA accepting peripherals) becomes desirable?  I'm fairly active this forum - have never seen such a recommendation.  Ask as uDMA does add code overhead - forces extra design considerations - thus its use should warrant some general rules/guidelines...  (of course every case is different - but there must be some "hooks" which signal the "tripping point" - in which uDMA makes sense...)

    Thanks again...

  • IT WORK'S!!!!!!!!

    Thank you very much to Sheldon and to cb1_mobile !!!!!!!!

    Thank thank thank you!!!!!

    It is from one week that i'm troubling on it !!!!!!

  • Hi all.

    I have a problem same that.
    I use TM4C123G launchpad to receive and transmit a frame. I use a MAX3485EESA, short circuit RE&DE and connect to a GPIO in launchpad. I want to put the GPIO high before transmit but I have a problem.

    Here is a 8 byte transmit:
    [URL=http://s1154.photobucket.com/user/huyphuc92/media/1_2.png.html][IMG]i1154.photobucket.com/.../URL]

    And the 32 byte transmit:
    [URL=http://s1154.photobucket.com/user/huyphuc92/media/2_3.png.html][IMG]i1154.photobucket.com/.../URL]

    You can see, the GPIO go to low before transmit is completely.

    I use uDMAChannelModeGet to determine transmit complete even.

    Manual sad: This function is used to get the transfer mode for the uDMA channel and to query the status of
    a transfer on a channel. When the transfer is complete the mode is UDMA_MODE_STOP.

    But it don't work correctly!


    The code reference here:
    while(1)
    {
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
    ModbusSend(buff,30);
    while(uDMAChannelModeGet(UDMA_CHANNEL_UART1TX)!=0)
    {
    }
    if(uDMAChannelModeGet(UDMA_CHANNEL_UART1TX)== UDMA_MODE_STOP)
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
    SysCtlDelay(SysCtlClockGet() / 3);
    }

    //The ModbusSend funcition:

    void ModbusSend(unsigned char* MBSendBuff, unsigned int dataleng)
    {
    unsigned int CRC;
    unsigned char CRCLow, CRCHigh;
    CRC= CRCCalculator(MBSendBuff,dataleng);
    CRCLow = (char)CRC;
    CRCHigh = (char)(CRC >> 8);
    MBSendBuff[dataleng]=CRCLow;
    MBSendBuff[dataleng+1]=CRCHigh;
    uDMAChannelTransferSet(UDMA_CHANNEL_UART1TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC,
    (void *)MBSendBuff,
    (void *)(UART1_BASE + UART_O_DR), (dataleng+2));
    uDMAChannelEnable(UDMA_CHANNEL_UART1TX);
    }
  • Hello user4124359,

    The DMA Transfer completion is not related to the data in the UART Transmit FIFO. The DMA may have completed the transaction, but UART has to still shift the data out of the Transmit FIFO and that would take more time. An interrupt must be used to qualify End of Transmission and set GPIO low.

    Regards
    Amit