From 4d175076d526bad4d80fa7edbf9fd59a67962db4 Mon Sep 17 00:00:00 2001 From: whowechina Date: Sun, 26 Nov 2023 21:14:22 +0800 Subject: [PATCH] PN5180 work started (only reads a bit Mifare) --- firmware/src/CMakeLists.txt | 4 +- firmware/src/commands.c | 135 +++++++++++++++++++++++ firmware/src/main.c | 7 ++ firmware/src/pn5180.c | 208 ++++++++++++++++++++++++++++++++++++ firmware/src/pn5180.h | 44 ++++++++ 5 files changed, 396 insertions(+), 2 deletions(-) create mode 100644 firmware/src/pn5180.c create mode 100644 firmware/src/pn5180.h diff --git a/firmware/src/CMakeLists.txt b/firmware/src/CMakeLists.txt index 48d800c..89dc338 100644 --- a/firmware/src/CMakeLists.txt +++ b/firmware/src/CMakeLists.txt @@ -5,7 +5,7 @@ function(make_firmware board board_def) pico_sdk_init() add_executable(${board} main.c save.c config.c commands.c light.c keypad.c - aime.c cli.c pn532.c + aime.c cli.c pn532.c pn5180.c usb_descriptors.c) target_compile_definitions(${board} PUBLIC ${board_def}) pico_enable_stdio_usb(${board} 1) @@ -21,7 +21,7 @@ function(make_firmware board board_def) target_link_libraries(${board} PRIVATE pico_multicore pico_stdlib hardware_pio hardware_pwm hardware_flash - hardware_adc hardware_i2c hardware_watchdog + hardware_adc hardware_i2c hardware_spi hardware_watchdog tinyusb_device tinyusb_board) pico_add_extra_outputs(${board}) diff --git a/firmware/src/commands.c b/firmware/src/commands.c index 54c1766..bb32eef 100644 --- a/firmware/src/commands.c +++ b/firmware/src/commands.c @@ -12,6 +12,7 @@ #include "cli.h" #include "pn532.h" +#include "pn5180.h" static int fps[2]; void fps_count(int core) @@ -146,6 +147,134 @@ static void handle_level(int argc, char *argv[]) handle_display(); } +static void handle_pnboot() +{ + pn5180_reset(); +} + +static void handle_pnver() +{ + uint8_t buf[6]; + pn5180_read_eeprom(0x10, buf, sizeof(buf)); + + printf("Version: %02x %02x %02x %02x %02x %02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + pn5180_print_rf_cfg(); +} + +static void handle_pnread(int argc, char *argv[]) +{ + int reg = cli_extract_non_neg_int(argv[0], 0); + printf("%2d: %08lx\n", reg, pn5180_read_reg(reg)); +} + +static void handle_pnmifare() +{ + pn5180_load_rf_config(0x00, 0x80); // 1 + pn5180_rf_on(); // 2 + + sleep_ms(2000); + + pn5180_and_reg(PN5180_REG_CRC_TX_CONFIG, 0xfffffffe); // 3 + pn5180_and_reg(PN5180_REG_CRC_RX_CONFIG, 0xfffffffe); // 4 + + pn5180_and_reg(PN5180_REG_IRQ_CLEAR, 0x000fffff); // 5 + pn5180_and_reg(PN5180_REG_SYSTEM_CONFIG, 0xfffffff8); // 6 + pn5180_or_reg(PN5180_REG_SYSTEM_CONFIG, 0x03); // 7 + + uint8_t buf[] = {0x26}; + pn5180_send_data(buf, sizeof(buf), 7); // 8 + + for (int i = 0; i < 10; i++) { + printf("irq: %08lx rx: %08lx\n", pn5180_read_reg(PN5180_REG_IRQ_STATUS), + pn5180_read_reg(PN5180_REG_RX_STATUS)); + sleep_ms(2); + } + + uint8_t out[128] = {0}; + pn5180_read_data(out, 2); // 10 + + printf("2: %02x %02x\n", out[0], out[1]); + +#if 0 + uint8_t anti_collision[] = {0x93, 0x20}; + pn5180_send_data(anti_collision, sizeof(anti_collision), 0); + + pn5180_read_data(out + 2, 5); + printf("5: %02x %02x %02x %02x %02x\n", out[2], out[3], out[4], out[5], out[6]); + + pn5180_or_reg(PN5180_REG_CRC_RX_CONFIG, 0x01); + pn5180_or_reg(PN5180_REG_CRC_TX_CONFIG, 0x01); + + anti_collision[1] = 0x70; + pn5180_send_data(anti_collision, sizeof(anti_collision), 0); + pn5180_read_data(out + 7, 1); // sak + printf("1: %02x\n", out[7]); +#endif + pn5180_rf_off(); +} + +static void handle_pnfeli() +{ + pn5180_load_rf_config(0x09, 0x89); + pn5180_rf_on(); + + sleep_ms(1000); + + pn5180_and_reg(PN5180_REG_SYSTEM_CONFIG, 0xffffffbf); + + uint8_t cmd[] = {0x06, 0x00, 0xff, 0xff, 0x01, 0x00}; + + pn5180_send_data(cmd, 6, 0x00); + + sleep_ms(100); + + uint8_t out[32] = {0}; + pn5180_read_data(out, 20); + + pn5180_rf_off(); + + printf("feli:"); + for (int i = 0; i < 20; i++) { + printf(" %02x", out[i]); + } + printf("\n"); +} + + +static void handle_pninv() +{ + pn5180_load_rf_config(0x0d, 0x8d); + pn5180_rf_on(); + + sleep_ms(1000); + + pn5180_and_reg(PN5180_REG_IRQ_CLEAR, 0x000fffff); // 5 + pn5180_and_reg(PN5180_REG_SYSTEM_CONFIG, 0xfffffff8); // 6 + pn5180_or_reg(PN5180_REG_SYSTEM_CONFIG, 0x03); // 7 + + uint8_t cmd[] = {0x06, 0x01, 0x00}; + pn5180_send_data(cmd, 3, 0); + + for (int i = 0; i < 10; i++) { + printf("irq: %08lx rx: %08lx\n", pn5180_read_reg(PN5180_REG_IRQ_STATUS), + pn5180_read_reg(PN5180_REG_RX_STATUS)); + sleep_ms(2); + } + + uint32_t rxstatus = pn5180_read_reg(PN5180_REG_RX_STATUS); + int len = rxstatus & 0x1ff; + uint8_t buf[len]; + pn5180_read_data(buf, len); + + printf("uid:"); + for (int i = 0; i < len; i++) { + printf(" %02x", buf[i]); + } + printf("\n"); + pn5180_rf_off(); +} + void commands_init() { cli_register("display", handle_display, "Display all settings."); @@ -154,4 +283,10 @@ void commands_init() cli_register("nfc", handle_nfc, "NFC debug."); cli_register("light", handle_light, "Turn on/off lights."); cli_register("level", handle_level, "Set light level."); + cli_register("pnboot", handle_pnboot, "PN5180 reboot"); + cli_register("pnver", handle_pnver, "PN5180 version"); + cli_register("pnread", handle_pnread, "PN5180 debug rf"); + cli_register("pnmifare", handle_pnmifare, "PN5180 mifare"); + cli_register("pnfeli", handle_pnfeli, "PN5180 felica"); + cli_register("pninv", handle_pninv, "PN5180 15693"); } diff --git a/firmware/src/main.c b/firmware/src/main.c index c195a7f..49a9821 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -31,6 +31,8 @@ #include "keypad.h" #include "pn532.h" +#include "pn5180.h" + #include "aime.h" static struct { @@ -211,6 +213,11 @@ void init() pn532_init(I2C_PORT, I2C_SCL, I2C_SDA, I2C_FREQ); pn532_set_wait_loop(wait_loop); + + pn5180_init(spi0, 16, 18, 19, 27, 17, 26); + pn5180_load_rf_config(0x0d, 0x8d); + pn5180_rf_on(); + aime_init(cdc_aime_putc); cli_init("aic_pico>", "\n << AIC Pico >>\n" diff --git a/firmware/src/pn5180.c b/firmware/src/pn5180.c new file mode 100644 index 0000000..547ca16 --- /dev/null +++ b/firmware/src/pn5180.c @@ -0,0 +1,208 @@ +/* + * PN5180 NFC Reader + * WHowe + * + */ + +#include +#include +#include + +#include "pico/stdlib.h" + +#include "hardware/gpio.h" +#include "hardware/spi.h" + +#include "pn5180.h" + +#define IO_TIMEOUT_US 1000 +#define PN5180_I2C_ADDRESS 0x24 + +#define CMD_WRITE_REG 0x00 +#define CMD_WRITE_REG_OR 0x01 +#define CMD_WRITE_REG_AND 0x02 +#define CMD_READ_REG 0x04 +#define CMD_WRITE_EEPROM 0x06 +#define CMD_READ_EEPROM 0x07 +#define CMD_SEND_DATA 0x09 +#define CMD_READ_DATA 0x0a +#define CMD_LOAD_RF_CONFIG 0x11 +#define CMD_RF_ON 0x16 +#define CMD_RF_OFF 0x17 + +static struct { + spi_inst_t *port; + uint8_t rst; + uint8_t nss; + uint8_t busy; +} spi; + +void pn5180_init(spi_inst_t *port, uint8_t rx, uint8_t sck, uint8_t tx, + uint8_t rst, uint8_t nss, uint8_t busy) +{ + spi_init(port, 2000 * 1000); + spi_set_format(port, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST); + + gpio_set_function(rx, GPIO_FUNC_SPI); + gpio_set_function(sck, GPIO_FUNC_SPI); + gpio_set_function(tx, GPIO_FUNC_SPI); + //gpio_set_function(nss, GPIO_FUNC_SPI); + + gpio_init(nss); + gpio_set_dir(nss, GPIO_OUT); + gpio_pull_up(nss); + gpio_put(nss, 1); + + gpio_init(rst); + gpio_set_dir(rst, GPIO_OUT); + gpio_pull_up(rst); + gpio_put(rst, 1); + + spi.port = port; + spi.rst = rst; + spi.nss = nss; + spi.busy = busy; +} + +static inline void wait_not_busy() +{ + while (gpio_get(spi.busy)) { + sleep_us(10); + } +} + +static inline void wait_until_busy() +{ + while (!gpio_get(spi.busy)) { + sleep_us(10); + } +} + +static inline void begin_transmission() +{ + wait_not_busy(); + gpio_put(spi.nss, 0); + sleep_ms(10); +} + +static inline void end_transmission() +{ + gpio_put(spi.nss, 1); + sleep_ms(10); +} + +static pn5180_wait_loop_t wait_loop = NULL; + +void pn5180_set_wait_loop(pn5180_wait_loop_t loop) +{ + wait_loop = loop; +} + +static bool read_write(const uint8_t *data, uint8_t len, uint8_t *buf, uint8_t buf_len) +{ + begin_transmission(); + spi_write_blocking(spi.port, data, len); + end_transmission(); + + if (!buf || (buf_len == 0)) { + return true; + } + + begin_transmission(); + spi_read_blocking(spi.port, 0, buf, buf_len); + end_transmission(); + + return true; +} + +static bool write_reg(uint8_t cmd, uint8_t reg, uint32_t v32) +{ + uint8_t buf[] = { cmd, reg, v32 & 0xff, (v32 >> 8) & 0xff, + (v32 >> 16) & 0xff, (v32 >> 24) & 0xff }; + return read_write(buf, sizeof(buf), NULL, 0); +} + +void pn5180_write_reg(uint8_t reg, uint32_t v32) +{ + write_reg(CMD_WRITE_REG, reg, v32); +} + +void pn5180_or_reg(uint8_t reg, uint32_t mask) +{ + write_reg(CMD_WRITE_REG_OR, reg, mask); +} + +void pn5180_and_reg(uint8_t reg, uint32_t mask) +{ + write_reg(CMD_WRITE_REG_AND, reg, mask); +} + +uint32_t pn5180_read_reg(uint8_t reg) +{ + uint8_t buf[] = { CMD_READ_REG, reg }; + uint8_t out[4]; + read_write(buf, sizeof(buf), out, sizeof(out)); + return out[0] | (out[1] << 8) | (out[2] << 16) | (out[3] << 24); +} + +void pn5180_send_data(const uint8_t *data, uint8_t len, uint8_t last_bits) +{ + uint8_t buf[len + 2]; + buf[0] = CMD_SEND_DATA; + buf[1] = last_bits; + memmove(buf + 2, data, len); + read_write(buf, sizeof(buf), NULL, 0); +} + +void pn5180_read_data(uint8_t *data, uint8_t len) +{ + uint8_t buf[] = { CMD_READ_DATA, 0x00 }; + read_write(buf, sizeof(buf), data, len); +} + +void pn5180_read_eeprom(uint8_t addr, uint8_t *buf, uint8_t len) +{ + uint8_t cmd[3] = { CMD_READ_EEPROM, addr, len }; + read_write(cmd, sizeof(cmd), buf, len); +} + +void pn5180_load_rf_config(uint8_t tx_cfg, uint8_t rx_cfg) +{ + uint8_t buf[] = { CMD_LOAD_RF_CONFIG, tx_cfg, rx_cfg}; + read_write(buf, sizeof(buf), NULL, 0); +} + +void pn5180_rf_on() +{ + uint8_t buf[] = { CMD_RF_ON, 0 }; + read_write(buf, sizeof(buf), NULL, 0); +} + +void pn5180_rf_off() +{ + uint8_t buf[] = { CMD_RF_OFF, 0 }; + read_write(buf, sizeof(buf), NULL, 0); +} + +void pn5180_reset() +{ + gpio_put(spi.rst, 0); + sleep_ms(10); + gpio_put(spi.rst, 1); + sleep_ms(10); + while (pn5180_read_reg(PN5180_REG_IRQ_STATUS) & (1 << 2)) { + printf("irq: %08lx\n", pn5180_read_reg(PN5180_REG_IRQ_STATUS)); + } + + pn5180_write_reg(PN5180_REG_IRQ_CLEAR, 0xffffffff); // clear all flags +} + +void pn5180_print_rf_cfg() +{ + printf("RF_CONTROL_TX_CLK: %08lx\n", pn5180_read_reg(0x21)); + printf("TX_DATA_MOD: %08lx\n", pn5180_read_reg(0x16)); + printf("TX_UNDERSHOOT_CFG: %08lx\n", pn5180_read_reg(0x14)); + printf("TX_OVERSHOOT_CFG: %08lx\n", pn5180_read_reg(0x15)); + printf("RF_CONTROL_TX: %08lx\n", pn5180_read_reg(0x20)); + printf("ANT_CONTROL: %08lx\n", pn5180_read_reg(0x29)); +} \ No newline at end of file diff --git a/firmware/src/pn5180.h b/firmware/src/pn5180.h new file mode 100644 index 0000000..8a87673 --- /dev/null +++ b/firmware/src/pn5180.h @@ -0,0 +1,44 @@ +/* + * PN5180 NFC Reader + * WHowe + * + */ + +#ifndef PN5180_H +#define PN5180_H + +#include "hardware/spi.h" + +#define PN5180_REG_SYSTEM_CONFIG 0x00 +#define PN5180_REG_IRQ_ENABLE 0x01 +#define PN5180_REG_IRQ_STATUS 0x02 +#define PN5180_REG_IRQ_CLEAR 0x03 +#define PN5180_REG_RX_STATUS 0x13 +#define PN5180_REG_RF_STATUS 0x1d +#define PN5180_REG_CRC_RX_CONFIG 0x12 +#define PN5180_REG_CRC_TX_CONFIG 0x19 + +typedef void (*pn5180_wait_loop_t)(); + +void pn5180_set_wait_loop(pn5180_wait_loop_t loop); + +void pn5180_init(spi_inst_t *port, uint8_t rx, uint8_t sck, uint8_t tx, + uint8_t rst, uint8_t nss, uint8_t busy); + +void pn5180_write_reg(uint8_t reg, uint32_t v32); +void pn5180_or_reg(uint8_t reg, uint32_t mask); +void pn5180_and_reg(uint8_t reg, uint32_t mask); +uint32_t pn5180_read_reg(uint8_t reg); +void pn5180_send_data(const uint8_t *data, uint8_t len, uint8_t last_bits); +void pn5180_read_data(uint8_t *data, uint8_t len); +void pn5180_read_eeprom(uint8_t addr, uint8_t *buf, uint8_t len); + +void pn5180_load_rf_config(uint8_t tx_cfg, uint8_t rx_cfg); +void pn5180_rf_on(); +void pn5180_rf_off(); + +void pn5180_reset(); + +void pn5180_print_rf_cfg(); + +#endif