267 lines
7.8 KiB
C++
267 lines
7.8 KiB
C++
/*
|
|
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(__attribute__((unused)) int8_t idx, __attribute__((unused)) SercomClockSource src, __attribute__((unused)) bool 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
|