request for help with DMA

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

request for help with DMA

Jump to solution
2,573 Views
comsosysarch
Contributor III

I have a project (IAR) where I am setting up a buffer in memory and at a certain point in a loop I am trying to get the buffer to dump out of a uart using DMA.

I know I have the uart set up correctly because it is the same set up for another test app where it communicates with a PC. And data is coming out the uart and being read by the PC, which is great.

Unfortunately, the data is supposed to be framed and I suspect the DMA is not stopping when it should so I am getting extra superfluous bytes at the end of each frame and the PC is unable to sync on frames (custom frame format).

Seems like it should be a simple solution to someone familiar with DMA on the Kinetis device.

Here is the code I am using to set up the DMA channel:

// TDC for DMA Channel 1DMA_SADDR_REG(eDMA_BASE_PTR,1) = (UInt32)&tlmBuf;DMA_SOFF_REG(eDMA_BASE_PTR,1) = 1;DMA_ATTR_REG(eDMA_BASE_PTR,1) = DMA_ATTR_SMOD(0) | DMA_ATTR_SSIZE(0) | DMA_ATTR_DMOD(0) | DMA_ATTR_DSIZE(0);DMA_NBYTES_MLNO_REG(eDMA_BASE_PTR,1) = sizeof(UART0_D);DMA_SLAST_REG(eDMA_BASE_PTR,1) = -sizeof(tlmBuf);DMA_DADDR_REG(eDMA_BASE_PTR,1) = (UInt32)&UART0_D;DMA_DOFF_REG(eDMA_BASE_PTR,1) = 0;DMA_CITER_ELINKNO_REG(eDMA_BASE_PTR,1) = sizeof(tlmBuf);DMA_DLAST_SGA_REG(eDMA_BASE_PTR,1) = 0;DMA_CSR_REG(eDMA_BASE_PTR,1) = 0;DMA_BITER_ELINKNO_REG(eDMA_BASE_PTR,1) = sizeof(tlmBuf);DMAMUX_CHCFG_REG(DMAMUX_BASE_PTR,1) = DMAMUX_CHCFG_ENBL_MASK | DMAMUX_DMA_REQ_SRC_UART0_TX;

After this I set up the interrupt channel for DMA complete, enable the DMA (SERQ) and finally set the UART TIE mask to enable it to trigger the DMA channel.

Here is the DMA ISR code:

__irq void DMA1_IRQHandler(void){ DMA_CERQ = DMA_CERQ_CERQ(1); DMA_CINT = DMA_CINT_CINT(1);}

The ISR is supposed to turn off the DMA when complete.

I am clocking the K60 at 50 MHz (25 MHz flash) and the UART runs at 921600bps. So I would think I have some latency to be able to get to the ISR and switch off DMA before any extra bytes are transferred, although the way I have done it is not the way I would really prefer.

What I'd like is a way to run a single major loop of the DMA and have it automatically know to shut off at the end of the that one major loop without relying on an ISR that may have latency issues. Since I have a single-byte minor loop in this case maybe there is a way to run N bytes in the minor loop and shut off after one major loop instead. Either way.

I'm still reading through the DMA chapter in the FRM but if someone has experience doing this it would be a huge help.

Thanks.


0 Kudos
1 Solution
1,036 Views
comsosysarch
Contributor III

LOL...

The final version above works.

Turns out I was also having trouble with the buffer size on my PC test application and bytes were dropping by the wayside.

 

View solution in original post

0 Kudos
8 Replies
1,036 Views
renka
Contributor II

Hi,

 

I red that you successfully solved your problem.Could you help me? I have a problem with UART by DMA.

I'm worked with Kinetis K60 and IAR workspace. I have a buffer of 512 bytes in RAM. 

DMA should out this buffer to UART. when i set CITER=BITER=1,i could receive the characters by UART with DMA completion ISR upon 1 byte.

But when i set CITER=BITER=512 and NBYTE_MLNO=1,then the DMA completion ISR doesn't occur.

My setup code is here:

 

SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;  SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;  enable_irq(DMA1_IRQn);                         DMAMUX_CHCFG_REG(DMAMUX_BASE_PTR,1) = DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(DMA_UART3TX_CH);      DMA_CR = 0;       // no minor loop mapping  DMA_DCHPRI1 = 1; //the low priority according to fixed priority schema.can be preempted  // TDC for DMA Channel 1  DMA_CITER_ELINKNO_REG(DMA_BASE_PTR,1) = DMA_BLK_SIZE; //"DMA_BLK_SIZE Nbytes transfer"  DMA_BITER_ELINKNO_REG(DMA_BASE_PTR,1) = DMA_BLK_SIZE;  DMA_SADDR_REG(DMA_BASE_PTR,1) = (uint32)Dma_Source_Blk;  DMA_SOFF_REG(DMA_BASE_PTR,1) = 1; //increment source address by 1  DMA_ATTR_REG(DMA_BASE_PTR,1) = DMA_ATTR_SMOD(0) | DMA_ATTR_SSIZE(0) | DMA_ATTR_DMOD(0) | DMA_ATTR_DSIZE(0);  DMA_NBYTES_MLNO_REG(DMA_BASE_PTR,1) = sizeof(UART3_D); //transfer DMA_BLK_SIZE upon channel activation  DMA_SLAST_REG(DMA_BASE_PTR,1) = 0; //don't adjust SADDR upon channel completion  DMA_DADDR_REG(DMA_BASE_PTR,1) = (uint32)&UART3_D;  DMA_DOFF_REG(DMA_BASE_PTR,1) = 0; //one byte UART FIFO  DMA_DLAST_SGA_REG(DMA_BASE_PTR,1) = 0; //Do not adjust DADDR upon channel completion  DMA_SERQ |= 0x02; //set DMA enable request  uart_init (TERM_PORT, periph_clk_khz, TERMINAL_BAUD); //set UART TIE mask  DMA_CSR_REG(DMA_BASE_PTR,1) = (DMA_CSR_INTMAJOR_MASK | DMA_CSR_DREQ_MASK | DMA_CSR_START_MASK);

 

 

0 Kudos
1,036 Views
comsosysarch
Contributor III

10-11 days later, sorry...

 

1. You do not usally use the DMA software start along with a hardware trigger... maybe you are trying to kick-start it here with the software start or something (not clear from your snippet), but if not intentional that could be an issue.

2. I do not know what happens if you |= the SERQ register... have to look it up, but normally you just write the bit or bits you want to set. It is a set register, not the actual data that you would |=. Again, maybe it works like that just not I think how it was intended and could be a problem. Er not.

3. You are enabling the DMAMUX first. Again, this is not the way I did it or I think the way the sample code from Freescale does it. Maybe it works like that but you might be missing the initial trigger (which may be why you are using the software trigger?).

 

Off hand hard to say otherwise... are you certain the IRQ is being properly set up?

0 Kudos
1,036 Views
tty
Contributor I

Hi, All.

 

I have some other problem. I need to configure Uart0_rx to Uart1_tx via dma channel. How can I do this?

 

Thanx

0 Kudos
1,036 Views
JessicaKedz
Contributor I

Hi, I just started working with the kinetics using IAR. When I try to write to the DMA MUX registers i get a "hard fault" interrupt.

 

I guess you already figured out how to do this, is there something special that needs to be done before writing to these registers? The peripheral clocks are running, and I am using the A/D sucessfully already.

 

The write is as follows:

DMAMUX_CHCFG0 = (DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(40));

one instruction past this, I get the vector 3 interrupt. I followed it woth NOP's to be sure it wasnt something else.

 

ANy ideas would be great!

 

Thanx

0 Kudos
1,035 Views
JessicaKedz
Contributor I

OOps, missed the clock controll for the DMA MUX!

 

        //enable DMA and PIT clock
        SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK | SIM_SCGC6_PIT_MASK;
    SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;

0 Kudos
1,036 Views
comsosysarch
Contributor III

This was the trick, of course, in lieu of the corresponding line in the OP...

DMA_CSR_REG(eDMA_BASE_PTR,1) = DMA_CSR_INTMAJOR_MASK;

So now I get _kind of_ the expected behavoir.

 

Problem is that I still do not get a consistent length per DMA corresponding to the buffer size in bytes, which to my naive view this code shoud do. The buffer length is 26136 bytes, and I appear to be getting about 50% more than that, and not always the same. But I'll dig a little further and in any case the original particular problem is answered by reading the FRM.

0 Kudos
1,036 Views
comsosysarch
Contributor III

Well, actually...

DMA_CSR_REG(eDMA_BASE_PTR,1) = DMA_CSR_INTMAJOR_MASK | DMA_CSR_DREQ_MASK;

 ...and...

__irq void DMA1_IRQHandler(void){ UART_C2_REG(UART0_BASE_PTR) &= ~UART_C2_TIE_MASK; DMA_CINT = DMA_CINT_CINT(1);}

However, while that _looks_ like what I wanted, the results are no different, I still seem to be getting substantially (50% ish, not always consistent but always in the range of 40% to 60% or so) more bytes per DMA transfer out the UART than I have set in the TCD for this channel. I do have channel 0 running continuously while channel 1 (described here) is single bursts.

 

0 Kudos
1,037 Views
comsosysarch
Contributor III

LOL...

The final version above works.

Turns out I was also having trouble with the buffer size on my PC test application and bytes were dropping by the wayside.

 

0 Kudos