Quote:
|
Originally Posted by WizardOfAz
...
Next try was to read the analog inputs in the ISR itself. I hoped that doing
#pragma interruptlow InterruptHandlerLow save=PROD, section(".tmpdata")
would save enough context, but it evidently does not - I am getting a smattering of wild data now in the main polling process. First I thought this was because I was calling Get_Analog_Value in the ISR as well as in the main process. Get_Analog_Value uses some SFRs, and they are not saved across the interrupt, so this would be expected to at least give some bad samples if not worse data mangling. But I moved all the analog sampling to the ISR so Get_Analog_Value would be called from only one thread. This did not eliminate the problem.
Anybody have suggestions?
Also, my assumption is that Get_Analog_Value only runs a few tens of microseconds (15-30 or so) so I can do many of them in a 4ms ISR w/o an overrun problem. This is what it looks like in the pic datasheet. Can anyone confirm this?
Thanks for any help.
Bill
|
According to the C compiler manual you need to save additional context when calling functions that return values. Specifically, for 8 & 16 bit return values you need to save 'PROD'. I believe it is page 28...
Team 492 samples the ADXSR150 at 100hz (10ms). Our basic logic is a 1khz timer that increments a byte counter (atomic operation). In the fast loop of the IFI code we check that counter and do stuff when it increments.
The fast loop is called often enough to sample the timer directly (e.g. no interrupts) but we used them anyway in case some code in the Autonomous routines took longer than a milli-second to run.
Code:
void Process_Tasks(void)
{
static char GyroTimer = 0, PrintTimer = 0;
Poll_Rx1(); // The fast loop runs > 100khz
Poll_Tx1(); // Poll rather than interrupts
Poll_Rx2();
Poll_Tx2();
while (MsTimer) // Incremented by TimerInterrupt.
{
MsTimer--; // Section.
if (++GyroTimer == 10) // 100hz
{
GyroTimer = 0;
Gyro_Task();
} // END GyroTimer
if (++PrintTimer == 100) // 10hz
{
SysTimer++; // General timer for system
PrintTimer = 0;
TetherTask(STDIO);
} // END Print task
}// END Tasking
}
Here is a snipped of our interrupt code
Code:
/*******************************************************************************
* FUNCTION NAME: InterruptHandlerLow
*
* If you want to use these external low priority interrupts or any of the
* peripheral interrupts then you must enable them in your initialization
* routine. Read p. 28 of the "MPLAB(R) C18 C Compiler User's Guide" for
* information on context saving.
*
* Because this handler calls something, it must save ".tmpdata". If the called
* routine returned a 16 bit variable, "PROD" would need to be saved as well.
*******************************************************************************/
#pragma code
#pragma interruptlow InterruptHandlerLow save=section(".tmpdata")/* You may want to save additional symbols. */
void InterruptHandlerLow ()
{
If (INTCONbits.RBIF) /* INTERRUPTS 3-4 (RB4, RB5, RB6, or RB7) changed. */
{
DecodeQuadrature(PORTB); // Read PORTB and clear IF to
INTCONbits.RBIF = 0; // clear interrupt
}
if (PIR1bits.TMR2IF) // timer 2 interrupt?
{
PIR1bits.TMR2IF = 0; // clear the timer 2 interrupt flag [92]
MsTimer++; // Increment millisecond timer
}
}