Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
pn512_transceive.c
00001 /* 00002 * Copyright (c) 2014-2018, ARM Limited, All Rights Reserved 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00006 * not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 /** 00018 * \file pn512_transceive.c 00019 * \copyright Copyright (c) ARM Ltd 2014 00020 * \author Donatien Garnier 00021 */ 00022 00023 #define __DEBUG__ 0 00024 #ifndef __MODULE__ 00025 #define __MODULE__ "pn512_transceive.c" 00026 #endif 00027 00028 #include "stack/nfc_errors.h" 00029 00030 #include "pn512.h" 00031 #include "pn512_transceive.h" 00032 #include "pn512_rf.h" 00033 #include "pn512_irq.h" 00034 #include "pn512_cmd.h" 00035 #include "pn512_registers.h" 00036 #include "pn512_internal.h" 00037 00038 00039 #define TIMEOUT 1000 00040 00041 void pn512_transceive_hw_tx_iteration(pn512_t *pPN512, bool start) 00042 { 00043 uint16_t irqs_en = pn512_irq_enabled(pPN512); 00044 00045 if (ac_buffer_reader_readable(&pPN512->writeBuf) > 0) { 00046 //Fill FIFO 00047 pn512_fifo_write(pPN512, &pPN512->writeBuf); 00048 00049 if (ac_buffer_reader_readable(&pPN512->writeBuf) > 0) { //Did not fit in FIFO 00050 pn512_irq_clear(pPN512, PN512_IRQ_LOW_ALERT); 00051 //Has low FIFO alert IRQ already been enabled? 00052 if (!(irqs_en & PN512_IRQ_LOW_ALERT)) { 00053 irqs_en |= PN512_IRQ_LOW_ALERT; 00054 pn512_irq_set(pPN512, irqs_en); 00055 } 00056 } else { 00057 if (irqs_en & PN512_IRQ_LOW_ALERT) { 00058 //Buffer has been fully sent 00059 irqs_en &= ~PN512_IRQ_LOW_ALERT; 00060 pn512_irq_set(pPN512, irqs_en); 00061 } 00062 } 00063 } 00064 00065 00066 if (start) { 00067 if ((pPN512->transceive.mode == pn512_transceive_mode_transmit) || (pPN512->transceive.mode == pn512_transceive_mode_transmit_and_target_autocoll)) { 00068 //Update bitframing register 00069 pn512_register_write(pPN512, PN512_REG_BITFRAMING, 00070 0x00 | ((pPN512->readFirstByteAlign & 0x7) << 4) | (pPN512->writeLastByteLength & 0x7)); 00071 00072 //Use transmit command 00073 pn512_cmd_exec(pPN512, PN512_CMD_TRANSMIT); 00074 } else { 00075 NFC_DBG("Bitframing %02X", 0x80 | ((pPN512->readFirstByteAlign & 0x7) << 4) | (pPN512->writeLastByteLength & 0x7)); 00076 //Update bitframing register to start transmission 00077 pn512_register_write(pPN512, PN512_REG_BITFRAMING, 00078 0x80 | ((pPN512->readFirstByteAlign & 0x7) << 4) | (pPN512->writeLastByteLength & 0x7)); 00079 } 00080 00081 //Reset last byte length, first byte align 00082 pPN512->writeLastByteLength = 8; 00083 pPN512->readFirstByteAlign = 0; 00084 } 00085 00086 //Queue task to process IRQ 00087 task_init(&pPN512->transceiver.task, EVENT_HW_INTERRUPT | EVENT_TIMEOUT, TIMEOUT, pn512_transceive_hw_tx_task, pPN512); 00088 nfc_scheduler_queue_task(&pPN512->transceiver.scheduler, &pPN512->transceiver.task); 00089 } 00090 00091 void pn512_transceive_hw_tx_task(uint32_t events, void *pUserData) 00092 { 00093 pn512_t *pPN512 = (pn512_t *) pUserData; 00094 00095 if (events & EVENT_ABORTED) { 00096 //Stop command 00097 pn512_cmd_exec(pPN512, PN512_CMD_IDLE); 00098 pPN512->transceive.mode = pn512_transceive_mode_idle; 00099 00100 NFC_ERR("Aborted TX"); 00101 00102 pn512_irq_set(pPN512, PN512_IRQ_NONE); 00103 pn512_irq_clear(pPN512, PN512_IRQ_ALL); 00104 00105 pn512_transceive_callback(pPN512, NFC_ERR_ABORTED); 00106 return; 00107 } 00108 00109 NFC_DBG("TX task"); 00110 if (events & EVENT_TIMEOUT) { 00111 // Check status 00112 NFC_DBG("Status = %02X %02X", pn512_register_read(pPN512, PN512_REG_STATUS1), pn512_register_read(pPN512, PN512_REG_STATUS2)); 00113 00114 //Stop command 00115 pn512_cmd_exec(pPN512, PN512_CMD_IDLE); 00116 pPN512->transceive.mode = pn512_transceive_mode_idle; 00117 00118 NFC_ERR("Timeout on TX"); 00119 00120 pn512_irq_set(pPN512, PN512_IRQ_NONE); 00121 pn512_irq_clear(pPN512, PN512_IRQ_ALL); 00122 00123 //Call callback 00124 pn512_transceive_callback(pPN512, NFC_ERR_TIMEOUT); 00125 return; 00126 } 00127 00128 uint16_t irqs_en = pn512_irq_enabled(pPN512); 00129 uint16_t irqs = pn512_irq_get(pPN512); 00130 00131 if (irqs & PN512_IRQ_RF_OFF) { 00132 //Stop command 00133 pn512_cmd_exec(pPN512, PN512_CMD_IDLE); 00134 pPN512->transceive.mode = pn512_transceive_mode_idle; 00135 00136 pn512_irq_set(pPN512, PN512_IRQ_NONE); 00137 pn512_irq_clear(pPN512, PN512_IRQ_ALL); 00138 NFC_WARN("RF Off"); 00139 pn512_transceive_callback(pPN512, NFC_ERR_FIELD); 00140 return; 00141 } 00142 if (irqs & PN512_IRQ_TX) { 00143 if (irqs_en & PN512_IRQ_LOW_ALERT) { 00144 //If the transmission has been completed without us getting a chance to fill the buffer up it means that we had a buffer underflow 00145 NFC_ERR("Buffer underflow"); 00146 pn512_irq_set(pPN512, PN512_IRQ_NONE); 00147 pn512_irq_clear(pPN512, PN512_IRQ_ALL); 00148 00149 pn512_transceive_callback(pPN512, NFC_ERR_UNDERFLOW); 00150 return; 00151 } 00152 00153 //Transmission complete 00154 pn512_irq_set(pPN512, PN512_IRQ_NONE); 00155 pn512_irq_clear(pPN512, PN512_IRQ_TX | PN512_IRQ_LOW_ALERT); 00156 00157 //Start receiving 00158 NFC_DBG("Transmission complete"); 00159 if (pPN512->transceive.mode != pn512_transceive_mode_transmit) { 00160 if (pPN512->transceive.mode == pn512_transceive_mode_transmit_and_target_autocoll) { 00161 //Make sure bitframing reg is clean 00162 pn512_register_write(pPN512, PN512_REG_BITFRAMING, 0x00); 00163 00164 pn512_cmd_exec(pPN512, PN512_CMD_IDLE); 00165 pn512_transceive_hw_rx_start(pPN512); 00166 00167 //Start autocoll 00168 pn512_cmd_exec(pPN512, PN512_CMD_AUTOCOLL); 00169 } else { 00170 pn512_transceive_hw_rx_start(pPN512); 00171 } 00172 return; 00173 } else { 00174 pn512_irq_set(pPN512, PN512_IRQ_NONE); 00175 pn512_irq_clear(pPN512, PN512_IRQ_RX | PN512_IRQ_HIGH_ALERT); 00176 00177 pn512_transceive_callback(pPN512, NFC_OK); 00178 return; 00179 } 00180 } 00181 if ((irqs & PN512_IRQ_LOW_ALERT) && (ac_buffer_reader_readable(&pPN512->writeBuf) > 0)) { 00182 //Continue to fill FIFO 00183 pn512_irq_clear(pPN512, PN512_IRQ_LOW_ALERT); 00184 00185 pn512_transceive_hw_tx_iteration(pPN512, false); 00186 return; 00187 } 00188 00189 if (irqs & PN512_IRQ_IDLE) { 00190 pn512_irq_clear(pPN512, PN512_IRQ_ERR); 00191 00192 NFC_ERR("Modem went to idle"); 00193 00194 pn512_cmd_exec(pPN512, PN512_CMD_IDLE); 00195 pPN512->transceive.mode = pn512_transceive_mode_idle; 00196 00197 pn512_irq_set(pPN512, PN512_IRQ_NONE); 00198 pn512_irq_clear(pPN512, PN512_IRQ_ALL); 00199 pn512_transceive_callback(pPN512, NFC_ERR_WRONG_COMM); 00200 return; 00201 } 00202 00203 //Call back function 00204 pn512_transceive_hw_tx_iteration(pPN512, false); 00205 } 00206 00207 void pn512_transceive_hw_rx_start(pn512_t *pPN512) 00208 { 00209 uint16_t irqs_en = PN512_IRQ_RX | PN512_IRQ_HIGH_ALERT | PN512_IRQ_ERR; 00210 if (PN512_FRAMING_IS_TARGET(pPN512->framing)) { 00211 irqs_en |= PN512_IRQ_RF_OFF; 00212 } 00213 00214 pn512_irq_set(pPN512, irqs_en); 00215 00216 //Reset buffer except if data should be appended to this -- TODO 00217 ac_buffer_builder_reset(&pPN512->readBufBldr); 00218 00219 //Queue task to process IRQ 00220 task_init(&pPN512->transceiver.task, EVENT_HW_INTERRUPT | EVENT_TIMEOUT, 00221 pPN512->timeout, pn512_transceive_hw_rx_task, pPN512); 00222 nfc_scheduler_queue_task(&pPN512->transceiver.scheduler, 00223 &pPN512->transceiver.task); 00224 } 00225 00226 void pn512_transceive_hw_rx_task(uint32_t events, void *pUserData) 00227 { 00228 pn512_t *pPN512 = (pn512_t *) pUserData; 00229 00230 NFC_DBG("RX task"); 00231 if (events & EVENT_ABORTED) { 00232 //Stop command 00233 pn512_cmd_exec(pPN512, PN512_CMD_IDLE); 00234 pPN512->transceive.mode = pn512_transceive_mode_idle; 00235 00236 NFC_ERR("Aborted RX"); 00237 00238 pn512_irq_set(pPN512, PN512_IRQ_NONE); 00239 pn512_irq_clear(pPN512, PN512_IRQ_ALL); 00240 00241 pn512_transceive_callback(pPN512, NFC_ERR_ABORTED); 00242 return; 00243 } 00244 00245 if (events & EVENT_TIMEOUT) { 00246 NFC_WARN("Timeout"); 00247 //Stop command 00248 pn512_cmd_exec(pPN512, PN512_CMD_IDLE); 00249 pPN512->transceive.mode = pn512_transceive_mode_idle; 00250 00251 pn512_irq_set(pPN512, PN512_IRQ_NONE); 00252 pn512_irq_clear(pPN512, PN512_IRQ_ALL); 00253 00254 //Call callback 00255 pn512_transceive_callback(pPN512, NFC_ERR_TIMEOUT); 00256 return; 00257 } 00258 00259 uint16_t irqs = pn512_irq_get(pPN512); 00260 NFC_DBG("irqs %04x", irqs); 00261 bool collision_detected = false; 00262 if (irqs & PN512_IRQ_ERR) { 00263 pn512_irq_clear(pPN512, PN512_IRQ_ERR); 00264 00265 uint8_t err_reg = pn512_register_read(pPN512, PN512_REG_ERROR); 00266 NFC_ERR("Got error - error reg is %02X", err_reg); 00267 // if err_reg == 0, sticky error that must have been cleared automatically, continue 00268 if (err_reg != 0) { 00269 //If it's a collsision, flag it but still carry on with RX procedure 00270 collision_detected = true; 00271 00272 if ((err_reg == 0x08) || (err_reg == 0x0A)) { // Collision (and maybe parity) (and no other error) 00273 irqs &= ~PN512_IRQ_ERR; 00274 irqs |= PN512_IRQ_RX; 00275 } else { 00276 NFC_DBG_BLOCK( 00277 //Empty FIFO into buffer 00278 pn512_fifo_read(pPN512, &pPN512->readBufBldr); 00279 00280 NFC_DBG("Received"); 00281 ac_buffer_dump(ac_buffer_builder_buffer(&pPN512->readBufBldr)); 00282 00283 NFC_DBG("Computed CRC = %02X %02X", pn512_register_read(pPN512, PN512_REG_CRCRESULT_MSB), pn512_register_read(pPN512, PN512_REG_CRCRESULT_LSB)); 00284 00285 ) 00286 00287 //Stop command 00288 pn512_cmd_exec(pPN512, PN512_CMD_IDLE); 00289 pPN512->transceive.mode = pn512_transceive_mode_idle; 00290 00291 pn512_irq_set(pPN512, PN512_IRQ_NONE); 00292 pn512_irq_clear(pPN512, PN512_IRQ_ALL); 00293 00294 //Call callback 00295 pn512_transceive_callback(pPN512, NFC_ERR_WRONG_COMM); 00296 return; 00297 } 00298 } 00299 } 00300 if ((irqs & PN512_IRQ_RX) || (irqs & PN512_IRQ_HIGH_ALERT)) { 00301 //Empty FIFO into buffer 00302 pn512_fifo_read(pPN512, &pPN512->readBufBldr); 00303 00304 if ((ac_buffer_builder_writable(&pPN512->readBufBldr) == 0) && (pn512_fifo_length(pPN512) > 0)) { 00305 //Stop command 00306 pn512_cmd_exec(pPN512, PN512_CMD_IDLE); 00307 pPN512->transceive.mode = pn512_transceive_mode_idle; 00308 00309 NFC_WARN("RX buffer overflow"); 00310 00311 pn512_irq_set(pPN512, PN512_IRQ_NONE); 00312 pn512_irq_clear(pPN512, PN512_IRQ_ALL); 00313 //Call callback 00314 pn512_transceive_callback(pPN512, NFC_ERR_BUFFER_TOO_SMALL); 00315 return; //overflow 00316 } 00317 00318 if (irqs & PN512_IRQ_HIGH_ALERT) { 00319 NFC_DBG("High alert"); 00320 pn512_irq_clear(pPN512, PN512_IRQ_HIGH_ALERT); 00321 } 00322 00323 if (irqs & PN512_IRQ_RX) { 00324 pn512_irq_clear(pPN512, PN512_IRQ_RX); 00325 00326 size_t last_byte_length = pn512_register_read(pPN512, PN512_REG_CONTROL) & 0x7; 00327 if (last_byte_length == 0) { 00328 last_byte_length = 8; 00329 } 00330 pPN512->readLastByteLength = last_byte_length; 00331 00332 pn512_irq_set(pPN512, PN512_IRQ_NONE); 00333 pn512_irq_clear(pPN512, PN512_IRQ_RX | PN512_IRQ_HIGH_ALERT); 00334 00335 NFC_DBG("Received:"); 00336 NFC_DBG_BLOCK(ac_buffer_dump(ac_buffer_builder_buffer(&pPN512->readBufBldr));) 00337 00338 if ((pPN512->transceive.mode == pn512_transceive_mode_target_autocoll) || (pPN512->transceive.mode == pn512_transceive_mode_transmit_and_target_autocoll)) { 00339 //Check if target was activated 00340 if (!(pn512_register_read(pPN512, PN512_REG_STATUS2) & 0x10)) { 00341 pPN512->transceive.mode = pn512_transceive_mode_idle; 00342 00343 pn512_irq_set(pPN512, PN512_IRQ_NONE); 00344 pn512_irq_clear(pPN512, PN512_IRQ_ALL); 00345 //Call callback 00346 pn512_transceive_callback(pPN512, NFC_ERR_PROTOCOL); 00347 return; 00348 } 00349 //PN512 switches to transceive automatically 00350 pPN512->transceive.mode = pn512_transceive_mode_transceive; 00351 } else if (pPN512->transceive.mode == pn512_transceive_mode_receive) { 00352 pPN512->transceive.mode = pn512_transceive_mode_transceive; 00353 //pn512_cmd_exec(pPN512, PN512_CMD_IDLE); //Useful? 00354 } 00355 00356 if (!collision_detected) { 00357 pn512_transceive_callback(pPN512, NFC_OK); 00358 } else { 00359 pn512_transceive_callback(pPN512, NFC_ERR_COLLISION); 00360 } 00361 00362 return; 00363 } 00364 } 00365 if (irqs & PN512_IRQ_RF_OFF) { 00366 //Stop command 00367 pn512_cmd_exec(pPN512, PN512_CMD_IDLE); 00368 pPN512->transceive.mode = pn512_transceive_mode_idle; 00369 00370 pn512_irq_set(pPN512, PN512_IRQ_NONE); 00371 pn512_irq_clear(pPN512, PN512_IRQ_ALL); 00372 00373 //Call callback 00374 pn512_transceive_callback(pPN512, NFC_ERR_FIELD); 00375 return; 00376 } 00377 00378 //Queue task to process IRQ 00379 task_init(&pPN512->transceiver.task, EVENT_HW_INTERRUPT | EVENT_TIMEOUT, 00380 pPN512->timeout, pn512_transceive_hw_rx_task, pPN512); 00381 nfc_scheduler_queue_task(&pPN512->transceiver.scheduler, 00382 &pPN512->transceiver.task); 00383 } 00384 00385 void pn512_transceive_hw(pn512_t *pPN512, pn512_transceive_mode_t mode, pn512_cb_t cb) 00386 { 00387 uint16_t irqs_en; 00388 00389 //Store callback 00390 pPN512->transceive.cb = cb; 00391 00392 //Clear FIFO 00393 pn512_fifo_clear(pPN512); 00394 00395 //Clear previous IRQs if present 00396 pn512_irq_clear(pPN512, PN512_IRQ_RX | PN512_IRQ_TX | PN512_IRQ_HIGH_ALERT | PN512_IRQ_LOW_ALERT | PN512_IRQ_ERR | PN512_IRQ_IDLE | PN512_IRQ_RF_OFF); 00397 00398 if (PN512_FRAMING_IS_TARGET(pPN512->framing)) { 00399 //RF off? 00400 if (!(pn512_register_read(pPN512, PN512_REG_STATUS1) & 0x04)) { 00401 //Call callback 00402 pn512_transceive_callback(pPN512, NFC_ERR_FIELD); 00403 return; 00404 } 00405 } else if ((pPN512->transceive.mode != mode) && (mode == pn512_transceive_mode_transceive)) { 00406 pn512_cmd_exec(pPN512, PN512_CMD_TRANSCEIVE); 00407 } 00408 00409 pPN512->transceive.mode = mode; 00410 00411 if (mode == pn512_transceive_mode_receive) { 00412 pn512_cmd_exec(pPN512, PN512_CMD_IDLE); 00413 pn512_transceive_hw_rx_start(pPN512); 00414 pn512_cmd_exec(pPN512, PN512_CMD_TRANSCEIVE); 00415 } else if (mode == pn512_transceive_mode_target_autocoll) { 00416 //Make sure bitframing reg is clean 00417 pn512_register_write(pPN512, PN512_REG_BITFRAMING, 0x00); 00418 00419 pn512_transceive_hw_rx_start(pPN512); 00420 00421 //Start autocoll 00422 pn512_cmd_exec(pPN512, PN512_CMD_AUTOCOLL); 00423 return; 00424 } else { 00425 NFC_DBG("Sending:"); 00426 NFC_DBG_BLOCK(ac_buffer_dump(&pPN512->writeBuf);) 00427 00428 //Transmit a frame to remote target/initiator 00429 irqs_en = PN512_IRQ_TX | PN512_IRQ_IDLE; 00430 if (PN512_FRAMING_IS_TARGET(pPN512->framing)) { 00431 irqs_en |= PN512_IRQ_RF_OFF; 00432 } 00433 00434 pn512_irq_set(pPN512, irqs_en); 00435 00436 pn512_transceive_hw_tx_iteration(pPN512, true); 00437 } 00438 } 00439 00440 00441
Generated on Tue Jul 12 2022 13:54:42 by
