lpcware

LPC4350 DMA Timer Match Unexpected Behaviour

Discussion created by lpcware Employee on Jun 15, 2016
Latest reply on Jun 15, 2016 by lpcware
Content originally posted in LPCWare by hangdog on Sat Feb 01 09:20:01 MST 2014
Hi

I'm going to try to keep this code-light in the hope that the pertinent info is in my description, but I attach code. I think everything relevant is in the attachment, sorry if I've left out any important config stuff but I think not.

I've set up a GPDMA channel to respond to a DMA request from Timer 1 Match 0 with a peripheral-to-memory burst (of 1 byte). The DMA is the flow controller, the Transfer Size is 3 (bytes). Following a hard reset, this works correctly. Each timer Timer1 has counted one second, a transfer executes and Transfer Size is decremented, and after 3 transfers the Terminal Count ISR fires. Happy, lovely.

However, following a vectreset from the programmer, the first transfer occurs immediately that the DMA channel is enabled. Now, I know what you're thinking - this fool isn't clearing the Interrupt Register of Timer 1. Well, I am so. I'm also - afaik - clearing everything in Timer 1 state and in the GPDMA state, so I can't see where the hangover is.

Clearly it is a hangover - if I halt Timer 1 in the TC ISR, then the next time round, following the vectreset, the behaviour is correct (no immediate transfer from the DMA channel, it waits for the timer to reach match). If I don't reset Timer 1 in the TC ISR, presumably it keeps counting up, keeps generating requests, and these are stacked somewhere up to some height because they're being ignored by the GPDMA which has disabled itself after reaching the Transfer Size.

Fine, I get all that. I could disable the timer in the TC ISR and the problem would go away, but I'd be worried in case the state was unknown following a soft reset. But I could live with that, put in some catch condition just in case.

But the thing that gets me, that makes me think I must surely have missed the documentation for some buffer somewhere, is this: If I set the Interrupt Register to 0xFF once (thus, clearing any pending interrupts), I get the incorrect behaviour:


//  clear
TIMER_IR(TIMER_CAM1) = 0xFF;

//  disable, configure, enable DMA channel
...

//  first transfer occurs immediately


However, if I do it twice...


//  clear
TIMER_IR(TIMER_CAM1) = 0xFF;
TIMER_IR(TIMER_CAM1) = 0xFF;


Then the correct behaviour is recovered. Does this mean anything to anyone? It's exactly as written above, the instructions are consecutive. Look like a timing issue? Well, this doesn't work, and still gets incorrect behaviour:


//  clear
delay_ms(10);
TIMER_IR(TIMER_CAM1) = 0xFF;


Riddle me that.

Thanks

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

Outcomes