用 FPGA 從底層開始搭建一個 NFC PCD (讀卡器),支持 ISO14443A 標(biāo)準(zhǔn)。
名詞釋義
| 名詞 | 簡稱 | 直觀名稱 | 釋義 |
|---|---|---|---|
| Proximity Coupling Device | PCD | 讀卡器、讀寫器、Reader | 給卡片提供能量,并作為通訊主機的設(shè)備,其實就是讀卡器,也就是本項目要實現(xiàn)的東西。 |
| Proximity Card | PICC | 標(biāo)簽、卡片、TAG | M1卡、UID卡、電子標(biāo)簽這些卡片。不同類的卡片可能滿足不同標(biāo)準(zhǔn)。 |
| PCD-to-PICC | TX | 發(fā)送 | PCD 對載波進行調(diào)制,傳輸信息到 PICC |
| PICC-to-PCD | RX | 接收 | PICC 改變自身阻抗,使得 PCD 探測到載波幅度發(fā)生變化,從而傳輸信息到 PCD 。 |
| NXP MIFARE Classic 1K | M1卡 | 一種滿足 ISO14443A 的卡片,日常生活很常見,比如門禁卡。 | |
| ISO14443A | NFCA | 一種 NFC 標(biāo)準(zhǔn),用于個人卡片。本項目從硬件到協(xié)議完全支持。詳見 [1,2,3] | |
| ISO14443B | NFCB | 一種 NFC 標(biāo)準(zhǔn),用于個人卡片。本項目硬件不支持。詳見 [1,2,3] | |
| ISO15693 | NFCV | 一種 NFC 標(biāo)準(zhǔn),用于工業(yè)電子標(biāo)簽。本項目硬件支持,但 FPGA 尚未編寫其協(xié)議。詳見 [1,2] | |
| Carrier、載波 | fc | 13.56MHz 載波 | FPGA 發(fā)射引腳需要產(chǎn)生的頻率,驅(qū)動線圈在這個頻率下諧振。 |
| Subcarrier、副載波 | fs | 847.5 kHz 副載波 | 調(diào)制的最小單位(PCD和PICC會以這個頻率改變調(diào)制幅度),是載波頻率的 1/16 |
| 位頻率 | 105.9375 kHz | 8個副載波周期可能攜帶一位 (bit) 數(shù)據(jù)信息 | |
| Amplitude Shift Keying | ASK | 調(diào)幅 | 通過改變載波幅度來傳送信息 |
更多簡稱詳見引用 [1,2,3]
項目思路
首先是載波生成,我們用 FPGA 的引腳產(chǎn)生 13.56MHz 的信號(對應(yīng)代碼文件 nfca_tx_modulate.v),該信號驅(qū)動一個 MOS 管 (FDV301N) + 一個諧振電路來讓天線(線圈)諧振。
其次是載波調(diào)制發(fā)送,ISO14443A 的 PCD-to-PICC 的副載波調(diào)制方式是 100% ASK (即在一個副載波周期內(nèi),要么滿幅度發(fā)送載波,要么完全不發(fā)送載波),這對 FPGA 也是很容易實現(xiàn)的(對應(yīng)代碼文件 nfca_tx_modulate.v)。
然后是接收卡片的調(diào)制信息,PICC-to-PCD 的調(diào)制方式是 2%~10% 的 ASK (即在一個副載波周期內(nèi),要么讓載波衰減一點,要么不衰減)。我用二極管(1N4148)+電容+電阻來做包絡(luò)檢波,得到包絡(luò)線的頻率=副載波頻率=847.5kHz,然后用 ADC 對包絡(luò)線采樣(對應(yīng)代碼文件 ad7276_read.v)。包絡(luò)檢波降低了 ADC 采樣率的需求,避免直接使用 ≥20Msps 的 ADC 來采樣載波,而是只用一個 3Msps 的 ADC (AD7276B) 來采樣副載波即可。在 FPGA 內(nèi),用一個數(shù)字信號處理(DSP)算法來從 ADC 采樣數(shù)據(jù)中檢測 PICC-to-PCD 的 ASK 信號,即檢測 ADC 采樣數(shù)據(jù)幅度的微小變化,需要有抗噪聲能力,并自適應(yīng)信號幅度。我用的是中值濾波減去原始信號,再做比例閾值判斷,效果不錯(對應(yīng)代碼文件 nfca_rx_dsp.v)。
最后是實現(xiàn) ISO14443A 的編解碼協(xié)議,包括發(fā)送校驗生成和封包(對應(yīng)代碼文件 nfca_tx_frame.v)、接收協(xié)議的解包(對應(yīng)代碼文件 nfca_rx_tobits.v 和 nfca_rx_tobytes.v),這部分是按照 Spec 文檔 [3] 編寫的。
我還在 FPGA 中實現(xiàn)了串口控制邏輯,將 Host-PC 發(fā)送給 FPGA 的串口命令解析成 NFC 發(fā)送數(shù)據(jù)(對應(yīng)代碼文件 uart_rx.v 和 uart_rx_parser.v),并將 NFC 接收數(shù)據(jù)通過串口發(fā)送給 Host-PC (對應(yīng)代碼文件 uart_tx.v)。用戶可以在 Host-PC 的”串口調(diào)試工具“中發(fā)送數(shù)據(jù)給卡片,然后收到卡片返回的數(shù)據(jù)。
下圖是系統(tǒng)框圖,其中 FPGA 中的模塊下方逐個標(biāo)注了 Verilog 代碼文件名。
_________ _________________________________________________________________________________________________________
| | ___________________________________________________________________________________________________ |
| | | _________________________________________________________ | |
| | | ___________ | ____________ _____________ | | | ____________ ____________
| | | uart_rx | UART RX | | | frame | | RFID TX | | | | | FDV301N | | Resonant | ___________
uart_tx |---|->|-------->| logic |---|--->| pack |--------->| modulate |--------------->|---------------->|--|-->| N-MOSFET |--->| circuit | | |
| | | ----------- | ------------ ------------- | carrier_out | | | | | |---v->| Antenna |
| | | uart_rx.v | nfca_tx_frame.v | nfca_tx_modulate.v | | | ------------ ------------ | | Coil |
| | | uart_rx_parser.v | rx_on | | | | | | |
| | | fifo_sync.v | | | | | | -----------
| | | ___________ | ___________ ______V____ ____________ | _____________ | | ___________ ____________ |
| | | uart_tx | UART TX | | | bytes | | bits | | ADC data | | | AD7276B | | | | AD7276B | | Envelop | |
uart_rx |<--|--|<--------| ?logic ?|<--|--| rebuild |<--------| rebuild |<-------| DSP ? ? ?|<-|--|ADC reader |<-|<-|-----| ? ADC ? |<--| detection|<---
? ? ? ? | ? | ?| ? ? ? ? ----------- ? | ?----------- ? ? ? ? ----------- ? ? ? ?------------ ?| ?------------- ?| ?| SPI | ? ? ? ? | ? | ? ? ? ? ?|
? ? ? ? | ? | ?| ? ? ? ? ?uart_tx.v ? ?|nfca_rx_tobytes.v ? ?nfca_rx_tobits.v ? nfca_rx_dsp.v ?| ?ad7276_read.v ?| ?| ? ? ----------- ? ------------
? ? GND |---| ?| ? ? ? ? ? ? ? ? ? ? ? --------------------------------------------------------| ? ? ? ? ? ? ? ? | ?|
? ? ? ? | ? | ?| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?nfca_controller.v ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| ?|
? ? ? ? | ? | ?--------------------------------------------------------------------------------------------------- ?|
? ? ? ? | ? | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?uart2nfca_system_top.v ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
--------- ? ?--------------------------------------------------------------------------------------------------------
?Host-PC ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FPGA (fpga_top.v ) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Analog Circuit
搭建硬件
PCB 文件夾里是本庫的硬件設(shè)計(命名為 NFC_BreakoutBoard),上面主要包括:
發(fā)送電路: N-MOSFET、電感等。
接收電路:檢波二極管、AD7276B。
4匝線圈。

