/* Copyright (c) 2014 Arduino. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SERCOM_CLASS_ #define _SERCOM_CLASS_ #include "sam.h" // SAMD51 has configurable MAX_SPI, else use peripheral clock default. // Update: changing MAX_SPI via compiler flags is DEPRECATED, because // this affects ALL SPI peripherals including some that should NOT be // changed (e.g. anything using SD card). Instead, use setClockSource(). // This is left here for compatibility w/interim MAX_SPI-dependent code: #if defined(MAX_SPI) #define SERCOM_SPI_FREQ_REF (MAX_SPI * 2) #else #define SERCOM_SPI_FREQ_REF 48000000ul #endif // Other SERCOM peripherals always use the 48 MHz clock #define SERCOM_FREQ_REF 48000000ul #define SERCOM_NVIC_PRIORITY ((1<<__NVIC_PRIO_BITS) - 1) typedef enum { UART_EXT_CLOCK = 0, UART_INT_CLOCK = 0x1u } SercomUartMode; typedef enum { SPI_SLAVE_OPERATION = 0x2u, SPI_MASTER_OPERATION = 0x3u } SercomSpiMode; typedef enum { I2C_SLAVE_OPERATION = 0x4u, I2C_MASTER_OPERATION = 0x5u } SercomI2CMode; typedef enum { SERCOM_EVEN_PARITY = 0, SERCOM_ODD_PARITY, SERCOM_NO_PARITY } SercomParityMode; typedef enum { SERCOM_STOP_BIT_1 = 0, SERCOM_STOP_BITS_2 } SercomNumberStopBit; typedef enum { MSB_FIRST = 0, LSB_FIRST } SercomDataOrder; typedef enum { UART_CHAR_SIZE_8_BITS = 0, UART_CHAR_SIZE_9_BITS, UART_CHAR_SIZE_5_BITS = 0x5u, UART_CHAR_SIZE_6_BITS, UART_CHAR_SIZE_7_BITS } SercomUartCharSize; typedef enum { SERCOM_RX_PAD_0 = 0, SERCOM_RX_PAD_1, SERCOM_RX_PAD_2, SERCOM_RX_PAD_3 } SercomRXPad; typedef enum { UART_TX_PAD_0 = 0x0ul, // Only for UART UART_TX_PAD_2 = 0x1ul, // Only for UART UART_TX_RTS_CTS_PAD_0_2_3 = 0x2ul, // Only for UART with TX on PAD0, RTS on PAD2 and CTS on PAD3 } SercomUartTXPad; typedef enum { SAMPLE_RATE_x16 = 0x1, // Fractional SAMPLE_RATE_x8 = 0x3, // Fractional } SercomUartSampleRate; typedef enum { SERCOM_SPI_MODE_0 = 0, // CPOL : 0 | CPHA : 0 SERCOM_SPI_MODE_1, // CPOL : 0 | CPHA : 1 SERCOM_SPI_MODE_2, // CPOL : 1 | CPHA : 0 SERCOM_SPI_MODE_3 // CPOL : 1 | CPHA : 1 } SercomSpiClockMode; typedef enum { SPI_PAD_0_SCK_1 = 0, SPI_PAD_2_SCK_3, SPI_PAD_3_SCK_1, SPI_PAD_0_SCK_3 } SercomSpiTXPad; typedef enum { SPI_CHAR_SIZE_8_BITS = 0x0ul, SPI_CHAR_SIZE_9_BITS } SercomSpiCharSize; typedef enum { WIRE_UNKNOWN_STATE = 0x0ul, WIRE_IDLE_STATE, WIRE_OWNER_STATE, WIRE_BUSY_STATE } SercomWireBusState; typedef enum { WIRE_WRITE_FLAG = 0x0ul, WIRE_READ_FLAG } SercomWireReadWriteFlag; typedef enum { WIRE_MASTER_ACT_NO_ACTION = 0, WIRE_MASTER_ACT_REPEAT_START, WIRE_MASTER_ACT_READ, WIRE_MASTER_ACT_STOP } SercomMasterCommandWire; typedef enum { WIRE_MASTER_ACK_ACTION = 0, WIRE_MASTER_NACK_ACTION } SercomMasterAckActionWire; // SERCOM clock source override is available only on SAMD51 (not 21) // but the enumeration is made regardless so user code doesn't need // ifdefs or lengthy comments explaining the different situations -- // the clock-sourcing functions just compile to nothing on SAMD21. typedef enum { SERCOM_CLOCK_SOURCE_FCPU, // F_CPU clock (GCLK0) SERCOM_CLOCK_SOURCE_48M, // 48 MHz peripheral clock (GCLK1) (standard) SERCOM_CLOCK_SOURCE_100M, // 100 MHz peripheral clock (GCLK2) SERCOM_CLOCK_SOURCE_32K, // XOSC32K clock (GCLK3) SERCOM_CLOCK_SOURCE_12M, // 12 MHz peripheral clock (GCLK4) SERCOM_CLOCK_SOURCE_NO_CHANGE // Leave clock source setting unchanged } SercomClockSource; class SERCOM { public: SERCOM(Sercom* s) ; /* ========== UART ========== */ void initUART(SercomUartMode mode, SercomUartSampleRate sampleRate, uint32_t baudrate=0) ; void initFrame(SercomUartCharSize charSize, SercomDataOrder dataOrder, SercomParityMode parityMode, SercomNumberStopBit nbStopBits) ; void initPads(SercomUartTXPad txPad, SercomRXPad rxPad) ; void resetUART( void ) ; void enableUART( void ) ; void flushUART( void ) ; void clearStatusUART( void ) ; bool availableDataUART( void ) ; bool isBufferOverflowErrorUART( void ) ; bool isFrameErrorUART( void ) ; void clearFrameErrorUART( void ) ; bool isParityErrorUART( void ) ; bool isDataRegisterEmptyUART( void ) ; uint8_t readDataUART( void ) ; int writeDataUART(uint8_t data) ; bool isUARTError() ; void acknowledgeUARTError() ; void enableDataRegisterEmptyInterruptUART(); void disableDataRegisterEmptyInterruptUART(); /* ========== SPI ========== */ void initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize charSize, SercomDataOrder dataOrder) ; void initSPIClock(SercomSpiClockMode clockMode, uint32_t baudrate) ; void resetSPI( void ) ; void enableSPI( void ) ; void disableSPI( void ) ; void setDataOrderSPI(SercomDataOrder dataOrder) ; SercomDataOrder getDataOrderSPI( void ) ; void setBaudrateSPI(uint8_t divider) ; void setClockModeSPI(SercomSpiClockMode clockMode) ; uint8_t transferDataSPI(uint8_t data) ; bool isBufferOverflowErrorSPI( void ) ; bool isDataRegisterEmptySPI( void ) ; bool isTransmitCompleteSPI( void ) ; bool isReceiveCompleteSPI( void ) ; /* ========== WIRE ========== */ void initSlaveWIRE(uint8_t address, bool enableGeneralCall = false) ; void initMasterWIRE(uint32_t baudrate) ; void resetWIRE( void ) ; void enableWIRE( void ) ; void disableWIRE( void ); void prepareNackBitWIRE( void ) ; void prepareAckBitWIRE( void ) ; void prepareCommandBitsWire(uint8_t cmd); bool startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag) ; bool sendDataMasterWIRE(uint8_t data) ; bool sendDataSlaveWIRE(uint8_t data) ; bool isMasterWIRE( void ) ; bool isSlaveWIRE( void ) ; bool isBusIdleWIRE( void ) ; bool isBusOwnerWIRE( void ) ; bool isBusUnknownWIRE( void ) ; bool isArbLostWIRE( void ); bool isBusBusyWIRE( void ); bool isDataReadyWIRE( void ) ; bool isStopDetectedWIRE( void ) ; bool isRestartDetectedWIRE( void ) ; bool isAddressMatch( void ) ; bool isMasterReadOperationWIRE( void ) ; bool isRXNackReceivedWIRE( void ) ; int availableWIRE( void ) ; uint8_t readDataWIRE( void ) ; int8_t getSercomIndex(void); #if defined(__SAMD51__) // SERCOM clock source override is only available on // SAMD51 (not 21) ... but these functions are declared // regardless so user code doesn't need ifdefs or lengthy // comments explaining the different situations -- these // just compile to nothing on SAMD21. void setClockSource(int8_t idx, SercomClockSource src, bool core); SercomClockSource getClockSource(void) { return clockSource; }; uint32_t getFreqRef(void) { return freqRef; }; #else // The equivalent SAMD21 dummy functions... void setClockSource(int8_t idx, SercomClockSource src, bool core) { (void)idx; (void)src; (void)core; }; SercomClockSource getClockSource(void) { return SERCOM_CLOCK_SOURCE_FCPU; }; uint32_t getFreqRef(void) { return F_CPU; }; #endif private: Sercom* sercom; #if defined(__SAMD51__) SercomClockSource clockSource; uint32_t freqRef; // Frequency corresponding to clockSource #endif uint8_t calculateBaudrateSynchronous(uint32_t baudrate); uint32_t division(uint32_t dividend, uint32_t divisor) ; void initClockNVIC( void ) ; }; #endif