#include "pn512.h" /** * About register bits * Higher 8 bits is page number, e.g. 0x8100 -> Page 1 addr 0 * Bit 15 is always 1 since we use page select. */ #define PN512_REG_COMMAND 0x8001U #define PN512_REG_PAGE_SELECT 0x8000U #define PN512_REG_VERSION 0x8337U /** * Command List */ #define PN512_CMD_SOFT_RESET 0x0F #define PN512_REG_PAGE(x) ((uint8_t)(x >> 0x08U)) #define PN512_REG_ADDR(x) ((uint8_t)(x & 0xFFU)) /** * @brief Switch register page to the same page as * specified by `reg`. * * @param nfc: pointer to pn512_t struct * @param reg: 16bit register to be set, `PN512_REG_XXXX` * @return pn512_ret_t: PN512_OK for success, PN512_FAIL for error. */ static pn512_ret_t pn512_switch_register_page(pn512_t *nfc, uint16_t reg) { pn512_ret_t ret = PN512_OK; if (PN512_REG_PAGE(reg) != nfc->info.current_page) { /* Select page */ uint8_t payload = PN512_REG_PAGE(reg); ret = nfc->ops.write(nfc->ops_handle, PN512_REG_ADDR(PN512_REG_PAGE_SELECT), &payload, 1U); if (ret != PN512_OK) return ret; nfc->info.current_page = PN512_REG_PAGE(reg); } return ret; } /** * @brief Read a register, except FIFO register. * * @param nfc: pointer to pn512_t struct * @param reg: 16bit register to be set, `PN512_REG_XXXX` * @param value: [OUT] value to be read * @return pn512_ret_t: PN512_OK for success, PN512_FAIL for error. */ static pn512_ret_t pn512_read_register(pn512_t *nfc, uint16_t reg, uint8_t *value) { pn512_ret_t ret = PN512_OK; ret = pn512_switch_register_page(nfc, reg); if (ret != PN512_OK) return ret; /* Issue read operation */ ret = nfc->ops.read(nfc->ops_handle, PN512_REG_ADDR(reg), value, 1U); return ret; } /** * @brief Write a register, except FIFO register. * * @param nfc: pointer to pn512_t struct * @param reg: 16bit register to be set, `PN512_REG_XXXX` * @param value: value to be written * @return pn512_ret_t: PN512_OK for success, PN512_FAIL for error. */ static pn512_ret_t pn512_write_register(pn512_t *nfc, uint16_t reg, uint8_t value) { pn512_ret_t ret = PN512_OK; ret = pn512_switch_register_page(nfc, reg); if (ret != PN512_OK) return ret; /* Issue read operation */ ret = nfc->ops.write(nfc->ops_handle, PN512_REG_ADDR(reg), &value, 1U); return ret; } /** * @brief Soft reset PN512 by sending an SoftReset command. * * @param nfc: pointer to pn512_t struct * @return pn512_ret_t: PN512_OK for success, PN512_FAIL for error. */ static pn512_ret_t pn512_soft_reset(pn512_t *nfc) { return pn512_write_register(nfc, PN512_REG_COMMAND, PN512_CMD_SOFT_RESET); } pn512_ret_t pn512_init(pn512_t *nfc) { pn512_ret_t ret = PN512_OK; /* Reset chip */ ret = nfc->ops.reset(nfc->ops_handle); if (ret != PN512_OK) return ret; /* Set current page to 0 */ uint8_t payload = 0x80; ret = nfc->ops.write(nfc->ops_handle, PN512_REG_ADDR(PN512_REG_PAGE_SELECT), &payload, 1U); if (ret != PN512_OK) return ret; nfc->info.current_page = 0; /* Synchronize status */ ret = pn512_soft_reset(nfc); if (ret != PN512_OK) return ret; // Read chip version. ret = pn512_read_register(nfc, PN512_REG_VERSION, &nfc->info.version); return ret; }