void __ISR(_TIMER_4_VECTOR, ipl4) interruptForTransmitingIRSignals(void)
{
    if (mT4GetIntFlag())
    {
        if (irTransmitBufferIndex >= IR_TRANSMSIT_BUFFER_SIZE)
        {
            OC3CONbits.ON = 0;
            irTransmitBufferIndex = 0;
            T4CONbits.ON = 0;
            sendingIR = 0;
            mPORTGClearBits(BIT_6);
            //printf("S\r\n");
        }
        else
        {
            //printf("T\r\n");
            mPORTGToggleBits(BIT_6);
            //toggle OC3
            OC3CONINV = 0b1000000000000000;
            //OC3CONbits.ON = !OC3CONbits.ON;
            //mPORTBToggleBits(BIT_13);
            PR4 = irTransmitBuffer[irTransmitBufferIndex++];
            TMR4 = 0;
        }
        mT4ClearIntFlag();
    }
}
Exemple #2
0
//Interrupt handler to
void __ISR(_TIMER_4_VECTOR, ipl4) _Timer4Handler(void)
{
    //Reset the flag
    mT4ClearIntFlag();

    //Put code here
}
void __ISR(_TIMER_4_VECTOR, ipl2) _InterruptHandler_TMR4(void)
{
   // if(current_block->direction_bits[Z_AXIS])
    //   PORTSetBits(zAxis.directionPin.port, zAxis.directionPin.pin);
   // else
     //  PORTClearBits(zAxis.directionPin.port, zAxis.directionPin.pin);
    if(steps_Z)
    {
        if(!(mPORTAReadBits(zAxis.enablePin.pin)))
            steps_Z--;
    }
    if (current_block != Null)
    {
        if (current_block->steps_z)
        {
            if(!(mPORTAReadBits(zAxis.enablePin.pin)))
                current_block->steps_z--;
        }
       else
        {
            //CloseOC2();
            BSP_AxisDisable(Z_AXIS);
            BSP_Timer4Stop();
        }
    }
    else
    {
       BSP_AxisDisable(Z_AXIS);
    }
    // clear the interrupt flag
    mT4ClearIntFlag();
}
Exemple #4
0
void rk86_video_init_cursor_timer(void) {
    // Setup timer 4.
    PR4 = 1 * ((BUSFREQ/2)/1000) - 1;
    T4CON = 0x8010;
    mT4SetIntPriority(1);
    mT4ClearIntFlag();
    mT4IntEnable(1);
}
Exemple #5
0
//=============================================
// Configure the Timer 4 interrupt handler
//=============================================
void __ISR(_TIMER_4_VECTOR, T4_INTERRUPT_PRIORITY) Timer4InterruptHandler(void)
{
  oTimerSendData = 1;

  // Increment the number of overflows from this timer. Used primarily by Input Capture
  Timer.Var.nOverflows[3]++;

  mT4ClearIntFlag();
}
/***************************************************************************************************
InitTimers
Initialise the 1 mSec timer used for internal timekeeping.
****************************************************************************************************/
void initTimers(void) {

 	// setup timer 4
    PR4 = 1 * ((BUSFREQ/2)/1000) - 1;       					// 1 mSec
    T4CON = 0x8010;         							// T4 on, prescaler 1:2
    mT4SetIntPriority(1);  							// lower priority
    mT4ClearIntFlag();      							// clear interrupt flag
    mT4IntEnable(1);       							// enable interrupt 
    P_SD_ACTIVITY_TRIS = 0; P_SD_LED_SET_LO;				// initialise the SD card activity led (maintained by timers.c)
}
Exemple #7
0
//******************************************************************
void Stepper_InitIO (void)
{
	// Setup timers
	//Timer 1
	T1CON = 0x8030;	//Set up timer 1 Fosc/2, prescaled 1:256 
	
	DDPCONbits.JTAGEN = 0; //To release port A pins from use by JTAG port
	
	//Set Tris for Stepper
	//X
	 AD1PCFGbits.PCFG8 = 1;   //AtoD port cfg AN8/B8
	 TRISBbits.TRISB8    = OUTPUT;	//Step
	 AD1PCFGbits.PCFG9 = 1;   //AtoD port cfg AN9/B9
	 TRISBbits.TRISB9    = OUTPUT;	//Dir
	 AD1PCFGbits.PCFG13 = 1;   //AtoD port cfg AN13/B13
	 TRISBbits.TRISB13    = OUTPUT;	//Enable
	 TRISDbits.TRISD4    = INPUT;	//X_HomeSwitch
	//Y
	 TRISDbits.TRISD8    = OUTPUT;	//Step
	 TRISDbits.TRISD9    = OUTPUT;	//Dir
	 TRISDbits.TRISD10    = OUTPUT;	//Enable
	 TRISCbits.TRISC13     = INPUT;	//Y_HomeSwitch
	 
	//Z
	 TRISDbits.TRISD2     = OUTPUT;	//Step
	 TRISDbits.TRISD7    = OUTPUT;	//Dir
	 TRISDbits.TRISD3     = OUTPUT;	//Enable
	 TRISCbits.TRISC14     = INPUT;	//Z_HomeSwitch
	 
	X_Disable = TRUE; 		
	Y_Disable = TRUE; 		
	Z_Disable = TRUE; 		
	
	//Timer 4 is used to time the stepper motor steps
	//PB clk = 8MHz Post scaler = 2 to 1 tick every 25nS	
	T4CON = 0x0;			//Clear timer setting register
	T4CONSET = 0x0010;		//Set PS to 2
	TMR4 = 0;				//Reset clock
	PR4 = 500;				//Initialise PR4 value (when T4 matches PR4 it interrupts)
	mT4SetIntPriority(7);	//Set T4 interrupt to top priority
	INTEnableSystemMultiVectoredInt();//Set T4 to vectored i.e. Fast
	mT4ClearIntFlag();		//Clear interrupt flag
	T4CONSET = 0x8000;		//Turn on T4
	mT4IntEnable(!TRUE);	//Disable T4 interrputs
	
	// init the circular buffer pointers
	 SBR = 0;
	 SBW = 0;
	 // Init Rapid moves
	 G_CodeRapidXYMove=0;
	 G_CodeRapidZMove=0;
	 
}//InitStepper
Exemple #8
0
//Aqu? invocaremos la ejecucion de optimizer en caso de que est? definido el
//modulo cognitivo. Si no har? lo que el usuario considere oportuno a?adir
//siempre y cuando haya configurado el la interrupcion (habilitar, etc.). En
//caso de que CRModule est? definido el usuario NO DEBER? RECONFIGURAR LA
//INTERRUPCION PUESTO QUE YA ESTA HECHO en boardinit() y podria afectar a la
//ejecucion de las rutinas.
void __ISR(_TIMER_4_VECTOR, ipl3)RutinaOptimizer(void)
{
    //Printf("\r\nSe ejecuta la rutina cognitiva.");
    #if defined(CRMODULE)
        CRM_Optm_Int(); //Rutina de ejecucion de optimoizer.
    #endif
    /*Espacio reservado para que el usuario invoque, si lo desea, a funciones
     que quiera ejectuar periodicamente con interrupcion del timer.*/

    /*Fin del espacio reservado*/

    mT4ClearIntFlag(); //Siempre hay que limpiar el flag de interrupcion en la
                       //rutina de atencion.
}
Exemple #9
0
/**
 * @function TmrLaunch
 * @brief enable a given timer, if this one is correctly configured
 * @param tmr_t tmr_id: timer id
 * @return none
 */
