Skip to content

Instantly share code, notes, and snippets.

@jef-sure
Last active December 30, 2025 22:52
Show Gist options
  • Select an option

  • Save jef-sure/f118547f273e2acfa9b4600f053ecca7 to your computer and use it in GitHub Desktop.

Select an option

Save jef-sure/f118547f273e2acfa9b4600f053ecca7 to your computer and use it in GitHub Desktop.
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "esp_rom_sys.h"
#include "esp_system.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
#include "hal/gpio_hal.h"
bool get_out_gp_level_hal(gpio_num_t gpio_num)
{
gpio_dev_t *hw = GPIO_HAL_GET_HW(GPIO_PORT_0);
if (gpio_num < 32) {
return (hw->out >> gpio_num) & 0x1;
} else {
return (hw->out1.data >> (gpio_num - 32)) & 0x1;
}
}
*/
enum
{
PN5180_RST = GPIO_NUM_12,
PN5180_SCK = GPIO_NUM_18,
PN5180_MOSI = GPIO_NUM_23,
PN5180_MISO = GPIO_NUM_19,
PN5180_NSS = GPIO_NUM_5,
PN5180_CS_DUMMY = GPIO_NUM_22,
PN5180_BUSY = GPIO_NUM_21,
PN5180_FREQ = 7000000,
};
const char *TAG = "PN5180";
#define PN5180_SPI_HOST SPI3_HOST
#define PN5180_MAX_BUF_SIZE 512
#define PN5180_TIMEOUT 500 // ms
static bool pn5180_wait_busy_level(int expected_level, int timeout_ms, const char *timeout_log)
{
int64_t deadline_us = esp_timer_get_time() + ((int64_t)timeout_ms * 1000);
while (gpio_get_level(PN5180_BUSY) != expected_level) {
if (esp_timer_get_time() >= deadline_us) {
ESP_LOGE(TAG, "%s (BUSY=%d)", timeout_log, gpio_get_level(PN5180_BUSY));
return false;
}
esp_rom_delay_us(1);
}
return true;
}
void pn5180_delay_ms(int ms)
{
int64_t start = esp_timer_get_time();
while ((esp_timer_get_time() - start) < (ms * 1000)) {
esp_rom_delay_us(100);
}
}
void app_main(void)
{
spi_bus_config_t bus_config = {
.mosi_io_num = PN5180_MOSI,
.miso_io_num = PN5180_MISO,
.sclk_io_num = PN5180_SCK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 0,
};
spi_device_interface_config_t dev_config = {
.clock_speed_hz = PN5180_FREQ,
.mode = 0,
.spics_io_num = PN5180_CS_DUMMY,
.queue_size = 2,
.flags = 0 // SPI_DEVICE_HALFDUPLEX,
};
if (spi_bus_initialize(PN5180_SPI_HOST, &bus_config, SPI_DMA_DISABLED) != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize SPI bus");
return;
}
spi_device_handle_t spi_handle;
if (spi_bus_add_device(PN5180_SPI_HOST, &dev_config, &spi_handle) != ESP_OK) {
ESP_LOGE(TAG, "Failed to add SPI device");
return;
}
uint8_t *send_buf = (uint8_t *)heap_caps_calloc(1, PN5180_MAX_BUF_SIZE, MALLOC_CAP_DMA);
uint8_t *recv_buf = (uint8_t *)heap_caps_calloc(1, PN5180_MAX_BUF_SIZE, MALLOC_CAP_DMA);
gpio_set_direction(PN5180_NSS, GPIO_MODE_OUTPUT);
gpio_set_direction(PN5180_RST, GPIO_MODE_OUTPUT);
gpio_set_direction(PN5180_BUSY, GPIO_MODE_INPUT);
// gpio_config_t busy_cfg = {
// .pin_bit_mask = (1ULL << PN5180_BUSY), //
// .mode = GPIO_MODE_INPUT, //
// .pull_up_en = GPIO_PULLUP_ENABLE, //
// .pull_down_en = GPIO_PULLDOWN_DISABLE, //
// .intr_type = GPIO_INTR_DISABLE //
// };
// gpio_config(&busy_cfg);
// gpio_dump_io_configuration(stdout, (1ULL << PN5180_RST) | (1ULL << PN5180_NSS) | (1ULL << PN5180_BUSY) |
// (1ULL << PN5180_MOSI) | (1ULL << PN5180_MISO) | (1ULL << PN5180_SCK));
gpio_set_level(PN5180_NSS, 1);
gpio_set_level(PN5180_RST, 1); //
pn5180_delay_ms(100);
gpio_set_level(PN5180_RST, 0); // reset low
pn5180_delay_ms(50);
gpio_set_level(PN5180_RST, 1); // release reset
pn5180_delay_ms(100);
printf("Initial BUSY state: %d\n", gpio_get_level(PN5180_BUSY));
spi_transaction_t trans;
memset(&trans, 0, sizeof(trans));
send_buf[0] = 0x04; // PN5180_READ_REGISTER
send_buf[1] = 0x02; // IRQ_STATUS
trans.tx_buffer = send_buf;
trans.rx_buffer = recv_buf;
trans.length = 2 * 8; // 2 bytes
if (!pn5180_wait_busy_level(0, PN5180_TIMEOUT, "PN5180 BUSY pin timeout")) {
return;
}
gpio_set_level(PN5180_NSS, 0); // assert nss
esp_rom_delay_us(10);
if (spi_device_polling_transmit(spi_handle, &trans) != ESP_OK) {
ESP_LOGE(TAG, "Failed to transmit SPI transaction");
return;
}
if (!pn5180_wait_busy_level(1, PN5180_TIMEOUT, "PN5180 is not BUSY after transfer")) {
return;
}
gpio_set_level(PN5180_NSS, 1);
if (!pn5180_wait_busy_level(0, PN5180_TIMEOUT, "PN5180 is BUSY after send")) {
return;
}
printf("Reading response...\n");
memset(&trans, 0, sizeof(trans));
memset(send_buf, 0xff, PN5180_MAX_BUF_SIZE);
trans.tx_buffer = send_buf;
trans.rx_buffer = recv_buf;
trans.length = 4 * 8; // 4 bytes
gpio_set_level(PN5180_NSS, 0); //
esp_rom_delay_us(10);
if (spi_device_polling_transmit(spi_handle, &trans) != ESP_OK) {
ESP_LOGE(TAG, "Failed to transmit SPI transaction");
return;
}
if (!pn5180_wait_busy_level(1, PN5180_TIMEOUT, "PN5180 no BUSY after recv")) {
gpio_set_level(PN5180_NSS, 1);
return;
}
gpio_set_level(PN5180_NSS, 1);
if (!pn5180_wait_busy_level(0, PN5180_TIMEOUT, "PN5180 is BUSY after recv")) {
return;
}
ESP_LOGI(TAG, "Received data: %02x %02x %02x %02x", recv_buf[0], recv_buf[1], recv_buf[2], recv_buf[3]);
free(send_buf);
free(recv_buf);
}
/*
Log:
Initial BUSY state: 0
E (1094) PN5180: PN5180 is not BUSY after transfer (BUSY=0)
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment