Page 1 of 1

Surprise effect in turning dma timer interrupts off and on

Posted: Sat Apr 21, 2012 11:25 pm
by ScottM
Summary: I turn a DMA timer interrupt on and off and back on. When I turn it on the first time, it works. Once I turn it off, turning it on again doesn't work. I'm using (sim.timer[IndexDMAOneWire].tmr &= ~0x0001) and (sim.timer[IndexDMAOneWire].tmr |= 0x0001).

Experimenting showed I had to rewrite the timer configuration:
sim.timer[IndexDMAOneWire].tmr = 0x001A; // 0000 0000 0001 1010
sim.timer[IndexDMAOneWire].txmr = 0x00; // 0000 0000
sim.timer[IndexDMAOneWire].ter |= 0x02;
before turning the interrupt back on, each and every time, or nothing works.

Is that expected? I was hoping I could just suppress or allow the interrupt with just .tmr changes. Rewriting the registers isn't a big deal, but it was annoying to figure out it was needed. Is it documented somewhere? Anyone else seen this?

(I'm turning them on and off because I'm big-banging the one-wire protocol, using interrupts to get the timing exact; which involves rewriting tcn and trr on each interrupt, and turning them off entirely when there's no one-wire stuff happening.)

Re: Surprise effect in turning dma timer interrupts off and

Posted: Sun Apr 22, 2012 10:33 pm
by roland.ames
From the processor (5234, 5270, 5282) manual:

If an interrupt source is being masked in the interrupt controller mask
register (IMR) or a module’s interrupt mask register while the
interrupt mask in the status register (SR) is set to a value lower than
the interrupt’s level, a spurious interrupt may occur. This is because by
the time the status register acknowledges this interrupt, the interrupt
has been masked. A spurious interrupt is generated because the CPU
cannot determine the interrupt source. To avoid this situation for
interrupts sources with levels 1-6, first write a higher level interrupt
mask to the status register, before setting the mask in the IMR or the
module’s interrupt mask register. After the mask is set, return the
interrupt mask in the status register to its previous value. Since level 7
interrupts cannot be disabled in the status register prior to masking,
use of the IMR or module interrupt mask registers to disable level 7
interrupts is not recommended.

I don't know if this is part of your problem, but I would recommend putting UCOS_ENTER_CRITICAL() and UCOS_EXIT_CRITICAL() around your read-modify-write of the sim.tmr[].imr register. this would prevent any spurious interrupt which may occur while disabling the timer interrupt, the spurious interrupt MIGHT be putting the timer into a weird or unexpected mode.

There is a lot of guesswork in this answer but it won't hurt to try.

I wrote these a while ago but never got any feedback.

http://forum.embeddedethernet.com/viewt ... f=5&t=1116
http://forum.embeddedethernet.com/viewt ... f=5&t=1117

Re: Surprise effect in turning dma timer interrupts off and

Posted: Mon Apr 23, 2012 7:24 pm
by roland.ames
roland.ames wrote:I would recommend putting UCOS_ENTER_CRITICAL() and UCOS_EXIT_CRITICAL() around your read-modify-write of the sim.tmr[].imr register.
Sorry that should have been USER_ENTER_CRITICAL() and USER_EXIT_CRITICAL().

Re: Surprise effect in turning dma timer interrupts off and

Posted: Tue Apr 24, 2012 4:22 am
by ScottM
I don't THINK that's related, but it lead me to look at the spurious interrupt thread, and now I'm turning interrupts off and on around my use of setIntc. So that's another future problem killed.

I guess I'm going to have to dig deeper into the implementation of sim.timer[]. I can see it's a basic struct with no member functions, so bit twiddles are just bit twiddles and presumably can make no direct changes to the hardware state. That means there's code elsewhere, presumably written by Netburner, that looks at these bits while interrupts are happening, and that code doesn't like it when they are touched during interrupts. And this is not documented. *sigh*

I can work around this. Instead of twiddling .tmr in the interrupt handler to turn the interrupt off and on, I can just leave them on, and set my own flag elsewhere to tell my interrupt handler to just dismiss and return if I don't really want that interrupt. I don't like this. It's sloppy and means I'll be getting interrupts when I don't need them.

I really wish the documentation was more detailed.

Re: Surprise effect in turning dma timer interrupts off and

Posted: Tue Apr 24, 2012 6:14 am
by mhoyt
Scott,

There is no implementation of sim.timer[] to delve into. It is a simple struct as you see, but it does not exist in program RAM. The struct is based at address 0x4000_0000 by the linker as directed by the sys.ld file. When you "twiddle" the bits in any sim member, you are directly affecting the processor registers which occupy the address space starting at 0x4000_0000.

--Mike

Re: Surprise effect in turning dma timer interrupts off and

Posted: Tue Apr 24, 2012 9:19 am
by rnixon
Scott, the documentation is in the Freescale processor manual. Is that the one without enough detail? If so, maybe a post to the freescale message board might help.

Re: Surprise effect in turning dma timer interrupts off and

Posted: Tue Apr 24, 2012 8:51 pm
by ScottM
mhoyt wrote:Scott,

There is no implementation of sim.timer[] to delve into. It is a simple struct as you see, but it does not exist in program RAM. The struct is based at address 0x4000_0000 by the linker as directed by the sys.ld file. When you "twiddle" the bits in any sim member, you are directly affecting the processor registers which occupy the address space starting at 0x4000_0000.

--Mike
Ah, it's mapped. Ok, I'm off to the freescale manuals. Although - note to rnixon - it's nice when the product documentation presents the behaviour essentials, and doesn't send you manual chasing.