From 0fc4c78d7211a4e21615f08a3fbaaaf49c6faee0 Mon Sep 17 00:00:00 2001 From: kazu Date: Fri, 15 Sep 2017 18:02:15 +0200 Subject: [PATCH] worked on SoftSPI and RFID-Reader MFRC522 --- ext/rfid/MFRC522.h | 618 ++++++++++++++++++++++++++++++++++++++++++++- io/SoftSPI.h | 59 ++++- 2 files changed, 651 insertions(+), 26 deletions(-) diff --git a/ext/rfid/MFRC522.h b/ext/rfid/MFRC522.h index b3577b1..75b30a5 100644 --- a/ext/rfid/MFRC522.h +++ b/ext/rfid/MFRC522.h @@ -2,6 +2,8 @@ #define MFRC522_H #include "../../io/SoftSPI.h" +#define WITH_DEBUG + /** * RFID reader based on MFRC522 @@ -9,9 +11,23 @@ * * http://www.nxp.com/documents/data_sheet/MFRC522.pdf * + * http://www.gorferay.com/initialization-and-anticollision-iso-iec-14433-3/ + * https://community.nxp.com/thread/437908 + * https://www.nxp.com/docs/en/application-note/AN10833.pdf + * https://www.slideshare.net/contactsarbjeet/architecture-development-of-nfc-applications + * http://www.gorferay.com/mifare-and-handling-of-uids/ + * http://www.proxmark.org/files/Documents/13.56%20MHz%20-%20MIFARE%20Classic/MIFARE%20Classic%20clones/ISSI_IS23SC4439_User_Manual.pdf */ class MFRC522 { + typedef struct { + uint8_t size; // Number of bytes in the UID. 4, 7 or 10. + uint8_t uidByte[10]; + uint8_t sak; // The SAK (Select acknowledge) byte returned from the PICC after successful selection. + } Uid; + + Uid uid; + struct OP { uint8_t addr : 7; // bits 0-6 uint8_t rw : 1; // bit 7 [MSB] 1 = read, 0 = write @@ -19,20 +35,78 @@ class MFRC522 { enum class Register { - COMMAND_REG = 0x01, - INTERRUPTS_REG = 0x02, - ERROR_REG = 0x06, - STATUS1_REG = 0x07, - STATUS2_REG = 0x08, - FIFI_DATA_REG = 0x09, // access fifo buffer - FIFO_SIZE_REG = 0x0A, // number of available fifo data - MOD_REG = 0x11, - DEMOG_REG = 0x19, + COMMAND_REG = 0x01 << 1, + INTERRUPTS_REG = 0x02 << 1, + COM_IRQ_REG = 0x04 << 1, + DIV_IRQ_REG = 0x05 << 1, + ERROR_REG = 0x06 << 1, + STATUS1_REG = 0x07 << 1, + STATUS2_REG = 0x08 << 1, + FIFO_DATA_REG = 0x09 << 1, // access fifo buffer + FIFO_LEVEL_REG = 0x0A << 1, // number of available fifo data + CONTROL_REG = 0x0C << 1, + BIT_FRAMING_REG = 0x0D << 1, + COLL_REG = 0x0E << 1, + MODE_REG = 0x11 << 1, + TX_MODE_REG = 0x12 << 1, + RX_MODE_REG = 0x13 << 1, + TX_CONTROL_REG = 0x14 << 1, + TX_AUTO_REG = 0x15 << 1, + DEMOG_REG = 0x19 << 1, - TEST_SEL_1_REG = 0x31, - TEST_SEL_2_REG = 0x32, - VERSION_REG = 0x37, // software version + CRC_RES_H = 0x21 << 1, + CRC_RES_L = 0x22 << 1, + MOD_WIDTH_REG = 0x24 << 1, + T_MODE_REG = 0x2A << 1, + T_PRESCALER_REG = 0x2B << 1, + T_RELOAD_REG_H = 0x2C << 1, + T_RELOAD_REG_L = 0x2D << 1, + TEST_SEL_1_REG = 0x31 << 1, + TEST_SEL_2_REG = 0x32 << 1, + VERSION_REG = 0x37 << 1, // software version + + + + }; + + enum class Command { + IDLE = 0x00, + MEM = 0x01, + GEN_RANDOM_ID = 0x02, + CALC_CRC = 0x03, + TRANSMIT = 0x04, + NO_CMD_CHANGE = 0x07, + RECEIVE = 0x08, + TRANSCEIVE = 0x0C, + MF_AUTHENT = 0x0E, + SOFT_RESET = 0x0F, + }; + + enum class PICCComand { + REQA = 0x26, + PICC_CMD_READ = 0x30, + PICC_CMD_WUPA = 0x52, // Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame. + PICC_CMD_CT = 0x88, // Cascade Tag. Not really a command, but used during anti collision. + PICC_CMD_SEL_CL1 = 0x93, // Anti collision/Select, Cascade Level 1 + PICC_CMD_SEL_CL2 = 0x95, // Anti collision/Select, Cascade Level 2 + PICC_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 3 + PICC_CMD_HLTA = 0x50, // HaLT command, Typ + }; + + enum class Status { + OK, + TIMEOUT_IRQ, + TIMEOUT_MANUAL, + TIMEOUT_CRC, + ERROR, + RESPONSE_TOO_LONG, + COLLISION, + INVALID, + INVALID_ATQA, + INTERNAL_ERROR, + WRONG_CRC, + WRONG_BCC, }; struct CommandReg { @@ -60,12 +134,530 @@ private: public: MFRC522() { - ; + } /** init */ void init() { + os_printf("init MFRC522\n"); spi.init(); + + os_delay_us(5000); + +// writeReg8(Register::T_MODE_REG, 0x8D); +// writeReg8(Register::T_PRESCALER_REG, 0x3E); +// writeReg8(Register::T_RELOAD_REG_L, 0x30); +// writeReg8(Register::T_RELOAD_REG_H, 0x00); +// writeReg8(Register::TX_AUTO_REG, 0x40); +// writeReg8(Register::T_MODE_REG, 0x3D); +// antennaOn(); + + // Reset baud rates + writeReg8(Register::TX_MODE_REG, 0x00); + writeReg8(Register::RX_MODE_REG, 0x00); + // Reset ModWidthReg + writeReg8(Register::MOD_WIDTH_REG, 0x26); + + writeReg8(Register::T_MODE_REG, 0x80); + writeReg8(Register::T_PRESCALER_REG, 0xA9); + writeReg8(Register::T_RELOAD_REG_L, 0xE8); + writeReg8(Register::T_RELOAD_REG_H, 0x03); + writeReg8(Register::TX_AUTO_REG, 0x40); + writeReg8(Register::MODE_REG, 0x3D); // very important. set CRC preset to 0x6363 by setting bit 0 and clearing bit 1 in MODE_REG + + antennaOn(); + + writeReg8(Register::COMMAND_REG, Command::IDLE); + + } + + + + void getStatus() { + + uint8_t s1 = readReg8(Register::STATUS1_REG); + uint8_t s2 = readReg8(Register::STATUS2_REG); + + os_printf("s1: %d, s2: %d \n", (int)s1, (int)s2); + + } + + /** is there a card present? */ + bool isCard() { + + os_printf("** is card?\n"); + + uint8_t bufferATQA[2]; + uint8_t bufferSize = sizeof(bufferATQA); + + // Reset baud rates + writeReg8(Register::TX_MODE_REG, 0x00); + writeReg8(Register::RX_MODE_REG, 0x00); + + // Reset ModWidthReg + writeReg8(Register::MOD_WIDTH_REG, 0x26); + + Status res = requestA(bufferATQA, &bufferSize); + os_printf("isCard: %d type: %s\n", (int)res, getCardType(bufferATQA)); + + return res == Status::OK; + + } + + /** yes, card is present -> read it */ + bool select() { + + os_printf("** select\n"); + ensureSane(); + + Status res; + uint8_t uid[10] = {}; + res = anticol(1, &uid[0]); + debugShow(uid, 10); + + return (res == Status::OK); + + } + + /** read the given 14-byte sector from the card */ + void read(uint8_t address) { + + os_printf("** read block %d\n", address); + + os_delay_us(1000*50); + + clearRegBits(Register::COLL_REG, 0x80); + writeReg8(Register::BIT_FRAMING_REG, 0); + + // READ command: 0x30 ADR CRC1 CRC2 + uint8_t buffer[4] = {(uint8_t)PICCComand::PICC_CMD_READ, address}; + + // calculate the CRC + calculateCRC(buffer, 2, &buffer[2]); + + // response-buffer + uint8_t res[16]; + uint8_t resLen = 16; + + // send + transceive(buffer, 4, res, &resLen); + + } + + /** stop talking to the card */ + void halt() { + + os_printf("** halt the card\n"); + + // HALT command: 0x50 ADR CRC1 CRC2 + uint8_t buffer[4] = {(uint8_t)PICCComand::PICC_CMD_HLTA, 0x00}; + + // calculate the CRC + calculateCRC(buffer, 2, &buffer[2]); + + // send + uint8_t resLen = 1; + transceive(buffer, 4, buffer, &resLen); + + } + + void selftest() { + + os_printf("MODE_REG: %d\n", readReg8(Register::MODE_REG)); + writeReg8(Register::MODE_REG, 61); + os_printf("MODE_REG: %d\n", readReg8(Register::MODE_REG)); + + uint8_t res[2]; + + // MUST BE 3c a2 + uint8_t out2[9] = {0x93, 0x70, 0x12, 0x34, 0x56, 0x78, 0x08, 0x00, 0x00}; + calculateCRC(out2, 7, res); + debugShow(res, 2); + + } + +private: + + void stopCrypto1() { + clearRegBits(Register::STATUS2_REG, 0x08); // reset MFCrypto1On + } + + void antennaOn() { + uint8_t val = readReg8(Register::TX_CONTROL_REG); + if ((val & 0x03) != 0x03) { + writeReg8(Register::TX_CONTROL_REG, val | 0x03); + } + val = readReg8(Register::TX_CONTROL_REG); + os_printf("antenna: %d\n", (int) val); + } + + + Status requestA(uint8_t* bufferATQA, uint8_t* bufferSize) { + return piccREQAorWUPA(PICCComand::REQA, bufferATQA, bufferSize); + } + + Status piccREQAorWUPA(const PICCComand cmd, uint8_t* buffer, uint8_t* bufferSize) { + + clearRegBits(Register::COLL_REG, 0x80); + uint8_t validBits = 7; + const uint8_t _cmd = (uint8_t) cmd; + + const Status status = transceive(&_cmd, 1, buffer, bufferSize, &validBits); + + if (status != Status::OK) {return status;} + + os_printf("response-size: %d, valid bits: %d\n", (int)*bufferSize, (int)validBits); + + // ATQA must be 16 bits + if ((*bufferSize != 2) || (validBits != 0)) { + return Status::INVALID_ATQA; + } + + return Status::OK; + + } + + void debugShow(const uint8_t* buf, uint8_t len) { + for (int i = 0; i < len; ++i) { + os_printf("%02x ", buf[i]); + } + os_printf("\n"); + } + + /** get card-type-name for the given 2-byte ATQA response */ + const char* getCardType(const uint8_t* atqa) { + const uint16_t resp = atqa[0] << 8 | atqa[1]; + if (resp == 0x0400) {return "MFOne-S50";} // http://www.elechouse.com/elechouse/images/product/13.56MHZ_RFID_Module/mifare_S50.pdf + if (resp == 0x0200) {return "MFOne-S70";} + if (resp == 0x4400) {return "MF-UltraLight";} + if (resp == 0x0800) {return "MF-Pro";} + if (resp == 0x4403) {return "MF Desire";} + return "Unknown"; + } + + + Status anticol(int level, uint8_t* uidDst) { + + os_printf("** anticol level %d\n", level); + + // Prepare MFRC522 + clearRegBits(Register::COLL_REG, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. + + uint8_t out[9]; + uint8_t resLen; + + Status s; + + // send 2 bytes: 0x93 0x20 and expect 5 bytes of response : 4 bytes UID + 1 byte BCC checksum + // the first byte of the UID might be 0x88 to indicate that there are more requests needed + // to get the full UID + + resLen = 5; + out[0] = (uint8_t)PICCComand::PICC_CMD_SEL_CL1; + out[1] = 0x20; + writeReg8(Register::BIT_FRAMING_REG, 0); + s = transceive(out, 2, uidDst, &resLen); + if (s != Status::OK) {return s;} + + // NOTES + // if the received UID starts with 0x88, then we have to read the next block (like UTF-8) + // if the received UID starts with 0x08, it is a random number that will change every time + + // response is SN0 SN1 SN2 SN3 BCC where BCC = SN0^SN1^SN2^SN3 -> check this! + const uint8_t serNumCheck = uidDst[0] ^ uidDst[1] ^ uidDst[2] ^ uidDst[3]; + if (serNumCheck != uidDst[4]) {return Status::WRONG_BCC;} + os_printf("** ser num check %d == %d ?\n", serNumCheck, uidDst[4]); + + // go on with select + return select(level, uidDst); + + } + + Status select(int level, uint8_t* uidPart) { + + os_printf("** select level %d\n", level); + + uint8_t cmd = (uint8_t) PICCComand::PICC_CMD_SEL_CL1; // TODO: depends on level + + uint8_t bcc = uidPart[0] ^ uidPart[1] ^ uidPart[2] ^ uidPart[3]; + uint8_t out[9] = {cmd, 0x70, uidPart[0], uidPart[1], uidPart[2], uidPart[3], bcc, 0x00, 0x00}; + + // replace 0x00 0x00 with the crc + calculateCRC(out, 7, &out[7]); + + // transmit + uint8_t res[3]; + uint8_t resLen = 3; + Status status = transceive(out, 9, res, &resLen); + + // NOTES on SAK (selective ACK) + // result starts with 0x04? -> UID not complete, go on reading! + // result starts with 0x08? -> UID complete, + // this one also contains some details on the card we see + uint8_t SAK = res[0]; + + // another UID part needs to be read? (max: 3) + if (SAK == 0x04) { return anticol(level+1, &uidPart[4]); } + + // done + return status; + + } + + + + /** + * calculate the CRC for the given bytes and write them (2 bytes) to the given destination + * NOTE: the CRC depends on the settings of ModeReg (bit 0 and 1) which control + * the CRC-16's preset: 0x0000 0x6363 0xa671 0xffff + * 0x6363 seems to be the "correct" one?! + */ + Status calculateCRC(const uint8_t *data, const uint8_t length, uint8_t* result) { + + os_printf("calculate CRC for %d bytes\n", length); + + writeReg8(Register::COMMAND_REG, Command::IDLE); // Stop any active command. + writeReg8(Register::DIV_IRQ_REG, 0x04); // Clear the CRCIRq interrupt request bit + fillFIFO(data, length); // fill the FIFO with the data to CRC + writeReg8(Register::COMMAND_REG, Command::CALC_CRC); // Start the calculation + + // Wait for the CRC calculation to complete. Each iteration of the while-loop takes 17.73us. + for (int i = 0; i < 25; ++i) { + + os_delay_us(1000*1); + + // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved + const uint8_t n = readReg8(Register::DIV_IRQ_REG); + + // CRCIRq bit set - calculation done + if (n & 0x04) { + writeReg8(Register::COMMAND_REG, Command::IDLE); // Stop calculating CRC for new content in the FIFO. + result[0] = readReg8(Register::CRC_RES_L); + result[1] = readReg8(Register::CRC_RES_H); + os_printf("crc calculation: OK!\n"); + return Status::OK; + } + + } + + os_printf("CRC: TIMEOUT!!!\n"); + return Status::TIMEOUT_CRC; + + } + + Status transceive(const uint8_t* srcData, const uint8_t srcDataLen, uint8_t* dstData, uint8_t* dstDataLen, uint8_t* validBits = nullptr, uint8_t rxAlign = 0, bool checkCRC = false) { + //os_printf("transceive %d bytes of data (valid bits: %d), expecting %d bytes of response\n", srcDataLen, *validBits, *dstDataLen); + os_printf("transceive %d bytes of data:", srcDataLen); + debugShow(srcData, srcDataLen); + const Status s = picc(Command::TRANSCEIVE, 0x30, srcData, srcDataLen, dstData, dstDataLen, validBits, rxAlign, checkCRC); + os_printf("transceive status: %d bytes: ", (int) s); + debugShow(dstData, *dstDataLen); + return s; + } + + void fillFIFO(const uint8_t* srcData, const uint8_t srcDataLen) { + setRegBits(Register::FIFO_LEVEL_REG, 0x80); // flush FIFO (empty any existing data) + if (readReg8(Register::FIFO_LEVEL_REG) != 0) { + os_printf("!!!!!!!!!!!!!!!!! FIFO NOT EMPTY THOUGH IT SHOULD BE!\n"); + } + writeReg(Register::FIFO_DATA_REG, srcData, srcDataLen); // write to-be-sent data to FIFO + if (readReg8(Register::FIFO_LEVEL_REG) != srcDataLen) { + os_printf("!!!!!!!!!!!!!!!!!failed to fill fifo\n"); + } + } + + void ensureSane() { + setRegBits(Register::FIFO_LEVEL_REG, 0x80); // flush FIFO (empty any existing data) + //writeReg8(Register::FIFO_LEVEL_REG, 0x80); // flush FIFO (empty any existing data) + writeReg8(Register::COMMAND_REG, (int) Command::IDLE); // stop previous commands + } + + Status picc(Command cmd, const uint8_t waitIRQ, const uint8_t* srcData, const uint16_t srcDataLen, uint8_t* dstData, uint8_t* dstLen, uint8_t* validBits, uint8_t rxAlign, bool checkCRC) { + + const uint8_t txLastBits = validBits ? *validBits : 0; + const uint8_t bitFraming = (rxAlign << 4) + txLastBits; + + //os_printf("-- txLastBits: %d, bitFraming: %d \n", txLastBits, bitFraming); + + ensureSane(); + writeReg8(Register::COM_IRQ_REG, 0x7f); // clear interrupt flags + fillFIFO(srcData, srcDataLen); + writeReg8(Register::BIT_FRAMING_REG, bitFraming); + writeReg8(Register::COMMAND_REG, (int) cmd); + + if (cmd == Command::TRANSCEIVE) { + //os_printf("-- start seding...\n"); + setRegBits(Register::BIT_FRAMING_REG, 0x80); // startSend = 1 + } + + //const uint8_t _errReg = readReg8(Register::ERROR_REG); + //os_printf("cur err reg: %d\n", (int)_errReg); + + int maxRuns = 10; + while(true) { + + const uint8_t res = readReg8(Register::COM_IRQ_REG); + //os_printf("irq reg: %d\n", res); + + // received the interrupt we are waiting for? + if (res & waitIRQ) { + os_printf("got needed interrupt\n"); break; + } + + if (res & 0x01) { + return Status::TIMEOUT_IRQ; + } + + if (--maxRuns == 0) { + os_printf("picc() Timeout\n"); + return Status::TIMEOUT_MANUAL; + } + + os_delay_us(1000*5); + + } + + // buffer overflow? + const uint8_t errReg = readReg8(Register::ERROR_REG); + if (errReg & 0x13) {return Status::ERROR;} + + // caller wants to read a response? + if (dstData && dstLen) { + + const uint8_t n = readReg8(Register::FIFO_LEVEL_REG); + os_printf("got %d bytes to read\n", (int) n); + + // not enough space for the response data? + if (n > *dstLen) { return Status::RESPONSE_TOO_LONG; } + + // read response + *dstLen = n; + readReg(Register::FIFO_DATA_REG, dstData, n, rxAlign); + + uint8_t _validBits = readReg8(Register::CONTROL_REG) & 0x07; + if (validBits) { + *validBits = _validBits; + } + + #ifdef WITH_DEBUG + // ensure fifo is now empty + if (readReg8(Register::FIFO_LEVEL_REG) != 0) { + os_printf("fifo not empty!\n"); + return Status::INTERNAL_ERROR; + } + #endif + + } + + if (errReg & 0x08) { + return Status::COLLISION; + } + + // TODO CRC + + return Status::OK; + + } + + + + +private: + + void writeReg8(const Register reg, const Command cmd) { + writeReg8(reg, (uint8_t) cmd); + } + + void writeReg8(const Register reg, const uint8_t value) { + spi.chipSelect(); + writeTo((int)reg); + spi.writeByte(value); + spi.chipDeselect(); + //uint8_t written = readReg8(reg); + //os_printf("write: %d to %d, re-read: %d \n", (int) value, (int) reg, (int) written); + } + + void setRegBits(const Register reg, const uint8_t mask) { + const uint8_t tmp = readReg8(reg); + writeReg8(reg, tmp | mask); + } + + void clearRegBits(const Register reg, const uint8_t mask) { + const uint8_t tmp = readReg8(reg); + writeReg8(reg, tmp & (~mask)); + } + + void writeReg(const Register reg, const uint8_t* data, const uint16_t len) { + //os_printf("writing %d bytes of data to %d\n", (int)len, (int)reg); + spi.chipSelect(); + writeTo((int)reg); + for (int i = 0; i < len; ++i){ + spi.writeByte(data[i]); + } + spi.chipDeselect(); + } + + uint8_t readReg8(const Register reg) { + spi.chipSelect(); + readFrom((int)reg); + const uint8_t res = spi.readByte(); + spi.chipDeselect(); + return res; + } + +// void readReg(const Register reg, uint8_t* dst, const uint8_t count, const uint8_t rxAlign = 0) { + +// if (!count) {return;} + +// for (int i = 0; i < count; ++i) { +// dst[i] = readReg8(reg); +// } + +// #ifdef WITH_DEBUG +// if (readReg8(Register::FIFO_LEVEL_REG) != 0) { +// os_printf("!!!!!!!!!!!!! fifo is not empty"); +// } +// #endif + +// } + + + /** read multiple bytes from the same register (mainly FIFO) */ + void readReg(const Register reg, uint8_t* dst, const uint8_t count, const uint8_t rxAlign = 0) { + + spi.chipSelect(); + + // address for reading (MSB = 1) + const uint8_t address = (int) reg | 0x80; + spi.writeByte(address); + + int i; + for (i = 0; i < count-1; ++i) { + + if ( (i == 0) && rxAlign ) { + uint8_t mask = (0xFF << rxAlign) & 0xFF; + const uint8_t value = spi.readWriteByte(address); + dst[0] = (dst[0] & ~mask) | (value & mask); + } else { + dst[i] = spi.readWriteByte(address); + } + + } + + // read last byte and stop reading + dst[i] = spi.readWriteByte(0); + + spi.chipDeselect(); + + } + + + // highest bit denotes whether reading or writing + void readFrom(uint8_t address) { + spi.writeByte(address | 0x80); + } + void writeTo(uint8_t address) { + spi.writeByte(address); } diff --git a/io/SoftSPI.h b/io/SoftSPI.h index 6dcb47d..7ab63a9 100644 --- a/io/SoftSPI.h +++ b/io/SoftSPI.h @@ -4,6 +4,26 @@ //#include "IO.h" #include "fastGPIO.h" +// wemos D1 mini +#define SPI_CS_OUTPUT GPIO15_OUTPUT_SET +#define SPI_MOSI_OUTPUT GPIO13_OUTPUT_SET +#define SPI_MISO_INPUT GPIO12_INPUT_SET +#define SPI_MISO_NO_PULLUP GPIO12_INPUT_PULLUP_UNSET +#define SPI_CLK_OUTPUT GPIO14_OUTPUT_SET + +#define SPI_CS_LO GPIO15_L +#define SPI_CS_HI GPIO15_H + +#define SPI_CLK_LO GPIO14_L +#define SPI_CLK_HI GPIO14_H + +#define SPI_MOSI_LO GPIO13_L +#define SPI_MOSI_HI GPIO13_H + +#define SPI_MISO_READ GPIO12_IN + +#define SPI_FAST + class SoftSPI { // MTDI GPIO12 MISO (DIN) D6 @@ -25,10 +45,10 @@ public: } void init() const { - GPIO12_INPUT_SET; GPIO12_INPUT_PULLUP_UNSET; // D6: MISO - GPIO13_OUTPUT_SET; // D7: MOSI - GPIO14_OUTPUT_SET; // D5: CLK - GPIO15_OUTPUT_SET; // D8: CS + SPI_MISO_INPUT; SPI_MISO_NO_PULLUP; // D6: MISO + SPI_MOSI_OUTPUT; // D7: MOSI + SPI_CLK_OUTPUT; // D5: CLK + SPI_CS_OUTPUT; // D8: CS } inline void chipSelect() const { @@ -46,13 +66,13 @@ public: } - inline void csLo() const { GPIO15_L; } // D8 - inline void csHi() const { GPIO15_H; } // D8 + inline void csLo() const { SPI_CS_LO; } // D8 + inline void csHi() const { SPI_CS_HI; } // D8 - inline void clkHi() const { GPIO14_H; } // D5 - inline void clkLo() const { GPIO14_L; } // D5 + inline void clkLo() const { SPI_CLK_LO; } // D5 + inline void clkHi() const { SPI_CLK_HI; } // D5 - inline bool getMISO() const {return GPIO12_IN;} // D6 + inline bool getMISO() const {return SPI_MISO_READ;} // D6 /** read 16 bits */ @@ -77,7 +97,7 @@ public: } /** read 8 bits */ - inline uint16_t readByte() const { + inline uint8_t readByte() const { return (readBit() << 7) | (readBit() << 6) | @@ -156,23 +176,25 @@ private: inline uint8_t readWriteBit(const bool out) const { - if(out) {GPIO13_H;} else {GPIO13_L;} + if(out) {SPI_MOSI_HI;} else {SPI_MOSI_LO;} wait(); clkHi(); wait(); const bool inp = getMISO(); wait(); clkLo(); + wait(); return (inp) ? 1 : 0; } /** write one bit to the bus */ inline void writeBit(const bool out) const { - if(out) {GPIO13_H;} else {GPIO13_L;} + if(out) {SPI_MOSI_HI;} else {SPI_MOSI_LO;} wait(); clkHi(); wait(); clkLo(); + wait(); } /** read one bit from the bus */ @@ -186,14 +208,25 @@ private: return (val) ? 1 : 0; } +#ifdef SPI_FAST inline void wait() const { __asm__ __volatile__("nop"); } - inline void waitLong() const { os_delay_us(1); } +#else + + inline void wait() const { + os_delay_us(2); + } + inline void waitLong() const { + os_delay_us(50); + } + +#endif + }; #endif // SOFTSPI_H