void TmrLaunch(tmr_t tmr_id) {
  switch(tmr_id) {
    case TMR_1:
      if(timer1Configured == 1 && tmr1PtrCallback != NULL) {
        mT1ClearIntFlag();
        T1CONSET = 0x8000;
      }
      break;
    case TMR_4:
      if(timer4Configured == 1 && tmr4PtrCallback != NULL) {
        mT4ClearIntFlag();
        T4CONSET = 0x8000;
      }
      break;
    case TMR_5:
      if(timer5Configured == 1 && tmr5PtrCallback != NULL) {
        mT5ClearIntFlag();
        T5CONSET = 0x8000;
      }
      break;
    default:
      break;
  }
}
*****************************************************************************************************************/void __ISR( _TIMER_4_VECTOR, ipl1) T4Interrupt(void) {

	/////////////////////////// count up timers /////////////////////////////////////
	//if(ExtCurrentConfig[11] == EXT_PER_IN) INT1Count++;			// if we are measuring period increment the count
	if(ExtCurrentConfig[5] == EXT_PER_IN) INT2Count++;
	if(ExtCurrentConfig[6] == EXT_PER_IN) INT3Count++;
	if(ExtCurrentConfig[7] == EXT_PER_IN) INT4Count++;
	mSecTimer++;                                                            // used by the TIMER function
	TickTimer++;								// used in the interrupt tick
	PauseTimer++;								// used by the PAUSE command
	IntPauseTimer++;							// used by the PAUSE command inside an interrupt
	InkeyTimer++;								// used to delay on an escape character
	if(++CursorTimer > CURSOR_OFF + CURSOR_ON) CursorTimer = 0;		// used to control cursor blink rate
//	GS I2C Start
	if (I2C_Timer) {
		if (--I2C_Timer == 0) {
			I2C_Status |= I2C_Status_Timeout;
			mI2C1MSetIntFlag();
		}
	}
	if (I2C_Status & I2C_Status_MasterCmd) {
		if (!(I2C1STAT & _I2C1STAT_S_MASK)) {
			I2C_Status &= ~I2C_Status_MasterCmd;
			I2C_State = I2C_State_Start;
			I2C1CONSET =_I2C1CON_SEN_MASK;
		}
	}
//	GS I2C End
#ifdef MAXIMITE
	if(SDActivityLED) {
		P_SD_LED_SET_HI;
		SDActivityLED--;
	} else
		P_SD_LED_SET_LO;
#endif
	
	if(SD_CD) SDCardRemoved = true;

	// check if the sound has expired
	if(SoundPlay > 0) {												// if we are still playing the sound
		SoundPlay--;
		if(SoundPlay == 0) {
			CloseTimer2();
#ifdef MAXIMITE
        CloseOC2();
#endif
#ifdef OLIMEX
        CloseOC1();
#endif
		}
	}		


	//////////////////////////////// keep track of the date and time ////////////////////////////////
	////////////////////////////////// this code runs once a second /////////////////////////////////
	if(++SecondsTimer >= 1000) {
		SecondsTimer = 0;											// reset every second
                if(S.ScreenSave){           //if screen saver is enabled count it down
                if(ScreenSaveTime >0)
                    ScreenSaveTime--;
                else
                mT3IntEnable(0);        // turn off video int
                }
                //if(ExtCurrentConfig[11] == EXT_FREQ_IN) { INT1Value = INT1Count; INT1Count = 0; }
		if(ExtCurrentConfig[5] == EXT_FREQ_IN) { INT2Value = INT2Count; INT2Count = 0; }
		if(ExtCurrentConfig[6] == EXT_FREQ_IN) { INT3Value = INT3Count; INT3Count = 0; }
		if(ExtCurrentConfig[7] == EXT_FREQ_IN) { INT4Value = INT4Count; INT4Count = 0; }
#ifdef MAXMITE
                if(++second >= 60) {										// keep track of the time and date
			second = 0 ;
			if(++minute >= 60) {
				minute = 0;
				if(++hour >= 24) {
					hour = 0;
					if(++day > DaysInMonth[month + ((month == 2 && (year % 4) == 0)?1:0)]) {
						day = 1;
						if(++month > 12) {
							month = 1;
							year++;
						}
					}
				}
			}
		}
#endif
        }

    // Clear the interrupt flag
    mT4ClearIntFlag();
    //return;
}
Exemple #11
0
/**
 * @function TmrSetFrequency
 * @brief configure a given timer with a desired frequency
 * @param tmr_t tmr_id: timer id
 * @param uint32_t desiredFrequency: desired frequency, in Hz
 * @return int8_t: 0 sucess, otherwise error
 */
int8_t TmrSetFrequency(tmr_t tmr_id, uint32_t desiredFrequency) {

  uint16_t tmrValue = 0xFFFF;
  uint16_t prescale;
  uint32_t cfg;
  int8_t res = -1;

  
    switch(tmr_id) {
    
      case TMR_1:
        if(SetTimerFrequency(TMR_TYPE_A, desiredFrequency, &tmrValue, &prescale) == 0) {
          TmrStop(TMR_1);
          mT1ClearIntFlag();
          ConfigIntTimer1(T1_INT_ON | T1_INT_PRIOR_1 | T1_INT_SUB_PRIOR_1);
          cfg = T1_SOURCE_INT | T1_IDLE_CON;
          if(prescale == 1) cfg |= T1_PS_1_1;
          else if(prescale == 8) cfg |= T1_PS_1_8;
          else if(prescale == 64) cfg |= T1_PS_1_64;
          else cfg |= T1_PS_1_256;
          OpenTimer1(cfg, tmrValue);
          timer1Configured = 1;
          res = 0;
        }
        break;
        
      case TMR_4:
        if(SetTimerFrequency(TMR_TYPE_B, desiredFrequency, &tmrValue, &prescale) == 0) {
          TmrStop(TMR_4);
          mT4ClearIntFlag();
          ConfigIntTimer4(T4_INT_ON | T4_INT_PRIOR_4 | T4_INT_SUB_PRIOR_1);
          cfg = T4_SOURCE_INT | T4_IDLE_CON;
          if(prescale == 1) cfg |= T4_PS_1_1;
          else if(prescale == 2) cfg |= T4_PS_1_2;
          else if(prescale == 4) cfg |= T4_PS_1_4;
          else if(prescale == 8) cfg |= T4_PS_1_8;
          else if(prescale == 16) cfg |= T4_PS_1_16;
          else if(prescale == 32) cfg |= T4_PS_1_32;
          else if(prescale == 64) cfg |= T4_PS_1_64;
          else cfg |= T4_PS_1_256;
          OpenTimer4(cfg, tmrValue);
          timer4Configured = 1;
          res = 0;
        }
        break;
        
      case TMR_5:
        if(SetTimerFrequency(TMR_TYPE_B, desiredFrequency, &tmrValue, &prescale) == 0) {
          TmrStop(TMR_5);
          mT5ClearIntFlag();
          ConfigIntTimer5(T5_INT_ON | T5_INT_PRIOR_5 | T5_INT_SUB_PRIOR_1);
          cfg = T5_SOURCE_INT | T5_IDLE_CON;
          if(prescale == 1) cfg |= T5_PS_1_1;
          else if(prescale == 2) cfg |= T5_PS_1_2;
          else if(prescale == 4) cfg |= T5_PS_1_4;
          else if(prescale == 8) cfg |= T5_PS_1_8;
          else if(prescale == 16) cfg |= T5_PS_1_16;
          else if(prescale == 32) cfg |= T5_PS_1_32;
          else if(prescale == 64) cfg |= T5_PS_1_64;
          else cfg |= T5_PS_1_256;
          OpenTimer5(cfg, tmrValue);
          timer5Configured = 1;
          res = 0;
        }
        break;
        
      default:
        break;
    }
  return res;
}
Exemple #12
0
/**
 * @function Timer4Handler
 * @brief Timer4 interruption handler
 * @param none
 * @return none
 */
