diff --git a/cores/arduino/RingBuffer.cpp b/cores/arduino/RingBuffer.cpp index 123f895edb16002394fd28308becf11e861dd2e4..f35e5df328ac8be463f84af98231bbcfc7bbe114 100644 --- a/cores/arduino/RingBuffer.cpp +++ b/cores/arduino/RingBuffer.cpp @@ -78,4 +78,9 @@ int RingBuffer::peek() int RingBuffer::nextIndex(int index) { return (uint32_t)(index + 1) % SERIAL_BUFFER_SIZE; +} + +int RingBuffer::isFull() +{ + return (nextIndex(_iTail) == _iHead); } \ No newline at end of file diff --git a/cores/arduino/RingBuffer.h b/cores/arduino/RingBuffer.h index 030620b39f1250e2acc9eec75de5e8443a15cc3d..49bbe8cd6f8961d7e3e65e468e6fc51156fff734 100644 --- a/cores/arduino/RingBuffer.h +++ b/cores/arduino/RingBuffer.h @@ -41,6 +41,7 @@ class RingBuffer int read_char(); int available(); int peek(); + bool isFull(); private: int nextIndex(int index); diff --git a/cores/arduino/SERCOM.cpp b/cores/arduino/SERCOM.cpp index 298ed07ed79768fc469071e742fa04bd200c362f..d37396f86a6feaa50ef0e0eba305ab07f8c2e84e 100644 --- a/cores/arduino/SERCOM.cpp +++ b/cores/arduino/SERCOM.cpp @@ -8,103 +8,280 @@ SERCOM::SERCOM(Sercom* sercom) sercomSpi = sercom->SPI; } +/* ========================= + * ===== Sercom UART + * ========================= +*/ void SERCOM::initUART(SercomUartMode mode, SercomUartSampleRate sampleRate, uint32_t baudrate) { resetUART(); - sercomUart->CTRLA.reg = SERCOM_UART_CTRLA_MODE(mode) | + //Setting the CTRLA register + sercom->USART.CTRLA.reg = SERCOM_UART_CTRLA_MODE(mode) | SERCOM_USART_CTRLA_SAMPR(sampleRate); + // if(mode == UART_INT_CLOCK) { uint32_t sampleRateValue; + if(sampleRate == SAMPLE_RATE_x16) - { sampleRateValue = 16; - } else if(sampleRate == SAMPLE_RATE_x8) - { sampleRateValue = 8; - } else - { sampleRateValue = 3; - } - + //Asynchronous arithmetic mode - sercomUart->BAUD.reg = 65535 * ( 1 - sampleRateValue * (baudrate / SERCOM_FREQ_REF)); + sercom->USART.BAUD.reg = 65535 * ( 1 - sampleRateValue * (baudrate / SERCOM_FREQ_REF)); } } -void initFrame(SercomCharSize charSize, SercomDataOrder dataOrder, SercomParityMode parityMode, SercomNumberStopBit nbStopBits) +void initFrame(SercomUartCharSize charSize, SercomDataOrder dataOrder, SercomParityMode parityMode, SercomNumberStopBit nbStopBits) { - sercomUart->CTRLA.reg |= SERCOM_UART_CTRLA_FORM( (parityMode == NO_PARITY ? 0 : 1) ) | + //Setting the CTRLA register + sercom->USART.CTRLA.reg |= SERCOM_UART_CTRLA_FORM( (parityMode == NO_PARITY ? 0 : 1) ) | dataOrder << SERCOM_UART_CTRLA_DORD_Pos; - sercomUart->CTRLB.reg |= SERCOM_UART_CTRLB_CHSIZE(charSize) | + //Setting the CRTLB register + sercom->USART.CTRLB.reg |= SERCOM_UART_CTRLB_CHSIZE(charSize) | nbStopBits << SERCOM_UART_CTRLB_SBMODE_Pos | - (parityMode == NO_PARITY ? 0 : parityMode) << SERCOM_UART_CTRLB_PMODE_Pos |; + (parityMode == NO_PARITY ? 0 : parityMode) << SERCOM_UART_CTRLB_PMODE_Pos; //If no parity use default value } -void initPads(SercomUartTXPad txPad, SercomUartRXPad rxPad) +void initPads(SercomUartTXPad txPad, SercomRXPad rxPad) { - sercomUart->CTRLA.reg |= SERCOM_UART_CTRLA_TXPO(txPad) | + //Setting the CTRLA register + sercom->USART.CTRLA.reg |= SERCOM_UART_CTRLA_TXPO(txPad) | SERCOM_UART_CTRLA_RXPO(rxPad); - sercomUart->CTRLB.reg |= SERCOM_UART_CTRLB_TXEN | + //Setting the CRTLB register (Enabling Transceiver and Receiver) + sercom->USART.CTRLB.reg |= SERCOM_UART_CTRLB_TXEN | SERCOM_UART_CTRLB_RXEN; } void SERCOM::resetUART() { - sercomUart->CTRLA.bit.SWRST = 0x1u; - while(sercomUart->CTRLA.bit.SWRST || sercomUart->SYNCBUSY.SWRST); + //Setting the Software bit to 1 + sercom->USART.CTRLA.bit.SWRST = 0x1u; + + //Wait for both bits Software Reset from CTRLA and SYNCBUSY are equal to 0 + while(sercom->USART.CTRLA.bit.SWRST || sercom->USART.SYNCBUSY.SWRST); } void SERCOM::enableUART() { - sercomUart->CTRLA.bit.ENABLE = 0x1u; + //Setting the enable bit to 1 + sercom->USART.CTRLA.bit.ENABLE = 0x1u; + + //Wait for then enable bit from SYNCBUSY is equal to 0; + while(sercom->USART.SYNCBUSY.bit.ENABLE); } void SERCOM::flushUART() { - while(sercomUart->INTFLAG.bit.DRE != SERCOM_USART_INTFLAG_DRE); + // Wait for transmission to complete + while(sercom->USART.INTFLAG.bit.DRE != SERCOM_USART_INTFLAG_DRE); } void SERCOM::clearStatusUART() { - sercomUart->STATUS.reg = SERCOM_USART_STATUS_RESETVALUE; + //Reset (with 0) the STATUS register + sercom->USART.STATUS.reg = SERCOM_USART_STATUS_RESETVALUE; } bool SERCOM::availableDataUART() { - return sercomUart->INTFLAG.bit.RXC; + //RXC : Receive Complete + return sercom->USART.INTFLAG.bit.RXC; } bool SERCOM::isBufferOverflowErrorUART() { - return sercomUart->STATUS.bit.BUFOVF; + //BUFOVF : Buffer Overflow + return sercom->USART.STATUS.bit.BUFOVF; } bool SERCOM::isFrameErrorUART() { - return sercomUart->STATUS.bit.FERR; + //FERR : Frame Error + return sercom->USART.STATUS.bit.FERR; } bool SERCOM::isParityErrorUART() { - return sercomUart->STATUS.bit.PERR; + //PERR : Parity Error + return sercom->USART.STATUS.bit.PERR; +} + +bool SERCOM::isDataRegisterEmptyUART() +{ + //DRE : Data Register Empty + return sercom->USART.INTFLAG.bit.DRE; } uint8_t SERCOM::readDataUART() { - return sercomUart->DATA.bit.DATA; + return sercom->USART.DATA.bit.DATA; } int SERCOM::writeDataUART(uint8_t data) { + //Flush UART buffer flushUART(); - sercomUart->DATA.bit.DATA = data; + //Put data into DATA register + sercom->USART.DATA.bit.DATA = data; return 1; } +/* ========================= + * ===== Sercom SPI + * ========================= +*/ +void SERCOM::initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize charSize, SercomDataOrder dataOrder) +{ + resetSPI(); + + //Setting the CTRLA register + sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE(SPI_MASTER_OPERATION) | + SERCOM_SPI_CTRLA_DOPO(mosi) | + SERCOM_SPI_CTRLA_DIPO(miso) | + dataOrder << SERCOM_SPI_CTRLA_DORD_Pos; + + //Setting the CTRLB register + sercom->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_CHSIZE(charSize) | + (0x1ul) << SERCOM_SPI_CTRLB_RXEN_Pos; //Active the SPI receiver. +} + +void SERCOM::initClock(SercomSpiClockMode clockMode, uint32_t baudrate) +{ + //Extract data from clockMode + int cpha, cpol; + + if((clockMode & (0x1ul)) == 0 ) + cpha = 0; + else + cpha = 1; + + if((clockMode & (0x2ul)) == 0) + cpol = 0; + else + cpol = 1; + + //Setting the CTRLA register + sercom->SPI.CTRLA.reg |= cpha << SERCOM_SPI_CTRLA_CPHA_Pos | + cpol << SERCOM_SPI_CTRLA_CPOL_Pos; + + //Synchronous arithmetic + sercom->SPI.BAUD.reg = calculateBaudrateSynchronous(baudrate); +} + +void SERCOM::resetSPI() +{ + //Set the Software bit to 1 + sercom->SPI.CTRLA.bit.SWRST = 0x1u; + + //Wait both bits Software Reset from CTRLA and SYNCBUSY are equal to 0 + while(sercom->SPI.CTRLA.bit.SWRST || sercom->SPI.SYNCBUSY.SWRST); +} + +void SERCOM::enableSPI() +{ + //Set the enable bit to 1 + sercom->SPI.CTRLA.bit.ENABLE = 0x1ul; + + //Waiting then enable bit from SYNCBUSY is equal to 0; + while(sercom->SPI.SYNCBUSY.bit.ENABLE); +} + +void SERCOM::disableSPI() +{ + //Set the enable bit to 0 + sercom->SPI.CTRLA.bit.ENABLE = 0x0ul; + + //Waiting then enable bit from SYNCBUSY is equal to 0; + while(sercom->SPI.SYNCBUSY.bit.ENABLE); +} + +void setDataOrderSPI(SercomDataOrder dataOrder) +{ + //Register enable-protected + disableSPI(); + + sercom->SPI.CTRLA.bit.DORD = dataOrder; + + enableSPI(); +} + +void setBaudrateSPI(uint8_t divider) +{ + //Can't divide by 0 + if(baudrate == 0) + return; + + //Register enable-protected + disableSPI(); + + sercom->SPI.BAUD.reg = calculateBaudrateSynchronous(SERCOM_FREQ_REF / baudrate); + + enableSPI(); +} + +void setClockModeSPI(SercomSpiClockMode clockMode) +{ + int cpha, cpol; + if((clockMode & (0x1ul)) == 0) + cpha = 0; + else + cpha = 1; + + if((clockMode & (0x2ul)) == 0) + cpol = 0; + else + cpol = 1; + + //Register enable-protected + disableSPI(); + + sercom->SPI.CTRLA.bit.CPOL = cpol; + sercom->SPI.CTRLA.bit.CPHA = cpha; + + enableSPI(); +} +void writeDataSPI(uint8_t data) +{ + sercom->SPI.DATA.bit.DATA = data; +} + +uint8_t readDataSPI() +{ + return sercom->SPI.DATA.bit.DATA; +} + +bool SERCOM::isBufferOverflowErrorSPI() +{ + return sercom->SPI.STATUS.bit.BUFOVF; +} + +bool SERCOM::isDataRegisterEmptySPI() +{ + //DRE : Data Register Empty + return sercom->SPI.INTFLAG.bit.DRE; +} + +bool SERCOM::isTransmitCompleteSPI() +{ + //TXC : Transmit complete + return sercom->SPI.INTFLAG.bit.TXC; +} + +bool SERCOM::isReceiveCompleteSPI() +{ + //RXC : Receive complete + return sercom->SPI.INTFLAG.bit.RXC; +} + +uint8_t SERCOM::calculateBaudrateSynchronous(uint32_t baudrate) +{ + return SERCOM_FREQ_REF / (2 * baudrate) - 1; +} diff --git a/cores/arduino/SERCOM.h b/cores/arduino/SERCOM.h index db45139a464c4ac15e19cb2e58188ab56faf7224..a7df4cf1567ea401663776fdef0bfd74464f7400 100644 --- a/cores/arduino/SERCOM.h +++ b/cores/arduino/SERCOM.h @@ -49,7 +49,7 @@ typedef enum 5_BITS = 0x5u, 6_BITS, 7_BITS -} SercomCharSize; +} SercomUartCharSize; typedef enum { @@ -57,7 +57,7 @@ typedef enum PAD_1, PAD_2, PAD_3 -} SercomUartRXPad; +} SercomRXPad; Vtypedef enum { @@ -76,15 +76,25 @@ typedef enum typedef enum { - CPOL_0 = 0, - CPOL_1 -} SercomSpiCphaMode; + SPI_MODE_0 = 0, // CPOL : 0 | CPHA : 0 + SPI_MODE_1, // CPOL : 0 | CPHA : 1 + SPI_MODE_2, // CPOL : 1 | CPHA : 0 + SPI_MODE_3 // CPOL : 1 | CPHA : 1 +} SercomSpiClockMode; typedef enum { - CPHA_0 = 0, - CPHA_1 -} SercomSpiCpolMode; + PAD_0_SCK_1 = 0, + PAD_2_SCK_3, + PAD_3_SCK_1, + PAD_0_SCK_3 +} SercomSpiTXPad; + +typedef enum +{ + 8_BITS = 0, + 9_BITS = 1 +} SercomSpiCharSize; class SERCOM { @@ -93,8 +103,8 @@ class SERCOM /* ========== UART ========== */ void initUART(SercomUartMode mode, SercomUartSampleRate sampleRate, uint32_t baudrate=0); - void initFrame(SercomCharSize charSize, SercomDataOrder dataOrder, SercomParityMode parityMode, SercomNumberStopBit nbStopBits); - void initPads(SercomUartTXPad txPad, SercomUartRXPad rxPad); + void initFrame(SercomUartCharSize charSize, SercomDataOrder dataOrder, SercomParityMode parityMode, SercomNumberStopBit nbStopBits); + void initPads(SercomUartTXPad txPad, SercomRXPad rxPad); void resetUART(); void enableUART(); @@ -104,17 +114,31 @@ class SERCOM bool isBufferOverflowErrorUART(); bool isFrameErrorUART(); bool isParityErrorUART(); + bool isDataRegisterEmptyUART() uint8_t readDataUART(); int writeDataUART(uint8_t data); /* ========== SPI ========== */ - void initSPI(); + void initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize charSize, SercomDataOrder dataOrder); + void initClock(SercomSpiClockMode clockMode, uint32_t baudrate); + + void resetSPI(); + void enableSPI(); + void disableSPI(); + void setDataOrderSPI(SercomDataOrder dataOrder); + void setBaudrateSPI(uint8_t divider); + void setClockModeSPI(SercomSpiClockMode clockMode); + void writeDataSPI(uint8_t data); + uint8_t readDataSPI(); + bool isBufferOverflowErrorSPI(); + bool isDataRegisterEmptySPI(); + bool isTransmitCompleteSPI(); + bool isReceiveCompleteSPI(); private: Sercom* sercom; - SercomUart* sercomUart; - SercomSpi* sercomSpi; + uint8_t calculateBaudrateSynchronous(uint32_t baudrate); }; #endif diff --git a/cores/arduino/SERCOMUart.cpp b/cores/arduino/SERCOMUart.cpp index c3aa4a139514b64d407eb59df53a015328c4b304..ee3767e37b180bfdb174de62c6eaf6ee73ad9d3c 100644 --- a/cores/arduino/SERCOMUart.cpp +++ b/cores/arduino/SERCOMUart.cpp @@ -37,7 +37,12 @@ void SERCOMUart::IrqHandler() { rxBuffer.store_char(sercom->readDataUART()) } - + + if(sercom->isDataRegisterEmptyUART()) + { + writeDataUART(txBuffer.read_char()); + } + if( sercom->isBufferOverflowErrorUART() || sercom->isFrameErrorUART() || sercom->isParityErrorUART()) @@ -46,7 +51,7 @@ void SERCOMUart::IrqHandler() } } -bool SERCOMUart::available() +int SERCOMUart::available() { return rxBuffer.available(); } @@ -63,7 +68,11 @@ int SERCOMUart::read() size_t SERCOMUart::write(uint8_t data) { - return sercom->writeDataUART(data); + if(txBuffer.isFull()) + return 0; + + txBuffer.store_char(data); + return 1; } SercomNumberStopBit extractNbStopBit(uint8_t config) diff --git a/cores/arduino/SERCOMUart.h b/cores/arduino/SERCOMUart.h index c1c8d8dfe3d0f34a8241d26695909da10d13f8fd..7d845899e3fb75186d7ed8ba8599a1a77cfbf92b 100644 --- a/cores/arduino/SERCOMUart.h +++ b/cores/arduino/SERCOMUart.h @@ -25,6 +25,7 @@ class SERCOMUart private: SERCOM *sercom; RingBuffer rxBuffer; + RingBuffer txBuffer; SercomNumberStopBit extractNbStopBit(uint8_t config); SercomCharSize extractCharSize(uint8_t config); diff --git a/libraries/SPI/SPI.cpp b/libraries/SPI/SPI.cpp index 9517e22263a272b4dba3b6d7c2b3e8d42763c55e..a2a55c83814e7b48e8b746dfda26a69017054933 100644 --- a/libraries/SPI/SPI.cpp +++ b/libraries/SPI/SPI.cpp @@ -10,109 +10,79 @@ #include "SPI.h" -SPIClass::SPIClass(Spi *_spi, uint32_t _id, void(*_initCb)(void)) : - spi(_spi), id(_id), initCb(_initCb), initialized(false) +SPIClass::SPIClass(SERCOM *sercom) { - // Empty + this->sercom = sercom; } void SPIClass::begin() { - init(); - - // NPCS control is left to the user - - // Default speed set to 4Mhz - setClockDivider(BOARD_SPI_DEFAULT_SS, 21); - setDataMode(BOARD_SPI_DEFAULT_SS, SPI_MODE0); - setBitOrder(BOARD_SPI_DEFAULT_SS, MSBFIRST); -} - -void SPIClass::begin(uint8_t _pin) { - init(); - - uint32_t spiPin = BOARD_PIN_TO_SPI_PIN(_pin); - PIO_Configure( - g_APinDescription[spiPin].pPort, - g_APinDescription[spiPin].ulPinType, - g_APinDescription[spiPin].ulPin, - g_APinDescription[spiPin].ulPinConfiguration); - - // Default speed set to 4Mhz - setClockDivider(_pin, 21); - setDataMode(_pin, SPI_MODE0); - setBitOrder(_pin, MSBFIRST); -} - -void SPIClass::init() { - if (initialized) - return; - initCb(); - SPI_Configure(spi, id, SPI_MR_MSTR | SPI_MR_PS | SPI_MR_MODFDIS); - SPI_Enable(spi); - initialized = true; -} - -void SPIClass::end(uint8_t _pin) { - uint32_t spiPin = BOARD_PIN_TO_SPI_PIN(_pin); - // Setting the pin as INPUT will disconnect it from SPI peripheral - pinMode(spiPin, INPUT); + // Default speed set to 4Mhz, SPI mode set to MODE 0 and Bit order set to MSB first. + sercom->initSPI(PAD_0_SCK_1, PAD_2, 8_BITS, MSB_FIRST); + sercom->initClock(MODE_0, 4000000); } void SPIClass::end() { - SPI_Disable(spi); - initialized = false; + sercom->resetSPI(); } -void SPIClass::setBitOrder(uint8_t _pin, BitOrder _bitOrder) { - uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(_pin); - bitOrder[ch] = _bitOrder; +void setBitOrder(BitOrder order) +{ + if(order == LSBFIRST) + sercom->setDataOrderSPI(LSB_FIRST); + else + sercom->setDataOrderSPI(MSB_FIRST); } -void SPIClass::setDataMode(uint8_t _pin, uint8_t _mode) { - uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(_pin); - mode[ch] = _mode | SPI_CSR_CSAAT; - // SPI_CSR_DLYBCT(1) keeps CS enabled for 32 MCLK after a completed - // transfer. Some device needs that for working properly. - SPI_ConfigureNPCS(spi, ch, mode[ch] | SPI_CSR_SCBR(divider[ch]) | SPI_CSR_DLYBCT(1)); +void setDataMode(uint8_t mode) +{ + switch(mode) + { + case SPI_MODE0: + sercom->setClockModeSPI(MODE_0); + break; + + case SPI_MODE1: + sercom->setClockModeSPI(MODE_1); + break; + + case SPI_MODE2: + sercom->setClockModeSPI(MODE_2); + break; + + case SPI_MODE3: + sercom->setClockModeSPI(MODE_3); + break; + + default: + break; + } } -void SPIClass::setClockDivider(uint8_t _pin, uint8_t _divider) { - uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(_pin); - divider[ch] = _divider; - // SPI_CSR_DLYBCT(1) keeps CS enabled for 32 MCLK after a completed - // transfer. Some device needs that for working properly. - SPI_ConfigureNPCS(spi, ch, mode[ch] | SPI_CSR_SCBR(divider[ch]) | SPI_CSR_DLYBCT(1)); +void setClockDivider(uint8_t div) +{ + sercom->setBaudrateSPI(div); } -byte SPIClass::transfer(byte _pin, uint8_t _data, SPITransferMode _mode) { - uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(_pin); - // Reverse bit order - if (bitOrder[ch] == LSBFIRST) - _data = __REV(__RBIT(_data)); - uint32_t d = _data | SPI_PCS(ch); - if (_mode == SPI_LAST) - d |= SPI_TDR_LASTXFER; - - // SPI_Write(spi, _channel, _data); - while ((spi->SPI_SR & SPI_SR_TDRE) == 0) - ; - spi->SPI_TDR = d; - - // return SPI_Read(spi); - while ((spi->SPI_SR & SPI_SR_RDRF) == 0) - ; - d = spi->SPI_RDR; - // Reverse bit order - if (bitOrder[ch] == LSBFIRST) - d = __REV(__RBIT(d)); - return d & 0xFF; +byte SPIClass::transfer(uint8_t _data) +{ + //Can writing new data? + while(!sercom->isDataRegisterEmptySPI()); + + //Writing the data + sercom->writeDataSPI(data); + + //Data sent? new data to read? + while(!sercom->isTransmitCompleteSPI() || !sercom->isReceiveCompleteSPI()); + + //Read data + return sercom->readDataSPI(); } -void SPIClass::attachInterrupt(void) { +void SPIClass::attachInterrupt() { // Should be enableInterrupt() } -void SPIClass::detachInterrupt(void) { +void SPIClass::detachInterrupt() { // Should be disableInterrupt() } diff --git a/libraries/SPI/SPI.h b/libraries/SPI/SPI.h index 735bd4bf9a517af2c6a5e7f68bf7dde9bf00fdc3..9f3830bf03397d16c40cebc46ea303ef9a0117bd 100644 --- a/libraries/SPI/SPI.h +++ b/libraries/SPI/SPI.h @@ -12,57 +12,29 @@ #define _SPI_H_INCLUDED #include "variant.h" -#include <stdio.h> - -#define SPI_MODE0 0x02 -#define SPI_MODE1 0x00 -#define SPI_MODE2 0x03 -#define SPI_MODE3 0x01 +#include "SERCOM.h" -enum SPITransferMode { - SPI_CONTINUE, - SPI_LAST -}; +#include <stdio.h> class SPIClass { public: - SPIClass(Spi *_spi, uint32_t _id, void(*_initCb)(void)); + SPIClass(SERCOM *sercom); - byte transfer(uint8_t _data, SPITransferMode _mode = SPI_LAST) { return transfer(BOARD_SPI_DEFAULT_SS, _data, _mode); } - byte transfer(byte _channel, uint8_t _data, SPITransferMode _mode = SPI_LAST); + byte transfer(uint8_t _data); // SPI Configuration methods + void attachInterrupt(); + void detachInterrupt(); - void attachInterrupt(void); - void detachInterrupt(void); - - void begin(void); - void end(void); - - // Attach/Detach pin to/from SPI controller - void begin(uint8_t _pin); - void end(uint8_t _pin); - - // These methods sets a parameter on a single pin - void setBitOrder(uint8_t _pin, BitOrder); - void setDataMode(uint8_t _pin, uint8_t); - void setClockDivider(uint8_t _pin, uint8_t); - - // These methods sets the same parameters but on default pin BOARD_SPI_DEFAULT_SS - void setBitOrder(BitOrder _order) { setBitOrder(BOARD_SPI_DEFAULT_SS, _order); }; - void setDataMode(uint8_t _mode) { setDataMode(BOARD_SPI_DEFAULT_SS, _mode); }; - void setClockDivider(uint8_t _div) { setClockDivider(BOARD_SPI_DEFAULT_SS, _div); }; + void begin(); + void end(); + + void setBitOrder(BitOrder order); + void setDataMode(uint8_t mode); + void setClockDivider(uint8_t div); private: - void init(); - - Spi *spi; - uint32_t id; - BitOrder bitOrder[SPI_CHANNELS_NUM]; - uint32_t divider[SPI_CHANNELS_NUM]; - uint32_t mode[SPI_CHANNELS_NUM]; - void (*initCb)(void); - bool initialized; + SERCOM *sercom; }; #if SPI_INTERFACES_COUNT > 0