Class pn532::esp32::spi_channel

Inheritance Relationships

Base Type

Class Documentation

class spi_channel : public pn532::channel

Implementation of SPI channel protocol for PN532 over ESP32’s SPI driver (UM0701-02 §6.2.5).

This class supports, when specified, the possibility of using a GPIO pin for the PN532’s IRQ line; in that case, the class does not have to poll the controller until the answers are ready, but it will instead idle and wait for the IRQ line to become active, and read the answer only then once it’s ready. That is done through a semaphore and an interrupt installed on the GPIO.

Note

This class supports a “stream-like” usage, i.e. it can progressively read pieces of an incoming info frame in order to determine its length. To achieve that, it is stateful (during a receive operation), as any receive operation other than the first has to omit specifying the data read prefix.

Warning

Experiments have shown that the SPI channel is often unstable, especially at high clocks (> 1MHz). It is not clear why this occurs, but it looks like at high speeds it fails when transmitting extended info frames. Even at low speeds, it seldom fails after long exchanges. The PN532 enters an invalid state in which it never returns an answer. Therefore it’s recommended to stay within 1MHz of speed.

Public Functions

virtual bool wake() override

Sends the byte sequence 55 55 55.

spi_channel(spi_host_device_t host, spi_bus_config_t const &bus_config, spi_device_interface_config_t device_cfg, spi_dma_chan_t dma_chan)

Construct an SPI channel for a PN532.

Note

In case of invalid host, device or bus configuration, an error message is printed, but the class is correctly constructed. It will simply always fail to send and receive anything (and may clog your output with error messages).

Parameters:
  • host – SPI Host to use. Note that on ESP32-S2 SPI1_HOST is not supported (as per ESP32’s documentation).

  • bus_config – SPI bus configuration.

  • device_cfg – SPI device configuration. Note that despite PN532 supporting up to 5MHz speed, the channel may be unstable and a lower speed (1MHz) is recommended.

  • dma_chan – The DMA channel to use for transmitting data. Note that DMA channel 0 is not supported (as per ESP32’s documentation), therefore it must be either DMA channel 1 or DMA channel 2.

spi_channel(spi_host_device_t host, spi_bus_config_t const &bus_config, spi_device_interface_config_t device_cfg, int dma_chan, gpio_num_t response_irq_line, bool manage_isr_service)

Construct an SPI channel for a PN532, using the given GPIO pin to signal when the answer is ready (IRQ line).

Using the IRQ line reduces the amount of noise on the line because it will only read the answer once it’s available.

See also

irq_assert

Note

In case of invalid host, device or bus configuration, an error message is printed, but the class is correctly constructed. It will simply always fail to send and receive anything (and may clog your output with error messages).

Parameters:
  • host – SPI Host to use. Note that on ESP32-S2 SPI1_HOST is not supported (as per ESP32’s documentation).

  • bus_config – SPI bus configuration.

  • device_cfg – SPI device configuration. Note that despite PN532 supporting up to 5MHz speed, the channel may be unstable and a lower speed (1MHz) is recommended.

  • dma_chan – The DMA channel to use for transmitting data. Note that DMA channel 0 is not supported (as per ESP32’s documentation), therefore it must be either DMA channel 1 or DMA channel 2.

  • response_irq_line – The GPIO pin connected to the IRQ line on the PN532. The PN532 signals when the responses are available by setting this line to low; an interrupt triggers then a semaphore that allows this class to read the answer only once it’s ready.

  • manage_isr_service – If set to true, the class will call gpio_install_isr_service and the corresponding uninstall command at destruction. Unless the caller manages the ISR service, this parm should be set to true.

~spi_channel() override

Frees the SPI device and uninstalls the ISR service, if specified.

Protected Functions

virtual result raw_send(mlab::range<bin_data::const_iterator> buffer, ms timeout) override

Wraps around spi_device_transmit, where only spi_transaction_ext_t.base.tx_buffer is populated.

virtual result raw_receive(mlab::range<bin_data::iterator> buffer, ms timeout) override

Wraps around spi_device_transmit, where only spi_transaction_ext_t.base.rx_buffer is populated.

result raw_poll_status(ms timeout)

Waits until data is ready to be received when an IRQ line is not available.

In IRQ mode, this method always immediately returns (because no polling has to occur). Without IRQ line, we can send a spi_command::status_read command to poll whether incoming data is ready to be received. This is sent every 10ms until timeout runs out or data is available.

Parameters:

timeout – Maximum timeout before returning channel_error::timeout

Returns:

mlab::result_success or one of

virtual bool on_receive_prepare(ms timeout) override

Asserts that that data is available to receive.

When using an IRQ line, it waits until the the IRQ line is triggered. When not using an IRQ line, it will poll the PN532 every 10ms to know whether a response is ready or not. This is done through raw_poll_status.

See also

raw_poll_status.

virtual void on_receive_complete(result<> const&) override

Close the communications by unasserting the CS line.

But there is no good way to end the transaction, so this method just reads an empty byte and releases the bus.

virtual comm_rx_mode raw_receive_mode() const override
Returns:

For spi_channel, this is always comm_rx_mode::stream.