MCF5282 UART Rx DMA Request

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

MCF5282 UART Rx DMA Request

4,987 Views
Juason
Contributor I
Hello everyone,
 
 
   I am looking to use DMA on our MCF5282 core, but am having some issues with it.  First, some background...
 
  Our design is currently utilizing UART1 at 2Mbps to handle serial data transactions.  The current code is interrupt driven, and works remarkably well at the high data rate.  However, peformance tests have shown that we need the core to be servicing the main loop during recieves, which it cannot do due to the interrupt overhead.
 
  The solution would be to let DMA handle the receives, removing the interrupt overhead and freeing the core to handle the main loop.  Well, that is if I could get DMA working :smileytongue:
 
   I have attempted to setup the DMA Channel 0 to handle UART1, Source to UART1's Rx address, Source Size as 1 byte, Source increment Off, Destination to an address in memory, Destination Size of 1, Destination Increment On, Cycle Steal On, Byte count set to 0x00FFFFFF (255), and External Enable On.  My register setup is as follows:
 
 
// Serial Setup //
 
// No code, but we setup UART1 for 8 bits/character, no parity, Interrupt on RXRdy Fifo Not full @ 2Mbps

MCF5282_DMA0_DCR  |= 0x00100000;              // Source Size 1 (destination hold by default)
MCF5282_DMA0_DCR  |=  0x20000000;             // Enable Cycle Steal Mod
MCF5282_DMA0_DCR  |=  0x00080000;             // Enable Destination Increment
MCF5282_DMA0_DCR  |=  0x00020000;             // Destination Size 1

ptr = &ModNetUart->RxBuffer[ModNetUart->RxWritePtr];
MCF5282_DMA0_DAR = (DWORD)ptr;             // Setup Destination Address

MCF5282_DMA0_BCR |= 0x00FFFFFF;             //  Setup Byte Count to 255 (ignores lower 2 bytes)

MCF5282_DMA0_SAR    |= (DWORD)&MCF5282_UART1_URB;   // Source to UART1 Receive Buffer
MCF5282_SCM_DMAREQC = 0x0009;      // Setup DMA0 for UART1
MCF5282_DMA0_DCR   |=  0x40000000;   // External Enable

Now, what ends up happening is I enable the External DMA0 Enable, and I get an Error 0x21 in the MCF5282_DMA0_DSR register (Source Error). 

 

Some points of confusion:

1). There is no clear way to setup DMA for only transmits or only recieves in the 5282 user manual.
2). There is a footnote in the UART register description saying DMA only works on channels 2 and 3 - but this is not clear and never repeated in the documentation.

3). The masking of Rx interrupts is described in a confusing manner in the documentation.  What should the status of the IMR and UMR registers be for UART1 for DMA to work on only recieves?

Could anyone possibly provide me with some sample code for making DMA work on recieves for a 5282 core?  I've seen a previous thread with samples for a 5223 transmit driven by an external peripheral, but was unable to adapt it for what I need.  Thank you very much in advance for any help you can provide me with!

 

- Jason

Labels (1)
0 Kudos
11 Replies

1,120 Views
Juason
Contributor I
Yeah!  The security settings appeared to be the main culprit of my read errors.  Thank you for the tip.
 
It looks like the 5282 only has 1 interrupt bit in the IMR register that handles both transmits and recieves.   I only want DMA working for UART1 receives while still using interrupts for my transmits. (preferably in full duplex mode)  Is there a clean way of doing this?   
 
Right now I am running half duplex, and disabling all UART1 interrupts following a 9th bit receive (packet start), and re-enabling them just prior to my next transmit.  This is very messy however, and prone to an error when I miss a spot where I need to re-enable interrupts.  Thanks again!
0 Kudos

1,120 Views
wstrong
Contributor I

Jason,

The UISR1/UIMR1 register allows you to select 4 interrupt sources, COS-CTS, DB-break, FFULL/RXRDY, and TXRDY. 

If you use DMA for receiving data, then you have an option to trigger a DMA interrupt upon completion of the DMA’s transferring BCR0 bytes.  As Mark pointed out, you don’t want to use the UART’s RXRDY interrupt when using DMA for receiving.

I’m working on the MCF5329 which has the same UART module but a little bit fancier DMA module.  My situation is similar to yours in that my program would like to know when a message has been received.  My messages are variable length and I don’t have a trailer sequence in my protocol to use.  I’m looking at using a DMA timer interrupt to monitor the DMA’s transfer count (BCRn) since my protocol has some timing constraints.  My other option is to set up a DMA transfer to continuously fill a ring-buffer

Do you need to look at or process each byte as it’s received?

