Robert,
I do not read C code very well but there is one thing that I have learned to look for. In one of the last lines in your code, you do something to the CIER -- Channel Interrupt Enable Register. There is a note above this code that says "/* enable the interrupt to measure again */".
Probably, the machine code that is generated uses a bit field instruction, such as BSET or BCLR, to clear or set the interrupt enable bit.
A problem that can occur is when an interrupt is asserted during the execution of the BCLR instruction.
If the interrupt flag for a particular TPU channel becomes set during the execution of the BCLR instruction that disables the interrupt, here is what can happen.
1. BCLR starts execution
2. Interrupt occurs
3. Interrupt signal starts through the hardware synchronizers
4. On last cycle of the BCLR instruction, the bit in the CIER register is cleared, which turns off the interrupting source TO THE SYNCHRONIZERS.
5. The interrupt gets RECOGNIZED at the end of the BCLR instruction.
6. The CPU starts to service the interrupt but by this time, the interrupt signal to the CPU has been turned off since the bit in the CIER has been cleared.
7. The CPU still thinks it has a valid interrupt but when the actual interrupt acknowledgement cycle occurs, there is no interrupt.
8. If the internal Bus Monitor is turned on, the IACK cycle will be terminated with BERR instead of DSACK (since there is no interrupting source anymore -- your code turned it off)
9. If the IACK cycle is terminated by BERR, the code takes a Spurious Interrupt exception. (My guess is that you have an RTE instruction only for the Spurious Interrupt handler.)
So, what to do?
In the most general sense, one must first turn off the source of an interrupt and then make sure that the interrupt source did NOT create an interrupt between the time you tried to turn off the source and the latest time that the interrupting source could possibly create an interrupt once the source is disabled. Whoa -- what a mouth full.
OK, here is an example. Say you are running the UART function and the TPU is actually servicing this channel and the STOP bit is coming in. Now, your code does a BCLR on the Channel Interrupt Enable Register to disable the interrupt for this channel. But, because of asynchronous timing, the TPU's microcode sets the interrupt flag for this channel about 1/2 way through the BCLR instruction. So, in this case, you get a flag and an interrupt just at the time when the interrupt can get recognized (causing the CPU to start in Interrupt Acknowledgement Cycle) but the interrupt will get turned off before the IACK cycle actually occurs.
In your case, it is probably impractical to disable the PTA channel. So, here is what I would do. Set up the Spurious Interrupt handler to:
1. Check to see if the interrupt flag for the PTA channel is set
2. If set, jump to the interrupt service handler that would normally be used for this TPU channel.
Well, this sort of depends. You need to determine what the code should do if you get an interrupt for the TPU's PTA channel after you clear the interrupt enable bit.
I hope that at least some of this is clear. The entire message is to warn you of the danger of clearing a bit in the CIER when a TPU channel could still possibly cause an interrupt.
Regards,
Charlie
Show quoted textHide quoted text
-----Original Message-----
From: Robert Yablonski [mailto:yabo@...]
Sent: Sunday, March 30, 2003 7:24 PM
To: 68300@yahoogroups.com
Subject: [68300] TPU Problem
Hello Group,
We have a TPU problem. When using the PTA function, in Mode 3 we sometimes
get a reading that is 1/2 the actual period Plus 1035+-1. The hardware
signals look good. Increasing the period count reduces the number of times
we see the error but does not stop the error.
The code looks as follows:
volatile UL pta;
volatile B cpta;
UL ptaRead(UW pin_index0)
{
UL ptaLocal;
if(pin_index0 != 8)
return 0;
if(cpta != 0)
return 0xffffffff;
ptaLocal = pta;
/* enable the interrupt to measure again */
cpta = 2;
CIER |= (W)(~CISR_MASK(pin_index0));
return ptaLocal;
}
/* written in assembly because it runs often- optimizing it is good */
asm void tpuPin8(void);
asm void tpuPin8(void)
{
/* no registers used, so no need to save & restore them */
/* count reads */
sub.b #1,cpta ;
bgt.s tp8_no_disable
/* clear the flag */
clr.b cpta
/* clear the interrupt enable bit in CIER */
andi.w #(~(1 << 8)),(Y + 0xffe0a );
tp8_no_disable:
/* clear the interrupt status bit in CISR */
andi.w #(~(1 << 8)),(Y + 0xffe20 );
/* read period with a coherent long read, and put it in the array */
move.l (Y+0xfff00+(8<<4)+8),pta ;
/* clear the pin's high word */
clr.w (Y+0xfff00+(8<<4)+8) ;
/* no registers used, so no need to save & restore them */
rte
}
/* initialize a TPU pin to count using TCR1, the faster, internal TCR. */
void ptaInit(UW pin_index0)
{
W tmp;
/* turn off pin by setting the priority to zero */
tmp = CPR(pin_index0);
tmp &= ((W)(~(3 << ((pin_index0 & 7)<<1)))); /* clear the priority */
CPR(pin_index0) = tmp;
/* disable the interrupt */
CIER &= CISR_MASK(pin_index0);
/* clear the interrupt status bit */
CISR &= CISR_MASK(pin_index0);
/* first, set up the first pin's function code; only write it once */
tmp = CFSR(pin_index0);
tmp &= ((W)~(0x0F << (4*(pin_index0 & 3)))); /* clear the code */
tmp |= ((W)(PTA_FN_CODE << (4*(pin_index0 & 3)))); /* time accumulate */
CFSR(pin_index0) = tmp;
PARM16(pin_index0, 0x00) = 0x07; /* measure period with TCR1 */
/* measure a whole period from a rising edge */
tmp = HSQR(pin_index0);
tmp &= ((W)~(3 << (2*(pin_index0 & 7))));
tmp |= ((W)(2 << (2*(pin_index0 & 7))));
HSQR(pin_index0) = tmp;
/* initialize MAX_COUNT & PERIOD COUNT */
PARM16(pin_index0, 0x02) = 0x100;
/* initialize LAST_TIME */
PARM16(pin_index0, 0x04) = 0;
/* initialize ACCUM */
PARM16(pin_index0, 0x06) = 0;
/* initialize HW */
PARM16(pin_index0, 0x08) = 0;
/* initialize LW */
PARM16(pin_index0, 0x10) = 0;
/* install or check the interrupt */
irqVector((UB)(0x50+pin_index0), tpuPin8); /* assure a vector */
/* enable the interrupt */
CIER |= (W)(~CISR_MASK(pin_index0));
/* send the initialize fn */
tmp = HSRR(pin_index0);
tmp &= (W)(~(3 << ((pin_index0 & 7)<<1))); /* clear the function code */
tmp |= (W)(3 << ((pin_index0 & 7)<<1)); /* initialize channel */
HSRR(pin_index0) = tmp;
/* update pins to high priority */
tmp = CPR(pin_index0);
tmp &= ((W)(~(3 << ((pin_index0 & 7)<<1)))); /* clear the priority */
tmp |= ((W)(3 << ((pin_index0 & 7)<<1))); /* set high priority- 3 */
CPR(pin_index0) = tmp;
ptaRead((UW)8);
}
Yahoo! Groups Sponsor
ADVERTISEMENT
<http://us.adserver.yahoo.com/l?M=240537.3105911.4426332.1728375/D=egroupmail/S=:HM/A=1368547/rand=480206332>
---------------------------------------------------
To unsubscribe from this group, send an email to:
68300-unsubscribe@yahoogroups.com
To learn more about Motorola Microcontrollers, please visit
http://www.motorola.com/mcu <http://www.motorola.com/mcu>
Your use of Yahoo! Groups is subject to the Yahoo! Terms of Service <http://docs.yahoo.com/info/terms/> .
[Non-text portions of this message have been removed]