圖: NFC_BreakoutBoard 原理圖

圖: NFC_BreakoutBoard
請用制造文件 NFC_BreakoutBoard_gerber.zip 來打樣 PCB ,然后焊接元件。
硬件連接方法:
J1 連接 7V~9V 的電源。
J2 連接 FPGA 開發(fā)板(占用 FPGA 4 個普通 IO 引腳,電平為 3.3V 或 2.5V 均可)。注意:ADC_SCK 的頻率高達 40.68MHz,因此不建議用杜邦線,而是用排針直插到 FPGA 開發(fā)板。
該 PCB 設(shè)計在立創(chuàng) EDA 開源: oshwhub.com/wangxuan/rfid_nfc_iso14443a_iso15693_breakoutboard
FPGA 部署
部署到 FPGA 時,所有 RTL 目錄 和 RTL/nfca_controller 目錄 中的 .v 文件都需要加入工程。頂層文件為 fpga_top.v ,它的每個引腳的連接方式見代碼注釋,如下:
modulefpga_top( inputwire rstn_btn, // press button to reset, pressed=0, unpressed=1 inputwire clk50m, // a 50MHz Crystal oscillator // AD7276 ADC SPI interface outputwire ad7276_csn, // connect to AD7276's CSN (NFC_Breakboard's AD7276_CSN) outputwire ad7276_sclk, // connect to AD7276's SCLK (NFC_Breakboard's AD7276_SCLK) inputwire ad7276_sdata, // connect to AD7276's SDATA (NFC_Breakboard's AD7276_SDATA) // NFC carrier generation signal outputwire carrier_out, // connect to FDV301N(N-MOSFET)'s gate (柵極) (NFC_Breakboard's CARRIER_OUT) // connect to Host-PC (typically via a USB-to-UART chip on FPGA board, such as FT232, CP2102 or CH340) inputwire uart_rx, // connect to USB-to-UART chip's UART-TX outputwire uart_tx, // connect to USB-to-UART chip's UART-RX // connect to on-board LED's (optional) outputwire led0, // led0=1 indicates PLL is normally run outputwire led1, // led1=1 indicates carrier is on outputwire led2 // led2=1 indicates PCD-to-PICC communication is done, and PCD is waiting for PICC-to-PCD );
所有代碼都是 Verilog 行為級實現(xiàn),支持任意 FPGA 平臺。除了 fpga_top.v 里的 altpll 模塊是僅限于 Altera Cyclone IV 的原語,它用來生成 81.36MHz 時鐘,驅(qū)動 NFC 控制器。如果你用的不是 Altera Cyclone IV,請使用其它的 IP 核(例如Xilinx 的 clock wizard)或原語來替換,總之只要生成 81.36MHz 的時鐘來驅(qū)動 NFC 子模塊即可。
串口交互
FPGA 燒錄之后,Host-PC 可以通過串口控制 FPGA 和 PICC 進行交互。串口格式為 9600,8,n,1 (即波特率=9600,8個數(shù)據(jù)位,無校驗位,1個停止位)。串口通信是“一問一答”的形式,發(fā)送你要發(fā)給卡片的數(shù)據(jù),然后卡片返回數(shù)據(jù)。每個命令和響應(yīng)都以 或 或 結(jié)尾(也就是一行一個命令/響應(yīng))
首先,建議在 PC 上使用“串口調(diào)試助手”,而不是 putty 等軟件。因為我設(shè)計的邏輯是: FPGA 會在收到串口命令時打開載波,如果1.2秒內(nèi)沒有下一個命令到來,就自動關(guān)閉載波。這對于一個控制串口的應(yīng)用程序是足夠的時間。但1.2秒是不夠人是打出下一條命令的,會導(dǎo)致載波關(guān)閉,卡片下電,卡片之前獲得的狀態(tài)都消失了?!按谡{(diào)試助手”可以一次發(fā)送多行命令,而 Putty 則一次只能打一條命令。
注意:“串口調(diào)試助手” 往往有“16進制顯示”和“16進制發(fā)送”選項,不需要勾選。本項目里 FPGA 會把收到的 ASCII 的十六進制形式處理成數(shù)字,也會把發(fā)出的 數(shù)字轉(zhuǎn)成 ASCII 十六進制形式。
與 M1 卡通信
我用自己的門禁卡,和幾個在 taobao 上買了的 M1 “白卡”試了試,因為都是 M1 卡,行為類似。以其中一個卡舉例:
在 “串口調(diào)試助手” 中輸入如下命令并點擊發(fā)送,這會發(fā)送 0x26(ISO14443 [3] 規(guī)定的 REQA)給卡片(注意末尾要加回車,這樣才會被當(dāng)成一條完整的命令):
26
然后串口收到如下,這是 ISO14443 規(guī)定的 ATQA,含義是 Bit frame anticollision 。
04 00
注:如果沒檢測到卡,或者因噪聲干擾而收到不符合標(biāo)準(zhǔn)規(guī)定的波形,串口的行尾會收到字符 n。表示: FPGA正常工作,但沒檢測到卡/出現(xiàn)錯誤。
然后我們在“發(fā)送框”里下一行附加一個 ISO14443 規(guī)定的 AntiCollision 命令,用來獲得卡的 UID (因為很可能1.2秒已經(jīng)過去了,卡片已經(jīng)丟失了上次上電的信息,需要重新發(fā)送 REQA 0x26)。
26 93 20
卡片響應(yīng)如下(第一行是響應(yīng) REQA 的 ATQA,第二行是 響應(yīng) anticollision 的 UID):
04 00 4B BE DE 79 52
然后我們在“發(fā)送框”里下一行附加一個 ISO14443 規(guī)定的 SELECT 命令,用剛剛獲取到的 UID 選中該卡:
26 93 20 93 70 4B BE DE 79 52
卡響應(yīng) ISO14443 規(guī)定的 SAK=0x08(代表它是 M1 卡。后面的 0xB6 0xDD 則是 CRC 校驗碼):
04 00 4B BE DE 79 52 08 B6 DD
注:發(fā)送時不需要用戶附加 CRC 校驗碼, FPGA 會在協(xié)議規(guī)定的需要加校驗碼的地方自動計算并追加 CRC。
注:接收時,CRC 碼不會被 FPGA 檢查和刪掉,會從串口展示出來。
根據(jù)卡片返回的 SAK ,知道這是 M1 卡后,我們可以發(fā)送 M1 卡的 Key 認(rèn)證命令的 Phase1 (第一階段),從卡片獲取隨機數(shù)(注意,該命令不是 ISO14443 規(guī)定的,而是 M1 卡獨有的,其它卡不會響應(yīng)這個命令)。我們在“發(fā)送框”里下一行附加:
26 93 20 93 70 4B BE DE 79 52 60 07
卡片響應(yīng) 4 字節(jié)隨機數(shù):
04 00 4B BE DE 79 52 08 B6 DD EF 9B B6 5A
M1 卡的后續(xù)認(rèn)證、讀寫步驟很復(fù)雜,不是本工程關(guān)注的范圍。本工程僅關(guān)注 ISO14443A PCD 與 PICC 交互的底層實現(xiàn)。你可以用上層應(yīng)用程序(C, Python, C# 編程)控制串口來進行 M1 卡的進一步操作。
測試 AntiCollision
AntiCollision 是 ISO14443 規(guī)定的多卡檢測和防沖突機制,因為不同的卡擁有不同的 UID,讀卡器用 UID 來區(qū)分不同的卡。
我把 2 張 M1 卡放在線圈上,串口發(fā)送 REQA 和 AntiCollision 命令,試圖獲取卡的 UID:
26 93 20
串口收到:
04 00 01:1
01:1 的含義是一個不完整的字節(jié) 0x01(00000001),:1 代表該沖突發(fā)生在該字節(jié)的從低到高第1位。
這說明,這兩個卡的 UID 的第一個字節(jié)的低2位分別是 01 和 11。第0位一樣所以沒發(fā)生沖突,第1位不一樣所以發(fā)生了沖突。
現(xiàn)在你想選擇低2位是 11 的那個卡,就需要發(fā)送 ISO14443 規(guī)定的 bit-oriented 幀,這種幀的最后一個字節(jié)是不完整的。用串口發(fā)送:
26 93 20 93 22 03:2
93 22 03:2 是一個 bit-oriented 幀。 22 代表:讀卡器額外指定 UID 中的 2 個 bit,滿足的卡才會響應(yīng),不滿足的卡就不要響應(yīng)。后面的 03:2 代表只發(fā)送 0x03 (00000011) 的低2位,即 11 。
串口收到:
04 00 01:1 48 BE DE 79 52
最后一條響應(yīng)是 48 BE DE 79 52 ,注意,48 并不是一個完整字節(jié),它只有高6bit有效,他還需要拼接上低2bit(即0x03的低2bit),才是完整的字節(jié)。
一個簡單的拼接方法是將讀卡器發(fā)送的不完整字節(jié) 0x03 和卡片返回的不完整字節(jié) 0x48 進行按位或,得到 0x4B。
表明這張卡的 UID = 4B BE DE 79 52。
同理,如果想選擇低2位是 01 的那個卡,就需要串口發(fā)送:
26 93 20 93 22 01:2
串口收到:
04 00 01:1 00 1D DD 79 B8
將讀卡器發(fā)送的不完整字節(jié) 0x01 和卡片返回的不完整字節(jié) 0x00 進行按位或,得到 0x01。
表明另一張卡的 UID = 01 1D DD 79 B8。
如果卡的數(shù)量有3張以上,依照這個流程還可能發(fā)生多次沖突,每發(fā)生一次沖突都要指定你要選擇發(fā)生沖突的那一位=0的卡,還是=1的卡。
逐位 AntiCollision 的例子
為了方便大家加深對 ISO14443 的 AntiCollision 過程的理解,下面我們展示一個逐位 AntiCollision 的例子,用串口發(fā)送如下這些命令,每條命令都只多指定一位。
26 93 20 93 21 01:1 93 22 01:2 93 23 01:3 93 24 01:4 93 25 01:5 93 26 01:6 93 27 01:7 93 30 01 93 31 01 01:1 93 32 01 01:2 93 33 01 05:3 93 34 01 0D:4 93 35 01 1D:5 93 36 01 1D:6 93 37 01 1D:7 93 40 01 1D 93 41 01 1D 01:1 93 42 01 1D 01:2 93 43 01 1D 05:3 93 44 01 1D 0D:4 93 45 01 1D 1D:5 93 46 01 1D 1D:6 93 47 01 1D 5D:7 93 50 01 1D DD 93 51 01 1D DD 01:1 93 52 01 1D DD 01:2 93 53 01 1D DD 01:3 93 54 01 1D DD 09:4 93 55 01 1D DD 19:5 93 56 01 1D DD 39:6 93 57 01 1D DD 79:7 93 60 01 1D DD 79 93 61 01 1D DD 79 00:1 93 62 01 1D DD 79 00:2 93 63 01 1D DD 79 00:3 93 64 01 1D DD 79 08:4 93 65 01 1D DD 79 18:5 93 66 01 1D DD 79 38:6 93 67 01 1D DD 79 38:7
串口收到:
04 00 01 1D DD 79 B8 00 1D DD 79 B8 00 1D DD 79 B8 00 1D DD 79 B8 00 1D DD 79 B8 00 1D DD 79 B8 00 1D DD 79 B8 00 1D DD 79 B8 1D DD 79 B8 1C DD 79 B8 1C DD 79 B8 18 DD 79 B8 10 DD 79 B8 00 DD 79 B8 00 DD 79 B8 00 DD 79 B8 DD 79 B8 DC 79 B8 DC 79 B8 D8 79 B8 D0 79 B8 C0 79 B8 C0 79 B8 80 79 B8 79 B8 78 B8 78 B8 78 B8 70 B8 60 B8 40 B8 00 B8 B8 B8 B8 B8 B0 A0 80 80
調(diào)試
如果你將卡放在線圈上,并發(fā)送串口命令后,串口響應(yīng)不符合預(yù)期,應(yīng)該:
看看串口是否響應(yīng)字符 'n',若沒有,說明 FPGA 工作不正常。檢查串口連接和波特率設(shè)置,并看看程序有沒有燒到 FPGA 里。
如果無論發(fā)什么,都響應(yīng)字符 'n' ,說明 FPGA 正常工作,但沒檢測到卡。請檢查 NFC_BreakoutBoard 的電源、FPGA 和 NFC_BreakoutBoard 的連接和引腳分配。如果沒問題,將卡貼在線圈上保證信號強度。
如果還不行,進一步的調(diào)試方法是用示波器觀察信號,將示波器接在 NFC_BreakoutBoard 的 J3 (SMA 接口上),這里應(yīng)該能觀察到對載波的包絡(luò)檢波。讓串口每隔2秒發(fā)送一次 26 (REQA),在示波器上應(yīng)該能看到載波啟動、調(diào)制 0x26 的調(diào)制過程。然后觀察發(fā)送調(diào)制后大概 8us 后是否有微弱的信號變化(大概只會有幾十 mV的浮動),這就是卡片對讀卡器的響應(yīng)。
仿真所需要的文件在目錄 SIM 里,其中:
tb_nfca_controller.v 是針對 nfca_controller.v 的 testbench 。
tb_nfca_controller_run_iverilog.bat 包含了 iverilog 仿真命令。
該仿真的行為是:向 nfca_controller 的發(fā)送接口發(fā)送一些幀,在 carrier_out 信號上可以看到調(diào)制的 PCD-to-PICC 發(fā)送數(shù)據(jù)。但該仿真并不會仿真 PICC-to-PCD ,因為我沒有編寫 PICC 的 model 代碼。
使用 iverilog 進行仿真前,需要安裝 iverilog ,見:iverilog_usage
然后雙擊 tb_nfca_controller_run_iverilog.bat 運行仿真,然后可以打開生成的 dump.vcd 文件查看波形。下圖是看到的 0x26(REQA)幀的調(diào)制波形:

圖:仿真中看到的 0x26(REQA)幀的調(diào)制波形。
-
FPGA
+關(guān)注
關(guān)注
1662文章
22472瀏覽量
638252 -
讀卡器
+關(guān)注
關(guān)注
2文章
470瀏覽量
41849 -
nfc
+關(guān)注
關(guān)注
62文章
1738瀏覽量
185895 -
串口
+關(guān)注
關(guān)注
15文章
1626瀏覽量
83183
原文標(biāo)題:FPGA NFC (RFID)
文章出處:【微信號:gh_9d70b445f494,微信公眾號:FPGA設(shè)計論壇】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
基于CC3200的SimpleLink Wi-Fi NFC讀卡器參考設(shè)計方案
SimpleLink? Wi-Fi? NFC讀卡器參考設(shè)計
是否有人有X-NUCLEO-NFC05A1 NFC讀卡器的RFAL和NDEF庫的實現(xiàn)代碼?
適用于支付、消費和工業(yè)應(yīng)用的NFC讀卡器
ST25R NFC讀卡器開發(fā)流程與設(shè)計資源簡介
模擬近場通信(NFC)讀卡器的TRF7970 NFC BoosterPack
藍牙無線讀卡器方案
藍牙無線讀卡器方案
ST25R300 NFC讀卡器技術(shù)解析與應(yīng)用指南
基于STMicroelectronics X-NUCLEO-NFC10A1的NFC讀卡器技術(shù)解析與應(yīng)用指南
使用FPGA搭建NFC讀卡器的實現(xiàn)方案
評論