It seems that you would save more cpu cycles by using interrupts for Rx, and DMA for Tx.

-- Wayne

0 Kudos

1,120 Views
Juason
Contributor I
I understand what you are saying about not being able to use receive interrupts while doing receive DMA.  However can I still use TX interrupts?
 
Right now we are generating a packet, and transmitting it using an interrupt driven routine (each byte write generates an interrupt that writes the next byte).  While it would be nice to drive this with DMA, it isn't slowing us down by using interrupts at the moment since the main loop has nothing else to do during this time.
 
Moving recieves to DMA vastly sped up our application because the main loop can now calculate the checksum on the packet as it is recieved, and begin handling of it.  With interrupts the main loop can do nothing but receive data, leaving checksum and packet handling to the end.  This results in a 20% dead time at the end of a packet recieve, that DMA removed.
 
At the moment I am disabling all UART1 interrupts while receiving a packet using DMA, and then enabling all UART1 interrupts (and disabling the DMA) before transmitting the next packet.  I suppose that to get both transmit and recieve DMA working on UART1 I could just change the source and destination of the DMA channel I am using each time, since I'm only really running half duplex right now.
 
My curiosity was if a full duplex DMA was possible, where 1 DMA channel is doing RX and 1 DMA channel is doing TX.  The problem I see here is since the 5282 only has 1 IMR register for TX and RX, interrupts on both would generate DMA requests on both channels and mess everything up.
 
I am sorry if this isn't coming across clear.  The problem is complicated and the datasheets are confusing.  Many of the Coldfire line show UART1 TX DMA and UART1 RX DMA register codes for the DMAREQC register.  The 5282 only has a single one.  So this leads me to believe you can either do TX or RX DMA on that core, but both both at the same time.
 
Thank you as always for your help in this matter.
 
- Jason
0 Kudos

1,120 Views
Juason
Contributor I
Well I've decided to pursue transmit DMA, and after speaking with a Freescale FAE it sounds like this part is only capable of half duplex DMA transfers.  That should be fine, as we're really only running in half duplex mode right now anyways.
 
So, what are some typical transmit DMA designs? I'm just starting to play with it, and had a few thoughts for how to make it work.  If it works like I suspect, I should be able to write the ByteCount register with the size of my packet, then manually write the first byte with the 9th bit set to the UART.
 
Then I can disable transmit interrupts and enable the TX DMA.  The first DMA-handled-interrupt (from the manually written byte) should result in the next byte being sent automatically via the DMA.  Then each subsequent byte transfer will result in an interrupt request that results in the DMA continually streaming data out of the UART - until the ByteCount register hits 0.
 
Am I correct in thinking this can be done? The only other option I can think of is to setup a DMA timer somehow.  If that is necessary, would anyone happen to have an example of it being done?  Thanks!
0 Kudos

1,120 Views
Juason
Contributor I
Alright so Transmit DMA is giving me fits.  Here's what I have so far....
 
1).  I setup UART1 for interrupt driven transmits and receives.
 
2).  I write a single byte out the serial port with the 9th bit set (packet start).
 
3). This creates another TX interrupt, and in the ISR I disable the 9th bit (packet data) and disable UART 1 interrupts in the IMR register, then enable the DMA on channel 1.
 
4). The BCR register decrementing to 0 creates a DMA interrupt where I disable the DMA controller, write 0x0001 to its status regiser ( to reset it) and I then enable UART1 interrupts.
 
5). The module response (with a 9th bit set) creates an RX interrupt where I handle the byte, disable UART1 Interrupts, enable UART1 receive DMA on channel 0, and exit.
 
6). My main loop processes the packet as it arrives, then I disable receive DMA, enable UART1 interrupts, and send the next packet.
 
Currently steps 5 and 6 work just fine when TX is interrupt driven.  Receive DMA on channel 0 is perfect at 2Mbps.  Ran it for 3 days now without any issues.  However, TX DMA is really flakey. 
 
Basically in cycle steal mode it sends 2 to the BCR register number of bytes.  Its almost entirely random.  In non cycle steal mode it always sends 2 bytes and quits, even though its decremented the BCR register to 0 and incremented the source address by BCR * bytes... just like you'd expect. 
 
What might be artificially causing the BCR register to decrement?  In cycle steal mode I'll see as many as 6 good packets get sent and recieve, and then suddenly a packet will go out missing a few bytes.  I have seen in the debugger where on occasion the DMA interrupt is fired, and the status register is 0x41 - configuraton error.  This would indicate a transmit request when the BCR was 0, but I don't see how that is possible. 
 
Blegh, so confusing!  Thanks for any help you can give me.  I can post a more explicit set of register values if you want me to.
0 Kudos

1,120 Views
bkatt
Contributor IV
The 5282 user manual / data sheet clearly states that you cannot use DMA with UART transmit, only with UART receive.

0 Kudos

1,120 Views
Juason
Contributor I
Do you have a more up to date data sheet on the 5282 than is posted on Freescale's site?  I don't find anything stating a lack of DMA transfer capability.  It only describe receive DMA, but doesn't say you can't do transfers.
 
I guess this also confused their FAE's, because after looking at the datasheet they also thought the 5282 was capable of transmit DMA (just not in full duplex mode). 
 
I'd appreciate if you could point out where it says the DMA can only handle receives.  I just read the datasheet again and must have missed it.  I have transmit DMA working in cycle steal mode (just not reliably) using the masked interrupts to trigger it.  Its lacking just a tiny bit of hold off to work every time. 
 
Thank you for your help.
0 Kudos

1,120 Views
Juason
Contributor I
Actually I just saw this....
 

NOTE

The DMA should not be used to write data to the UART transmit FIFO in

cycle steal mode. When the UART interrupt is used as a DMA request it

does not negate fast enough to get a single transfer. The UART transmit

FIFO only has one entry so the data from the second byte would be lost.

 

Which indicates you should be able to use the DMA on the 5282 in continous mode to write to the UART's transmit buffers.  Unfortunately this results in only 2 bytes being sent, and the DMA doesn't hold off until the TB's are empty.   But I see how it explains that the UART interrupt request happens too early before the transmit buffer has been sent.

Now if only continous mode worked properly...

0 Kudos

1,120 Views
Alban
Senior Contributor II
Hi Juason,

May you please feed back to your FAE that he has been misleading you ?
That would prevent him from telling rubbish to someone else... :smileyvery-happy:

Cheers,
Alban.
0 Kudos

1,120 Views
Juason
Contributor I
I'm working on it.  Its been almost week and I've gotten no response, so we'll see!
 
As an update, using DMA Timers to transmit out of the UART has proven successful!
 
I set the 9th bit and write the first byte, which generates a transmit interrupt.  Inside the interrupt I mask off UART interrupts, reset the interrupt bit, enable the DMA Timer for 5.5us ticks, and setup the DMA channel to start from the timer ticks at ~5.5us and bingo, successfully transmitting and receiving on the UARTs using DMA at 2Mbps! 
 
When the DMA BCR register hits 0 it triggers an interrupt where I disable DMA and the DMA Timer and unmask the UART interrupts.
 
This is my first time working with DMA, so the obvious solution for transmit (DMA Timers) just didn't occur to me.   Thank you again to everyone that helped out.  That early clue with the access permissions was the real key, the rest was just me learning how it works.
 
0 Kudos

1,120 Views
mjbcswitzerland
Specialist V
Hi Jason

The most challenging part of using peripheral DMA is getting the access rights set up correctly. Per default, DMA controller is neither allowed to access peripherals nor RAM etc.

I don't use the 5282 so there may be some spcialities involved but generally the Coldfire devices have more or less the same building blocks. (You will have to interpret the defines I use from the register descriptions but this should be no problem).

A. The following is required otherwise there will be a DMA access error when a transfer is attempted. It is a global setting (not per UART)
***********************************************************
 GPACR0 = SUP_USER_FULL_ACCESS;  // enable peripheral SRAM access
***********************************************************

B. The following access rights have to be set on a per UART basis (this example is for UART0)
   PACR_UART0  |= (SUP_USER_FULL_ACCESS << UART0_ACCESS_SHIFT); // enable DMA access to UART0
***********************************************************

Your points of confusion:
1. Each direction requires one DMA channel. If no DMA channel is assigned the UART will/can use interrupts for the transfer.
2. Don't use this device so don't know any details about this.
3. When using DMA on Tx or Rx don't set up any UART interrupts - interrupts for that direction are via DMA controller.
If not using DMA on Tx or Rx set up the UART interrupt for that direction - eg for UART1:
        IC_ICR_0_14 = UART1_INTERRUPT_PRIORITY;                          // define interrupts level and priority
        fnSetIntHandler(UART1_VECTOR, (unsigned char *)_SCI1_Interrupt); // enter the handler routine
        IC_IMRL_0 &= ~(UART1_PIF_INT_L | MASK_ALL_INT);                  // unmask interrupt source

If both directions use DMA no interrupt need to be set up.
For any direction using DMA do not enable the perticular interrupt source.

Sorry that I have nothing specific for the 5282 but you may still see something which helps.

Good luck

Regards

Mark Butcher

www.uTasker.com


0 Kudos