jandle wrote on Tuesday, October 25, 2011:
I am measuring the time that LATA bit 9 is high with a digital scope. I also measured the RX ISR and so on. I have all ISR priorities at 1 (though I had earlier set RX to 2, I caught that and it changed nothing.) The RX ISR is only engaged a typical 10-20 us and closer to 60us when I post 256 bytes to the queue.
void __attribute__((__interrupt__, auto_psv)) _T1Interrupt( void )
{
/* Clear the timer interrupt. */
IFS0bits.T1IF = 0;
LATA |= 0x0200;
vTaskIncrementTick();
#if configUSE_PREEMPTION == 1
portYIELD();
#endif
LATA &= 0xFDFF;
}
I already do have a hardware timer instead of a task:
/* --------------- Platform includes ---------------------*/
#include “iSAW_Base.h”
#include “MBPortTimer.h”
#include “Serial.h”
static xSemaphoreHandle rxCharRecievedSemaphore;
// =====================================================================
// Timer 2 is inter-character timeout for Serial 0
// Timer 3 is inter-character timeout for Serial 1
// PR3 is set to give an interrupt after the delay specified in
// the parameters, in milliseconds.
// also register the semaphores as this module will be
// keeping Serial#Monitor in line (unless it replaces it?)
//
void vInitMBTimers(unsigned short usDelay0, xSemaphoreHandle xSP0,
unsigned short usDelay1, xSemaphoreHandle xSP1)
{
rxCharRecievedSemaphore = xSP0;
rxCharRecievedSemaphore = xSP1;
T2CONbits.TON = 0; // Stop any 16/32-bit Timer3 operation
T2CONbits.T32 = 0; // Disable 32-bit Timer mode
T2CONbits.TCS = 0; // Select internal instruction cycle clock
T2CONbits.TGATE = 0; // Disable Gated Timer mode
T2CONbits.TCKPS = 0b01; // Select Prescaler = 8 -> 2500 pulses per millisecond
TMR2 = 0x00; // Clear 16-bit Timer
PR2 = TICKS_PER_MS * usDelay0; // Set 16-bit Timer range
T2CONbits.TON = 0; // Don’t start 16-bit Timer
__TIM2_ENBIT = 1;
__TIM2_PRIOR = 1;
__TIM2_FLAG = 0;
T3CONbits.TON = 0; // Stop any 16-bit Timer3 operation
T3CONbits.TCS = 0; // Select internal instruction cycle clock
T3CONbits.TGATE = 0; // Disable Gated Timer mode
T3CONbits.TCKPS = 0b01; // Select Prescaler = 8 -> 2500 pulses per millisecond
TMR3 = 0x00; // Clear 16-bit Timer
PR3 = TICKS_PER_MS * usDelay1; // Set 16-bit Timer range
T3CONbits.TON = 0; // Don’t start 16-bit Timer
__TIM3_ENBIT = 1;
__TIM3_PRIOR = 1;
__TIM3_FLAG = 0;
}
// ===================================================================================
// call this on each received character to start or reset the appropriate timer
//
void vTimerOnCharRX (unsigned short usPort)
{
switch (usPort)
{
case 0:
T2CONbits.TON = 1;
TMR2 = 0x0000;
__TIM2_FLAG = 0;
break;
case 1:
T3CONbits.TON = 1;
TMR3 = 0x0000;
__TIM3_FLAG = 0;
break;
default:
break;
}
}
void __attribute__((__interrupt__)) __attribute__((no_auto_psv)) _T2Interrupt(void)
{
portBASE_TYPE xHigherPriorityTaskWoken __attribute__ ((aligned (2))) = pdFALSE;
__TIM2_FLAG = 0;
T2CONbits.TON = 0;
//xSemaphoreGiveFromISR(rxCharRecievedSemaphore, &xHigherPriorityTaskWoken);
unsigned short usPort = 0;
switch (xSerState.usProtocol)
{
// In native protocol the ISR parses and this just resets
case SER_PROT_NATIVE:
//taskENTER_CRITICAL();
if (xSerState.usRxBufLen)
{
if (xDiag.ulSer1ResetRXState != 0xFFFFFFFF) xDiag.ulSer1ResetRXState++;
}
xSerState.usRxBufLen = 0;
xSerState.usCMDstate = SER_CMD_NONE; // start over on next message!
xSerState.usRXing = SER_RX_IDLE;
//taskEXIT_CRITICAL();
break;
// in MODBUS RTU the ISR collects and this dispatches
case SER_PROT_MODBUS:
//taskENTER_CRITICAL();
if (//!cSerRxBuf || // need to think more about multicast
(cSerRxBuf == xSerState.usAddress))
{
if (usSerProcessCRC(usPort))
{
// pop out for API call. Only post if it is ours and valid.
//taskEXIT_CRITICAL();
xQueueSendFromISR( xSerState.xRXMsgQueue, cSerRxBuf, &xHigherPriorityTaskWoken);
//taskENTER_CRITICAL();
}
}
xSerState.usRxBufLen = 0;
xSerState.usCMDstate = SER_CMD_NONE; // start over on next message!
xSerState.usRXing = SER_RX_IDLE;
//taskEXIT_CRITICAL();
break;
// case SER_PROT_STRIPPED cannot be assigned to a port.
default:
break;
}
if( xHigherPriorityTaskWoken != pdFALSE )
{
taskYIELD();
}
}
the commented critical enter and exit calls are from when the logic was in the task.
On the one hand, the Timer 1 interrupt is only long when there are commands being processed because otherwise it’s idle. Tomorrow I’ll contrive to make it busy without external cause (interrupts) to see if it’s a task switch issue or an ISR competition issue.
To be clear, one level-1 interrupt cannot interrupt another on Microchip hardware, right?