; TIRIS2.ASM
; TIRIS reader with external amplifier
; AT90S1200 processor , 12.00 MHz XTAL
; RS232 out 10 bytes data+crc, 2 bytes CRC checksum result
; combined TX/RX-coil
;
.device at90s1200
.nolist
.include "1200def.inc"
.list
; hardware connections:
; PORTD,0 : CRC-LED : low if CRC check OK
; PORTD,1 : INT-HANDLER active = high
; PORTD,2 : bit sample time
; PORTD,3 : TX output
; PORTD,4 : RS232 direct OUT to PC without inverting buffer !
; PORTD,5 : CTRL-PIN : status of progress
; PORTD,6 : TX-PIN : high if TX is on
.equ threshold = 27 ; level for low/high decision
; start/stop-byte accepted are : R/W-transponder : $FE
; R/O-transponder : $7E
.equ start_byte1=$7E ;
.equ stop_byte1=start_byte1
.equ start_byte2=$FE
.equ stop_byte2=start_byte2
.def zero =r0
.def CLKcnt =r1
.def mail =r2 ; bit 0: contents , bit 1: signal mail_there
.def FIR0 = r3
.def FIR1 = r4
.def FIR2 = r5
.def FIR3 = r6
.def BITcnt= r7
; r8..r17=buffer !! pointed to by ZL in getBYTE
; r18+r19=buffer and CRC16
; const poly=$1021 ;
; var crc16:word ;
;
;procedure add_bit(b:integer) ;
;var xor_value:word ;
;begin
;if (crc16 and $8000)<>0
; then xor_value:=poly
; else xor_value:=0 ;
;crc16:=((crc16 shl 1)+b ) xor xor_value ;
;end ;
.def CRC16L=r18
.def CRC16H=r19
; warning: overloaded registers
.def hex_buf =r22
.def rs232_time =r25
.def rs232_buf =r26
.def rs232_cnt =r27
; warning: buffer and CRC overloaded register
.def duration=r16
.def DDSfine=r17
.def INTtmp =r22
.def SREGsav =r23
.def TIMEcnt =r24
.def Pcnt0 =r25
.def Pcnt1 =r26
.def SYNCstate =r27 ; 0:unsynced
.def tmp =r28
.def BITsreg =r29
.def Zreg=r30
rjmp RESET ;
rjmp RESET ; xINT0
rjmp RESET ; xTIMER
rjmp xINT0 ; xCOMPARATOR
RESET: ldi tmp,$0 ; get constant
mov zero,tmp
ldi tmp,0b11111100 ; set output B to totem-pole , comparator on
out DDRB,tmp
ldi tmp,$0 ; inputs to HI-Z
out PORTB,tmp
ldi tmp,0b00001011 ; rising edge trigger ;
out ACSR,tmp
ldi tmp,0b01111111 ; set output D.0 ... D.6 to totem-pole
out DDRD,tmp
ldi TIMEcnt,0
ldi tmp,$1
out TCCR0,tmp ; start TIMER
; ; main loop starts here
SEND: cli
sbi PORTD,0 ; CRC-LED off
cbi PORTD,5 ; CTRL-PIN low at TX phase
; @@ following two lines only for version without amplifier
; ldi tmp,0b11111111; set output B to totem-pole
; out DDRB,tmp
; @@ following two lines only for version with amplifier
ldi tmp,0b11111100 ; set ADC input on
out DDRB,tmp
ldi tmp,$0 ; inputs to HI-Z
out PORTB,tmp
sbi PORTD,6 ; TX-PIN on
ldi Pcnt0,0
ldi PCNT1,25 ; 25*256 cycles at 134kHz is approx 50ms
clr DDSfine ; always the same pattern
;
; charge frequency generation
;
LP1:
; @@ following two lines only for version without amplifier
; ldi TIMEcnt,0b10+4*threshold ; out 10B + DAC threshold
; out PORTB,TIMEcnt
; @@ following line only only for version with external amplifier
cbi PORTD,3
ldi duration,$d ; wait a little
wait1: subi duration,1
brne wait1
nop
; @@ following two lines only for version without amplifier
; ldi TIMEcnt,0b01+4*threshold ; out 01B + DAC threshold
; out PORTB,TIMEcnt
; @@ following line only only for version with external amplifier
sbi PORTD,3
ldi duration,$d ; wait a little
wait2: subi duration,1
brne wait2
subi DDSfine,$95 ; fine frequency control
brcc wait3 ; sometimes 2 cycles !
wait3: subi PCNT0,1 ; 16 Bit down count
sbci PCNT1,0
brcc LP1 ; until charging done
sbi PORTD,3 ; definite state of TX amplifier
cbi PORTD,6 ; TX-PIN low
; silence
ldi tmp,0b11111100 ; set ADC input on
out DDRB,tmp
ldi tmp,$0 ; inputs to HI-Z
out PORTB,tmp
; guard time start
ldi TIMEcnt,4*threshold ; out DAC threshold
out PORTB,TIMEcnt
ldi PCNT0,0
ldi PCNT1,10
LP4: subi PCNT0,1 ; 16 Bit down count
sbci PCNT1,0
brcc LP4
; start now
ldi tmp,10 ; initialize
mov FIR0,tmp
mov FIR1,tmp
mov FIR2,tmp
mov FIR3,tmp
out TCNT0,zero ; reset timer
clr CLKcnt
clr SYNCstate
cbi PORTD,2 ; sample bit out
clr BITsreg
sei ; enable interrupts
; wait until synchronized
ldi PCNT0,0
ldi PCNT1,100
LP5: cpi SYNCstate,2
breq SRCstart
subi PCNT0,1 ; 16 Bit down count
sbci PCNT1,0
brcc LP5
rjmp error ; if waited too long: error
SRCstart:
; search for start byte in next 15 bits
; sbi PORTD,3
ldi tmp,15
mov BITcnt,tmp
skip2:
rcall BITwait
brcs error
cpi BITsreg,start_byte1
breq foundSTART
cpi BITsreg,start_byte2
breq foundSTART
dec BITcnt
brne skip2
rjmp error ; not found
foundSTART:
clr CRC16L ; reset CRC sum
clr CRC16H
ldi ZL,8 ; pointer on buffer start
getBYTE:ldi tmp,8 ; get 8 bits
mov BITcnt,tmp
getB1: rcall BITwait
brcs error
rcall CRC16do ; CRC check add
dec BITcnt
brne getB1
mov tmp,BITsreg ; store byte at pointer
st Z,tmp
inc ZL ; next pointer
cpi ZL,8+10 ; until 10 bytes in buffer
brne getBYTE
;
; ; search for stop byte
;
ldi tmp,8 ; get 8 bits
mov BITcnt,tmp
getB2: rcall BITwait ; without CRC adding !
brcs error
dec BITcnt
brne getB2
mov tmp,BITsreg ; check for stop-byte
cpi tmp,stop_byte1
breq stop_ok1
cpi tmp,stop_byte2
brne error
stop_ok1:
cli ; stop interrupts
sbi PORTD,5 ; CTRL-PIN high
OUT232: ldi rs232_buf,13 ; send CRLF
rcall out_char
ldi rs232_buf,10
rcall out_char
ldi ZL,8 ; initialize pointer
loop: ld hex_buf,Z ; load register to hex_buf
rcall out_hex1 ; and output both nibbles
rcall out_hex0
ldi rs232_buf,$20 ; send a blank
rcall out_char
inc ZL ; increment pointer
cpi ZL,8+10+2
brne loop ; until 10 bytes out
;---
mov tmp,CRC16L ; check CRC=0
or tmp,CRC16H
brne CRCbad
cbi PORTD,0 ; on CRC-LED: all ok
CRCbad: rjmp RXok1
error: cli ; interrupts off for RS232 timing
cbi PORTD,5 ; error: CTRL-PIN low
ldi rs232_buf,13 ; send CRLF
rcall out_char
ldi rs232_buf,10
rcall out_char
ldi rs232_buf,$3f ; send '?'
rcall out_char
RXok1: cli ; stop interrupts
;
; wait a little bit
;
ldi PCNT0,0 ; 16 Bit counter PCNT1,PCNT0
ldi PCNT1,20
LP2: ldi TIMEcnt,100 ; inner loop 100 times
LP3: subi TIMEcnt,1
brcc LP3
subi PCNT0,1 ; 16 Bit subtract 1
sbci PCNT1,0
brcc LP2 ; loop on
; and restart again
rjmp SEND
;
;-------------------------------------------------------------------
;
BITwait:clr PCNT0 ; wait max 256 loops for a bit
BITw1: mov tmp,mail
tst tmp
brne bitTHERE ; <>0 : mail must be there
dec PCNT0 ; count wait-time
brne BITw1 ; keep on waiting on PCNT0<>0
sec ; signal error
ret
bitTHERE:
andi tmp,1 ; get bit
clr mail ; reset mail
ror tmp ; into CY
ror BITsreg ; move into shift register @@
clc ; signal success
ret
CRC16do: ; CRC add
mov tmp,BITsreg
rol tmp ; new bit into CY
rol CRC16L ; and into CRC register
rol CRC16H
brcc noXOR ; shift out bit 1 : correction
ldi tmp,$10
eor CRC16H,tmp ; xor with polynomial
ldi tmp,$21
eor CRC16L,tmp
noXOR: ret
;-------------------------------------------------------------------
xINT0: in SREGsav,SREG ; save status
in INTtmp,TCNT0 ; get timer count = period of last cycle
out TCNT0,zero ; reset timer
sbi PORTD,1 ; signal INT-handler on
subi INTtmp,85 ; subtract bias
;
; ; now period-value is in INTtmp
; ; do mean-value computation
;
mov FIR3,FIR2 ; shift values
mov FIR2,FIR1
mov FIR1,FIR0
mov FIR0,INTtmp
add INTtmp,FIR1 ; and sum up last 4 values
add INTtmp,FIR2
add INTtmp,FIR3
;
; ; here INTtmp=mean of last 4 values
; ; now do bit-decision
;
cpi INTtmp,threshold-7
brsh hi1
cpi INTtmp,threshold+7
brlo lo1
; keep old bit-value
rjmp BITinput
lo1: cbi PORTD,5 ; signal on pin
clt ; T:=bit
rjmp BITinput
hi1: sbi PORTD,5 ; signal on pin
set ; T:=bit
BITinput:
; now we have actual bit in T
; output 4*(analog value) to PORTB
;
rol INTtmp
rol INTtmp
andi INTtmp,$0FE
out PORTB,INTtmp
;
; here we have a bit, check sync-state to determine what to do
;
cpi SYNCstate,0
brne nSYNC0
; sync state is 0 ; simply wait 20 interrupts
inc CLKcnt
mov INTtmp,CLKcnt
cpi INTtmp,20
brne RETI1
ldi SYNCstate,1 ; next sync-state
rjmp RETI1
nSYNC0: cpi SYNCstate,1
brne nSYNC1
; sync state is 1 ; wait for first HIGH-Bit = 1-BIT
brtc RETI1 ; check bit in T
ldi SYNCstate,2 ; next sync state
ldi INTtmp,255
mov CLKcnt,INTtmp ; set bit-sample timer to -1
rjmp RETI1
nSYNC1: inc CLKcnt ; advance bit-sample timer
cbi PORTD,2 ; reset sample bit out-pin
mov INTtmp,CLKcnt ; CLKcnt mod 16
andi INTtmp,$0F
cpi INTtmp,7 ; is bit-middle reached ?
brne noCLK
; evaluate T for bit ; yes: sample BIT
brts send1
ldi INTtmp,2 ; signal bit=0 to main
rjmp send2
send1: ldi INTtmp,3 ; signal bit=1 to main
send2: mov mail,INTtmp ; bit0=contents , bit1=bit-there-flag
sbi PORTD,2
noCLK:
RETI1: cbi PORTD,1 ; signal INT-handler off
out SREG,SREGsav
reti
;--------------------------------------------------------------------
; out_hex1 : output higher nibble from hex_buf
; hex_buf is not changed
;
out_hex1:
mov rs232_buf,hex_buf
swap rs232_buf ; msb into lower position
rjmp out_hnib
;
; out_hex0 : output lower nibble from hex_buf
; hex_buf is not changed
;
out_hex0:
mov rs232_buf,hex_buf
rjmp out_hnib
out_hnib:
andi rs232_buf,$0F ; mask off nibble
subi rs232_buf,-6 ; add 6 ; bit 3 is set if >9
sbrc rs232_buf,4 ; offset to add depends on case
subi rs232_buf,-7 ; for 0 we add 48=6+42
subi rs232_buf,-42 ; for A we add 55=6+7+42
rjmp out_char ; and output this character
;--------------------------------------------------------------------
; output the character in rs232_buf
; via RS232 at 9600 bits/sec on PORTD,4
out_char:
ldi rs232_cnt,11 ; 1-START 8-DATA 2-STOP bits
bit_loop:
cpi rs232_cnt,11 ; start-bit ?
breq txmark ; start bit is mark
cpi rs232_cnt,3 ; stop bits ?
brcs txspace ; stop bits are space
ror rs232_buf ; transfer LSB first
brcs txspace ; a 1 translates to space
txmark: sbi PORTD,4 ; mark is HIGH
rjmp goon
txspace:cbi PORTD,4 ; space is LOW
goon: ldi rs232_time,249 ; wait 249*5 cycles
time1: dec rs232_time
nop
nop
brne time1 ; time-loop-end
dec rs232_cnt ; count down bit number
brne bit_loop ; loop of all bits
ret
;--------------------------------------------------------------------
; end of the stuff
;