Created
July 19, 2015 12:08
-
-
Save BobBurns/beda039a5c6531fd19cd to your computer and use it in GitHub Desktop.
avr code to control pn532 to read and decrement MiFare card value
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;this program attempts to read a MiFare card initialized with a name at address 0x04 | |
; and a value block at 0x05 | |
; | |
;compile with gavrasm read_dec.asm ;flash with avrdude -c avrisp -p m168 -P /dev/tty.usbmodem1411 -b 19200 -U flash:w:read_dec.hex | |
; | |
; I/O pins: | |
; ** use PORTB except RDYN on PORTD ** | |
; ** SCK on pin 5 configured as output ** | |
; ** MISO on pin 4 configured as input with pullup ** | |
; ** MOSI on pin 3 configured as output ** | |
; ** NSS on pin 2 configured as output ** | |
; ** NSS on pin 2 not selected (high) | |
; ** IRQ on PB1 configured as input with pullup ** | |
;---- defines ---- | |
.device atmega168 | |
.equ HAL_PORT = 0x05 ;PORTB | |
.equ HAL_DDR = 0x04 ;DDRB | |
.equ HAL_PIN = 0x03 ;PINB | |
.equ HAL_SCK = 5 | |
.equ HAL_MISO = 4 | |
.equ HAL_MOSI = 3 | |
.equ HAL_NSS = 2 | |
; not using IRQ | |
; | |
.equ MSG_FLG = 0 | |
.equ RD_FLG = 1 | |
; | |
;UBBR value for USART from f_cpu 1000000 | |
.equ UBBRvalue = 12 | |
;*** some opcodes for PN532 *** | |
.equ C_TEST = 0x00 | |
;*** delay constant | |
.equ dlp_init = 50000 | |
;---- registers | |
.def temp = r16 | |
.def count = r17 | |
.def temp2 = r18 | |
.def r_dcs = r19 | |
.def delayL = r24 | |
.def delayH = r25 | |
.def xL = r26 | |
.def xH = r27 | |
.def yL = r28 | |
.def yH = r29 | |
.def zL = r30 | |
.def zH = r31 | |
.cseg | |
;---- Interrupt Vector --- | |
.org 0 | |
rjmp reset | |
rjmp RDYN_L ;INT0 vector | |
RDYN_L: | |
; I'm not going to use this yet | |
reti | |
reset: | |
;Initialize Stack | |
ldi temp,low(RAMEND) | |
out SPL,temp | |
ldi temp,high(RAMEND) | |
out SPH,temp | |
;Init SPI | |
;** don't have to set phase or polarity. PN532 uses mode 0 | |
in temp,SPCR | |
sbr temp,(1 << SPR0) ;divide f_cpu by 16, better for breadboards | |
sbr temp,(1 << MSTR) ;set AVR to SPI Master mode | |
sbr temp,(1 << DORD) ;use LSB bit order | |
sbr temp,(1 << SPE) ;enable SPI | |
out SPCR,temp | |
; | |
;*** set ddr and output on pin lines | |
; | |
sbi HAL_DDR,HAL_NSS ;output on NSS | |
cbi HAL_PORT,HAL_NSS ;lower NSS to wake up pn532 | |
sbi HAL_DDR,HAL_SCK ;output on SCK | |
sbi HAL_PORT,HAL_MISO ;set pullup on MISO // confg as input | |
sbi HAL_DDR,HAL_MOSI ;output on MOSI | |
; wait to set pullup on IRQ line sbi HAL_PORT,HAL_IRQ ;set pullup on IRQ line | |
; | |
;initialize USART | |
ldi temp,high(UBBRvalue) ;baud rate param | |
sts UBRR0H,temp | |
ldi temp,low(UBBRvalue) | |
sts UBRR0L,temp | |
lds temp,UCSR0A | |
ori temp,(1 << U2X0) ;set use 2x because %error actual baud > .5 | |
sts UCSR0A,temp | |
;--- USART register values | |
ldi temp,(1 << TXEN0) | (1 << RXEN0) ;enable transmit and receive | |
sts UCSR0B,temp | |
ldi temp,(1 << UCSZ01) | (1 << UCSZ00) ;8 data bits, 1 stop bit | |
sts UCSR0C,temp | |
;********* Main Program ********** | |
; | |
; wake up pn532 | |
ldi count,5 ;one second | |
rcall delay ;delay after startup | |
start: | |
ldi zH,high(gfv << 1) ;call get firmware version to sync? | |
ldi zL,low(gfv << 1) | |
rcall snd_cmd | |
sbi HAL_PORT,HAL_NSS ;snd_cmd doesn't raise NSS when finished | |
ldi xL,low(in_buf) ;set up pointer to storage buffer | |
ldi xH,high(in_buf) | |
rcall ack_resp | |
ldi zH,high(samc << 1) ;next configure SAM normal 14 01 | |
ldi zL,low(samc << 1) | |
rcall snd_cmd | |
sbi HAL_PORT,HAL_NSS | |
ldi xL,low(in_buf) ;set up pointer to storage buffer | |
ldi xH,high(in_buf) | |
rcall ack_resp | |
poll: | |
ldi zH,high(ilpt << 1) | |
ldi zL,low(ilpt << 1) | |
rcall snd_cmd ;send inListPassiveTarget command | |
sbi HAL_PORT,HAL_NSS | |
ldi xL,low(in_buf) ;set up pointer to storage buffer | |
ldi xH,high(in_buf) | |
rcall ack_resp ;get response | |
ldi xL,low(in_buf) | |
ldi xH,high(in_buf) | |
adiw xH:xL,9 | |
ld temp,X+ | |
cpi temp,4 ;make sure NFCID is MiFare1 | |
breq cont_2 | |
rjmp error | |
cont_2: ldi zH,high(ide_a << 1) | |
ldi zL,low(ide_a << 1) | |
rcall snd_cmd ;send first part of command | |
ldi count,4 | |
ldi r_dcs,0x76 ;dcs before NFCID | |
auth_end: | |
ld temp,X+ | |
add r_dcs,temp | |
rcall SPI_tradeByte | |
dec count | |
brne auth_end | |
mov byte_tx,r_dcs | |
; rcall transmit | |
neg r_dcs | |
mov byte_tx,r_dcs | |
; rcall transmit | |
mov temp,r_dcs | |
rcall SPI_tradeByte | |
ldi temp,0x00 | |
rcall SPI_tradeByte | |
sbi HAL_PORT,HAL_NSS | |
ldi xL,low(in_buf) ;set up pointer to storage buffer | |
ldi xH,high(in_buf) | |
rcall ack_resp | |
ldi xL,low(in_buf) | |
ldi xH,high(in_buf) | |
adiw xH:xL,4 ;check response status | |
ld temp,X | |
cpi temp,0x00 | |
breq cont_1 | |
rjmp error | |
;********* send read and dec commands ************ | |
cont_1: | |
ldi zH,high(cmd_head << 1) | |
ldi zL,low(cmd_head << 1) | |
rcall snd_cmd | |
ldi zH,high(read_name << 1) ;read name on card | |
ldi zL,low(read_name << 1) | |
rcall snd_dcs | |
sbi HAL_PORT,HAL_NSS | |
ldi xL,low(name_buf) ;set up pointer to name buffer | |
ldi xH,high(name_buf) | |
rcall ack_resp | |
ldi zH,high(cmd_head << 1) | |
ldi zL,low(cmd_head << 1) | |
rcall snd_cmd | |
ldi zH,high(dec_vb << 1) ;decrement value-block 05 | |
ldi zL,low(dec_vb << 1) | |
rcall snd_dcs | |
sbi HAL_PORT,HAL_NSS | |
ldi xL,low(in_buf) | |
ldi xH,high(in_buf) | |
rcall ack_resp | |
ldi zH,high(cmd_head << 1) | |
ldi zL,low(cmd_head << 1) | |
rcall snd_cmd | |
ldi zH,high(tra_vb << 1) ;transfer value to block | |
ldi zL,low(tra_vb << 1) | |
rcall snd_dcs | |
sbi HAL_PORT,HAL_NSS | |
rcall ack_resp | |
ldi zH,high(cmd_head << 1) | |
ldi zL,low(cmd_head << 1) | |
rcall snd_cmd | |
ldi zH,high(read_vb << 1) ;read updated value block 05 | |
ldi zL,low(read_vb << 1) | |
rcall snd_dcs | |
sbi HAL_PORT,HAL_NSS | |
ldi xL,low(value_buf) ;set up pointer to name buffer | |
ldi xH,high(value_buf) | |
rcall ack_resp | |
;done | |
; ldi zH,high(succ_str << 1) | |
; ldi zL,low(succ_str << 1) | |
; rcall print_s ;print success | |
;****** serial tx ********* | |
;* first send STX(0x02) then full name block(16 bytes) | |
;* | |
ldi byte_tx,0x02 | |
rcall transmit | |
ldi xL,low(name_buf) | |
ldi xH,high(name_buf) | |
adiw xH:xL,5 ;should point to beginning of string | |
ldi count,0x10 | |
nm_lp: | |
ld byte_tx,X+ | |
rcall transmit | |
dec count | |
brne nm_lp | |
;* then ETX(0x03), STX(0x02), 4 byte value | |
;* | |
ldi byte_tx,0x03 | |
rcall transmit | |
ldi byte_tx,0x02 | |
rcall transmit | |
ldi xL,low(value_buf) | |
ldi xH,high(value_buf) | |
adiw xH:xL,5 ;should point to beginning of value | |
ldi count,4 | |
vl_lp: ld r24,X+ | |
rcall t_htoa ;send ascii representation of value | |
dec count | |
brne vl_lp | |
;* finally send ETX(0x03) and EOT(0x04) | |
ldi byte_tx,0x03 | |
rcall transmit | |
ldi byte_tx,0x04 | |
rcall transmit | |
ldi count,25 | |
rcall delay ;5 sec delay | |
rjmp poll | |
error: ldi byte_tx,0xEE | |
rcall transmit | |
rcall transmit ;EE EE on error | |
exit_lp: | |
nop | |
rjmp exit_lp | |
;****** Subroutines ****** | |
;print out message | |
prt_m: | |
push count | |
ldi xL,low(in_buf) | |
ldi xH,high(in_buf) ;load x reg with pointer to message | |
ld count,X+ | |
mov byte_tx,count | |
rcall transmit | |
p_lp: ld byte_tx,X+ | |
rcall transmit | |
dec count | |
brne p_lp | |
pop count | |
ret | |
.def byte_tx = r19 | |
;---- function to transmit byte ---- | |
;transmit byte from r19 over usart | |
transmit: | |
lds temp,UCSR0A | |
sbrs temp,UDRE0 | |
rjmp transmit | |
sts UDR0,byte_tx | |
ret | |
;print string function | |
;takes Z loaded with pointer to string with first byte being length | |
;uses r16,r17,r19 | |
print_s: | |
lpm count,Z+ | |
for1: lpm byte_tx,Z+ | |
wait: lds temp,UCSR0A | |
sbrs temp,UDRE0 ;wait for Tx buffer to be empty | |
rjmp wait ;not ready | |
sts UDR0,byte_tx; | |
dec count | |
brne for1 | |
ret | |
; | |
;-------- delay subroutines ------------ | |
;takes count in reg r17 * 200 milliseconds | |
delay: | |
ldi delayH,high(dlp_init) | |
ldi delayL,low(dlp_init) | |
dlp: sbiw delayH:delayL,1 | |
nop ;makes 4 clock cycles | |
brne dlp | |
dec count | |
brne delay | |
ret | |
;millisecond delay *** takes count (r17) as msecond value | |
m_delay: | |
ldi temp,0xfa | |
md_lp: nop | |
nop | |
dec temp | |
brne md_lp ;4 clock cycles times 250 = 1000us (1000000 f_cpu) | |
dec count | |
brne m_delay | |
ret | |
;----- SPI routines ----- | |
;uses temp r16 as tx byte and returns with rx byte in temp | |
SPI_tradeByte: | |
out SPDR,temp | |
lp1: in temp2,SPSR | |
sbrs temp2,SPIF | |
rjmp lp1 | |
in temp,SPDR | |
ret | |
;send ascii representation of one byte over serial | |
;byte to convert in r24 | |
;uses r24 as low nibble to send and r25 for high nibble | |
t_htoa: | |
lds temp,UCSR0A | |
sbrs temp,UDRE0 | |
rjmp t_htoa | |
ldi temp,0x30 ;ascii offset | |
mov r25,r24 | |
lsr r25 | |
lsr r25 | |
lsr r25 | |
lsr r25 | |
cpi r25,0x0A | |
brlt no_e | |
ldi temp,0x37 ;extended hex | |
no_e: add r25,temp | |
sts UDR0,r25 | |
t_2: lds temp,UCSR0A | |
sbrs temp,UDRE0 | |
rjmp t_2 | |
ldi temp,0x30 ;ascii offset | |
andi r24,0x0f ;low nibble | |
cpi r24,0x0a | |
brlt no_e2 | |
ldi temp,0x37 | |
no_e2: add r24,temp ;add 0x30 to get ascii representation | |
sts UDR0,r24 | |
ret | |
;print message from inbuf | |
p_mess: | |
ldi xL,low(in_buf) | |
ldi xH,high(in_buf) | |
ld count,X+ | |
mess_lp: | |
ld byte_tx,X+ ;reprint data | |
rcall transmit | |
dec count | |
brne mess_lp | |
ret | |
;send command routine | |
;Z reg points to command string with first byte being length | |
snd_cmd: | |
cbi HAL_PORT,HAL_NSS | |
lpm count,Z+ | |
snd_for: | |
lpm temp,Z+ | |
rcall SPI_tradeByte | |
dec count | |
brne snd_for | |
ret | |
; send routine with data checksum | |
snd_dcs: | |
lpm count,Z+ | |
mov temp,count | |
rcall SPI_tradeByte | |
mov temp,count ;count is same as length byte | |
neg temp | |
rcall SPI_tradeByte ;send length byte and length checksum | |
lpm temp,Z+ | |
mov r_dcs,temp ;first byte to add to (TFI) | |
rcall SPI_tradeByte | |
dec count | |
sdcs_for: | |
lpm temp,Z+ | |
add r_dcs,temp | |
rcall SPI_tradeByte | |
dec count | |
brne sdcs_for | |
mov temp,r_dcs | |
neg temp | |
rcall SPI_tradeByte | |
ldi temp,0x00 | |
rcall SPI_tradeByte | |
ret | |
;ack routine | |
; | |
ack_resp: | |
cbi HAL_PORT,HAL_NSS | |
sr_lp: ldi temp,0x02 ;status reading SR | |
rcall SPI_tradeByte | |
ldi temp,0x00 | |
rcall SPI_tradeByte | |
mov byte_tx,temp | |
; rcall transmit | |
sbrs byte_tx,0 ;ready bit | |
rjmp sr_lp | |
sbi HAL_PORT,HAL_NSS | |
;get ack and print for now | |
ldi count,0x06 ;6 bytes | |
cbi HAL_PORT,HAL_NSS | |
ldi temp,0x03 ;data reading | |
rcall SPI_tradeByte | |
ack_p: ldi temp,0x00 | |
rcall SPI_tradeByte | |
mov byte_tx,temp | |
; rcall transmit | |
dec count | |
brne ack_p | |
sbi HAL_PORT,HAL_NSS | |
ldi byte_tx,0xAC | |
; rcall transmit | |
cbi HAL_PORT,HAL_NSS | |
rec: ldi temp,0x02 ;status reading | |
rcall SPI_tradeByte | |
ldi temp,0x00 | |
rcall SPI_tradeByte | |
sbrs temp,0 | |
rjmp rec | |
sbi HAL_PORT,HAL_NSS | |
ldi count,0x03 ;first three bytes preamble + start code | |
cbi HAL_PORT,HAL_NSS | |
ldi temp,0x03 | |
rcall SPI_tradeByte ;data reading | |
out_p: ldi temp,0x00 | |
rcall SPI_tradeByte | |
mov byte_tx,temp | |
; rcall transmit ;print | |
dec count | |
brne out_p | |
ldi temp,0x00 | |
rcall SPI_tradeByte | |
mov byte_tx,temp | |
; rcall transmit | |
cpi byte_tx,0x01 ;length byte 1 on error | |
breq app_err | |
mov count,byte_tx | |
inc count | |
inc count | |
inc count | |
st X+,count ;store length first | |
rec_end: | |
ldi temp,0x00 | |
rcall SPI_tradeByte | |
st X+,temp ;store rec mess | |
mov byte_tx,temp | |
; rcall transmit | |
dec count | |
brne rec_end | |
sbi HAL_PORT,HAL_NSS | |
ret | |
app_err: | |
ldi count,0x04 | |
err_lp: ldi temp,0x00 | |
rcall SPI_tradeByte | |
mov byte_tx,temp | |
rcall transmit | |
dec count | |
brne err_lp | |
sbi HAL_PORT,HAL_NSS | |
end: nop ;dont return | |
rjmp end | |
;****** strings ****** | |
succ_str: .db 20,0x0d,0x0a,"*** Success! ***",0x0d,0x0a,0x00 | |
;******************************************************************** | |
;some commands to send | |
gfv: .db 0x0A,0x01,0x00,0x00,0xFF,0x02,0xFE,0xD4,0x02,0x2A,0x00,0x00 | |
samc: .db 0x0D,0x01,0x00,0x00,0xFF,0x05,0xFB,0xD4,0x14,0x01,0x00,0x01,0x16,0x00 | |
ilpt: .db 0x0C,0x01,0x00,0x00,0xFF,0x04,0xFC,0xD4,0x4A,0x01,0x00,0xE1,0x00,0x00 | |
ide_a: .db 0x11,0x01,0x00,0x00,0xFF,0x0F,0xF1,0xD4,0x40,0x01,0x60,0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF | |
cmd_head: .db 0x04,0x01,0x00,0x00,0xFF,0x00 | |
wr_name: .db 0x15,0xD4,0x40,0x01,0xA0,0x04,0x44,0x61,0x72,0x62,0x79,0x20,0x43,0x72,0x61,0x73,0x68,0x00,0x00,0x00,0x00,0x00 | |
credit_blk: .db 0x15,0xD4,0x40,0x01,0xA0,0x05,0x9B,0x02,0x00,0x00,0x64,0xFD,0xFF,0xFF,0x9B,0x02,0x00,0x00,0x05,0xFA,0x05,0xFA | |
read_st7: .db 0x05,0xD4,0x40,0x01,0x30,0x07 | |
read_name: .db 0x05,0xD4,0x40,0x01,0x30,0x04 | |
dec_vb: .db 0x09,0xD4,0x40,0x01,0xC0,0x05,0x01,0x00,0x00,0x00 | |
tra_vb: .db 0x05,0xD4,0x40,0x01,0xB0,0x05 | |
read_vb: .db 0x05,0xD4,0x40,0x01,0x30,0x05 | |
.dseg | |
;**** in_buf starts with a length byte | |
in_buf: .byte 0x40 | |
name_buf: .byte 0x32 | |
value_buf: .byte 0x32 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment