/********************************************************************* * Function: void InitSymbolTimer() * * PreCondition: none * * Input: none * * Output: none * * Side Effects: TMR0 for PIC18 is configured for calculating * the correct symbol times. TMR2/3 for PIC24/dsPIC * is configured for calculating the correct symbol * times * * Overview: This function will configure the UART for use at * in 8 bits, 1 stop, no flowcontrol mode * * Note: The timer interrupt is enabled causing the timer * roll over calculations. Interrupts are required * to be enabled in order to extend the timer to * 4 bytes in PIC18. PIC24/dsPIC version do not * enable or require interrupts ********************************************************************/ void InitSymbolTimer() { #if defined(__18CXX) TMR_CON = 0b00000000 | CLOCK_DIVIDER_SETTING; TMR_IP = 1; TMR_IF = 0; TMR_IE = 1; TMR_ON = 1; timerExtension1 = 0; timerExtension2 = 0; #elif defined(__dsPIC30F__) || defined(__dsPIC33F__) || defined(__PIC24F__) || defined(__PIC24FK__) || defined(__PIC24H__) T2CON = 0b0000000000001000 | CLOCK_DIVIDER_SETTING; T2CONbits.TON = 1; #elif defined(__PIC32MX__) #if defined (SECOND_PROTOTYPE) //Timer 3 freed for ADC rjk CloseTimer4(); WriteTimer4(0x00); WriteTimer5(0x00); WritePeriod5(0xFFFF); OpenTimer4((T4_ON|T4_32BIT_MODE_ON|CLOCK_DIVIDER_SETTING),0xFFFFFFFF); #else CloseTimer2(); WriteTimer2(0x00); WriteTimer3(0x00); WritePeriod3(0xFFFF); OpenTimer2((T2_ON|T2_32BIT_MODE_ON|CLOCK_DIVIDER_SETTING),0xFFFFFFFF); #endif #else #error "Symbol timer implementation required for stack usage." #endif }
// low level pulse timer - return prescaled ticks converted back to a long unsigned long GetTimer_ticks(BYTE reset) { unsigned long time; time= ReadTimer5(); if(reset) WriteTimer5(0); return time * TIMER5_PRESCALER; }
// low level pulse timer unsigned int GetTimer_us(BYTE reset) { unsigned int time; time= ReadTimer5(); if(reset) WriteTimer5(0L); return time / TimeScaler; }
void fis_Timer5_config(unsigned int period){ // 7654321076543210 unsigned int config = 0b1000000000110000; //T4_ON & T4_GATE_ON & T4_IDLE_CON & T4_PS_1_1 & T4_SOURCE_INT; // 7654321076543210 //unsigned int period = 0b0000000000000111; WriteTimer5(0x0000); OpenTimer5( config, period ); //ConfigIntTimer5(T5_INT_ON & T5_INT_PRIOR_1); EnableIntT5; //printf("t5_config\n"); }
// 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(); } }
// Reader clock ISR // also process RWD commands while we toggle clock line void __ISR(_OUTPUT_COMPARE_5_VECTOR, ipl6auto) reader_clock_tick (void) { static unsigned int count= 0; static unsigned int bcount= 0; // Clear interrupt flag mOC5ClearIntFlag(); mLED_Clock_On(); // process RWD commands (if any) switch (RWD_State) { case RWD_STATE_INACTIVE: case RWD_STATE_ACTIVE: //DEBUG_PIN_4= !DEBUG_PIN_4; break; case RWD_STATE_GO_TO_SLEEP: //DEBUG_PIN_4= !DEBUG_PIN_4; //DEBUG_PIN_4= !DEBUG_PIN_4; // initial shutdown of coil to restart tag READER_CLOCK_ENABLE_OFF(); COIL_OUT_LOW(); // time small amounts with ticks, large with uS if(RWD_Sleep_Period > MAX_TIMER5_TICKS) Delay_us(CONVERT_TICKS_TO_US(RWD_Sleep_Period)); else { WriteTimer5(0); while(GetTimer_ticks(NO_RESET) < RWD_Sleep_Period) ; } count= 0; RWD_State= RWD_STATE_WAKING; // restart clock only if we have a wake period if(RWD_Wake_Period) READER_CLOCK_ENABLE_ON(); break; case RWD_STATE_WAKING: //DEBUG_PIN_4= !DEBUG_PIN_4; // leave coil running for wakeup period if(count == RWD_Wake_Period) { count= 0; bcount = 0; if(*RWD_Command_ThisBit != '*') RWD_State= RWD_STATE_START_SEND; else RWD_State= RWD_STATE_ACTIVE; } else count++; break; case RWD_STATE_START_SEND: //DEBUG_PIN_4= !DEBUG_PIN_4; // send initial gap // stop modulation of coil and wait READER_CLOCK_ENABLE_OFF(); COIL_OUT_LOW(); count= 0; if(RWD_Barrier) RWD_State= RWD_STATE_SENDING_BARRIER_LOW; else RWD_State= RWD_STATE_SENDING_BIT_LOW; //DEBUG_PIN_4= !DEBUG_PIN_4; // restart clock //READER_CLOCK_ENABLE_ON(); break; case RWD_STATE_SENDING_BIT_HIGH: //DEBUG_PIN_4= !DEBUG_PIN_4; // clock running for bit period, then wait for gap period if((*RWD_Command_ThisBit && count == RWD_One_Period) || (!*RWD_Command_ThisBit && count == RWD_Zero_Period)) { count= 0; if(*RWD_Command_ThisBit == '*') RWD_State= RWD_STATE_POST_WAIT; else if(RWD_Barrier && bcount == 7) RWD_State= RWD_STATE_SENDING_BARRIER_LOW; else RWD_State= RWD_STATE_SENDING_BIT_LOW; READER_CLOCK_ENABLE_OFF(); COIL_OUT_LOW(); bcount++; if(bcount == 8) bcount = 0; } else count++; break; case RWD_STATE_SENDING_BIT_LOW: if((*RWD_Command_ThisBit && count == RWD_One_Gap_Period) || (!*RWD_Command_ThisBit && count == RWD_Zero_Gap_Period)) { ++RWD_Command_ThisBit; count= 0; RWD_State= RWD_STATE_SENDING_BIT_HIGH; // restart clock READER_CLOCK_ENABLE_ON(); } else count++; break; case RWD_STATE_SENDING_BARRIER_HIGH: if(count == RWD_One_Barrier_Period){ count= 0; RWD_State= RWD_STATE_SENDING_BIT_LOW; READER_CLOCK_ENABLE_OFF(); COIL_OUT_LOW(); }else count++; break; case RWD_STATE_SENDING_BARRIER_LOW: if(count == RWD_Zero_Barrier_Period){ count= 0; RWD_State= RWD_STATE_SENDING_BARRIER_HIGH; READER_CLOCK_ENABLE_ON(); }else count++; break; case RWD_STATE_POST_WAIT: //DEBUG_PIN_4= !DEBUG_PIN_4; // coil running for forced post-command wait period if(count == RWD_Post_Wait) { count= 0; RWD_State= RWD_STATE_ACTIVE; } else count++; break; default: break; } }
// raw timer wait - for things that don't want any delays... // 1us == x timer ticks where x is what MHz chip is running at (e.g. 80 for 80MHz) // note that we reset on the way out to ensure external code action is included in // the timing. void TimerWait(unsigned long ticks) { while (ReadTimer5() < ticks) ; WriteTimer5(0); }