Author Topic: Uart RX Dma with break 52259  (Read 11753 times)

Offline cmalan

  • Newbie
  • *
  • Posts: 14
    • View Profile
Uart RX Dma with break 52259
« on: June 26, 2012, 02:33:40 PM »
Hi
I have a problem with the rx dma on a uart. This is my setup.
Code: [Select]
tInterfaceParameters.Channel = 2; // set UART channel for serial use
    tInterfaceParameters.ucSpeed = SERIAL_BAUD_230400; // baud rate
    //tInterfaceParameters.ucSpeed = SERIAL_BAUD_9600; // baud rate
    tInterfaceParameters.Rx_tx_sizes.RxQueueSize = 40; // input buffer size
    tInterfaceParameters.Rx_tx_sizes.TxQueueSize = TX_BUFFER_SIZE; // output buffer size
    tInterfaceParameters.Task_to_wake = TASK_BACNET; // wake self when messages have been received
    tInterfaceParameters.Config = CHAR_8 | NO_PARITY | ONE_STOP | /*RTS_CTS*/NO_HANDSHAKE |MSG_MODE | MSG_MODE_RX_CNT | MSG_BREAK_MODE;
    tInterfaceParameters.ucDMAConfig = UART_RX_DMA |UART_RX_DMA_HALF_BUFFER |UART_RX_DMA_BREAK /*| UART_TX_DMA*/; // activate DMA on transmission

    if((MstpPortID = fnOpen(TYPE_TTY, FOR_I_O, &tInterfaceParameters)) != 0)
    { // open or change the channel with defined configurations (initially inactive)
        fnDriver(MstpPortID, (RX_ON|TX_ON), 0); // enable rx
        fnDebugMsg("fnInitialise dl port\r\n");
        //fnWrite(MstpPortID,(void*)&tInterfaceParameters,5);
    }

if  tInterfaceParameters.ucDMAConfig is 0 then I can receive my messages.

I added this
Code: [Select]
static __interrupt__ void _DMA2_Rx_handler(void)                         // rx buffer reception completed on SCI1
{
    DMA_SR_BCR2 = DSR_DONE;
        #ifdef _WINDOWS
    DMA_SR_BCR2 &= ~DSR_DONE;                                            // {100}
        #endif
    iInterruptLevel = 1;                                                 // ensure interrupts remain blocked during subroutine
    fnSciRxByte(0, 2);                                                   // tty block ready for read
    iInterruptLevel = 0;
}
to M5223X.c and changed fnConfigSCI to set up dma 2

Did I miss some thing.

Christo

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: Uart RX Dma with break 52259
« Reply #1 on: June 26, 2012, 03:10:02 PM »
Hi Christo

Have you tried on UART1 because this supports DMA in Rx mode?

Since the Coldfire has limited DMA channels it is not possible to use Rx and Tx DMA on all at the same time and so a combination is supported, but it should be possible to swap from UART1 to UART2.

You have to be careful that the DMA matrix is correctly set up and that the interrupt vector is also correctly entered; this is not seen in your code snippet above.

When debugging you can watch how the DMA registers behave as characters are received. When there are configuration errors they can usually be seen here; sometimes there is also an access conflict which causes a DMA error state which doesn't recover, which is also seen immediately. In any case it should be possible to see whether the data transfers are taking place correctly and whether the break detection is maybe not giving the signal that the data is ready.

Regards

Mark

Offline cmalan

  • Newbie
  • *
  • Posts: 14
    • View Profile
Re: Uart RX Dma with break 52259
« Reply #2 on: June 26, 2012, 03:29:05 PM »
Hi Mark

Uart 2 is unfortunately hard wired on the pcb. I don't want to start cutting tracks on the pcb, not yet anyway.
I will have a look at the registers

this is my setup code
Code: [Select]
if (ucUseDMA & UART_RX_DMA) {
            DMAREQC |= (DMA_UART_2_RX << DMAC_2_SHIFT);                  // select DMA matrix for Rx on DMA channel 1
            PACR_UART2  |= (SUP_USER_FULL_ACCESS << UART2_ACCESS_SHIFT); // enable DMA access to UART1
        #ifdef _M520X
            IC_ICR_0_9 = (DMA2_INTERRUPT_PRIORITY & LEVEL_MASK);         // define interrupt level
        #else
            IC_ICR_0_11 = DMA2_INTERRUPT_PRIORITY;                       // define interrupts level and priority
        #endif
            fnSetIntHandler(DMA2_VECTOR, (unsigned char *)_DMA2_Rx_handler);// enter the handler routine
            IC_IMRL_0 &= ~(DMA2_PIF_INT_L | MASK_ALL_INT);               // unmask interrupt source
        }

Thanks
Christo

Offline cmalan

  • Newbie
  • *
  • Posts: 14
    • View Profile
Re: Uart RX Dma with break 52259
« Reply #3 on: June 27, 2012, 11:03:24 AM »
Hi Mark
I found the problem when I moved my port to uart 1
If the dma is enabled on rx
fnRxOn() is never called and the RXD pin stays an normal input and not uart rx.

The dma is working on uart 2 it was only the pin function that was the problem

