Implement PN512 SPI transport driver

pull/7822/head
Donatien Garnier 2018-08-16 12:01:01 +01:00
parent d4c29207cc
commit 5fa27744b0
7 changed files with 213 additions and 8 deletions

View File

@ -20,19 +20,23 @@
#include <stdint.h>
#include "nfc/NFCControllerDriver.h"
#include "PN512TransportDriver.h"
namespace mbed {
namespace nfc {
struct PN512TransportDriver;
class PN512Driver : NFCControllerDriver {
class PN512Driver : public NFCControllerDriver, private PN512TransportDriver::Delegate {
public:
PN512Driver(PN512TransportDriver* transport_driver);
private:
virtual void initialize(nfc_scheduler_timer_t* pTimer) = 0;
virtual nfc_transceiver_t* get_transceiver() const;
private:
// PN512TransportDriver::Delegate implementation
void on_hw_interrupt();
pn512_t _pn512;
};

View File

@ -14,21 +14,22 @@
* limitations under the License.
*/
#ifndef MBED_PN512_TRANSPORT_DRIVER_H
#define MBED_PN512_TRANSPORT_DRIVER_H
#ifndef MBED_PN512_SPI_TRANSPORT_DRIVER_H
#define MBED_PN512_SPI_TRANSPORT_DRIVER_H
#include <stdint.h>
#include "platform/platform.h"
#include "platform/nfc_transport.h"
#include "PN512TransportDriver.h"
namespace mbed {
namespace nfc {
class PN512SPITransportDriver {
class PN512SPITransportDriver : public PN512TransportDriver {
public:
PN512SPITransportDriver(PinName mosi, PinName miso, PinName sclk, PinName ssel, PinName irq);
PN512SPITransportDriver(PinName mosi, PinName miso, PinName sclk, PinName ssel, PinName irq, PinName rst);
private:
virtual void initialize();
@ -43,7 +44,9 @@ namespace nfc {
nfc_transport_t _nfc_transport;
SPI _spi;
DigitalOut _ssel;
InterruptIn _irq;
DigitalOut _rst;
};
} // namespace nfc

View File

@ -23,10 +23,53 @@
namespace mbed {
namespace nfc {
struct PN512TransportDriver {
/**
* The PN512 supports multiple transport mechanisms (SPI, I2C, UART): this class provides a unified API across these transports
*/
class PN512TransportDriver {
public:
/**
* The PN512TransportDriver delegate
*/
struct Delegate {
/**
* Called when the PN512 asserts the interrupt line
*/
void on_hw_interrupt();
};
/**
* Create a PN512TransportDriver instance
*/
PN512TransportDriver();
/**
* Initialize transport driver and perform a chip reset
*/
virtual void initialize() = 0;
/**
* Retrieve the nfc_transport_t struct for the stack to use
*
* @return a pointer to a nfc_transport_t struct
*/
virtual nfc_transport_t* get_transport() const = 0;
/**
* Set this instance's delegate
*
* @param[in] delegate the delegate instance to use
*/
void set_delegate(Delegate* delegate);
protected:
/**
* An implementation must call this function (can be called from interrupt context)
* when the PN512 asserts its interrupt line
*/
void hw_interrupt();
private:
Delegate* _delegate;
};
} // namespace nfc

View File

@ -0,0 +1,17 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "PN512Driver.h"

View File

@ -0,0 +1,104 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "PN512SPITransportDriver.h"
#include "stack/transceiver/transceiver.h"
#include "platform/mbed_wait_api.h"
using namespace mbed;
using namespace mbed::nfc;
PN512SPITransportDriver::PN512SPITransportDriver(PinName mosi, PinName miso, PinName sclk, PinName ssel, PinName irq, PinName rst)) :
_spi(mosi, miso, sclk),
_ssel(ssel, 1),
_irq(irq, PullNone),
_rst(rst, 1) {
// Use SPI mode 0
_spi.format(8, 0);
// The PN512 supports SPI clock frequencies up to 10MHz, so use this if we can
_spi.frequency(10E6UL);
// Initialize NFC transport
nfc_transport_init(&_nfc_transport, &PN512SPITransportDriver::s_transport_write, &PN512SPITransportDriver::s_transport_read, this);
}
void PN512SPITransportDriver::initialize() {
// Deactivate IRQ
_irq.rise(callback(NULL));
// Assert reset pin
// According to the datasheet, it needs to be asserted for at least 100ns
// Wait for 1us as that's the shortest time we can wait for
_rst = 0;
wait_us(1);
_rst = 1;
// Setup IRQ pin
_irq.rise(callback(this, &PN512SPITransportDriver::hw_interrupt));
}
nfc_transport_t* PN512SPITransportDriver::get_transport() const {
return &_nfc_transport;
}
void PN512SPITransportDriver::transport_write( uint8_t address, const uint8_t* outBuf, size_t outLen ) {
if( outLen == 0 ) {
return;
}
// First byte is (address << 1) | 0x00 for a write
address = (address << 1) | 0x00;
_ssel = 0;
_spi.write(address); // First write address byte
_spi.write(outBuf, outLen, NULL, 0); // Ignore read bytes
_ssel = 1;
}
void PN512SPITransportDriver::transport_read( uint8_t address, uint8_t* inBuf, size_t inLen ) {
if( inLen == 0 ) {
return;
}
// Address byte is (address << 1) | 0x80 for a read
// This should be repeated accross the transfer, except for the last byte which should be 0
address = (address << 1) | 0x80;
// Set this byte across inBuf so that it's repeated accross the transfer
// Bit cheeky, but will work
memset(inBuf, address, inLen - 1);
// Also terminate with 0 so that it's a no-op
inBuf[inLen - 1] = 0;
_ssel = 0;
_spi.write(address); // First write address byte
_spi.write(inBuf, inLen, inBuf, inLen);
_ssel = 1;
}
// Callbacks from munfc
static void PN512SPITransportDriver::s_transport_write( uint8_t address, const uint8_t* outBuf, size_t outLen, void* pUser ) {
PN512SPITransportDriver* self = (PN512SPITransportDriver*)pUser;
self->transport_write(address, outBuf, outLen);
}
static void PN512SPITransportDriver::s_transport_read( uint8_t address, uint8_t* inBuf, size_t inLen, void* pUser ) {
PN512SPITransportDriver* self = (PN512SPITransportDriver*)pUser;
self->transport_read(address, inBuf, inLen);
}

View File

@ -0,0 +1,34 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "PN512TransportDriver.h"
using namespace mbed;
using namespace mbed::nfc;
PN512TransportDriver::PN512TransportDriver() : _delegate() {
}
void PN512TransportDriver::set_delegate(Delegate* delegate) {
_delegate = delegate;
}
void PN512TransportDriver::hw_interrupt() {
if(_delegate != NULL) {
_delegate->on_hw_interrupt();
}
}