;******************************************************************************* ;** ;** RFID reader section, generate 150KHz carrier frequency ;** and decode the basic data stream ;** ;** Written by Rick Huang, Copyright (C) 2007 ;** Revision YYYY/MM/DD ;** Rev 1. 2007/04/29 - Initial release ;** ;** Command Functions ;** '1' Initialize local LCD display ;** '2' Send Command to local Display ;** '3' Send String to Local Display ESC to break ;** '4' Hex test - echo any hex input ;** '7' Send command and data on iWire bus - Format: ;** 7 ;** '8' Send string on iWire bus - break when ESC is detected ;** 8 ;** ;** This program is free software; you can redistribute it and/or modify ;** it under the terms of the GNU General Public License as published by ;** the Free Software Foundation; either version 2 of the License, or ;** (at your option) any later version. ;** ;** This program is distributed in the hope that it will be useful, ;** but WITHOUT ANY WARRANTY; without even the implied warranty of ;** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;** GNU General Public License for more details. ;** ;** You should have received a copy of the GNU General Public License ;** along with this program; if not, write to the Free Software ;** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;******************************************************************************* ;**************************************************************************** ;** NOTE: Disable the WDT when debugging the code, however, make sure ;** the WDT is enabled when putting the system into lift time test ;** The timeout for WDT is about 2 seconds with 128:1 prescaler ;**************************************************************************** include __config _HS_OSC & _WDT_ON & _LVP_OFF & _BODEN_ON & _MCLRE_ON & _PWRTE_ON ;***************************************************************** ;** Variables TempW EQU 70h ; BitLocation EQU 71h CounterB EQU 72h NextFSR EQU 73h ; CounterW EQU 74h BitCount EQU 75h LastBitVal EQU 76h Data0 EQU 77h ; Final data output Data1 EQU 78h Data2 EQU 79h Data3 EQU 7ah Data4 EQU 62h Zero EQU 7bh ; Zero is 0x00 SerData EQU 7ch Temp EQU 7dh Output EQU 7eh Counter EQU 7fh TMRsample EQU 60h BinCnt EQU 61h Toggle EQU 63h #define _DIN PORTB, 7 ; Incoming data from 1wire bus #define _DOUT PORTB, 6 ; Outgoing data to the 1wire bus #define _MUX PORTB, 5 ; Select the multiplexer #define _DE PORTB, 4 ; Debug port #define DecisionVal d'170' ;Hard decision, 0 = 159 cycle, 1 = 198 cycle ;***************************************************************** ;** Program code here goto Start ORG 4 ;waiting for <0004> ;interrupt vector ;goto Interrupt ORG 5 ;***************************** DATA StringStart: PWelcomeMsg: addwf PCL, F DT "Welcome!" DT H'0d', H'0a', H'00' PCommandMsg: DT "Command Error?" DT H'0d', H'0a', H'00' PParameterMsg: DT "Parameter Error?" DT H'0d', H'0a', H'00' PNoAckMsg: DT "Missing Ack" DT H'0d', H'0a', H'00' StringEnd: WelcomeMsg EQU 0 CommandMsg EQU PCommandMsg - 1 - 5 ; 5 is the offset where the ParameterMsg EQU PParameterMsg - 1 - 5 ; Strings start NoAckMsg EQU PNoAckMsg - 1 - 5 HexTable: addwf PCL, F DT "0123456789ABCDEF" ;***************************************************************** ;******************** Program Starts here Start: ;********************* Setup WDT ;********************** Setting up TMR0, used to decode FSK clrwdt bsf STATUS, RP0 movlw b'00001111' ;Prescaler to WDT, 1:128 movwf OPTION_REG clrwdt ;********************* Setting up environment movlw b'10000010' ;Serial port in too movwf TRISB ;Set port B I/O movlw b'00000111' movwf TRISA ;Set port A I/O bcf STATUS, RP0 clrf PORTA ;********************** Disable 16f628 specific features movlw b'00000110' ;Setup comparator movwf CMCON ;********************** Setting up PWM module for 150KHz signal movlw b'00001100' ;Enable PWM module, duty = 2 movwf CCP1CON movlw b'00000010' ;Using source frequency = 12MHz movwf CCPR1L movlw b'00000101' ;Setting up TMR2, Prescale = 1:4 movwf T2CON bsf STATUS, RP0 movlw b'00000100' movwf PR2 ;Setting the period = 4 bcf STATUS, RP0 ;********************** Setup UART bsf STATUS, RP0 movlw d'12' ;57600 for 12MHz Clock, High speed movwf SPBRG ;The only rate with low mismatch movlw b'10100111' ;Async 8-bit @ High speed movwf TXSTA bcf STATUS, RP0 movlw b'10110000' ;Enable serial port movwf RCSTA clrf Zero movlw WelcomeMsg ;Display welcome string on startup call SendString ;----------------------- Debug insert goto SkipDebug movlw 0a0h movwf FSR movlw b'00000011' movwf INDF incf FSR, F movlw b'11111111' movwf INDF incf FSR, F movlw b'11111100' movwf INDF incf FSR, F movlw b'00011111' movwf INDF incf FSR, F movlw b'10000001' movwf INDF incf FSR, F movlw b'11110000' movwf INDF incf FSR, F movlw b'00111110' movwf INDF incf FSR, F movlw b'00000111' movwf INDF incf FSR, F goto FD_DecodeEntry SkipDebug: ;----------------------- Wait for command WaitMore: clrwdt btfsc RCSTA, OERR goto ClearError btfss PIR1, RCIF goto WaitMore movfw RCREG movwf SerData movwf TXREG ;Send it back out call SSpace movlw '1' ;Decode command xorwf SerData, W btfsc STATUS, Z goto AttemptSample ;Start a RFID sample movlw '2' xorwf SerData, W btfsc STATUS, Z goto DebugSample ;Debug run, output sampled data movlw '3' xorwf SerData, W btfsc STATUS, Z goto FullDecode ;Fully capture and decode data movlw '4' xorwf SerData, W btfsc STATUS, Z goto HexTest ;Testing HEX routine movlw '5' xorwf SerData, W btfsc STATUS, Z goto BinTest ;Testing Bin dump routine movlw '6' xorwf SerData, W btfsc STATUS, Z goto DummyNow ;Not in use movlw '7' xorwf SerData, W btfsc STATUS, Z goto DummyNow movlw '8' xorwf SerData, W btfsc STATUS, Z goto DummyNow DummyNow: ;For all command not in use movlw CommandMsg call SendString ;Send error command message goto WaitMore ;********************* Clear receving overrun error ClearError: movfw RCREG movfw RCREG bcf RCSTA, CREN bsf RCSTA, CREN goto WaitMore ;---------------------- Commands execution AttemptSample: ;Command 1: Sample RFID data, do 1024 bits call CompCheck ;Dummy read once to setup condition movlw 0a0h movwf FSR ;Use FSR to store data movlw d'80' ;Do this for 80 bytes movwf Counter SampleLoop1: call CaptureByte incf FSR, F ;A byte is full, move to the next one decfsz Counter, F goto SampleLoop1 ;---------------------- Switch memory bank movlw 020h movwf FSR ;Use FSR to store data movlw d'64' ;Do this for 64 bytes movwf Counter SampleLoop2: call CaptureByte incf FSR, F ;A byte is full, move to the next one decfsz Counter, F goto SampleLoop2 ;---------------------- Data is full, now dump the data out movlw d'80' ;Do this for 80 bytes movwf Counter movlw 0a0h movwf FSR ;Use FSR to access data SampleLoop10: movfw INDF call SendBin incf FSR, F decfsz Counter, F goto SampleLoop10 ;---------------------- Switch bank movlw d'64' ;Do this for 64 bytes movwf Counter movlw 020h movwf FSR ;Use FSR to access data SampleLoop11: movfw INDF call SendBin incf FSR, F decfsz Counter, F goto SampleLoop11 call NewLine goto WaitMore ;*********************** Command 2 Debug mode DebugSample: ;Command 2: Sample RFID data, debug mode call CompCheck ;Dummy read once to setup condition movlw 0a0h movwf FSR ;Use FSR to store data movlw d'80' ;Do this for 80 bytes movwf Counter DebugSLoop1: call CompCheck movfw TMRsample movwf INDF incf FSR, F ;A byte is full, move to the next one decfsz Counter, F goto DebugSLoop1 ;---------------------- Switch memory bank movlw 020h movwf FSR ;Use FSR to store data movlw d'64' ;Do this for 64 bytes movwf Counter DebugSLoop2: call CompCheck movfw TMRsample movwf INDF incf FSR, F ;A byte is full, move to the next one decfsz Counter, F goto DebugSLoop2 ;---------------------- Data is full, now dump the data out movlw d'80' ;Do this for 80 bytes movwf Counter movlw 0a0h movwf FSR ;Use FSR to access data DebugSLoop10: movfw INDF call SendHex call NewLine incf FSR, F decfsz Counter, F goto DebugSLoop10 ;---------------------- Switch bank movlw d'64' ;Do this for 64 bytes movwf Counter movlw 020h movwf FSR ;Use FSR to access data DebugSLoop11: movfw INDF call SendHex call NewLine incf FSR, F decfsz Counter, F goto DebugSLoop11 call NewLine goto WaitMore ;*********************** Command 3 Full capture and decode FullDecode: ;Wait for start sequence, than start capture call CompCheck ;Dummy read once to setup condition call WaitTillStart ;Wait for start movlw 0a0h movwf FSR ;Use FSR to store data movlw d'80' ;Do this for 80 bytes movwf Counter FDLoop1: call CaptureByte incf FSR, F ;A byte is full, move to the next one decfsz Counter, F goto FDLoop1 ;---------------------- Data is full, now dump the data out movlw d'80' ;Do this for 80 bytes movwf Counter movlw 0a0h movwf FSR ;Use FSR to access data FDLoop10: movfw INDF call SendBin incf FSR, F decfsz Counter, F goto FDLoop10 call NewLine FD_DecodeEntry: ;---------------------- Collaspe data bits movlw d'8' ;Set up for bit read movwf BitLocation movlw 0a0h movwf NextFSR ;---------------------- Start extraction clrf Data0 ;Clear data holder clrf Data1 clrf Data2 clrf Data3 clrf Data4 clrf Toggle FD_BitLoopZ: call GetBitCount movfw BitCount movlw d'20' subwf BitCount, W btfsc STATUS, C goto FD_DoneDecode ; Bitcount - 15 = Positive, Looped already, STOP movlw d'7' subwf BitCount, W btfss STATUS, C goto FD_Send2bit ;Negative, 1 bits movlw '*' ;Positive, 2 bit call SendChar call SendChar bsf STATUS, C call LongShift call LongShift goto FD_NextBit FD_Send2bit: movlw '_' call SendChar bcf STATUS, C call LongShift FD_NextBit: movlw 0efh subwf NextFSR, W ;NextFSR - W btfss STATUS, C goto FD_BitLoopZ ;Negative, keep looping call NewLine ;Positive, NextFSR > 0xef ;----------------------- Final data output FD_DoneDecode: call NewLine movfw Data4 call SendHex movfw Data3 call SendHex movfw Data2 call SendHex movfw Data1 call SendHex movfw Data0 call SendHex call NewLine goto WaitMore ;*********************** Command 4,5 Serial debug HexTest: call RcvHex ;Command 4: Hex test movfw Output call SendHex call NewLine goto WaitMore BinTest: call RcvHex ;Command 5: Bin test movfw Output call SendBin call NewLine goto WaitMore ;***************************** SUBROUTINE ;----------------------------------------------------------------- ; LongShift, Shift 1 bit of the data into Data[0:4] register ; Shift only 1 bit per two calls ; Input: C LongShift: btfss Toggle, 0 goto ToggleNotSet rlf Data0, F rlf Data1, F rlf Data2, F rlf Data3, F rlf Data4, F bcf Toggle, 0 return ToggleNotSet: bsf Toggle, 0 return ;----------------------------------------------------------------- ; CaptureByte, Capture a single byte of data ; Output: INDF CaptureByte: call CompCheck movlw DecisionVal ;Hard decision, 0 = 159 cycle, 1 = 198 cycle subwf TMRsample, W rlf INDF, F ;Store the data into pointed address call CompCheck ;Do this for 8 times to fill up a byte movlw DecisionVal subwf TMRsample, W rlf INDF, F call CompCheck movlw DecisionVal subwf TMRsample, W rlf INDF, F call CompCheck movlw DecisionVal subwf TMRsample, W rlf INDF, F call CompCheck movlw DecisionVal subwf TMRsample, W rlf INDF, F call CompCheck movlw DecisionVal subwf TMRsample, W rlf INDF, F call CompCheck movlw DecisionVal subwf TMRsample, W rlf INDF, F call CompCheck movlw DecisionVal subwf TMRsample, W rlf INDF, F return ;----------------------------------------------------------------- ; WaitTillStart, Wait until the start sequence is detected ; This is marked by 20 or more zeros WaitTillStart: movlw d'20' movwf CounterW WTS_next: call CompCheck movlw DecisionVal subwf TMRsample, W btfsc STATUS, C ;Check for a 0 value goto WaitTillStart ;If 1, restart decfsz CounterW, F goto WTS_next ;Loop until done return ;----------------------------------------------------------------- ; CompCheck, Check the comparator output and store the informtion in ; Output: TMRsample CompCheck: ;Process: Loop until a transition, clear TMR0, ;wait till next 0-1 transition SCSampleL3: btfsc CMCON, C1OUT goto SCSampleL3 SCSampleL2: ;Was a low, wait for a high btfss CMCON, C1OUT goto SCSampleL2 movfw TMR0 movwf TMRsample ;Store the result in TMRsample clrf TMR0 ;Clear TMR0 for the next bit return ;----------------------------------------------------------------- ; GetBitCount, Count number of bits until the next change ; Output: BitCount ; Address: BitLocation, NextFSR ; Use: LastBitVal, BitCount, NextFSR, BitLocation, TempW GetBitCount: clrf BitCount btfss LastBitVal, 0 goto GBC_lastbit0 ; goto GBC_lastbit1 ;Last bit is a 1 GBC_loop1: call GetNextBit btfss STATUS, Z goto GBC_done1 incf BitCount, F ;Continue if value is a zero goto GBC_loop1 GBC_done1: ;Done if bit change to one bcf LastBitVal, 0 return GBC_lastbit0: ;Last bit is a 0 GBC_loop0: call GetNextBit btfsc STATUS, Z goto GBC_done0 incf BitCount, F ;Continue if value is a one goto GBC_loop0 GBC_done0: ;Done if bit change to one bsf LastBitVal, 0 return ;----------------------------------------------------------------- ; GetNextBit, Get a bit from the buffer ; Output: Z ; Address: BitLocation, NextFSR, BitLocation = 1 for LSB GetNextBit: movfw NextFSR movwf FSR movfw BitLocation movwf CounterB decfsz BitLocation, F ;Go to the next bit goto GNB_nextStep movlw d'8' movwf BitLocation incf NextFSR, F ;Rollover for the next read GNB_nextStep: clrf TempW bsf STATUS, C GNB_loop: rlf TempW, F ;TempW contain bit mask decfsz CounterB, F goto GNB_loop movfw TempW andwf INDF, W ;Result in Z return ;***************************** SUBROUTINE ;----------------------------------------------------------------- ; SendHex, Send a single byte out of serial port, hex format ; Input: data stored in W SendHex: movwf Temp swapf Temp, W andlw 00fh call HexTable HexWaitLoop1: btfss PIR1, TXIF ;Wait till buffer is empty goto HexWaitLoop1 movwf TXREG movf Temp, W andlw 00fh call HexTable HexWaitLoop2: btfss PIR1, TXIF ;Wait till buffer is empty goto HexWaitLoop2 movwf TXREG return ;----------------------------------------------------------------- ; SendBin, Send a single byte out of serial port, binary format ; Input: data stored in W SendBin: movwf Temp movlw 8h movwf BinCnt BinWaitLoop1: btfss PIR1, TXIF ;Wait till buffer is empty goto BinWaitLoop1 movlw '0' btfsc Temp, 7 movlw '1' movwf TXREG rlf Temp, F decfsz BinCnt, F goto BinWaitLoop1 return ;----------------------------------------------------------------- ; RcvHex, Receive a single byte from serial port in hex format ; Output: data stored in Output RcvHex: btfss PIR1, RCIF goto RcvHex movfw RCREG movwf SerData movwf TXREG ; Send it back out movlw 30h subwf SerData, F movlw 10h subwf SerData, W ; F - W btfsc STATUS, C ; Positive means letter input goto Letter1 RtnLetter1: swapf SerData, W movwf Output RcvHexLoop: btfss PIR1, RCIF goto RcvHexLoop movfw RCREG movwf SerData movwf TXREG ; Send it back out movlw 30h subwf SerData, F movlw 10h subwf SerData, W ; F - W btfsc STATUS, C ; Positive means letter input goto Letter2 RtnLetter2: movfw SerData iorwf Output, F call SSpace return Letter1: movlw 07h subwf SerData, F movlw 10h subwf SerData, W btfsc STATUS, C ; Positive means bad input goto Letter1E goto RtnLetter1 Letter1E: movlw d'32' subwf SerData, F goto RtnLetter1 Letter2: movlw 07h subwf SerData, F movlw 10h subwf SerData, W btfsc STATUS, C ; Positive means bad input goto Letter2E goto RtnLetter2 Letter2E: movlw d'32' subwf SerData, F goto RtnLetter2 ;----------------------------------------------------------------- ; LongDelay, 15 cycles, 3ins/cycle 22.5uS for 8Mhz clock long_delay: movlw d'15' movwf Counter long_delay_L: decfsz Counter, F goto long_delay_L return ;----------------------------------------------------------------- ; SendString, send the string out to serial port ; Input: String location in W SendString: movwf Counter SendLoop: btfss PIR1, TXIF ;Wait till buffer is empty goto SendLoop call StringStart iorwf Zero, W btfsc STATUS, Z ;Zero is the end of string return movwf TXREG incf Counter, F movfw Counter goto SendLoop ;----------------------------------------------------------------- ; NewLine, send s newline character into serial port ; Input: None NewLine: btfss PIR1, TXIF ;Wait till buffer is empty goto NewLine movlw 0dh movwf TXREG movlw 0ah NewLineLoop: btfss PIR1, TXIF ;Wait till buffer is empty goto NewLineLoop movwf TXREG return ;----------------------------------------------------------------- ; Space, send a space character into serial port ; Input: None SSpace: btfss PIR1, TXIF ;Wait till buffer is empty goto SSpace movlw ' ' movwf TXREG return ;----------------------------------------------------------------- ; SendChar, send a character into serial port ; Input: W SendChar: btfss PIR1, TXIF ;Wait till buffer is empty goto SendChar movwf TXREG return ;----------------------------------------------------------------- ; End of program end