At the moment I added PUCPAR |= UC_RX2_FUNCTION; before fnOpen and it works.

Where should the pin function be set if the dma is used?

Christo

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: Uart RX Dma with break 52259
« Reply #4 on: June 27, 2012, 01:15:54 PM »
Hi Christo

This looks to be a general error in Rx DMA mode on the Coldfire.
Older versions had the receiver configuration in the fnOpen() call itself but this was moved later so that only rx or tx could be used if desired but this has indded left the RX pin unconfigured.

Checking other projects using Rx DMA I have seen that typically they call fnRxOn() from within fnPrepareRxDMA() when it is called the first time.
However this doesn't look to be suitable for the Coldfire's UART since this also enables Rx interrupts, which is not correct for DMA operation on this device (some devices use the interrupt as DMA trigger and so they are OK with this).

I would suggest the following correction:

1) In fnRxOn() call a local subroutine that performs the pin initialisation part (i.e. remove the pin configuration from this routine - the routine could be called fnConfigRxPin(), for example).
2) In fnPrepareRxDMA() check whether it is being used the first time - I think that this can be done with

if (*ptrDMA == 0) {  // first DMA configuration call
    fnConfigRxPin(channel);    // configure the Rx input
}


The reason for not calling fnRxOn() is as described above but this will allow the pin configuration parts to be shared without the operations that DMA doesn't want.


Thanks for identifying this problem - I have an active project using this feature (DMA with break detection) but it is based on an older version and, since DMA on Rx is used very rarely, it obviously hadn't been seen previously.


On a related subject - some processors allow the UART Rx DMA operation to work with automatic circular buffers. That means that the receiver fills the rx circular buffer infinitely without any interrupt requirements (the Coldfire would need two interrupts on half buffer lengths to do this with low risk of overrun [ping-pong]). This mode does however mean that the user gets no information about what is happening in the buffer (it could be overwriting itself all of the time if nothing is done) but, if the buffer is made fairly large and the user polls the buffer content by calling fnRead() at an adequate rate it does allow very high speed UART reception without and Rx interrupt overhead (I have prepared a new 'free-run' DMA mode for the Kinetis, for example).

Regards

Mark

Offline cmalan

  • Newbie
  • *
  • Posts: 14
    • View Profile
Re: Uart RX Dma with break 52259
« Reply #5 on: June 27, 2012, 10:03:29 PM »
Hi Mark
In my application I am not worried about message overruns. The messages can be big but nicely spaced.
You're mention of ring buffer got me thinking what will happen if I get a bunch of small messages followed by a big one. Will the ring buffer wrap properly.
Example if my tty que is 40 bytes big and I get 3 5 byte messages read them, what will happen with if the next message is 30 bytes big. Will the dma only be started for 25 bytes or will the last 5 bytes end up outside the que.

Christo

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: Uart RX Dma with break 52259
« Reply #6 on: June 29, 2012, 04:05:33 PM »
Hi Christo

The receive buffer is a circular buffer and the DMA is set up to either fill the complete buffer or half of the buffer and generate an interrupt. Usually half buffer interrupt mode is more useful becuase it give more opportunity to free the half buffer before it is used again.

When the break detection is used it is usally used together with the half buffer mode but, instead of the buffer being completed at the half buffer mark - this is more a safety mark to generate the DMA interrupt when there has been no break received, the break would signify a frame reception with less bytes in it.
Normally a break would thus be expected before the half buffer length is reached and the second half of the circular buffer is then set up for use by the folowing frame reception. This means that the complete circular buffer is used as two ping-pong buffers and each of the frames that are received start at a half-buffer location. Although a circular buffer, it is thus not really used as a circular buffer but instead a two fixed linear buffers.

In comparison, the use of DMA on transmission does use the circular buffer and each data packet sent is a DMA transfer up to the message length or up to the end of the circular buffer, depending on which is possible. When there is a wrap in the circular buffer it therefore requires two DMA transfers - one from the message start up to the end of the buffer and then one from the buffer start up to the end of the message. When a wrap-around takes place the operation is not as efficient as when a linear message can be sent. If the application wants to avoid this and also knows when complete transfers have complete it is possible to perform tx buffer flush between transmissions so that messages always start at the beginning of the buffer; usually the DMA tx operation is not so critical anyway - in the worst case there is an interrupt and maybe a very small gap between the two blocks of transmission at high speed.

This means that rx DMA on a real circular buffer is not a good idea. It would mean that toward the end of the circular buffer only a small amount of Rx DMA would be possible. This explains why Rx DMA is based on fixed locations in the buffer so that the programmed rx DMA length is always the same.

Generally when working with a circular buffer (referring to your particular question) new data that can't fit will always be discarded and data will never end up outside of the buffer space. Also DMA operation on a circular buffer that wasn't restricted to fixed locations would also need to respect these constraints.

Regards

Mark

Offline cmalan

  • Newbie
  • *
  • Posts: 14
    • View Profile
Re: Uart RX Dma with break 52259
« Reply #7 on: July 12, 2012, 08:23:47 AM »
Hi Mark
Tanks for clearing this up for me. I did not understand how it could be working, I missed the half buffer ping-pong part.
Christo