void __ISR(_TIMER_4_VECTOR, ipl4) Timer4Handler(void) {
  tmr4PtrCallback();
  mT4ClearIntFlag();
}
Exemple #13
0
// Timer 4 interrupt processor. This fires every millisecond.
void __ISR (_TIMER_4_VECTOR, ipl1) T4Interrupt(void) {
    if (++cursor_timer > CURSOR_OFF + CURSOR_ON) cursor_timer = 0;
    rk86_video_update_cursor(1);
    // Clear the interrupt flag.
    mT4ClearIntFlag();
}
Exemple #14
0
//******************************************************************
//		STEPPER INTERRUPT
//******************************************************************
void __ISR( _TIMER_4_VECTOR, ipl2) T4Interrupt( void)
{
//XYZ-Axis step timer
//SBCode is 32bit containing step and direction for xyz and speed data
//SBCode Bits 7 XDir, 6 X, 5 YDir, 4 Y, 3 ZDir, 2 Z, 1 & 0 Not used
int mask;
unsigned char bit_pos = 0;
unsigned char xs,ys;

if(Manual_Mode_Set){
	switch(ManualStepperInt_Cycle)
	{
		case 0:	//set Direction
		{
			X_Dir = Set_X_Dir;
			Y_Dir = Set_Y_Dir;
			Z_Dir = Set_Z_Dir;
			PR4 = 5;
			ManualStepperInt_Cycle = 1;
			break;
		}
			
		case 1:
		{
			if(moveX){
				X_Step = 1;
				if(!Set_X_Dir) lSaveSteps_X += 1;
				else lSaveSteps_X -= 1;
			}
			else X_Step = 0;
			if(moveY){
				Y_Step = 1;
				if(!Set_Y_Dir) lSaveSteps_Y += 1;
				else lSaveSteps_Y -= 1;
			}
			else Y_Step = 0;
			if(moveZ){
				Z_Step = 1;
				if(! Set_Z_Dir) lSaveSteps_Z += 1;
				else lSaveSteps_Z -= 1;
			}
			else Z_Step = 0;
		   					
			PR4 = 10;	//Set the on Time
			ManualStepperInt_Cycle = 2;
			break;
		}
			
		case 2:
		{
			PR4 = Feed_Rate;
			X_Step = 0; Y_Step = 0; Z_Step = 0;	
			ManualStepperInt_Cycle = 0;
			break;
		}
	}
	TMR4 = 0;
	mT4ClearIntFlag();
}		
else
{	
	switch(StepperInt_Cycle)
	{
		case 0:	//Read in new code and set Direction
			if(!SBReady&&(SBR!=SBW))
			{ //ready and the buffer is not empty
				SBCode =  SCB[ SBR];  //Read buffer
				SCB[ SBR] = 0x00;    //once read, set to zero 
				SBR++;  
				SBR %= SB_SIZE;
    			SBReady = 1;    //Step byte consumed - ready to take another byte
 			
 				mask = 0x08000000;
 				bit_pos = 3;
				do // Unpack the code into axis Step and Dir
				{	
  					if ( SBCode & mask )
   					{
	   					switch(bit_pos)
		   				{
		   				//set 1's in code
		   					case 3: Z_Dir  = 1; break;
		   					case 5: Y_Dir  = 1; break;
		   					case 7: X_Dir  = 1; break;
		   				}	
   					}
   					else
	   				{
	   					switch(bit_pos)
		   				{
		   				//set 0's in code
		   					case 3: Z_Dir  = 0; break;
		   					case 5: Y_Dir  = 0; break;
		   					case 7: X_Dir  = 0; break;
		   				}	
	   				}	
   					bit_pos += 2;
   					mask <<= 2;
 				}  
   			 	while (mask !=0);
			}		
			PR4 = 5;
			StepperInt_Cycle = 1;
			break;
						
		case 1:
			if (SBReady)
			{
				mask = 0x04000000;
 				bit_pos = 2;
				do // Unpack the code into axis Step and Dir
				{	
  					if ( SBCode & mask )
   					{
	   					switch(bit_pos)
		   				{
		   				//set 1's in code
		   					case 2: Z_Step = 1; break;
		   					case 4: Y_Step = 1; ys = 1; break;
		   					case 6: X_Step = 1; xs = 1; break;
		   				}	
   					}
   					else
	   				{
	   					switch(bit_pos)
		   				{
		   				//set 0's in code
		   					case 2: Z_Step = 0; break;
		   					case 4: Y_Step = 0; ys=0; break;
		   					case 6: X_Step = 0; xs=0; break;
		   				}	
	   				}	
   					bit_pos += 2;
   					mask <<= 2;
 				}  
   			 	while (mask !=0);
			}
			PR4 = 10;	//Set the on Time
			StepperInt_Cycle = 2;
			break;
				
		case 2:
			if (SBReady)
			{
				mask = 0xFFFF; //to return the bottom two bytes
				PR4_Setting = SBCode & mask;
				PR4 = PR4_Setting;	//Set the off time
			}
			else
				PR4 = 5000;
			
			X_Step = 0; Y_Step = 0; Z_Step = 0;	//turn off step pulse
			StepperInt_Cycle = 0;
			SBReady = 0;//code taken from buffer
			SBCode = 0;
			break;	
	}

	TMR4 = 0;
	mT4ClearIntFlag();
	}		
}//T4Interrupt
Exemple #15
0
// DATA reading ISR
void __ISR(_TIMER_4_VECTOR, ipl7auto) HW_read_bit(void)
{
    static unsigned long count= 0L;
    unsigned int time;
    static char out, previous= -1;
    BYTE i, *p;
    BOOL fskread= FALSE;

    // show trigger moment (you must also set end of routine debugger statement)
    //DEBUG_PIN_2= HIGH;

    // reset interrupt
    mT4ClearIntFlag();

    // toggle bit period flag for analogue sampler
    ReaderPeriod= !ReaderPeriod;

    if(FakeRead)
        return;


    // don't do anything unless we've got data to read - we may have been left running due to higher level error.
    if(!HW_Bits)
    {
        stop_HW_reader_ISR();
        return;
    }

    // debugging - monitor with a logic analyser
    // show data value
    //DEBUG_PIN_3= READER_DATA;

    switch(RFIDlerConfig.Modulation)
    {
        case MOD_MODE_ASK_OOK:

            // get current bit value
            out= READER_DATA;

            // check for manchester encoding sync/errors
            if(RFIDlerConfig.Manchester && count)
            {
                // the 2nd half bit may not be equal to the 1st
                // this error is allowed to occur exactly once, in which case we
                // are out of sync so we slip timing by half a bit
                if(count % 2 && out == previous)
                {
                    //DEBUG_PIN_4= !DEBUG_PIN_4;
                    // error LED on
                    mLED_Error_On();
                    if(Manchester_Error)
                    {
                        //DEBUG_PIN_4= !DEBUG_PIN_4;
                        // 2 strikes and we fail!
                        count= 0L;
                        previous= -1;
                        Manchester_Auto_Correct= FALSE;
                        stop_HW_reader_ISR();
                        return;
                    }
                    else
                    {
                        //DEBUG_PIN_4= !DEBUG_PIN_4;
                        // 1st error - reset data and start again, now offset by a half bit.
                        Manchester_Error= TRUE;
                        //DEBUG_PIN_2= LOW;

                        // special case - if tag can start with a '0' (i.e. there is no initial '1' as a sync
                        // bit, it will look like a 1/2 bit error, but we may only detect the error later on,
                        // so we must correct all the previous mis-reads, offset the count by 1/2 a bit and
                        // complete this read
                        if(Manchester_Auto_Correct && count != 1)
                        {
                            for(i= 0, p= EMU_Data ; i <= count / 2L ; ++i, --p)
                                *p= !*(p);
                            --count;
                        }
                        else
                        {
                            EMU_Data -= (count / 2L);
                            count= 1L;
                            // successful read resets timeout
                            WriteTimer5(0);
                            return;
                        }
                    }
                }
            }
            
            // now set data bit

            // biphase is 1 if mid-bit change or 0 if no mid-bit change
            if(RFIDlerConfig.BiPhase && count % 2L)
            {
                if(previous == out)
                    *(EMU_Data++)= 0x00 ^ RFIDlerConfig.Invert;
                else
                    *(EMU_Data++)= 0x01 ^ RFIDlerConfig.Invert;
               //DEBUG_PIN_1= *(EMU_Data - 1);
               // successful read resets timeout
               WriteTimer5(0);
            }

            // read data direct for normal ASK
            if(!RFIDlerConfig.Manchester && !RFIDlerConfig.BiPhase)
            {
                //DEBUG_PIN_1= out;
                *(EMU_Data++)= out ^ RFIDlerConfig.Invert;
                // successful read resets timeout
                WriteTimer5(0);
            }

            // read only 2nd half of bit if manchester
            if (RFIDlerConfig.Manchester && count % 2L)
            {
                //DEBUG_PIN_1= out;
                // always invert as we are now reading 2nd half bit, so opposite value
                *(EMU_Data++)= !(out ^ RFIDlerConfig.Invert);
                // successful read resets timeout
                WriteTimer5(0);
            }

            previous= out;

            break;

        case MOD_MODE_FSK1:
        case MOD_MODE_FSK2:
            // to read FSK we will measure a pulse width. we must stop before end of bit period so we don't
            // get caught by the next interrupt. accordingly our time period is shortened by 20%, but
            // that should be OK as we only need to see a single pulse.
            //DEBUG_PIN_4= !DEBUG_PIN_4;
            //time= CONVERT_TO_TICKS(RFIDlerConfig.FrameClock * (RFIDlerConfig.DataRate - (RFIDlerConfig.DataRate / 5)));
            time= RFIDlerConfig.FrameClock * (RFIDlerConfig.DataRate - (RFIDlerConfig.DataRate / 5));
            GetTimer_us(RESET);
            // measure 2nd pulse
            while(GetTimer_us(NO_RESET) < time && !fskread)
            {
              fskread= TRUE;
              //DEBUG_PIN_4= !DEBUG_PIN_4;
                // skip to first pulse
              while(READER_DATA)
                    if(GetTimer_us(NO_RESET) > time)
                    {
                        fskread= FALSE;
                        break;
                    }
                while(!READER_DATA)
                    if(GetTimer_us(NO_RESET) > time)
                    {
                        fskread= FALSE;
                        break;
                    }
                // skip first pulse
                while(READER_DATA)
                    if(GetTimer_us(NO_RESET) > time)
                    {
                        fskread= FALSE;
                        break;
                    }
                while(!READER_DATA)
                    if(GetTimer_us(NO_RESET) > time)
                    {
                        fskread= FALSE;
                        break;
                    }
                // measure second pulse
                GetTimer_us(RESET);
                //DEBUG_PIN_4= !DEBUG_PIN_4;
                while(READER_DATA)
                    if(GetTimer_us(NO_RESET) > time)
                    {
                        fskread= FALSE;
                        break;
                    }
            }
            //DEBUG_PIN_4= !DEBUG_PIN_4;
            // successful read resets timeout
            if(fskread)
                *(EMU_Data++)= GetTimer_us(RESET); // get pulsewidth in uS
            break;

        // TODO: PSK2, PSK3
        case MOD_MODE_PSK1:
            // READER_DATA goes high when a phase change occurs
            // we toggle bit value on phase change

            // data line should go high at start of bit period, but to allow for some lag
            // we will wait for up to a full frame clock just to be sure
            time= CONVERT_TO_TICKS(RFIDlerConfig.FrameClock);
            WriteTimer5(0);
            while(ReadTimer5() < time)
                if(READER_DATA)
                    break;

            // show toggle output
            //DEBUG_PIN_1 ^= READER_DATA;

            // get data
            out ^= (READER_DATA ^ RFIDlerConfig.Invert);

            // test read quality - pulsewidth wil be short if tag not correctly coupled
            if(PSK_Min_Pulse && READER_DATA)
            {
                // fast reset timer
                WriteTimer5(0);
                //DEBUG_PIN_1 ^= 1;
                while(READER_DATA)
                    ;
                time= GetTimer_us(NO_RESET);
                if(time < PSK_Min_Pulse)
                    PSK_Read_Error= 1;
                //DEBUG_PIN_1 ^= 1;
            }

            *(EMU_Data++)= out;
            // successful read resets timeout
            WriteTimer5(0);
            break;
            
        default:
            break;
    }

    ++count;

    // debugging - reset output line
    //DEBUG_PIN_2= LOW;

    // finished?
    if(count == HW_Bits)
    {
        HW_Bits= count= 0L;
        previous= -1;
        // if only 1 manchester error caught, that's OK
        Manchester_Error= FALSE;
        // caller must reset this to use again
        Manchester_Auto_Correct= FALSE;
        mLED_Error_Off();
        // stop reading, but leave clock running to preserve tag state - higher level will shut down when done
        stop_HW_reader_ISR();
    }
}