diff --git a/.gitignore b/.gitignore index ef8f29944..82515546a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ bootloaders/*/build/ *~ /libraries/**/build/ +.ci-home +.ci_home +*.log \ No newline at end of file diff --git a/cores/arduino/Arduino.h b/cores/arduino/Arduino.h index 175dcf705..9a67e1f46 100644 --- a/cores/arduino/Arduino.h +++ b/cores/arduino/Arduino.h @@ -45,9 +45,11 @@ extern "C"{ #endif // __cplusplus // Include Atmel headers -#include "sam.h" +#include #include "wiring_constants.h" +extern uint32_t SystemCoreClock; + #define clockCyclesPerMicrosecond() ( SystemCoreClock / 1000000L ) #define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (SystemCoreClock / 1000L) ) #define microsecondsToClockCycles(a) ( (a) * (SystemCoreClock / 1000000L) ) @@ -156,7 +158,9 @@ void loop( void ) ; #include "USB/USBDesc.h" #include "USB/USBCore.h" #include "USB/USBAPI.h" - #include "USB/USB_host.h" + #if !defined(__SAME53__) && !defined(__SAME54__) + #include "USB/USB_host.h" + #endif #endif #endif // Arduino_h diff --git a/cores/arduino/PendSV.cpp b/cores/arduino/PendSV.cpp new file mode 100644 index 000000000..6eb84af90 --- /dev/null +++ b/cores/arduino/PendSV.cpp @@ -0,0 +1,162 @@ +#include "PendSV.h" + +#include +#include + +#if defined(USE_TINYUSB) +extern "C" void TinyUSB_Device_Task(void); +#endif + +namespace { +PendSV pendSv; + +#if defined(USE_TINYUSB) +void tinyUsbDeviceTaskService(uint8_t serviceId, void *context) { + (void)serviceId; + (void)context; + // One invocation drains TinyUSB's queued controller events under OPT_OS_NONE. + TinyUSB_Device_Task(); +} +#endif +} + +PendSV &PendSV::instance() { + return pendSv; +} + +#if defined(USE_TINYUSB) +extern "C" void tud_event_hook_cb(uint8_t rhport, uint32_t eventId, bool inIsr) { + (void)rhport; + (void)eventId; + (void)inIsr; + // TinyUSB owns the event queue. PendSV is only its deferred wake signal, so + // multiple controller events before dispatch require only one service call. + PendSV::instance().setPendingOnce(PendSVChannels::Usb); +} +#endif + +bool PendSV::initializeCoreServices() { + NVIC_SetPriority(PendSV_IRQn, (1 << __NVIC_PRIO_BITS) - 1); +#if defined(USE_TINYUSB) + return instance().registerService(PendSVChannels::Usb, tinyUsbDeviceTaskService, nullptr); +#else + return true; +#endif +} + +uint32_t PendSV::enterCritical() { + const uint32_t primask = __get_PRIMASK(); + __disable_irq(); + return primask; +} + +void PendSV::exitCritical(uint32_t primask) { + __set_PRIMASK(primask); +} + +bool PendSV::registerService(uint8_t serviceId, ServiceFn fn, void *context) { + if (serviceId >= kMaxServices || fn == nullptr) + return false; + + const uint32_t primask = enterCritical(); + pendingCount_[serviceId] = 0; + pendingMask_ &= ~(1u << serviceId); + services_[serviceId].fn = fn; + services_[serviceId].context = context; + exitCritical(primask); + + return true; +} + +void PendSV::clearService(uint8_t serviceId) { + if (serviceId >= kMaxServices) + return; + + const uint32_t primask = enterCritical(); + services_[serviceId].fn = nullptr; + services_[serviceId].context = nullptr; + pendingCount_[serviceId] = 0; + pendingMask_ &= ~(1u << serviceId); + exitCritical(primask); +} + +void PendSV::setPending(uint8_t serviceId) { + if (serviceId >= kMaxServices) + return; + + const uint32_t primask = enterCritical(); + uint16_t &pendingCount = pendingCount_[serviceId]; + if (pendingCount < UINT16_MAX) + ++pendingCount; + pendingMask_ |= (1u << serviceId); + exitCritical(primask); + + __DMB(); + SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; +} + +void PendSV::setPendingOnce(uint8_t serviceId) { + if (serviceId >= kMaxServices) + return; + + const uint32_t primask = enterCritical(); + pendingCount_[serviceId] = 1; + pendingMask_ |= (1u << serviceId); + exitCritical(primask); + + __DMB(); + SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; +} + +void PendSV::dispatchPending() { + // Bound one PendSV entry so high-rate producers do not monopolize return to + // thread mode. Remaining work re-pends PendSV below. + uint8_t dispatched = 0; + + while (dispatched < kDispatchBudget) { + uint32_t primask = enterCritical(); + const uint32_t pending = pendingMask_; + if (pending == 0) { + exitCritical(primask); + return; + } + + const uint8_t serviceId = static_cast(__builtin_ctz(pending)); + uint16_t &pendingCount = pendingCount_[serviceId]; + + if (pendingCount == 0) { + // Defensive scrub in case mask and count drift out of sync. + pendingMask_ &= ~(1u << serviceId); + exitCritical(primask); + continue; + } + + --pendingCount; + if (pendingCount == 0) + pendingMask_ &= ~(1u << serviceId); + + ServiceEntry entry = services_[serviceId]; + exitCritical(primask); + + // Pending work without a registered service is intentionally dropped. + // Producers are expected to register before calling setPending(), and + // clearService() cancels queued work for that service. + if (entry.fn != nullptr) + entry.fn(serviceId, entry.context); + + ++dispatched; + } + + const uint32_t primask = enterCritical(); + const bool hasRemaining = (pendingMask_ != 0); + exitCritical(primask); + + if (hasRemaining) { + __DMB(); + SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; + } +} + +extern "C" void PendSV_Handler(void) { + PendSV::instance().dispatchPending(); +} diff --git a/cores/arduino/PendSV.h b/cores/arduino/PendSV.h new file mode 100644 index 000000000..98222b2c7 --- /dev/null +++ b/cores/arduino/PendSV.h @@ -0,0 +1,189 @@ +#pragma once + +#include + +#include +#include + +#if defined(SERCOM0) || defined(SERCOM0_REGS) +#define SIMIO_PENDSV_HAS_SERCOM0 true +#else +#define SIMIO_PENDSV_HAS_SERCOM0 false +#endif +#if defined(SERCOM1) || defined(SERCOM1_REGS) +#define SIMIO_PENDSV_HAS_SERCOM1 true +#else +#define SIMIO_PENDSV_HAS_SERCOM1 false +#endif +#if defined(SERCOM2) || defined(SERCOM2_REGS) +#define SIMIO_PENDSV_HAS_SERCOM2 true +#else +#define SIMIO_PENDSV_HAS_SERCOM2 false +#endif +#if defined(SERCOM3) || defined(SERCOM3_REGS) +#define SIMIO_PENDSV_HAS_SERCOM3 true +#else +#define SIMIO_PENDSV_HAS_SERCOM3 false +#endif +#if defined(SERCOM4) || defined(SERCOM4_REGS) +#define SIMIO_PENDSV_HAS_SERCOM4 true +#else +#define SIMIO_PENDSV_HAS_SERCOM4 false +#endif +#if defined(SERCOM5) || defined(SERCOM5_REGS) +#define SIMIO_PENDSV_HAS_SERCOM5 true +#else +#define SIMIO_PENDSV_HAS_SERCOM5 false +#endif +#if defined(SERCOM6) || defined(SERCOM6_REGS) +#define SIMIO_PENDSV_HAS_SERCOM6 true +#else +#define SIMIO_PENDSV_HAS_SERCOM6 false +#endif +#if defined(SERCOM7) || defined(SERCOM7_REGS) +#define SIMIO_PENDSV_HAS_SERCOM7 true +#else +#define SIMIO_PENDSV_HAS_SERCOM7 false +#endif +#if defined(DMAC) || defined(DMAC_REGS) +#define SIMIO_PENDSV_HAS_DMAC true +#else +#define SIMIO_PENDSV_HAS_DMAC false +#endif +#if defined(AES) || defined(AES_REGS) +#define SIMIO_PENDSV_HAS_AES true +#else +#define SIMIO_PENDSV_HAS_AES false +#endif +#if defined(ICM) || defined(ICM_REGS) +#define SIMIO_PENDSV_HAS_ICM true +#else +#define SIMIO_PENDSV_HAS_ICM false +#endif +#if defined(PUKCC) || defined(PUKCC_REGS) || defined(ID_PUKCC) || defined(PUKCC_INSTANCE_ID) || \ + defined(PUKCC_IRQn) +#define SIMIO_PENDSV_HAS_PUKCC true +#else +#define SIMIO_PENDSV_HAS_PUKCC false +#endif +#if defined(TRNG) || defined(TRNG_REGS) +#define SIMIO_PENDSV_HAS_TRNG true +#else +#define SIMIO_PENDSV_HAS_TRNG false +#endif +#if defined(GMAC) || defined(GMAC_REGS) +#define SIMIO_PENDSV_HAS_GMAC true +#define SIMIO_PENDSV_HAS_PHY true +#else +#define SIMIO_PENDSV_HAS_GMAC false +#define SIMIO_PENDSV_HAS_PHY false +#endif + +template +struct PendSVChannelMap { + static constexpr uint8_t kUnavailable = 0xFF; + +private: + static constexpr uint8_t assign(bool present, uint8_t next) { + return present ? next : kUnavailable; + } + static constexpr uint8_t advance(bool present, uint8_t next) { + return present ? static_cast(next + 1) : next; + } + + static constexpr uint8_t kBase = 0; + static constexpr uint8_t kAfterSercom0 = advance(HasSercom0, kBase); + static constexpr uint8_t kAfterSercom1 = advance(HasSercom1, kAfterSercom0); + static constexpr uint8_t kAfterSercom2 = advance(HasSercom2, kAfterSercom1); + static constexpr uint8_t kAfterSercom3 = advance(HasSercom3, kAfterSercom2); + static constexpr uint8_t kAfterSercom4 = advance(HasSercom4, kAfterSercom3); + static constexpr uint8_t kAfterSercom5 = advance(HasSercom5, kAfterSercom4); + static constexpr uint8_t kAfterSercom6 = advance(HasSercom6, kAfterSercom5); + static constexpr uint8_t kAfterSercom7 = advance(HasSercom7, kAfterSercom6); + static constexpr uint8_t kAfterRtc = advance(true, kAfterSercom7); + static constexpr uint8_t kAfterUsb = advance(true, kAfterRtc); + static constexpr uint8_t kAfterAdc = advance(true, kAfterUsb); + static constexpr uint8_t kAfterDmac = advance(HasDmac, kAfterAdc); + static constexpr uint8_t kAfterAes = advance(HasAes, kAfterDmac); + static constexpr uint8_t kAfterIcm = advance(HasIcm, kAfterAes); + static constexpr uint8_t kAfterPukcc = advance(HasPukcc, kAfterIcm); + static constexpr uint8_t kAfterTrng = advance(HasTrng, kAfterPukcc); + static constexpr uint8_t kAfterGmac = advance(HasGmac, kAfterTrng); + static constexpr uint8_t kAfterPhy = advance(HasPhy, kAfterGmac); + static constexpr uint8_t kAfterUsbProtocol = advance(true, kAfterPhy); + static constexpr uint8_t kAfterDiscreteInput = advance(true, kAfterUsbProtocol); + +public: + static constexpr uint8_t Sercom0 = assign(HasSercom0, kBase); + static constexpr uint8_t Sercom1 = assign(HasSercom1, kAfterSercom0); + static constexpr uint8_t Sercom2 = assign(HasSercom2, kAfterSercom1); + static constexpr uint8_t Sercom3 = assign(HasSercom3, kAfterSercom2); + static constexpr uint8_t Sercom4 = assign(HasSercom4, kAfterSercom3); + static constexpr uint8_t Sercom5 = assign(HasSercom5, kAfterSercom4); + static constexpr uint8_t Sercom6 = assign(HasSercom6, kAfterSercom5); + static constexpr uint8_t Sercom7 = assign(HasSercom7, kAfterSercom6); + static constexpr uint8_t Rtc = kAfterSercom7; + static constexpr uint8_t Usb = kAfterRtc; + static constexpr uint8_t Adc = kAfterUsb; + static constexpr uint8_t Dmac = assign(HasDmac, kAfterAdc); + static constexpr uint8_t Aes = assign(HasAes, kAfterDmac); + static constexpr uint8_t Icm = assign(HasIcm, kAfterAes); + static constexpr uint8_t Pukcc = assign(HasPukcc, kAfterIcm); + static constexpr uint8_t Trng = assign(HasTrng, kAfterPukcc); + static constexpr uint8_t Gmac = assign(HasGmac, kAfterTrng); + static constexpr uint8_t Phy = assign(HasPhy, kAfterGmac); + static constexpr uint8_t UsbProtocol = kAfterPhy; + static constexpr uint8_t DiscreteInput = kAfterUsbProtocol; + static constexpr uint8_t Count = kAfterDiscreteInput; + + static constexpr bool isAvailable(uint8_t channel) { return channel != kUnavailable; } + static constexpr uint8_t sercom(uint8_t index) { + return index == 0 ? Sercom0 : index == 1 ? Sercom1 : index == 2 ? Sercom2 + : index == 3 ? Sercom3 : index == 4 ? Sercom4 : index == 5 ? Sercom5 + : index == 6 ? Sercom6 : index == 7 ? Sercom7 : kUnavailable; + } + static constexpr uint8_t sercomIndex(uint8_t channel) { + return channel == Sercom0 ? 0 : channel == Sercom1 ? 1 : channel == Sercom2 ? 2 + : channel == Sercom3 ? 3 : channel == Sercom4 ? 4 : channel == Sercom5 ? 5 + : channel == Sercom6 ? 6 : channel == Sercom7 ? 7 : kUnavailable; + } +}; + +using PendSVChannels = PendSVChannelMap< + SIMIO_PENDSV_HAS_SERCOM0, SIMIO_PENDSV_HAS_SERCOM1, SIMIO_PENDSV_HAS_SERCOM2, + SIMIO_PENDSV_HAS_SERCOM3, SIMIO_PENDSV_HAS_SERCOM4, SIMIO_PENDSV_HAS_SERCOM5, + SIMIO_PENDSV_HAS_SERCOM6, SIMIO_PENDSV_HAS_SERCOM7, SIMIO_PENDSV_HAS_DMAC, + SIMIO_PENDSV_HAS_AES, SIMIO_PENDSV_HAS_ICM, SIMIO_PENDSV_HAS_PUKCC, + SIMIO_PENDSV_HAS_TRNG, SIMIO_PENDSV_HAS_GMAC, SIMIO_PENDSV_HAS_PHY>; + +class PendSV { +public: + using ServiceFn = void (*)(uint8_t serviceId, void *context); + static constexpr uint8_t kMaxServices = PendSVChannels::Count; + static constexpr uint8_t kDispatchBudget = 16; + static_assert(kMaxServices <= 32, "PendSV pending mask supports at most 32 services"); + + static PendSV &instance(); + static bool initializeCoreServices(); + + bool registerService(uint8_t serviceId, ServiceFn fn, void *context = nullptr); + void clearService(uint8_t serviceId); + void dispatchPending(); + void setPending(uint8_t serviceId); + void setPendingOnce(uint8_t serviceId); + +private: + static uint32_t enterCritical(); + static void exitCritical(uint32_t primask); + + struct ServiceEntry { + ServiceFn fn = nullptr; + void *context = nullptr; + }; + + std::array services_{}; + std::array pendingCount_{}; + volatile uint32_t pendingMask_ = 0; +}; diff --git a/cores/arduino/PendSVChannelMap.h b/cores/arduino/PendSVChannelMap.h new file mode 100644 index 000000000..441bb92cb --- /dev/null +++ b/cores/arduino/PendSVChannelMap.h @@ -0,0 +1,61 @@ +#pragma once + +#include + +template +struct PendSVChannelMap { + static constexpr uint8_t kMaxServices = 32; + static constexpr uint8_t kUnavailable = 0xFF; + +private: + static constexpr uint8_t assign(bool present, uint8_t next) { + return present ? next : kUnavailable; + } + + static constexpr uint8_t advance(bool present, uint8_t next) { + return present ? static_cast(next + 1) : next; + } + + static constexpr uint8_t kBase = 0; + static constexpr uint8_t kAfterSercom0 = advance(HasSercom0, kBase); + static constexpr uint8_t kAfterSercom1 = advance(HasSercom1, kAfterSercom0); + static constexpr uint8_t kAfterSercom2 = advance(HasSercom2, kAfterSercom1); + static constexpr uint8_t kAfterSercom3 = advance(HasSercom3, kAfterSercom2); + static constexpr uint8_t kAfterSercom4 = advance(HasSercom4, kAfterSercom3); + static constexpr uint8_t kAfterSercom5 = advance(HasSercom5, kAfterSercom4); + static constexpr uint8_t kAfterSercom6 = advance(HasSercom6, kAfterSercom5); + static constexpr uint8_t kAfterSercom7 = advance(HasSercom7, kAfterSercom6); + static constexpr uint8_t kAfterUsb = advance(HasUsb, kAfterSercom7); + static constexpr uint8_t kAfterGmac = advance(HasGmac, kAfterUsb); + static constexpr uint8_t kAfterPhy = advance(HasPhy, kAfterGmac); + static constexpr uint8_t kAfterAdc = advance(HasAdc, kAfterPhy); + static constexpr uint8_t kAfterAes = advance(HasAes, kAfterAdc); + static constexpr uint8_t kAfterPukcc = advance(HasPukcc, kAfterAes); + static constexpr uint8_t kAfterTrng = advance(HasTrng, kAfterPukcc); + +public: + static constexpr uint8_t Sercom0 = assign(HasSercom0, kBase); + static constexpr uint8_t Sercom1 = assign(HasSercom1, kAfterSercom0); + static constexpr uint8_t Sercom2 = assign(HasSercom2, kAfterSercom1); + static constexpr uint8_t Sercom3 = assign(HasSercom3, kAfterSercom2); + static constexpr uint8_t Sercom4 = assign(HasSercom4, kAfterSercom3); + static constexpr uint8_t Sercom5 = assign(HasSercom5, kAfterSercom4); + static constexpr uint8_t Sercom6 = assign(HasSercom6, kAfterSercom5); + static constexpr uint8_t Sercom7 = assign(HasSercom7, kAfterSercom6); + static constexpr uint8_t Usb = assign(HasUsb, kAfterSercom7); + static constexpr uint8_t Gmac = assign(HasGmac, kAfterUsb); + static constexpr uint8_t Phy = assign(HasPhy, kAfterGmac); + static constexpr uint8_t Adc = assign(HasAdc, kAfterPhy); + static constexpr uint8_t Aes = assign(HasAes, kAfterAdc); + static constexpr uint8_t Pukcc = assign(HasPukcc, kAfterAes); + static constexpr uint8_t Trng = assign(HasTrng, kAfterPukcc); + static constexpr uint8_t Rtc = assign(HasRtc, kAfterTrng); + static constexpr uint8_t Count = advance(HasRtc, kAfterTrng); + + static constexpr bool isAvailable(uint8_t channel) { + return channel != kUnavailable; + } +}; diff --git a/cores/arduino/Reset.cpp b/cores/arduino/Reset.cpp index 9bde4a8c0..9f93ebc43 100644 --- a/cores/arduino/Reset.cpp +++ b/cores/arduino/Reset.cpp @@ -33,7 +33,7 @@ extern const uint32_t __text_start__; #else -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) #define APP_START 0x00004004 #else #define APP_START 0x00002004 @@ -42,8 +42,10 @@ extern const uint32_t __text_start__; #endif static inline bool nvmReady(void) { -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) return NVMCTRL->STATUS.reg & NVMCTRL_STATUS_READY; +#elif defined(__SAME53__) || defined(__SAME54__) + return NVMCTRL_REGS->NVMCTRL_STATUS & NVMCTRL_STATUS_READY_Msk; #else return NVMCTRL->INTFLAG.reg & NVMCTRL_INTFLAG_READY; #endif @@ -54,7 +56,7 @@ static void banzai() { // Disable all interrupts __disable_irq(); -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) //THESE MUST MATCH THE BOOTLOADER #define DOUBLE_TAP_MAGIC 0xf01669efUL #define BOOT_DOUBLE_TAP_ADDRESS (HSRAM_ADDR + HSRAM_SIZE - 4) diff --git a/cores/arduino/RingBuffer.h b/cores/arduino/RingBuffer.h index deecb733c..3c6d1b95c 100644 --- a/cores/arduino/RingBuffer.h +++ b/cores/arduino/RingBuffer.h @@ -22,6 +22,7 @@ #define _RING_BUFFER_ #include +#include // Define constants and variables for buffering incoming serial data. We're // using a ring buffer (I think), in which head is the index of the location @@ -32,16 +33,19 @@ #define SERIAL_BUFFER_SIZE 350 #endif -template +template class RingBufferN { public: - uint8_t _aucBuffer[N] ; + T _aucBuffer[N] ; volatile int _iHead ; volatile int _iTail ; public: RingBufferN( void ) ; + bool store( const T& c ) ; + bool read( T& out ) ; + bool peek( T& out ) const ; void store_char( uint8_t c ) ; void clear(); int read_char(); @@ -57,15 +61,16 @@ class RingBufferN typedef RingBufferN RingBuffer; -template -RingBufferN::RingBufferN( void ) +template +RingBufferN::RingBufferN( void ) { - memset( _aucBuffer, 0, N ) ; + for (int i = 0; i < N; ++i) + _aucBuffer[i] = T{}; clear(); } -template -void RingBufferN::store_char( uint8_t c ) +template +bool RingBufferN::store( const T& c ) { int i = nextIndex(_iHead); @@ -77,30 +82,58 @@ void RingBufferN::store_char( uint8_t c ) { _aucBuffer[_iHead] = c ; _iHead = i ; + return true; } + return false; } -template -void RingBufferN::clear() +template +bool RingBufferN::read( T& out ) { - _iHead = 0; - _iTail = 0; + if(_iTail == _iHead) + return false; + + out = _aucBuffer[_iTail]; + _iTail = nextIndex(_iTail); + return true; } -template -int RingBufferN::read_char() +template +bool RingBufferN::peek( T& out ) const { if(_iTail == _iHead) - return -1; + return false; - uint8_t value = _aucBuffer[_iTail]; - _iTail = nextIndex(_iTail); + out = _aucBuffer[_iTail]; + return true; +} + +template +void RingBufferN::store_char( uint8_t c ) +{ + static_assert(std::is_same::value, "store_char only valid for uint8_t buffers"); + (void)store(static_cast(c)); +} + +template +void RingBufferN::clear() +{ + _iHead = 0; + _iTail = 0; +} +template +int RingBufferN::read_char() +{ + static_assert(std::is_same::value, "read_char only valid for uint8_t buffers"); + uint8_t value; + if (!read(value)) + return -1; return value; } -template -int RingBufferN::available() +template +int RingBufferN::available() { int delta = _iHead - _iTail; @@ -110,8 +143,8 @@ int RingBufferN::available() return delta; } -template -int RingBufferN::availableForStore() +template +int RingBufferN::availableForStore() { if (_iHead >= _iTail) return N - 1 - _iHead + _iTail; @@ -119,23 +152,25 @@ int RingBufferN::availableForStore() return _iTail - _iHead - 1; } -template -int RingBufferN::peek() +template +int RingBufferN::peek() { - if(_iTail == _iHead) + static_assert(std::is_same::value, "peek() only valid for uint8_t buffers"); + uint8_t value; + if (!peek(value)) return -1; - return _aucBuffer[_iTail]; + return value; } -template -int RingBufferN::nextIndex(int index) +template +int RingBufferN::nextIndex(int index) { return (uint32_t)(index + 1) % N; } -template -bool RingBufferN::isFull() +template +bool RingBufferN::isFull() { return (nextIndex(_iHead) == _iTail); } diff --git a/cores/arduino/SERCOM.cpp b/cores/arduino/SERCOM.cpp index f945a847f..4eeadba6e 100644 --- a/cores/arduino/SERCOM.cpp +++ b/cores/arduino/SERCOM.cpp @@ -18,20 +18,34 @@ */ #include "SERCOM.h" -#include "variant.h" +#include "SERCOM_WireBusErrorPolicy.h" #include "Arduino.h" +#include "PendSV.h" +#include "variant.h" + +#ifdef USE_ZERODMA +#include +#endif // USE_ZERODMA #ifndef WIRE_RISE_TIME_NANOSECONDS // Default rise time in nanoseconds, based on 4.7K ohm pull up resistors // you can override this value in your variant if needed #define WIRE_RISE_TIME_NANOSECONDS 125 -#endif +#endif // !WIRE_RISE_TIME_NANOSECONDS -SERCOM::SERCOM(Sercom* s) +#if defined(__SAME53__) || defined(__SAME54__) +SERCOM::SERCOM(sercom_registers_t *s) +#else +SERCOM::SERCOM(Sercom *s) +#endif // __SAME53__ / __SAME54__ { sercom = s; + int8_t idx = getSercomIndex(); + if (idx >= 0 && idx < (int8_t)kSercomCount) + s_instances[idx] = this; -#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || \ + defined(__SAME54__) // A briefly-available but now deprecated feature had the SPI clock source // set via a compile-time setting (MAX_SPI)...problem was this affected // ALL SERCOMs, whereas some (anything read/write, e.g. SD cards) should @@ -42,12 +56,32 @@ SERCOM::SERCOM(Sercom* s) // might have relied on the compile-time setting. But please, don't. #if SERCOM_SPI_FREQ_REF == F_CPU // F_CPU clock = GCLK0 clockSource = SERCOM_CLOCK_SOURCE_100M; - #elif SERCOM_SPI_FREQ_REF == 48000000 // 48 MHz clock = GCLK1 (standard) +#elif SERCOM_SPI_FREQ_REF == 48000000 // 48 MHz clock = GCLK1 (standard) clockSource = SERCOM_CLOCK_SOURCE_48M; - #elif SERCOM_SPI_FREQ_REF == 100000000 // 100 MHz clock = GCLK2 +#elif SERCOM_SPI_FREQ_REF == 100000000 // 100 MHz clock = GCLK2 clockSource = SERCOM_CLOCK_SOURCE_100M; - #endif -#endif // end __SAMD51__ +#endif // SERCOM_SPI_FREQ_REF == F_CPU +#endif // __SAMD51__ / __SAME51__ || __SAME53__ / __SAME54__ +} + +void SERCOM::resetSERCOM() +{ + // UART, SPI, I2CS, and I2CM use the same SWRST and DBGCTRL bits, so this works for all modes +#if defined(__SAME53__) || defined(__SAME54__) + sercom->USART_INT.SERCOM_CTRLA = SERCOM_USART_INT_CTRLA_SWRST_Msk; +#else + sercom->USART.CTRLA.bit.SWRST = 1; +#endif // __SAME53__ / __SAME54__ + + waitSyncBusySwrst(); + +#if defined(__SAME53__) || defined(__SAME54__) + sercom->USART_INT.SERCOM_DBGCTRL &= ~SERCOM_USART_INT_DBGCTRL_DBGSTOP_Msk; +#else + // DBGCTRL is not affected by SWRST, so explicitly clear it here to ensure debug behavior is + // consistent after reset + sercom->USART.DBGCTRL.bit.DBGSTOP = 0; +#endif // __SAME53__ / __SAME54__ } /* ========================= @@ -59,162 +93,401 @@ void SERCOM::initUART(SercomUartMode mode, SercomUartSampleRate sampleRate, uint initClockNVIC(); resetUART(); - //Setting the CTRLA register - sercom->USART.CTRLA.reg = SERCOM_USART_CTRLA_MODE(mode) | - SERCOM_USART_CTRLA_SAMPR(sampleRate); +#ifdef USE_ZERODMA + int8_t id = getSercomIndex(); - //Setting the Interrupt register - sercom->USART.INTENSET.reg = SERCOM_USART_INTENSET_RXC | //Received complete - SERCOM_USART_INTENSET_ERROR; //All others errors + if (id >= 0) { + dmaSetCallbacks(SERCOM::dmaTxCallbackUART, SERCOM::dmaRxCallbackUART); + dmaInit(id); + } +#endif // USE_ZERODMA - if ( mode == UART_INT_CLOCK ) - { - uint16_t sampleRateValue; + registerService(getSercomIndex(), &SERCOM::stopTransmissionUART); - if (sampleRate == SAMPLE_RATE_x16) { - sampleRateValue = 16; - } else { - sampleRateValue = 8; - } + uint32_t baudTimes8 = 0; + if (mode == UART_INT_CLOCK) { + const uint16_t sampleRateValue = (sampleRate == SAMPLE_RATE_x16) ? 16 : 8; // Asynchronous fractional mode (Table 24-2 in datasheet) // BAUD = fref / (sampleRateValue * fbaud) // (multiply by 8, to calculate fractional piece) - uint32_t baudTimes8 = (freqRef * 8) / (sampleRateValue * baudrate); + baudTimes8 = (freqRef * 8) / (sampleRateValue * baudrate); + } - sercom->USART.BAUD.FRAC.FP = (baudTimes8 % 8); +#if defined(__SAME53__) || defined(__SAME54__) + sercom->USART_INT.SERCOM_CTRLA = SERCOM_USART_INT_CTRLA_MODE(mode) | + SERCOM_USART_INT_CTRLA_SAMPR(sampleRate); + sercom->USART_INT.SERCOM_INTENSET = SERCOM_USART_INT_INTENSET_RXC_Msk | + SERCOM_USART_INT_INTENSET_ERROR_Msk; + + if (mode == UART_INT_CLOCK) { + sercom->USART_INT.SERCOM_BAUD = + SERCOM_USART_INT_BAUD_FRAC_FP(baudTimes8 % 8) | + SERCOM_USART_INT_BAUD_FRAC_BAUD(baudTimes8 / 8); + } +#else + // Setting the CTRLA register + sercom->USART.CTRLA.reg = SERCOM_USART_CTRLA_MODE(mode) | + SERCOM_USART_CTRLA_SAMPR(sampleRate); + + // Setting the Interrupt register + sercom->USART.INTENSET.reg = SERCOM_USART_INTENSET_RXC | // Received complete + SERCOM_USART_INTENSET_ERROR; // All others errors + + if (mode == UART_INT_CLOCK) { + sercom->USART.BAUD.FRAC.FP = (baudTimes8 % 8); sercom->USART.BAUD.FRAC.BAUD = (baudTimes8 / 8); } +#endif // __SAME53__ / __SAME54__ } -void SERCOM::initFrame(SercomUartCharSize charSize, SercomDataOrder dataOrder, SercomParityMode parityMode, SercomNumberStopBit nbStopBits) + +void SERCOM::initFrame(SercomUartCharSize charSize, SercomDataOrder dataOrder, + SercomParityMode parityMode, SercomNumberStopBit nbStopBits) { - //Setting the CTRLA register +#if defined(__SAME53__) || defined(__SAME54__) + sercom->USART_INT.SERCOM_CTRLA |= + SERCOM_USART_INT_CTRLA_FORM(parityMode == SERCOM_NO_PARITY ? 0 : 1) | + SERCOM_USART_INT_CTRLA_DORD(dataOrder); + sercom->USART_INT.SERCOM_CTRLB |= + SERCOM_USART_INT_CTRLB_CHSIZE(charSize) | + SERCOM_USART_INT_CTRLB_SBMODE(nbStopBits) | + SERCOM_USART_INT_CTRLB_PMODE(parityMode == SERCOM_NO_PARITY ? 0 : parityMode); +#else + // Setting the CTRLA register sercom->USART.CTRLA.reg |= - SERCOM_USART_CTRLA_FORM((parityMode == SERCOM_NO_PARITY ? 0 : 1) ) | - dataOrder << SERCOM_USART_CTRLA_DORD_Pos; - - //Setting the CTRLB register - sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_CHSIZE(charSize) | - nbStopBits << SERCOM_USART_CTRLB_SBMODE_Pos | - (parityMode == SERCOM_NO_PARITY ? 0 : parityMode) << - SERCOM_USART_CTRLB_PMODE_Pos; //If no parity use default value + SERCOM_USART_CTRLA_FORM((parityMode == SERCOM_NO_PARITY ? 0 : 1)) | + (dataOrder << SERCOM_USART_CTRLA_DORD_Pos); + + // Setting the CTRLB register + sercom->USART.CTRLB.reg |= + SERCOM_USART_CTRLB_CHSIZE(charSize) | + (nbStopBits << SERCOM_USART_CTRLB_SBMODE_Pos) | + ((parityMode == SERCOM_NO_PARITY ? 0 : parityMode) << SERCOM_USART_CTRLB_PMODE_Pos); +#endif // __SAME53__ / __SAME54__ } void SERCOM::initPads(SercomUartTXPad txPad, SercomRXPad rxPad) { - //Setting the CTRLA register +#if defined(__SAME53__) || defined(__SAME54__) + sercom->USART_INT.SERCOM_CTRLA |= SERCOM_USART_INT_CTRLA_TXPO(txPad) | + SERCOM_USART_INT_CTRLA_RXPO(rxPad); + sercom->USART_INT.SERCOM_CTRLB |= SERCOM_USART_INT_CTRLB_TXEN_Msk | + SERCOM_USART_INT_CTRLB_RXEN_Msk; +#else + // Setting the CTRLA register sercom->USART.CTRLA.reg |= SERCOM_USART_CTRLA_TXPO(txPad) | SERCOM_USART_CTRLA_RXPO(rxPad); // Enable Transceiver and Receiver - sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN ; + sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN; +#endif // __SAME53__ / __SAME54__ } void SERCOM::resetUART() { - // Start the Software Reset - sercom->USART.CTRLA.bit.SWRST = 1 ; - - while ( sercom->USART.CTRLA.bit.SWRST || sercom->USART.SYNCBUSY.bit.SWRST ) - { - // Wait for both bits Software Reset from CTRLA and SYNCBUSY coming back to 0 - } -} - -void SERCOM::enableUART() -{ - //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); + _txnQueue.clear(); + _uart.currentTxn = nullptr; + _uart.index = 0; + _uart.length = 0; + _uart.active = false; + _uart.returnValue = SercomUartError::SUCCESS; + +#ifdef USE_ZERODMA + _uart.dmaNeedTx = false; + _uart.dmaNeedRx = false; + _uart.dmaTxDone = false; + _uart.dmaRxDone = false; + dmaAbortTx(); + dmaAbortRx(); +#endif // USE_ZERODMA + + resetSERCOM(); } void SERCOM::flushUART() { // Skip checking transmission completion if data register is empty - if(isDataRegisterEmptyUART()) + if (isDataRegisterEmptyUART()) return; // Wait for transmission to complete - while(!sercom->USART.INTFLAG.bit.TXC); +#if defined(__SAME53__) || defined(__SAME54__) + while ((sercom->USART_INT.SERCOM_INTFLAG & SERCOM_USART_INT_INTFLAG_TXC_Msk) == 0) ; +#else + while (!sercom->USART.INTFLAG.bit.TXC) ; +#endif // __SAME53__ / __SAME54__ } void SERCOM::clearStatusUART() { - //Reset (with 0) the STATUS register +#if defined(__SAME53__) || defined(__SAME54__) + sercom->USART_INT.SERCOM_STATUS = SERCOM_USART_INT_STATUS_RESETVALUE; +#else + // Reset (with 0) the STATUS register sercom->USART.STATUS.reg = SERCOM_USART_STATUS_RESETVALUE; +#endif // __SAME53__ / __SAME54__ } bool SERCOM::availableDataUART() { - //RXC : Receive Complete + // RXC: Receive Complete +#if defined(__SAME53__) || defined(__SAME54__) + return (sercom->USART_INT.SERCOM_INTFLAG & SERCOM_USART_INT_INTFLAG_RXC_Msk) != 0; +#else return sercom->USART.INTFLAG.bit.RXC; +#endif // __SAME53__ / __SAME54__ } bool SERCOM::isUARTError() { +#if defined(__SAME53__) || defined(__SAME54__) + return (sercom->USART_INT.SERCOM_INTFLAG & SERCOM_USART_INT_INTFLAG_ERROR_Msk) != 0; +#else return sercom->USART.INTFLAG.bit.ERROR; +#endif // __SAME53__ / __SAME54__ } void SERCOM::acknowledgeUARTError() { +#if defined(__SAME53__) || defined(__SAME54__) + sercom->USART_INT.SERCOM_INTFLAG = SERCOM_USART_INT_INTFLAG_ERROR_Msk; +#else sercom->USART.INTFLAG.bit.ERROR = 1; +#endif // __SAME53__ / __SAME54__ +} + +void SERCOM::enableReceiveCompleteInterruptUART() +{ +#if defined(__SAME53__) || defined(__SAME54__) + sercom->USART_INT.SERCOM_INTENSET = SERCOM_USART_INT_INTENSET_RXC_Msk; +#else + sercom->USART.INTENSET.reg = SERCOM_USART_INTENSET_RXC; +#endif // __SAME53__ / __SAME54__ +} + +void SERCOM::disableReceiveCompleteInterruptUART() +{ +#if defined(__SAME53__) || defined(__SAME54__) + sercom->USART_INT.SERCOM_INTENCLR = SERCOM_USART_INT_INTENCLR_RXC_Msk; +#else + sercom->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_RXC; +#endif // __SAME53__ / __SAME54__ } bool SERCOM::isBufferOverflowErrorUART() { - //BUFOVF : Buffer Overflow + // BUFOVF: Buffer Overflow +#if defined(__SAME53__) || defined(__SAME54__) + return (sercom->USART_INT.SERCOM_STATUS & SERCOM_USART_INT_STATUS_BUFOVF_Msk) != 0; +#else return sercom->USART.STATUS.bit.BUFOVF; +#endif // __SAME53__ / __SAME54__ } bool SERCOM::isFrameErrorUART() { - //FERR : Frame Error + // FERR: Frame Error +#if defined(__SAME53__) || defined(__SAME54__) + return (sercom->USART_INT.SERCOM_STATUS & SERCOM_USART_INT_STATUS_FERR_Msk) != 0; +#else return sercom->USART.STATUS.bit.FERR; +#endif // __SAME53__ / __SAME54__ } void SERCOM::clearFrameErrorUART() { - // clear FERR bit writing 1 status bit + // Clear FERR bit writing 1 status bit +#if defined(__SAME53__) || defined(__SAME54__) + sercom->USART_INT.SERCOM_STATUS = SERCOM_USART_INT_STATUS_FERR_Msk; +#else sercom->USART.STATUS.bit.FERR = 1; +#endif // __SAME53__ / __SAME54__ } bool SERCOM::isParityErrorUART() { - //PERR : Parity Error + // PERR: Parity Error +#if defined(__SAME53__) || defined(__SAME54__) + return (sercom->USART_INT.SERCOM_STATUS & SERCOM_USART_INT_STATUS_PERR_Msk) != 0; +#else return sercom->USART.STATUS.bit.PERR; +#endif // __SAME53__ / __SAME54__ } bool SERCOM::isDataRegisterEmptyUART() { - //DRE : Data Register Empty + // DRE: Data Register Empty +#if defined(__SAME53__) || defined(__SAME54__) + return (sercom->USART_INT.SERCOM_INTFLAG & SERCOM_USART_INT_INTFLAG_DRE_Msk) != 0; +#else return sercom->USART.INTFLAG.bit.DRE; +#endif // __SAME53__ / __SAME54__ } uint8_t SERCOM::readDataUART() { +#if defined(__SAME53__) || defined(__SAME54__) + return (uint8_t)sercom->USART_INT.SERCOM_DATA; +#else return sercom->USART.DATA.bit.DATA; +#endif // __SAME53__ / __SAME54__ } int SERCOM::writeDataUART(uint8_t data) { // Wait for data register to be empty - while(!isDataRegisterEmptyUART()); + while (!isDataRegisterEmptyUART()); - //Put data into DATA register + // Put data into DATA register +#if defined(__SAME53__) || defined(__SAME54__) + sercom->USART_INT.SERCOM_DATA = data; +#else sercom->USART.DATA.reg = (uint16_t)data; +#endif // __SAME53__ / __SAME54__ return 1; } void SERCOM::enableDataRegisterEmptyInterruptUART() { +#if defined(__SAME53__) || defined(__SAME54__) + sercom->USART_INT.SERCOM_INTENSET = SERCOM_USART_INT_INTENSET_DRE_Msk; +#else sercom->USART.INTENSET.reg = SERCOM_USART_INTENSET_DRE; +#endif // __SAME53__ / __SAME54__ } void SERCOM::disableDataRegisterEmptyInterruptUART() { +#if defined(__SAME53__) || defined(__SAME54__) + sercom->USART_INT.SERCOM_INTENCLR = SERCOM_USART_INT_INTENCLR_DRE_Msk; +#else sercom->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_DRE; +#endif // __SAME53__ / __SAME54__ +} + +bool SERCOM::startTransmissionUART(void) +{ + SercomTxn* txn = nullptr; + if (!_txnQueue.peek(txn) || txn == nullptr) + return false; + + _uart.currentTxn = txn; + _uart.index = 0; + _uart.length = txn->length; + _uart.active = true; + _uart.returnValue = SercomUartError::SUCCESS; + +#ifdef USE_ZERODMA + _uart.useDma = _dmaConfigured; +#else + _uart.useDma = false; +#endif // USE_ZERODMA + + if (!_uart.useDma) + { + _uart.active = false; + _uart.currentTxn = nullptr; + _uart.returnValue = SercomUartError::UNKNOWN_ERROR; + return false; + } + +#ifdef USE_ZERODMA +#if defined(__SAME53__) || defined(__SAME54__) + void* dataReg = (void*)&sercom->USART_INT.SERCOM_DATA; +#else + void* dataReg = (void*)&sercom->USART.DATA.reg; +#endif // __SAME53__ / __SAME54__ + _uart.dmaNeedTx = (txn->txPtr != nullptr); + _uart.dmaNeedRx = (txn->rxPtr != nullptr); + _uart.dmaTxDone = !_uart.dmaNeedTx; + _uart.dmaRxDone = !_uart.dmaNeedRx; + + DmaStatus st = DmaStatus::Ok; + if (_uart.dmaNeedTx) + st = dmaStartTx(txn->txPtr, dataReg, txn->length); + else if (_uart.dmaNeedRx) + st = dmaStartRx(txn->rxPtr, dataReg, txn->length); + + if (st != DmaStatus::Ok) { + _uart.active = false; + _uart.currentTxn = nullptr; + _uart.returnValue = SercomUartError::UNKNOWN_ERROR; + return false; + } + return true; +#else + return false; +#endif // USE_ZERODMA +} + +bool SERCOM::enqueueUART(SercomTxn* txn) +{ + if (txn == nullptr) + return false; +#ifdef USE_ZERODMA + if (!_dmaConfigured) + return false; +#endif // USE_ZERODMA + if (_txnQueue.isFull()) + return false; // Queue full; caller must retry at runtime + if (!_txnQueue.store(txn)) + return false; + if (!_uart.active) { + if (!startTransmissionUART()) { + SercomTxn* tmp = nullptr; + _txnQueue.read(tmp); + if (tmp && tmp->onComplete) + tmp->onComplete(tmp->user, static_cast(SercomUartError::UNKNOWN_ERROR)); + return false; + } + } + return true; +} + +void SERCOM::deferStopUART(SercomUartError error) +{ + _uart.returnValue = error; + setPending((uint8_t)getSercomIndex()); +} + +SercomTxn* SERCOM::stopTransmissionUART(void) +{ + return stopTransmissionUART(_uart.returnValue); +} + +SercomTxn* SERCOM::stopTransmissionUART(SercomUartError error) +{ + SercomTxn* txn = nullptr; + if (!_txnQueue.peek(txn) || txn == nullptr) + return nullptr; + + // Call completion callback before deciding to dequeue + if (txn->onComplete) + txn->onComplete(txn->user, static_cast(error)); + + // Check if callback wants to chain another phase + if (txn->chainNext) { + txn->chainNext = false; // reset for next iteration + if (!startTransmissionUART()) { + // Hardware start failed, force dequeue + _txnQueue.read(txn); + _uart.active = false; + _uart.currentTxn = nullptr; + return txn; + } + return txn; + } + + // Normal completion: dequeue and start next transaction + _txnQueue.read(txn); + _uart.active = false; + _uart.currentTxn = nullptr; + + SercomTxn* next = nullptr; + if (_txnQueue.peek(next) && next) + startTransmissionUART(); + + return txn; } /* ========================= @@ -223,156 +496,292 @@ void SERCOM::disableDataRegisterEmptyInterruptUART() */ void SERCOM::initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize charSize, SercomDataOrder dataOrder) { - resetSPI(); initClockNVIC(); + resetSPI(); -#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) - sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE(0x3) | // master mode - SERCOM_SPI_CTRLA_DOPO(mosi) | - SERCOM_SPI_CTRLA_DIPO(miso) | - dataOrder << SERCOM_SPI_CTRLA_DORD_Pos; +#ifdef USE_ZERODMA + int8_t id = getSercomIndex(); + if (id >= 0) { + dmaSetCallbacks(SERCOM::dmaTxCallbackSPI, SERCOM::dmaRxCallbackSPI); + dmaInit(id); + } +#endif // USE_ZERODMA + + registerService(getSercomIndex(), &SERCOM::stopTransmissionSPI); + +#if defined(__SAME53__) || defined(__SAME54__) + sercom->SPIM.SERCOM_CTRLA = SERCOM_SPIM_CTRLA_MODE_SPI_MASTER | + SERCOM_SPIM_CTRLA_DOPO(mosi) | + SERCOM_SPIM_CTRLA_DIPO(miso) | + SERCOM_SPIM_CTRLA_DORD(dataOrder); + sercom->SPIM.SERCOM_CTRLB = SERCOM_SPIM_CTRLB_CHSIZE(charSize) | + SERCOM_SPIM_CTRLB_RXEN_Msk; #else - //Setting the CTRLA register - sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE_SPI_MASTER | + // Setting the CTRLA register + sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE(0x3) | SERCOM_SPI_CTRLA_DOPO(mosi) | SERCOM_SPI_CTRLA_DIPO(miso) | - dataOrder << SERCOM_SPI_CTRLA_DORD_Pos; -#endif - - //Setting the CTRLB register + (dataOrder << SERCOM_SPI_CTRLA_DORD_Pos); sercom->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_CHSIZE(charSize) | - SERCOM_SPI_CTRLB_RXEN; //Active the SPI receiver. + SERCOM_SPI_CTRLB_RXEN; // Active the SPI receiver. +#endif // __SAME53__ / __SAME54__ + waitSyncBusyCtrlB(); +} + +bool SERCOM::startTransmissionSPI(void) +{ + SercomTxn* txn = nullptr; + if (!_txnQueue.peek(txn) || txn == nullptr) + return false; + + _spi.currentTxn = txn; + _spi.index = 0; + _spi.length = txn->length; + _spi.active = true; + +#ifdef USE_ZERODMA + _spi.useDma = _dmaConfigured; + + if (_spi.useDma) { +#if defined(__SAME53__) || defined(__SAME54__) + void* dataReg = (void*)&sercom->SPIM.SERCOM_DATA; +#else + void* dataReg = (void*)&sercom->SPI.DATA.reg; +#endif // __SAME53__ / __SAME54__ + _spi.dmaNeedTx = (txn->txPtr != nullptr); + _spi.dmaNeedRx = (txn->rxPtr != nullptr); + _spi.dmaTxDone = !_spi.dmaNeedTx; + _spi.dmaRxDone = !_spi.dmaNeedRx; + + DmaStatus st = DmaStatus::Ok; + if (_spi.dmaNeedTx && _spi.dmaNeedRx) + st = dmaStartDuplex(txn->txPtr, txn->rxPtr, dataReg, dataReg, txn->length, nullptr); + else if (_spi.dmaNeedTx) + st = dmaStartTx(txn->txPtr, dataReg, txn->length); + else + st = dmaStartDuplex(nullptr, txn->rxPtr, dataReg, dataReg, txn->length, nullptr); + + if (st != DmaStatus::Ok) { + _spi.returnValue = SercomSpiError::UNKNOWN_ERROR; + deferStopSPI(_spi.returnValue); + return false; + } + return true; + } +#else + _spi.useDma = false; +#endif // USE_ZERODMA + +#if defined(__SAME53__) || defined(__SAME54__) + sercom->SPIM.SERCOM_INTENSET = SERCOM_SPIM_INTENSET_DRE_Msk | + SERCOM_SPIM_INTENSET_RXC_Msk | + SERCOM_SPIM_INTENSET_ERROR_Msk; +#else + sercom->SPI.INTENSET.reg = SERCOM_SPI_INTENSET_DRE | + SERCOM_SPI_INTENSET_RXC | + SERCOM_SPI_INTENSET_ERROR; +#endif // __SAME53__ / __SAME54__ + return true; +} + +bool SERCOM::enqueueSPI(SercomTxn* txn) +{ + if (txn == nullptr) + return false; + + if (_txnQueue.isFull()) + return false; // Queue full; caller must retry at runtime + + if (!_txnQueue.store(txn)) + return false; - while( sercom->SPI.SYNCBUSY.bit.CTRLB == 1 ); + if (!_spi.active) + startTransmissionSPI(); + + return true; +} + +void SERCOM::deferStopSPI(SercomSpiError error) +{ + _spi.returnValue = error; + setPending((uint8_t)getSercomIndex()); +} + +SercomTxn* SERCOM::stopTransmissionSPI(void) +{ + return stopTransmissionSPI(_spi.returnValue); +} + +SercomTxn* SERCOM::stopTransmissionSPI(SercomSpiError error) +{ + SercomTxn* txn = nullptr; + if (!_txnQueue.peek(txn) || txn == nullptr) + return nullptr; + + // Call completion callback before deciding to dequeue + if (txn->onComplete) + txn->onComplete(txn->user, static_cast(error)); + + // Check if callback wants to chain another phase + if (txn->chainNext) { + txn->chainNext = false; // reset for next iteration + startTransmissionSPI(); // restart with updated context, same queue slot + return txn; + } + + // Normal completion: dequeue and start next transaction + _txnQueue.read(txn); + _spi.active = false; + _spi.currentTxn = nullptr; + + SercomTxn* next = nullptr; + if (_txnQueue.peek(next) && next) + startTransmissionSPI(); + + return txn; } void SERCOM::initSPIClock(SercomSpiClockMode clockMode, uint32_t baudrate) { - //Extract data from clockMode + // Extract data from clockMode int cpha, cpol; - if((clockMode & (0x1ul)) == 0 ) + if ((clockMode & (0x1ul)) == 0) cpha = 0; else cpha = 1; - if((clockMode & (0x2ul)) == 0) + 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 ); + // Setting the CTRLA register +#if defined(__SAME53__) || defined(__SAME54__) + sercom->SPIM.SERCOM_CTRLA |= SERCOM_SPIM_CTRLA_CPHA(cpha) | + SERCOM_SPIM_CTRLA_CPOL(cpol); + sercom->SPIM.SERCOM_BAUD = SERCOM_SPIM_BAUD_BAUD(calculateBaudrateSynchronous(baudrate)); +#else + sercom->SPI.CTRLA.reg |= (cpha << SERCOM_SPI_CTRLA_CPHA_Pos) | + (cpol << SERCOM_SPI_CTRLA_CPOL_Pos); - //Synchronous arithmetic + // Synchronous arithmetic sercom->SPI.BAUD.reg = calculateBaudrateSynchronous(baudrate); +#endif // __SAME53__ / __SAME54__ } void SERCOM::resetSPI() { - //Setting the Software Reset bit to 1 - sercom->SPI.CTRLA.bit.SWRST = 1; - - //Wait both bits Software Reset from CTRLA and SYNCBUSY are equal to 0 - while(sercom->SPI.CTRLA.bit.SWRST || sercom->SPI.SYNCBUSY.bit.SWRST); -} - -void SERCOM::enableSPI() -{ - //Setting the enable bit to 1 - sercom->SPI.CTRLA.bit.ENABLE = 1; - - while(sercom->SPI.SYNCBUSY.bit.ENABLE) - { - //Waiting then enable bit from SYNCBUSY is equal to 0; - } -} - -void SERCOM::disableSPI() -{ - while(sercom->SPI.SYNCBUSY.bit.ENABLE) - { - //Waiting then enable bit from SYNCBUSY is equal to 0; - } - - //Setting the enable bit to 0 - sercom->SPI.CTRLA.bit.ENABLE = 0; + resetSERCOM(); } void SERCOM::setDataOrderSPI(SercomDataOrder dataOrder) { - //Register enable-protected + // Register enable-protected disableSPI(); +#if defined(__SAME53__) || defined(__SAME54__) + sercom->SPIM.SERCOM_CTRLA = + (sercom->SPIM.SERCOM_CTRLA & ~SERCOM_SPIM_CTRLA_DORD_Msk) | + SERCOM_SPIM_CTRLA_DORD(dataOrder); +#else sercom->SPI.CTRLA.bit.DORD = dataOrder; +#endif // __SAME53__ / __SAME54__ enableSPI(); } SercomDataOrder SERCOM::getDataOrderSPI() { +#if defined(__SAME53__) || defined(__SAME54__) + return (sercom->SPIM.SERCOM_CTRLA & SERCOM_SPIM_CTRLA_DORD_Msk) ? LSB_FIRST : MSB_FIRST; +#else return (sercom->SPI.CTRLA.bit.DORD ? LSB_FIRST : MSB_FIRST); +#endif // __SAME53__ / __SAME54__ } void SERCOM::setBaudrateSPI(uint8_t divider) { disableSPI(); // Register is enable-protected +#if defined(__SAME53__) || defined(__SAME54__) + sercom->SPIM.SERCOM_BAUD = SERCOM_SPIM_BAUD_BAUD(calculateBaudrateSynchronous(freqRef / divider)); +#else sercom->SPI.BAUD.reg = calculateBaudrateSynchronous(freqRef / divider); +#endif // __SAME53__ / __SAME54__ enableSPI(); } void SERCOM::setClockModeSPI(SercomSpiClockMode clockMode) { int cpha, cpol; - if((clockMode & (0x1ul)) == 0) + if ((clockMode & (0x1ul)) == 0) cpha = 0; else cpha = 1; - if((clockMode & (0x2ul)) == 0) + if ((clockMode & (0x2ul)) == 0) cpol = 0; else cpol = 1; - //Register enable-protected + // Register enable-protected disableSPI(); +#if defined(__SAME53__) || defined(__SAME54__) + sercom->SPIM.SERCOM_CTRLA = + (sercom->SPIM.SERCOM_CTRLA & ~(SERCOM_SPIM_CTRLA_CPOL_Msk | SERCOM_SPIM_CTRLA_CPHA_Msk)) | + SERCOM_SPIM_CTRLA_CPOL(cpol) | SERCOM_SPIM_CTRLA_CPHA(cpha); +#else sercom->SPI.CTRLA.bit.CPOL = cpol; sercom->SPI.CTRLA.bit.CPHA = cpha; +#endif // __SAME53__ / __SAME54__ enableSPI(); } uint8_t SERCOM::transferDataSPI(uint8_t data) { +#if defined(__SAME53__) || defined(__SAME54__) + sercom->SPIM.SERCOM_DATA = data; + while ((sercom->SPIM.SERCOM_INTFLAG & SERCOM_SPIM_INTFLAG_RXC_Msk) == 0); + return (uint8_t)sercom->SPIM.SERCOM_DATA; +#else sercom->SPI.DATA.bit.DATA = data; // Writing data into Data register - while(sercom->SPI.INTFLAG.bit.RXC == 0); // Waiting Complete Reception + while (sercom->SPI.INTFLAG.bit.RXC == 0); // Waiting Complete Reception - return sercom->SPI.DATA.bit.DATA; // Reading data + return sercom->SPI.DATA.bit.DATA; // Reading data +#endif // __SAME53__ / __SAME54__ } bool SERCOM::isBufferOverflowErrorSPI() { +#if defined(__SAME53__) || defined(__SAME54__) + return sercom->SPIM.SERCOM_STATUS & SERCOM_SPIM_STATUS_BUFOVF_Msk; +#else return sercom->SPI.STATUS.bit.BUFOVF; +#endif // __SAME53__ / __SAME54__ } bool SERCOM::isDataRegisterEmptySPI() { - //DRE : Data Register Empty + // DRE: Data Register Empty +#if defined(__SAME53__) || defined(__SAME54__) + return sercom->SPIM.SERCOM_INTFLAG & SERCOM_SPIM_INTFLAG_DRE_Msk; +#else return sercom->SPI.INTFLAG.bit.DRE; +#endif // __SAME53__ / __SAME54__ } //bool SERCOM::isTransmitCompleteSPI() //{ -// //TXC : Transmit complete +// // TXC: Transmit complete // return sercom->SPI.INTFLAG.bit.TXC; //} // //bool SERCOM::isReceiveCompleteSPI() //{ -// //RXC : Receive complete +// // RXC: Receive complete // return sercom->SPI.INTFLAG.bit.RXC; //} @@ -391,408 +800,1457 @@ uint8_t SERCOM::calculateBaudrateSynchronous(uint32_t baudrate) */ void SERCOM::resetWIRE() { - //I2CM OR I2CS, no matter SWRST is the same bit. + clearQueueWIRE(); // Drain pending transactions from queue + resetSERCOM(); // SWRST: hardware reset to default state + _wire = WireConfig{}; // Reset software state +} + +void SERCOM::clearQueueWIRE(void) +{ + // Drain all pending transactions from the queue without invoking callbacks + // This is needed for test teardown to ensure no stale transactions carry over + SercomTxn* txn = nullptr; + int drained = 0; + while (_txnQueue.read(txn)) { + drained++; + // Just discard - don't invoke callbacks during reset + } - //Setting the Software bit to 1 - sercom->I2CM.CTRLA.bit.SWRST = 1; + // Ensure wire state is completely clean + _wire.active = false; + _wire.slaveTransactionActive = false; + _wire.currentTxn = nullptr; + _wire.slaveTxn = nullptr; + _wire.txnIndex = 0; + _wire.txnLength = 0; + _wire.returnValue = SercomWireError::SUCCESS; + _wire.retryCount = 0; + _wire.releasePending = false; + _wire.abortPending = false; + _wire.busErrorRecoveryPending = false; + _wire.busErrorRecoveryStartedUs = 0; + _wire.busErrorRecoveryDeadlineActive = false; + _wire.busErrorRecoveryDeadlineStartedUs = 0; + _wire.busErrorRecoveryArbitrationLost = false; + _wire.busErrorRecoveryCommandReady = false; +#ifdef USE_ZERODMA + _wireRxSuspendPending = false; +#endif - //Wait both bits Software Reset from CTRLA and SYNCBUSY are equal to 0 - while(sercom->I2CM.CTRLA.bit.SWRST || sercom->I2CM.SYNCBUSY.bit.SWRST); + // Clear deferred callbacks (from slave/receive operations) + _wireCallbackUser = nullptr; + _wireReceiveCb = nullptr; + _wireRequestCb = nullptr; + _wireReceivePending = false; + _wireRequestPending = false; } -void SERCOM::enableWIRE() +void SERCOM::initWIRE(void) { - // I2C Master and Slave modes share the ENABLE bit function. + if (_wire.inited) // If already initialized, return + return; - // Enable the I2C master mode - sercom->I2CM.CTRLA.bit.ENABLE = 1 ; + uint8_t idx = getSercomIndex(); + initClockNVIC(); + registerService(idx, static_cast(&SERCOM::stopTransmissionWIRE)); - while ( sercom->I2CM.SYNCBUSY.bit.ENABLE != 0 ) - { - // Waiting the enable bit from SYNCBUSY is equal to 0; - } +#ifdef USE_ZERODMA + dmaSetCallbacks(SERCOM::dmaTxCallbackWIRE, SERCOM::dmaRxCallbackWIRE, + SERCOM::dmaErrorCallbackWIRE); + if (idx >= 0) + dmaInit(idx); + if (_dmaRx) + _dmaRx->setCallback(SERCOM::dmaRxSuspendCallbackWIRE, + DMA_CALLBACK_CHANNEL_SUSPEND); +#endif // USE_ZERODMA - // Setting bus idle mode - sercom->I2CM.STATUS.bit.BUSSTATE = 1 ; + _wire.inited = true; // Mark as initialized last +} - while ( sercom->I2CM.SYNCBUSY.bit.SYSOP != 0 ) - { - // Wait the SYSOP bit from SYNCBUSY coming back to 0 - } +void SERCOM::initSlaveWIRE( uint8_t ucAddress, bool enableGeneralCall, uint8_t speed ) +{ + initSlaveWIRE( ucAddress & 0x7Fu, enableGeneralCall, speed, false ); } -void SERCOM::disableWIRE() +void SERCOM::initSlaveWIRE( uint16_t ucAddress, bool enableGeneralCall, uint8_t speed, bool enable10Bit ) { - // I2C Master and Slave modes share the ENABLE bit function. + initWIRE(); + + uint16_t mask = enable10Bit ? 0x03FFul : 0x007Ful; + uint32_t generalCall = 0; + uint32_t tenBit = 0; +#if defined(__SAME53__) || defined(__SAME54__) + generalCall = enableGeneralCall ? SERCOM_I2CS_ADDR_GENCEN(1) : 0u; + tenBit = enable10Bit ? SERCOM_I2CS_ADDR_TENBITEN(1) : 0u; +#else + generalCall = enableGeneralCall ? SERCOM_I2CS_ADDR_GENCEN : 0u; + tenBit = enable10Bit ? SERCOM_I2CS_ADDR_TENBITEN : 0u; +#endif // __SAME53__ / __SAME54__ + + _wire.slaveSpeed = speed; + _wire.addr = SERCOM_I2CS_ADDR_ADDR(ucAddress & mask) | + SERCOM_I2CS_ADDR_ADDRMASK(0x00ul) | + tenBit | + generalCall; + _wire.slaveConfigured = true; + setSlaveWIRE(); +} - // Enable the I2C master mode - sercom->I2CM.CTRLA.bit.ENABLE = 0 ; +void SERCOM::registerReceiveWIRE(WireReceiveCallback callback, void *user) { + _wireReceiveCb = callback; + _wireCallbackUser = user; +} - while ( sercom->I2CM.SYNCBUSY.bit.ENABLE != 0 ) - { - // Waiting the enable bit from SYNCBUSY is equal to 0; - } +void SERCOM::registerRequestWIRE(WireRequestCallback callback, void *user) { + _wireRequestCb = callback; + _wireCallbackUser = user; } -void SERCOM::initSlaveWIRE( uint8_t ucAddress, bool enableGeneralCall ) +void SERCOM::initMasterWIRE( uint32_t baudrate ) { - // Initialize the peripheral clock and interruption - initClockNVIC() ; - resetWIRE() ; + initWIRE(); - // Set slave mode - sercom->I2CS.CTRLA.bit.MODE = I2C_SLAVE_OPERATION; + setBaudrateWIRE(baudrate); + _wire.slaveConfigured = false; + setMasterWIRE(); +} - sercom->I2CS.ADDR.reg = SERCOM_I2CS_ADDR_ADDR( ucAddress & 0x7Ful ) | // 0x7F, select only 7 bits - SERCOM_I2CS_ADDR_ADDRMASK( 0x00ul ); // 0x00, only match exact address - if (enableGeneralCall) { - sercom->I2CS.ADDR.reg |= SERCOM_I2CS_ADDR_GENCEN; // enable general call (address 0x00) - } +void SERCOM::deferReceiveWIRE(void) { + _wireReceivePending = true; + _wire.returnValue = SercomWireError::SUCCESS; +#ifdef USE_ZERODMA + // The RX suspend callback publishes the completed byte count and owns the + // retirement dispatch. Do not let PendSV abort the channel first. + if (_dmaRxActive) + return; +#endif // USE_ZERODMA + setPending((uint8_t)getSercomIndex()); +} - // Set the interrupt register - sercom->I2CS.INTENSET.reg = SERCOM_I2CS_INTENSET_PREC | // Stop - SERCOM_I2CS_INTENSET_AMATCH | // Address Match - SERCOM_I2CS_INTENSET_DRDY ; // Data Ready +void SERCOM::deferRequestWIRE(void) { + _wireRequestPending = true; + _wire.returnValue = SercomWireError::SUCCESS; +#ifdef USE_ZERODMA + // A repeated START may request a slave response while the preceding RX DMA + // descriptor is still being suspended. Its suspend callback owns the next + // PendSV dispatch so the receive length is published before onRequest can + // replace the active transaction. + if (_wireRxSuspendPending || _dmaRxActive) + return; +#endif // USE_ZERODMA + setPending((uint8_t)getSercomIndex()); +} - while ( sercom->I2CM.SYNCBUSY.bit.SYSOP != 0 ) - { - // Wait the SYSOP bit from SYNCBUSY to come back to 0 +void SERCOM::deferReceiveCompleteWIRE(void) { +#ifdef USE_ZERODMA + // BTCNT for the active channel lives in the DMAC's internal descriptor. + // Suspend first so hardware commits that counter to WRBADDR; the suspend + // callback snapshots it, aborts the channel, and defers normal retirement. + if (_dmaRxActive) { + if (!_wireRxSuspendPending && _dmaRx) { + _wireRxSuspendPending = true; + _dmaRx->suspend(); + } + return; } +#endif // USE_ZERODMA + deferStopWIRE(SercomWireError::SUCCESS); } -void SERCOM::initMasterWIRE( uint32_t baudrate ) -{ - // Initialize the peripheral clock and interruption - initClockNVIC() ; - - resetWIRE() ; - - // Set master mode and enable SCL Clock Stretch mode (stretch after ACK bit) - sercom->I2CM.CTRLA.reg = SERCOM_I2CM_CTRLA_MODE( I2C_MASTER_OPERATION )/* | - SERCOM_I2CM_CTRLA_SCLSM*/ ; +#ifdef USE_ZERODMA +void SERCOM::dmaRxSuspendCallbackWIRE(Adafruit_ZeroDMA *dma) { + SERCOM *inst = findDmaOwner(dma, false); + if (!inst || !inst->_wireRxSuspendPending) + return; - // Enable Smart mode and Quick Command - //sercom->I2CM.CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN /*| SERCOM_I2CM_CTRLB_QCEN*/ ; + inst->_wireRxSuspendPending = false; + size_t transferred = 0; + uint16_t remaining = 0; + const uint8_t channel = dma->getChannel(); + if (channel < DMAC_CH_NUM) { +#if defined(__SAME53__) || defined(__SAME54__) + const DmacDescriptor *writeback = + reinterpret_cast(DMAC_REGS->DMAC_WRBADDR); + remaining = writeback[channel].DMAC_BTCNT; +#else + const DmacDescriptor *writeback = + reinterpret_cast(DMAC->WRBADDR.reg); + remaining = writeback[channel].BTCNT.reg; +#endif // __SAME53__ / __SAME54__ + if (inst->_wire.dmaBlockLength >= remaining) + transferred = inst->_wire.dmaBlockLength - remaining; + } + inst->_wire.txnIndex += transferred; + inst->dmaAbortRx(); + inst->deferStopWIRE(SercomWireError::SUCCESS); +} +#endif // USE_ZERODMA + +SercomTxn *SERCOM::retireSlaveTransactionWIRE(bool reserveForFollowup) { + SercomTxn *txn = _wire.currentTxn; + _wire.retryCount = 0; + _wire.active = reserveForFollowup; + _wire.slaveTransactionActive = false; + _wire.currentTxn = nullptr; + return txn; +} +void SERCOM::setMasterWIRE(void) +{ + // Errata: do not enable QCEN when SCLSM=1 (bus error). Hs-mode requires SCLSM=1, + // so master Hs-mode must be DMA-only and STOP-only (no repeated starts). + disableWIRE(); + bool sclsm = (_wire.masterSpeed == 0x2); +#if defined(__SAME53__) || defined(__SAME54__) + sercom->I2CM.SERCOM_CTRLA = _wire.ctrla | + SERCOM_I2CM_CTRLA_MODE(I2C_MASTER_OPERATION) | + SERCOM_I2CM_CTRLA_SPEED(_wire.masterSpeed) | + (sclsm ? SERCOM_I2CM_CTRLA_SCLSM(1) : 0); + sercom->I2CM.SERCOM_CTRLB = _wire.ctrlb; + sercom->I2CM.SERCOM_BAUD = _wire.baud; + enableWIRE(); + sercom->I2CS.SERCOM_INTENCLR = SERCOM_I2CS_INTENCLR_ERROR_Msk | + SERCOM_I2CS_INTENCLR_AMATCH_Msk | + SERCOM_I2CS_INTENCLR_DRDY_Msk | + SERCOM_I2CS_INTENCLR_PREC_Msk; +#else + sercom->I2CM.CTRLA.reg = _wire.ctrla | + SERCOM_I2CM_CTRLA_MODE(I2C_MASTER_OPERATION) | + SERCOM_I2CM_CTRLA_SPEED(_wire.masterSpeed) | + (sclsm ? SERCOM_I2CM_CTRLA_SCLSM : 0 ); + sercom->I2CM.CTRLB.reg = _wire.ctrlb; + sercom->I2CM.BAUD.reg = _wire.baud; + enableWIRE(); + // Disable slave interrupts. + // Master interrupts are set in startTransmissionWIRE() when the transaction is enqueued, + // so we don't want to enable them here. + sercom->I2CS.INTENCLR.reg = SERCOM_I2CS_INTENSET_ERROR | + SERCOM_I2CS_INTENSET_AMATCH | + SERCOM_I2CS_INTENSET_DRDY | + SERCOM_I2CS_INTENSET_PREC; +#endif // __SAME53__ / __SAME54__ +} - // Enable all interrupts - // sercom->I2CM.INTENSET.reg = SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB | SERCOM_I2CM_INTENSET_ERROR ; +void SERCOM::setSlaveWIRE(void) +{ + disableWIRE(); + bool sclsm = (_wire.slaveSpeed == 0x2); +#if defined(__SAME53__) || defined(__SAME54__) + uint32_t slaveCtrlb = _wire.ctrlb; + if (slaveCtrlb & SERCOM_I2CS_CTRLB_SMEN_Msk) + slaveCtrlb &= ~SERCOM_I2CS_CTRLB_AACKEN_Msk; + sercom->I2CS.SERCOM_CTRLA = _wire.ctrla | + SERCOM_I2CS_CTRLA_MODE(I2C_SLAVE_OPERATION) | + SERCOM_I2CS_CTRLA_SPEED(_wire.slaveSpeed) | + (sclsm ? SERCOM_I2CS_CTRLA_SCLSM(1) : 0); + sercom->I2CS.SERCOM_CTRLB = slaveCtrlb; + sercom->I2CS.SERCOM_ADDR = _wire.addr; + enableWIRE(); + sercom->I2CS.SERCOM_INTENSET = + SERCOM_I2CS_INTENSET_ERROR_Msk | SERCOM_I2CS_INTENSET_AMATCH_Msk; +#else + uint32_t slaveCtrlb = _wire.ctrlb; + if (slaveCtrlb & SERCOM_I2CS_CTRLB_SMEN) + slaveCtrlb &= ~SERCOM_I2CS_CTRLB_AACKEN; + sercom->I2CS.CTRLA.reg = SERCOM_I2CS_CTRLA_MODE(I2C_SLAVE_OPERATION) | + SERCOM_I2CS_CTRLA_SPEED(_wire.slaveSpeed) | + (sclsm ? SERCOM_I2CS_CTRLA_SCLSM : 0 ); + sercom->I2CS.CTRLB.reg = slaveCtrlb; + sercom->I2CS.ADDR.reg = _wire.addr; + enableWIRE(); + // ERROR and AMATCH remain armed while the slave is idle. DRDY and PREC are + // owned by an active transaction and are enabled in startTransmissionWIRE(). + sercom->I2CS.INTENSET.reg = + SERCOM_I2CS_INTENSET_ERROR | SERCOM_I2CS_INTENSET_AMATCH; +#endif // __SAME53__ / __SAME54__ +} - // Determine speed mode based on requested baudrate +void SERCOM::setBaudrateWIRE(uint32_t baudrate) +{ +// Determine speed mode based on requested baudrate const uint32_t topSpeeds[3] = {400000, 1000000, 3400000}; // {(sm/fm), (fm+), (hs)} uint8_t speedBit; - uint8_t clockStretchMode; // See: 28.6.2.4.6 (SERCOM I2C Highspeed mode) - if (baudrate <= topSpeeds[0]) { + if (baudrate <= topSpeeds[0]) speedBit = 0; // Standard/Fast mode up to 400 khz - clockStretchMode = 0; - } else if (baudrate <= topSpeeds[1]) { + else if (baudrate <= topSpeeds[1]) speedBit = 1; // Fast mode+ up to 1 Mhz - clockStretchMode = 0; - } else { - // High speed up to 3.4 Mhz - speedBit = 2; - clockStretchMode = 1; - } + else + speedBit = 2; // High speed up to 3.4 Mhz - sercom->I2CM.CTRLA.bit.SPEED = speedBit; - sercom->I2CM.CTRLA.bit.SCLSM = clockStretchMode; + _wire.masterSpeed = speedBit; - uint32_t minBaudrate = freqRef / 512; // BAUD = 255: SAMD51(@100MHz) ~195kHz, SAMD21 ~94kHz + uint32_t fREF = getSercomFreqRef(); + uint32_t minBaudrate = fREF / 512; // BAUD = 255: SAMD51(@100MHz) ~195kHz, SAMD21 ~94kHz uint32_t maxBaudrate = topSpeeds[speedBit]; baudrate = max(minBaudrate, min(baudrate, maxBaudrate)); if (speedBit == 0x2) - sercom->I2CM.BAUD.bit.HSBAUD = freqRef / (2 * baudrate) - 1; + _wire.baud = SERCOM_I2CM_BAUD_HSBAUD(fREF / (2 * baudrate) - 1); else - sercom->I2CM.BAUD.bit.BAUD = freqRef / (2 * baudrate) - 5 - - (freqRef/1000000ul * WIRE_RISE_TIME_NANOSECONDS) / 2000; + _wire.baud = SERCOM_I2CM_BAUD_BAUD(fREF / (2 * baudrate) - 5 - + (fREF/1000000ul * WIRE_RISE_TIME_NANOSECONDS) / 2000); + + if (isMasterWIRE()) + setMasterWIRE(); } -void SERCOM::prepareNackBitWIRE( void ) + +SercomTxn* SERCOM::startTransmissionWIRE( void ) { - if(isMasterWIRE()) { - // Send a NACK - sercom->I2CM.CTRLB.bit.ACKACT = 1; - } else { - sercom->I2CS.CTRLB.bit.ACKACT = 1; + // Writing ADDR.ADDR drives different behavior based on BUSSTATE: + // UNKNOWN: MB and BUSERR assert and the transfer aborts. + // BUSY: The master waits until the bus is IDLE. + // IDLE: A START is generated, the address is sent, and on ACK the master + // holds SCL low with CLKHOLD set and MB asserted. OWNER: A repeated START is + // generated; if the prior transaction was a read, the ACK/NACK for the read + // is sent before the repeated START. The repeated START ADDR write must occur + // while MB or SB is set. Writing ADDR also clears BUSERR, ARBLOST, MB, and + // SB. + + if (isSlaveWIRE()) { + SercomTxn *txn = _wire.currentTxn; + if (txn == nullptr || txn->length == 0) + return nullptr; + const bool slaveTransmit = (txn->config & I2C_CFG_READ) != 0; + const auto clearAmatch = [this]() { +#if defined(__SAME53__) || defined(__SAME54__) + clearINTFLAG(SERCOM_I2CS_INTFLAG_AMATCH_Msk); +#else + clearINTFLAG(SERCOM_I2CS_INTFLAG_AMATCH); +#endif // __SAME53__ / __SAME54__ + }; + +#ifdef USE_ZERODMA + // Mirror the master engine selection: eligible transactions use DMA; + // larger transactions remain on the interrupt-driven DATA path. + if (isDmaWIRE()) { + if (!_dmaConfigured) + dmaInit(getSercomIndex()); + if (!_dmaConfigured || !_dmaTx || !_dmaRx) + return nullptr; + + // AMATCH holds SCL low while software prepares the transfer. Arm the + // DATA-triggered DMA channel before releasing AMATCH so the first DRDY + // request cannot arrive before DMAC is ready. + const bool started = slaveTransmit ? sendDataWIRE() : readDataWIRE(); + if (!started) + return nullptr; +#if defined(__SAME53__) || defined(__SAME54__) + enableInterrupts(SERCOM_I2CS_INTENSET_DRDY_Msk | + SERCOM_I2CS_INTENSET_PREC_Msk); +#else + enableInterrupts(SERCOM_I2CS_INTENSET_DRDY | SERCOM_I2CS_INTENSET_PREC); +#endif // __SAME53__ / __SAME54__ + clearAmatch(); + } else { +#if defined(__SAME53__) || defined(__SAME54__) + enableInterrupts(SERCOM_I2CS_INTENSET_DRDY_Msk | + SERCOM_I2CS_INTENSET_PREC_Msk); +#else + enableInterrupts(SERCOM_I2CS_INTENSET_DRDY | SERCOM_I2CS_INTENSET_PREC); +#endif // __SAME53__ / __SAME54__ + clearAmatch(); + } +#else + // The no-DMA build advances this transaction from slave DRDY interrupts. + setDmaWIRE(false); +#if defined(__SAME53__) || defined(__SAME54__) + enableInterrupts(SERCOM_I2CS_INTENSET_DRDY_Msk | + SERCOM_I2CS_INTENSET_PREC_Msk); +#else + enableInterrupts(SERCOM_I2CS_INTENSET_DRDY | SERCOM_I2CS_INTENSET_PREC); +#endif // __SAME53__ / __SAME54__ + clearAmatch(); +#endif // USE_ZERODMA +#if defined(__SAME53__) || defined(__SAME54__) + enableInterrupts(SERCOM_I2CS_INTENSET_AMATCH_Msk); +#else + enableInterrupts(SERCOM_I2CS_INTENSET_AMATCH); +#endif // __SAME53__ / __SAME54__ + return txn; } -} -void SERCOM::prepareAckBitWIRE( void ) -{ - if(isMasterWIRE()) { - // Send an ACK - sercom->I2CM.CTRLB.bit.ACKACT = 0; - } else { - sercom->I2CS.CTRLB.bit.ACKACT = 0; + if (isBusUnknownWIRE()) { + stopTransmissionWIRE(SercomWireError::BUS_STATE_UNKNOWN); + return nullptr; } -} -void SERCOM::prepareCommandBitsWire(uint8_t cmd) -{ - if(isMasterWIRE()) { - sercom->I2CM.CTRLB.bit.CMD = cmd; + SercomTxn* txn = nullptr; - while(sercom->I2CM.SYNCBUSY.bit.SYSOP) - { - // Waiting for synchronization - } - } else { - sercom->I2CS.CTRLB.bit.CMD = cmd; + if (!_txnQueue.peek(txn)) + return nullptr; + + if (txn != _wire.currentTxn) { + _wire.retryCount = 0; + _wire.busErrorRecoveryDeadlineActive = false; } -} -bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag) -{ - // 7-bits address + 1-bits R/W - address = (address << 0x1ul) | flag; + _wire.currentTxn = txn; + _wire.txnIndex = 0; + _wire.txnLength = txn->length; - // If another master owns the bus or the last bus owner has not properly - // sent a stop, return failure early. This will prevent some misbehaved - // devices from deadlocking here at the cost of the caller being responsible - // for retrying the failed transmission. See SercomWireBusState for the - // possible bus states. - if(!isBusOwnerWIRE()) - { - if( isBusBusyWIRE() || (isArbLostWIRE() && !isBusIdleWIRE()) || isBusUnknownWIRE() ) - { - return false; + setDmaWIRE(false); // Reset DMA mode - let code below decide if DMA is used + const bool read = (txn->config & I2C_CFG_READ) != 0; + uint16_t addr = (txn->config & I2C_CFG_10BIT) ? I2C_ADDR(txn->address) : I2C_ADDR7(txn->address); + addr = (uint16_t)((addr << 1) | (read ? 1u : 0u)); + + if (!isBusOwnerWIRE()) { + if (isBusUnknownWIRE()) { + stopTransmissionWIRE(SercomWireError::BUS_STATE_UNKNOWN); + return nullptr; } } - // Send start and address - sercom->I2CM.INTFLAG.bit.ERROR = 1; - sercom->I2CM.ADDR.reg = SERCOM_I2CM_ADDR_ADDR(address) | - ((sercom->I2CM.CTRLA.bit.SPEED == 0x2) ? SERCOM_I2CM_ADDR_HS : 0); + bool hsMode = (_wire.masterSpeed == 0x2); +#if defined(__SAME53__) || defined(__SAME54__) + bool sclsm = (sercom->I2CM.SERCOM_CTRLA & SERCOM_I2CM_CTRLA_SCLSM_Msk) != 0; + uint32_t addrReg = SERCOM_I2CM_ADDR_ADDR(addr) | + ((txn->config & I2C_CFG_10BIT) ? SERCOM_I2CM_ADDR_TENBITEN_Msk : 0) | + (hsMode ? SERCOM_I2CM_ADDR_HS(1) : 0); +#else + bool sclsm = sercom->I2CM.CTRLA.bit.SCLSM; + uint32_t addrReg = SERCOM_I2CM_ADDR_ADDR(addr) | + ((txn->config & I2C_CFG_10BIT) ? SERCOM_I2CM_ADDR_TENBITEN : 0) | + (hsMode ? SERCOM_I2CM_ADDR_HS : 0); +#endif // __SAME53__ / __SAME54__ + + if (hsMode || sclsm) { +#ifndef USE_ZERODMA + stopTransmissionWIRE(SercomWireError::OTHER); + return nullptr; +#endif // !USE_ZERODMA + if (txn->length > 255) { + stopTransmissionWIRE(SercomWireError::DATA_TOO_LONG); + return nullptr; + } - // Address Transmitted - if ( flag == WIRE_WRITE_FLAG ) // Write mode - { - while( !sercom->I2CM.INTFLAG.bit.MB ) { - // Wait transmission complete - - // If certain errors occur, the MB bit may never be set (RFTM: SAMD21 sec:28.10.6; SAMD51 sec:36.10.7). - // The data transfer errors that can occur (including BUSERR) are all - // rolled up into INTFLAG.bit.ERROR from STATUS.reg - if (sercom->I2CM.INTFLAG.bit.ERROR) { - return false; - } + if ( +#if defined(__SAME53__) || defined(__SAME54__) + sercom->I2CM.SERCOM_CTRLB & SERCOM_I2CM_CTRLB_QCEN_Msk +#else + sercom->I2CM.CTRLB.bit.QCEN +#endif // __SAME53__ / __SAME54__ + ) { + stopTransmissionWIRE(SercomWireError::OTHER); + return nullptr; } + + txn->config |= I2C_CFG_STOP; + setDmaWIRE(true); + } +#ifdef USE_ZERODMA + else { + setDmaWIRE(txn->length > 0 && txn->length < 256 && + (txn->config & I2C_CFG_STOP) && + !(txn->config & I2C_CFG_NODMA)); } - else // Read mode + + if (isDmaWIRE()) { - while( !sercom->I2CM.INTFLAG.bit.SB ) { - // Wait transmission complete - - // If the slave NACKS the address, the MB bit will be set. - // A variety of errors in the STATUS register can set the ERROR bit in the INTFLAG register - // In that case, send a stop condition and return false. - if (sercom->I2CM.INTFLAG.bit.MB || sercom->I2CM.INTFLAG.bit.ERROR) { - sercom->I2CM.CTRLB.bit.CMD = 3; // Stop condition - return false; - } + if (!_dmaConfigured) + dmaInit(getSercomIndex()); + + if (!_dmaConfigured || !_dmaTx || !_dmaRx) { + stopTransmissionWIRE(SercomWireError::OTHER); + return nullptr; } - // Clean the 'Slave on Bus' flag, for further usage. - //sercom->I2CM.INTFLAG.bit.SB = 0x1ul; +#if defined(__SAME53__) || defined(__SAME54__) + addrReg |= SERCOM_I2CM_ADDR_LENEN_Msk | SERCOM_I2CM_ADDR_LEN((uint8_t)txn->length); +#else + addrReg |= SERCOM_I2CM_ADDR_LENEN | SERCOM_I2CM_ADDR_LEN((uint8_t)txn->length); +#endif // __SAME53__ / __SAME54__ } +#endif // USE_ZERODMA + + // Send address (non-blocking; ISR handles ERROR/MB/SB) + _wire.active = true; +#if defined(__SAME53__) || defined(__SAME54__) + sercom->I2CM.SERCOM_INTENSET = SERCOM_I2CM_INTENSET_ERROR_Msk | + SERCOM_I2CM_INTENSET_SB_Msk | + SERCOM_I2CM_INTENSET_MB_Msk; + sercom->I2CM.SERCOM_ADDR = addrReg; +#else + sercom->I2CM.INTENSET.reg = SERCOM_I2CM_INTENSET_ERROR | SERCOM_I2CM_INTENSET_SB | SERCOM_I2CM_INTENSET_MB; + sercom->I2CM.ADDR.reg = addrReg; // ADDR is write synchronized so just wait for the MB/SB to know when synced +#endif // __SAME53__ / __SAME54__ + return txn; +} - //ACK received (0: ACK, 1: NACK) - if(sercom->I2CM.STATUS.bit.RXNACK) - { +bool SERCOM::enqueueWIRE(SercomTxn* txn) +{ + if (txn == nullptr) + return false; + + + if (_txnQueue.isFull()) + return false; // Queue full; caller must retry at runtime + + if (!_txnQueue.store(txn)) return false; + + if (isSlaveWIRE() && _wire.currentTxn == _wire.slaveTxn && + !_wire.slaveTransactionActive) { + _wire.active = false; + _wire.currentTxn = nullptr; + setMasterWIRE(); + return startTransmissionWIRE() != nullptr; } - else - { - return true; + + if (!_wire.active) { + // dI2C uses a single SERCOM in both slave and master roles. A queued + // master operation is the role-transition point; callers must not + // tear down and re-begin Wire around every transaction. + if (!isMasterWIRE()) + setMasterWIRE(); + + return startTransmissionWIRE() != nullptr; } + + return true; } -bool SERCOM::sendDataMasterWIRE(uint8_t data) +bool SERCOM::startNextQueuedWIRE(void) { + if (_wire.active || _wire.currentTxn != nullptr) + return false; + + SercomTxn *next = nullptr; + if (!_txnQueue.peek(next)) + return false; + + if (!isMasterWIRE()) + setMasterWIRE(); + startTransmissionWIRE(); + return true; +} + +bool SERCOM::abortWIRE(SercomWireError error) { + if (!_wire.active || _wire.currentTxn == nullptr) + return false; + + _wire.abortPending = true; + _wire.abortError = error; + setPending((uint8_t)getSercomIndex()); + return true; +} + +bool SERCOM::serviceAbortWIRE(void) { + if (!_wire.abortPending) + return false; + +#ifdef USE_ZERODMA + dmaAbortTx(); + dmaAbortRx(); + // Reject a completion callback already pending for the aborted phase. + setDmaWIRE(false); +#endif // USE_ZERODMA + + bool commandReady = false; + if (isMasterWIRE()) { +#if defined(__SAME53__) || defined(__SAME54__) + const uint32_t flags = sercom->I2CM.SERCOM_INTFLAG; + commandReady = + (flags & (SERCOM_I2CM_INTFLAG_MB_Msk | SERCOM_I2CM_INTFLAG_SB_Msk)) != + 0u; +#else + const uint8_t flags = sercom->I2CM.INTFLAG.reg; + commandReady = + (flags & (SERCOM_I2CM_INTFLAG_MB | SERCOM_I2CM_INTFLAG_SB)) != 0u; +#endif // __SAME53__ / __SAME54__ + } + + const bool busOwner = isBusOwnerWIRE(); + if (busOwner && commandReady) + prepareCommandBitsWIRE(WIRE_MASTER_ACT_STOP); + else if (busOwner) { + // A timed-out owner with no MB/SB flag has no legal command point. Reapply + // the cached master configuration to release the wedged transfer before + // publishing completion. This remains inside the SERCOM event chain. + setMasterWIRE(); + _wire.releasePending = false; + } + + const SercomWireError error = _wire.abortError; + _wire.abortPending = false; + + if (isMasterWIRE()) { + +#if defined(__SAME53__) || defined(__SAME54__) + sercom->I2CM.SERCOM_INTENCLR = SERCOM_I2CM_INTENCLR_ERROR_Msk | + SERCOM_I2CM_INTENCLR_MB_Msk | + SERCOM_I2CM_INTENCLR_SB_Msk; +#else + sercom->I2CM.INTENCLR.reg = SERCOM_I2CM_INTENCLR_ERROR | + SERCOM_I2CM_INTENCLR_MB | + SERCOM_I2CM_INTENCLR_SB; +#endif // __SAME53__ / __SAME54__ + } + + deferStopWIRE(error); + return true; +} + +void SERCOM::deferBusErrorRecoveryWIRE(bool arbitrationLost, + bool commandReady) { +#ifdef USE_ZERODMA + dmaAbortTx(); + dmaAbortRx(); + setDmaWIRE(false); +#endif + _wire.busErrorRecoveryPending = true; + _wire.busErrorRecoveryStartedUs = micros(); + if (!_wire.busErrorRecoveryDeadlineActive) { + _wire.busErrorRecoveryDeadlineActive = true; + _wire.busErrorRecoveryDeadlineStartedUs = _wire.busErrorRecoveryStartedUs; + } + _wire.busErrorRecoveryArbitrationLost = arbitrationLost; + _wire.busErrorRecoveryCommandReady = commandReady; + setPending((uint8_t)getSercomIndex()); +} + +SercomTxn *SERCOM::serviceBusErrorRecoveryWIRE(void) { + if (!_wire.busErrorRecoveryPending) + return _wire.currentTxn; + + if (_wire.abortPending) { + _wire.busErrorRecoveryPending = false; + return serviceAbortWIRE() ? _wire.currentTxn : nullptr; + } + + SercomTxn *txn = _wire.currentTxn; + if (!txn) { + _wire.busErrorRecoveryPending = false; + return nullptr; + } + + if (simio::wire::busErrorDeadlineExpired( + _wire.busErrorRecoveryDeadlineStartedUs, micros(), + _wire.busErrorRecoveryDeadlineActive)) { + _wire.busErrorRecoveryPending = false; + _wire.busErrorRecoveryDeadlineActive = false; + return stopTransmissionWIRE(SercomWireError::BUS_ERROR); + } + + simio::wire::BusState busState = simio::wire::BusState::Unknown; + if (isBusIdleWIRE()) + busState = simio::wire::BusState::Idle; + else if (isBusOwnerWIRE()) + busState = simio::wire::BusState::Owner; + else if (isBusBusyWIRE()) + busState = simio::wire::BusState::Busy; + + const auto action = simio::wire::decideBusErrorAction( + {true, busState, _wire.busErrorRecoveryArbitrationLost, + _wire.busErrorRecoveryCommandReady, false, true, true}); + if (action == simio::wire::BusErrorAction::RestartQueueHead) { + _wire.busErrorRecoveryPending = false; + return startTransmissionWIRE(); + } + + if (action == simio::wire::BusErrorAction::EstablishIdle) { +#if defined(__SAME53__) || defined(__SAME54__) + sercom->I2CM.SERCOM_STATUS = + (sercom->I2CM.SERCOM_STATUS & ~SERCOM_I2CM_STATUS_BUSSTATE_Msk) | + SERCOM_I2CM_STATUS_BUSSTATE(WIRE_IDLE_STATE); +#else + sercom->I2CM.STATUS.bit.BUSSTATE = WIRE_IDLE_STATE; +#endif // __SAME53__ / __SAME54__ + waitSyncBusySysOp(); + _wire.busErrorRecoveryPending = false; + return startTransmissionWIRE(); + } + + constexpr uint32_t kBusErrorRecoveryTimeoutUs = 100u; + const bool timedOut = + static_cast(micros() - _wire.busErrorRecoveryStartedUs) >= + kBusErrorRecoveryTimeoutUs; + if (simio::wire::decideBusErrorWaitAction(busState, timedOut) == + simio::wire::BusErrorAction::WaitForBusState) { + setPending((uint8_t)getSercomIndex()); + return txn; + } + + resetSERCOM(); + setMasterWIRE(); + _wire.busErrorRecoveryPending = false; + return startTransmissionWIRE(); +} + +SercomTxn* SERCOM::stopTransmissionWIRE( void ) { - //Send data - sercom->I2CM.INTFLAG.bit.ERROR = 1; - sercom->I2CM.DATA.bit.DATA = data; + return stopTransmissionWIRE( _wire.returnValue ); +} - //Wait transmission successful - while(!sercom->I2CM.INTFLAG.bit.MB) { - // If a data transfer error occurs, the MB bit may never be set. - // Check the error bit and bail if it's set. - // The data transfer errors that can occur (including BUSERR) are all - // rolled up into INTFLAG.bit.ERROR from STATUS.reg - if (sercom->I2CM.INTFLAG.bit.ERROR) { - return false; +SercomTxn* SERCOM::stopTransmissionWIRE( SercomWireError error ) +{ + constexpr uint32_t kWireStopSettleTimeoutUs = 100u; + if (_wire.busErrorRecoveryPending) + return serviceBusErrorRecoveryWIRE(); + // Policy: only auto-retry recoverable bus-state errors here. All other + // errors are surfaced to the transaction callback for protocol handling. + // Retry/backoff policy is intentionally deferred; a future change may add + // a retry budget or tick-based delay if needed. + SercomTxn *txn = _wire.currentTxn; + + SercomWireCompletionReport &report = _wire.lastCompletionReport; + report = {}; + report.error = error; + report.address = txn ? txn->address : 0u; + report.requestedLength = txn ? static_cast(txn->length) : 0u; + report.transferredLength = static_cast(_wire.txnIndex); + report.role = + isMasterWIRE() ? SercomWireRole::Master : SercomWireRole::Slave; + report.read = txn && (txn->config & I2C_CFG_READ); + + const auto refreshCompletionReport = [this, &report]() { + report.transferredLength = static_cast(_wire.txnIndex); + + if (report.role == SercomWireRole::Slave) { + report.bus = report.error == SercomWireError::SUCCESS + ? SercomWireBusDisposition::Released + : SercomWireBusDisposition::Unknown; + } else { + const uint16_t status = getSTATUS(); +#if defined(__SAME53__) || defined(__SAME54__) + const uint8_t busState = + static_cast((status & SERCOM_I2CM_STATUS_BUSSTATE_Msk) >> + SERCOM_I2CM_STATUS_BUSSTATE_Pos); + const bool clockHeld = + (status & SERCOM_I2CM_STATUS_CLKHOLD_Msk) != 0u; +#else + const uint8_t busState = + static_cast((status & SERCOM_I2CM_STATUS_BUSSTATE_Msk) >> + SERCOM_I2CM_STATUS_BUSSTATE_Pos); + const bool clockHeld = (status & SERCOM_I2CM_STATUS_CLKHOLD) != 0u; +#endif // __SAME53__ / __SAME54__ + + if (isBusOwnerWIRE()) + report.bus = SercomWireBusDisposition::LocalOwner; + else if (clockHeld) + report.bus = SercomWireBusDisposition::Unknown; + else if (busState == WIRE_IDLE_STATE) + report.bus = SercomWireBusDisposition::Released; + else if (busState == WIRE_BUSY_STATE) + report.bus = SercomWireBusDisposition::OtherOwner; + else + report.bus = SercomWireBusDisposition::Unknown; + } + + if (report.error == SercomWireError::SUCCESS) { + report.delivery = SercomWireDelivery::Complete; + } else if (report.error == SercomWireError::NACK_ON_ADDRESS || + report.error == SercomWireError::QUEUE_FULL || + report.error == SercomWireError::BUS_CONFLICT || + report.error == SercomWireError::BUS_STATE_UNKNOWN) { + report.delivery = report.transferredLength == 0u + ? SercomWireDelivery::None + : SercomWireDelivery::Ambiguous; + } else if (report.error == SercomWireError::NACK_ON_DATA) { + report.delivery = report.transferredLength == 0u + ? SercomWireDelivery::None + : SercomWireDelivery::Partial; + } else if (report.read && report.transferredLength != 0u) { + report.delivery = SercomWireDelivery::Partial; + } else { + report.delivery = SercomWireDelivery::Ambiguous; } + }; + + // Explicit timeout cancellation is a newer entrance into the shared + // PendSV retirement service. Keep it outside the tested normal master + // completion sequence below. + if (_wire.abortPending) { + serviceAbortWIRE(); + return txn; } - //Problems on line? nack received? - if(sercom->I2CM.STATUS.bit.RXNACK) - return false; - else - return true; + bool isMaster = isMasterWIRE(); + + if (!isMaster) { + const bool stopDetected = isStopDetectedWIRE(); +#if defined(__SAME53__) || defined(__SAME54__) + disableInterrupts(SERCOM_I2CS_INTENCLR_DRDY_Msk | + SERCOM_I2CS_INTENCLR_PREC_Msk); +#else + disableInterrupts(SERCOM_I2CS_INTENCLR_DRDY | SERCOM_I2CS_INTENCLR_PREC); +#endif // __SAME53__ / __SAME54__ + const bool receivePending = _wireReceivePending; + const bool requestPending = _wireRequestPending; + const bool followupPending = receivePending || requestPending; + SercomWireError completionError = error; + const bool slaveTransmit = + txn && (txn->config & I2C_CFG_READ) != 0; + if (slaveTransmit && + (error == SercomWireError::SUCCESS || + error == SercomWireError::NACK_ON_DATA)) { + if (!stopDetected) + prepareSlaveCommandBitsWIRE(WIRE_SLAVE_ACT_COMPLETE); + // A master NACK is the expected physical end of a slave response. Keep + // NACK_ON_DATA as the stop/release reason, but publish successful request + // completion after the slave has released the bus. + if (error == SercomWireError::NACK_ON_DATA) + completionError = SercomWireError::SUCCESS; + } + + if (stopDetected) { +#if defined(__SAME53__) || defined(__SAME54__) + clearINTFLAG(SERCOM_I2CS_INTFLAG_PREC_Msk); +#else + clearINTFLAG(SERCOM_I2CS_INTFLAG_PREC); +#endif // __SAME53__ / __SAME54__ + } + _wire.releasePending = false; + + if (txn) { +#ifdef USE_ZERODMA + dmaAbortTx(); + dmaAbortRx(); +#endif // USE_ZERODMA + retireSlaveTransactionWIRE(followupPending); + refreshCompletionReport(); + if (txn->onComplete) + txn->onComplete(txn->user, static_cast(completionError)); + } + + if (receivePending) { + _wireReceivePending = false; + if (_wireReceiveCb) + _wireReceiveCb(_wireCallbackUser); + } + + if (requestPending) { + _wireRequestPending = false; + if (_wireRequestCb) + _wireRequestCb(_wireCallbackUser); + } + + // An enqueue that arrives during an active slave transaction must wait + // until that transaction retires. Give that already-admitted master work + // the idle handoff before restoring the cached slave descriptor, whose + // active/current state would otherwise make startNextQueuedWIRE() refuse + // to run it. + if (_wire.currentTxn == nullptr) + startNextQueuedWIRE(); + + if (_wire.currentTxn == nullptr && _wire.slaveTxn != nullptr) + setTxnWIRE(_wire.slaveTxn); +#if defined(SERCOM_WIRE_TEST_POINTS) + recordTestPointWIRE(SercomWireTestEvent::StopSlaveComplete, + static_cast(completionError)); +#endif + return _wire.currentTxn; + } + + // Everything below is master-only: retry, bus-state recovery, STOP wait, + // queue retirement, transaction chaining, and return to slave mode. + constexpr uint8_t kMaxWireRetries = 3; + + if (error == SercomWireError::BUS_STATE_UNKNOWN) { + if (_wire.retryCount < kMaxWireRetries) { + ++_wire.retryCount; + +#if defined(__SAME53__) || defined(__SAME54__) + sercom->I2CM.SERCOM_STATUS = + (sercom->I2CM.SERCOM_STATUS & ~SERCOM_I2CM_STATUS_BUSSTATE_Msk) | + SERCOM_I2CM_STATUS_BUSSTATE(WIRE_IDLE_STATE); +#else + sercom->I2CM.STATUS.bit.BUSSTATE = 1; +#endif // __SAME53__ / __SAME54__ + waitSyncBusySysOp(); + startTransmissionWIRE(); + + return txn; + } + } + + if (error == SercomWireError::BUS_STATE_UNKNOWN) + _wire.retryCount = 0; + + waitSyncBusySysOp(); + + SercomWireError completionError = error; + + // Undocumented HW limitation: DMA transfers must terminate with STOP and bus release. + // After a DMA write, the host holds the bus ~7.33 us before the next transfer (Sr window). + // Writing ADDR during that window leaves the bus in an undefined state and breaks + // subsequent DMA/non-DMA transactions. To avoid this, we must wait for BUSSTATE + // to return to IDLE after a STOP returning the hardware to a known state. + // At the tested 48 MHz, this busy-wait is ~350 cycles corresponding to a 3.5 us delay + // at 100 MHz. This wait must occur BEFORE the callback to ensure the bus is stable + // before user code can enqueue the next transaction. + if (txn && (txn->config & I2C_CFG_STOP) && + error == SercomWireError::SUCCESS) { + const uint32_t stopSettleStart = micros(); + const auto busIsIdle = [this]() { +#if defined(__SAME53__) || defined(__SAME54__) + return ((sercom->I2CM.SERCOM_STATUS & SERCOM_I2CM_STATUS_BUSSTATE_Msk) >> + SERCOM_I2CM_STATUS_BUSSTATE_Pos) <= WIRE_IDLE_STATE; +#else + return sercom->I2CM.STATUS.bit.BUSSTATE <= WIRE_IDLE_STATE; +#endif // __SAME53__ / __SAME54__ + }; + + while (!busIsIdle() && static_cast(micros() - stopSettleStart) < + kWireStopSettleTimeoutUs) + ; + + if (!busIsIdle()) { + completionError = SercomWireError::BUS_RELEASE_TIMEOUT; + // The device datasheet identifies CTRLA.SWRST as recovery for an I2C + // protocol hang. Preserve the cached Wire configuration and transaction + // queue, reset only the peripheral, then restore a known master state. + resetSERCOM(); + setMasterWIRE(); + } + } + refreshCompletionReport(); + // Preserve the tested async-DMA master retirement order: publish the + // callback before inspecting chainNext, dequeuing, or restoring slave mode. + if (txn && txn->onComplete) + txn->onComplete(txn->user, static_cast(completionError)); + + // Allow multi-phase I2C transactions to chain without dequeuing. + if (txn && completionError == SercomWireError::SUCCESS && txn->chainNext) { + txn->chainNext = false; // reset for next iteration + startTransmissionWIRE(); + return txn; + } + if (txn) + txn->chainNext = false; + + SercomTxn* headTxn = nullptr; + if (_txnQueue.peek(headTxn) && headTxn == txn) + _txnQueue.read(txn); // remove completed master queue head + + _wire.retryCount = 0; + _wire.active = false; + _wire.currentTxn = nullptr; + _wire.busErrorRecoveryPending = false; + _wire.busErrorRecoveryDeadlineActive = false; + + SercomTxn *next = nullptr; + if (_txnQueue.peek(next)) + startTransmissionWIRE(); + else { +#if defined(__SAME53__) || defined(__SAME54__) + sercom->I2CM.SERCOM_INTENCLR = SERCOM_I2CM_INTENCLR_ERROR_Msk | + SERCOM_I2CM_INTENCLR_MB_Msk | + SERCOM_I2CM_INTENCLR_SB_Msk; +#else + sercom->I2CM.INTENCLR.reg = SERCOM_I2CM_INTENCLR_ERROR | + SERCOM_I2CM_INTENCLR_MB | + SERCOM_I2CM_INTENCLR_SB; +#endif // __SAME53__ / __SAME54__ + + if (_wire.slaveConfigured) { + setSlaveWIRE(); + setTxnWIRE(_wire.slaveTxn); + } + } + + return txn; } -bool SERCOM::sendDataSlaveWIRE(uint8_t data) +// Hardware metadata structure for SERCOM peripherals - private to this file +struct SercomData { +#if defined(__SAME53__) || defined(__SAME54__) + sercom_registers_t *sercomPtr; +#else + Sercom *sercomPtr; +#endif // __SAME53__ / __SAME54__ +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || \ + defined(__SAME54__) + uint8_t id_core; + uint8_t id_slow; + IRQn_Type irq[4]; +#else + uint8_t clock; + IRQn_Type irqn; +#endif // __SAMD51__ / __SAME51__ || __SAME53__ / __SAME54__ + uint8_t dmaTxTrigger; + uint8_t dmaRxTrigger; + void *dataReg; // Pointer to DATA register +}; + +static const SercomData sercomData[] = { +#if defined(__SAMD51__) || defined(__SAME51__) + {SERCOM0, SERCOM0_GCLK_ID_CORE, SERCOM0_GCLK_ID_SLOW, SERCOM0_0_IRQn, + SERCOM0_1_IRQn, SERCOM0_2_IRQn, SERCOM0_3_IRQn, SERCOM0_DMAC_ID_TX, + SERCOM0_DMAC_ID_RX, (void *)&SERCOM0->I2CM.DATA.reg}, + {SERCOM1, SERCOM1_GCLK_ID_CORE, SERCOM1_GCLK_ID_SLOW, SERCOM1_0_IRQn, + SERCOM1_1_IRQn, SERCOM1_2_IRQn, SERCOM1_3_IRQn, SERCOM1_DMAC_ID_TX, + SERCOM1_DMAC_ID_RX, (void *)&SERCOM1->I2CM.DATA.reg}, + {SERCOM2, SERCOM2_GCLK_ID_CORE, SERCOM2_GCLK_ID_SLOW, SERCOM2_0_IRQn, + SERCOM2_1_IRQn, SERCOM2_2_IRQn, SERCOM2_3_IRQn, SERCOM2_DMAC_ID_TX, + SERCOM2_DMAC_ID_RX, (void *)&SERCOM2->I2CM.DATA.reg}, + {SERCOM3, SERCOM3_GCLK_ID_CORE, SERCOM3_GCLK_ID_SLOW, SERCOM3_0_IRQn, + SERCOM3_1_IRQn, SERCOM3_2_IRQn, SERCOM3_3_IRQn, SERCOM3_DMAC_ID_TX, + SERCOM3_DMAC_ID_RX, (void *)&SERCOM3->I2CM.DATA.reg}, + {SERCOM4, SERCOM4_GCLK_ID_CORE, SERCOM4_GCLK_ID_SLOW, SERCOM4_0_IRQn, + SERCOM4_1_IRQn, SERCOM4_2_IRQn, SERCOM4_3_IRQn, SERCOM4_DMAC_ID_TX, + SERCOM4_DMAC_ID_RX, (void *)&SERCOM4->I2CM.DATA.reg}, + {SERCOM5, SERCOM5_GCLK_ID_CORE, SERCOM5_GCLK_ID_SLOW, SERCOM5_0_IRQn, + SERCOM5_1_IRQn, SERCOM5_2_IRQn, SERCOM5_3_IRQn, SERCOM5_DMAC_ID_TX, + SERCOM5_DMAC_ID_RX, (void *)&SERCOM5->I2CM.DATA.reg}, +#if defined(SERCOM6) + {SERCOM6, SERCOM6_GCLK_ID_CORE, SERCOM6_GCLK_ID_SLOW, SERCOM6_0_IRQn, + SERCOM6_1_IRQn, SERCOM6_2_IRQn, SERCOM6_3_IRQn, SERCOM6_DMAC_ID_TX, + SERCOM6_DMAC_ID_RX, (void *)&SERCOM6->I2CM.DATA.reg}, +#endif // SERCOM6 +#if defined(SERCOM7) + {SERCOM7, SERCOM7_GCLK_ID_CORE, SERCOM7_GCLK_ID_SLOW, SERCOM7_0_IRQn, + SERCOM7_1_IRQn, SERCOM7_2_IRQn, SERCOM7_3_IRQn, SERCOM7_DMAC_ID_TX, + SERCOM7_DMAC_ID_RX, (void *)&SERCOM7->I2CM.DATA.reg}, +#endif // SERCOM7 +#elif defined(__SAME53__) || defined(__SAME54__) + {SERCOM0_REGS, SERCOM0_GCLK_ID_CORE, SERCOM0_GCLK_ID_SLOW, SERCOM0_0_IRQn, + SERCOM0_1_IRQn, SERCOM0_2_IRQn, SERCOM0_OTHER_IRQn, SERCOM0_DMAC_ID_TX, + SERCOM0_DMAC_ID_RX, (void *)&SERCOM0_REGS->I2CM.SERCOM_DATA}, + {SERCOM1_REGS, SERCOM1_GCLK_ID_CORE, SERCOM1_GCLK_ID_SLOW, SERCOM1_0_IRQn, + SERCOM1_1_IRQn, SERCOM1_2_IRQn, SERCOM1_OTHER_IRQn, SERCOM1_DMAC_ID_TX, + SERCOM1_DMAC_ID_RX, (void *)&SERCOM1_REGS->I2CM.SERCOM_DATA}, + {SERCOM2_REGS, SERCOM2_GCLK_ID_CORE, SERCOM2_GCLK_ID_SLOW, SERCOM2_0_IRQn, + SERCOM2_1_IRQn, SERCOM2_2_IRQn, SERCOM2_OTHER_IRQn, SERCOM2_DMAC_ID_TX, + SERCOM2_DMAC_ID_RX, (void *)&SERCOM2_REGS->I2CM.SERCOM_DATA}, + {SERCOM3_REGS, SERCOM3_GCLK_ID_CORE, SERCOM3_GCLK_ID_SLOW, SERCOM3_0_IRQn, + SERCOM3_1_IRQn, SERCOM3_2_IRQn, SERCOM3_OTHER_IRQn, SERCOM3_DMAC_ID_TX, + SERCOM3_DMAC_ID_RX, (void *)&SERCOM3_REGS->I2CM.SERCOM_DATA}, + {SERCOM4_REGS, SERCOM4_GCLK_ID_CORE, SERCOM4_GCLK_ID_SLOW, SERCOM4_0_IRQn, + SERCOM4_1_IRQn, SERCOM4_2_IRQn, SERCOM4_OTHER_IRQn, SERCOM4_DMAC_ID_TX, + SERCOM4_DMAC_ID_RX, (void *)&SERCOM4_REGS->I2CM.SERCOM_DATA}, + {SERCOM5_REGS, SERCOM5_GCLK_ID_CORE, SERCOM5_GCLK_ID_SLOW, SERCOM5_0_IRQn, + SERCOM5_1_IRQn, SERCOM5_2_IRQn, SERCOM5_OTHER_IRQn, SERCOM5_DMAC_ID_TX, + SERCOM5_DMAC_ID_RX, (void *)&SERCOM5_REGS->I2CM.SERCOM_DATA}, +#if defined(SERCOM6_REGS) + {SERCOM6_REGS, SERCOM6_GCLK_ID_CORE, SERCOM6_GCLK_ID_SLOW, SERCOM6_0_IRQn, + SERCOM6_1_IRQn, SERCOM6_2_IRQn, SERCOM6_OTHER_IRQn, SERCOM6_DMAC_ID_TX, + SERCOM6_DMAC_ID_RX, (void *)&SERCOM6_REGS->I2CM.SERCOM_DATA}, +#endif // SERCOM6_REGS +#if defined(SERCOM7_REGS) + {SERCOM7_REGS, SERCOM7_GCLK_ID_CORE, SERCOM7_GCLK_ID_SLOW, SERCOM7_0_IRQn, + SERCOM7_1_IRQn, SERCOM7_2_IRQn, SERCOM7_OTHER_IRQn, SERCOM7_DMAC_ID_TX, + SERCOM7_DMAC_ID_RX, (void *)&SERCOM7_REGS->I2CM.SERCOM_DATA}, +#endif // SERCOM7_REGS +#else // SAMD21 + // SAMD21 has unified clock and single interrupt + {SERCOM0, GCM_SERCOM0_CORE, SERCOM0_IRQn, SERCOM0_DMAC_ID_TX, + SERCOM0_DMAC_ID_RX, (void *)&SERCOM0->I2CM.DATA.reg}, + {SERCOM1, GCM_SERCOM1_CORE, SERCOM1_IRQn, SERCOM1_DMAC_ID_TX, + SERCOM1_DMAC_ID_RX, (void *)&SERCOM1->I2CM.DATA.reg}, + {SERCOM2, GCM_SERCOM2_CORE, SERCOM2_IRQn, SERCOM2_DMAC_ID_TX, + SERCOM2_DMAC_ID_RX, (void *)&SERCOM2->I2CM.DATA.reg}, + {SERCOM3, GCM_SERCOM3_CORE, SERCOM3_IRQn, SERCOM3_DMAC_ID_TX, + SERCOM3_DMAC_ID_RX, (void *)&SERCOM3->I2CM.DATA.reg}, +#if defined(SERCOM4) + {SERCOM4, GCM_SERCOM4_CORE, SERCOM4_IRQn, SERCOM4_DMAC_ID_TX, + SERCOM4_DMAC_ID_RX, (void *)&SERCOM4->I2CM.DATA.reg}, +#endif // SERCOM4 +#if defined(SERCOM5) + {SERCOM5, GCM_SERCOM5_CORE, SERCOM5_IRQn, SERCOM5_DMAC_ID_TX, + SERCOM5_DMAC_ID_RX, (void *)&SERCOM5->I2CM.DATA.reg}, +#endif // SERCOM5 +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ / SAMD21 +}; + +std::array SERCOM::s_states = {}; +std::array SERCOM::s_instances = {}; +volatile uint32_t SERCOM::s_pendingMask = 0; + + +bool SERCOM::claim(uint8_t sercomId, Role role) { - //Send data - sercom->I2CS.DATA.bit.DATA = data; + if (sercomId >= kSercomCount) + return false; - //Problems on line? nack received? - if(!sercom->I2CS.INTFLAG.bit.DRDY || sercom->I2CS.STATUS.bit.RXNACK) + SercomState &state = s_states[sercomId]; + if (state.role != Role::None && state.role != role) return false; - else - return true; + + state.role = role; + return true; } -bool SERCOM::isMasterWIRE( void ) +void SERCOM::release(uint8_t sercomId) { - return sercom->I2CS.CTRLA.bit.MODE == I2C_MASTER_OPERATION; + if (sercomId >= kSercomCount) + return; + + SercomState &state = s_states[sercomId]; + state.role = Role::None; + state.service = nullptr; + PendSV::instance().clearService(PendSVChannels::sercom(sercomId)); +#ifdef SERCOM_STRICT_PADS + clearPads(sercomId); +#endif // SERCOM_STRICT_PADS } -bool SERCOM::isSlaveWIRE( void ) +bool SERCOM::registerService(uint8_t sercomId, ServiceFn fn) { - return sercom->I2CS.CTRLA.bit.MODE == I2C_SLAVE_OPERATION; + if (sercomId >= kSercomCount) + return false; + + s_states[sercomId].service = fn; + if (!PendSV::instance().registerService(PendSVChannels::sercom(sercomId), + &SERCOM::dispatchService, nullptr)) + { + s_states[sercomId].service = nullptr; + return false; + } + + return true; } -bool SERCOM::isBusIdleWIRE( void ) +#ifdef USE_ZERODMA +SERCOM::DmaStatus SERCOM::dmaInit(int8_t sercomId, uint8_t beatSize) { - return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_IDLE_STATE; + if (_dmaConfigured) + return DmaStatus::Ok; + + // Validate beat size: 0=byte, 1=halfword, 2=word + if (beatSize > DMA_BEAT_SIZE_WORD) + beatSize = DMA_BEAT_SIZE_BYTE; + + // Look up DMA triggers from sercomData table +#ifdef SERCOM0_DMAC_ID_TX + if (sercomId >= 0 && sercomId < (int8_t)kSercomCount && sercomData[sercomId].dmaTxTrigger != 0) + { + _dmaTxTrigger = sercomData[sercomId].dmaTxTrigger; + _dmaRxTrigger = sercomData[sercomId].dmaRxTrigger; + } + else +#endif // SERCOM0_DMAC_ID_TX + { + // Fallback: calculate triggers if table lookup unavailable + _dmaTxTrigger = SERCOM0_DMAC_ID_TX + (sercomId * 2); + _dmaRxTrigger = SERCOM0_DMAC_ID_RX + (sercomId * 2); + } + + // DATA register is at the same offset (0x28) for all protocols (I2C, SPI, UART). + // Access via any union member is transparent—just use I2CM as the canonical reference. +#if defined(__SAME53__) || defined(__SAME54__) + void* dataReg = (void*)&sercom->I2CM.SERCOM_DATA; +#else + void* dataReg = (void*)&sercom->I2CM.DATA.reg; +#endif // __SAME53__ / __SAME54__ + + if (!_dmaTx) + _dmaTx = new Adafruit_ZeroDMA(); + if (!_dmaRx) + _dmaRx = new Adafruit_ZeroDMA(); + if (!_dmaTx || !_dmaRx) + { + _dmaLastError = DmaStatus::AllocateFailed; + dmaRelease(); + return _dmaLastError; + } + + if (_dmaTx->allocate() != DMA_STATUS_OK) + { + _dmaLastError = DmaStatus::AllocateFailed; + dmaRelease(); + return _dmaLastError; + } + if (_dmaRx->allocate() != DMA_STATUS_OK) + { + _dmaLastError = DmaStatus::AllocateFailed; + dmaRelease(); + return _dmaLastError; + } + + _dmaTx->setTrigger(_dmaTxTrigger); + _dmaTx->setAction(DMA_TRIGGER_ACTON_BEAT); + _dmaRx->setTrigger(_dmaRxTrigger); + _dmaRx->setAction(DMA_TRIGGER_ACTON_BEAT); + + if (_dmaTxCb) + _dmaTx->setCallback(_dmaTxCb); + if (_dmaRxCb) + _dmaRx->setCallback(_dmaRxCb); + if (_dmaErrorCb) { + _dmaTx->setCallback(_dmaErrorCb, DMA_CALLBACK_TRANSFER_ERROR); + _dmaRx->setCallback(_dmaErrorCb, DMA_CALLBACK_TRANSFER_ERROR); + } + + if (_dmaTxDesc == nullptr) + _dmaTxDesc = _dmaTx->addDescriptor(&_dmaDummy, dataReg, 0, (dma_beat_size)beatSize, true, false); + if (_dmaRxDesc == nullptr) + _dmaRxDesc = _dmaRx->addDescriptor(dataReg, &_dmaDummy, 0, (dma_beat_size)beatSize, false, true); + if (_dmaTxDesc == nullptr || _dmaRxDesc == nullptr) + { + _dmaLastError = DmaStatus::DescriptorFailed; + dmaRelease(); + return _dmaLastError; + } + + _dmaConfigured = true; + _dmaLastError = DmaStatus::Ok; + return _dmaLastError; } -bool SERCOM::isBusOwnerWIRE( void ) -{ - return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_OWNER_STATE; +void SERCOM::dmaSetCallbacks(DmaCallback txCb, DmaCallback rxCb, + DmaCallback errorCb) { + _dmaTxCb = txCb; + _dmaRxCb = rxCb; + _dmaErrorCb = errorCb; + + if (_dmaConfigured) + { + if (_dmaTxCb) + _dmaTx->setCallback(_dmaTxCb); + if (_dmaRxCb) + _dmaRx->setCallback(_dmaRxCb); + _dmaTx->setCallback(_dmaErrorCb, DMA_CALLBACK_TRANSFER_ERROR); + _dmaRx->setCallback(_dmaErrorCb, DMA_CALLBACK_TRANSFER_ERROR); + } } -bool SERCOM::isBusUnknownWIRE( void ) +SERCOM::DmaStatus SERCOM::dmaStartTx(const void* src, volatile void* dstReg, size_t len) { - return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_UNKNOWN_STATE; + if (!_dmaConfigured || !_dmaTx) { + _dmaLastError = DmaStatus::NotConfigured; + return _dmaLastError; + } + if (src == nullptr || dstReg == nullptr) { + _dmaLastError = DmaStatus::NullPtr; + return _dmaLastError; + } + if (len == 0) { + _dmaLastError = DmaStatus::ZeroLen; + return _dmaLastError; + } + if (_dmaTxDesc == nullptr) { + _dmaLastError = DmaStatus::DescriptorFailed; + return _dmaLastError; + } + + _dmaTx->changeDescriptor(_dmaTxDesc, const_cast(src), + const_cast(dstReg), len); + + if (_dmaTx->startJob() != DMA_STATUS_OK) { + _dmaTx->abort(); + _dmaLastError = DmaStatus::StartFailed; + return _dmaLastError; + } + + _dmaTxActive = true; + _dmaLastError = DmaStatus::Ok; + return _dmaLastError; } -bool SERCOM::isArbLostWIRE( void ) +SERCOM::DmaStatus SERCOM::dmaStartRx(void* dst, volatile void* srcReg, size_t len) { - return sercom->I2CM.STATUS.bit.ARBLOST == 1; + if (!_dmaConfigured || !_dmaRx) { + _dmaLastError = DmaStatus::NotConfigured; + return _dmaLastError; + } + if (dst == nullptr || srcReg == nullptr) { + _dmaLastError = DmaStatus::NullPtr; + return _dmaLastError; + } + if (len == 0) { + _dmaLastError = DmaStatus::ZeroLen; + return _dmaLastError; + } + if (_dmaRxDesc == nullptr) { + _dmaLastError = DmaStatus::DescriptorFailed; + return _dmaLastError; + } + + _dmaRx->changeDescriptor(_dmaRxDesc, + const_cast(srcReg), + dst, len); + + if (_dmaRx->startJob() != DMA_STATUS_OK) { + _dmaRx->abort(); + _dmaLastError = DmaStatus::StartFailed; + return _dmaLastError; + } + + _dmaRxActive = true; + _dmaLastError = DmaStatus::Ok; + return _dmaLastError; } -bool SERCOM::isBusBusyWIRE( void ) +SERCOM::DmaStatus SERCOM::dmaStartDuplex(const void* txSrc, void* rxDst, volatile void* txReg, volatile void* rxReg, size_t len, + const uint8_t* dummyTx) { - return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_BUSY_STATE; + if (len == 0) + { + _dmaLastError = DmaStatus::ZeroLen; + return _dmaLastError; + } + DmaStatus st = dmaStartRx(rxDst, rxReg, len); + if (st != DmaStatus::Ok) + return st; + static const uint8_t kDummyByte = 0xFF; + const void* txPtr = txSrc ? txSrc : (dummyTx ? dummyTx : &kDummyByte); + st = dmaStartTx(txPtr, txReg, len); + if (st != DmaStatus::Ok) + { + dmaAbortRx(); + return st; + } + return DmaStatus::Ok; } -bool SERCOM::isDataReadyWIRE( void ) +void SERCOM::dmaAbortTx() { - return sercom->I2CS.INTFLAG.bit.DRDY; + if (_dmaTx) + _dmaTx->abort(); + _dmaTxActive = false; } -bool SERCOM::isStopDetectedWIRE( void ) +void SERCOM::dmaAbortRx() { - return sercom->I2CS.INTFLAG.bit.PREC; + if (_dmaRx) + _dmaRx->abort(); + _dmaRxActive = false; } -bool SERCOM::isRestartDetectedWIRE( void ) +void SERCOM::dmaRelease() { - return sercom->I2CS.STATUS.bit.SR; + if (!_dmaConfigured) + { + dmaResetDescriptors(); + if (_dmaTx) + { + delete _dmaTx; + _dmaTx = nullptr; + } + if (_dmaRx) + { + delete _dmaRx; + _dmaRx = nullptr; + } + _dmaLastError = DmaStatus::Ok; + return; + } + + dmaAbortTx(); + dmaAbortRx(); + + if (_dmaTx) + _dmaTx->free(); + if (_dmaRx) + _dmaRx->free(); + + dmaResetDescriptors(); + + _dmaConfigured = false; + if (_dmaTx) + { + delete _dmaTx; + _dmaTx = nullptr; + } + if (_dmaRx) + { + delete _dmaRx; + _dmaRx = nullptr; + } + _dmaLastError = DmaStatus::Ok; } -bool SERCOM::isAddressMatch( void ) +void SERCOM::dmaResetDescriptors() { - return sercom->I2CS.INTFLAG.bit.AMATCH; + _dmaTxDesc = nullptr; + _dmaRxDesc = nullptr; } -bool SERCOM::isMasterReadOperationWIRE( void ) +bool SERCOM::dmaTxBusy() const { - return sercom->I2CS.STATUS.bit.DIR; + return _dmaTxActive; } -bool SERCOM::isRXNackReceivedWIRE( void ) +bool SERCOM::dmaRxBusy() const { - return sercom->I2CM.STATUS.bit.RXNACK; + return _dmaRxActive; } -int SERCOM::availableWIRE( void ) +SERCOM::DmaStatus SERCOM::dmaLastError() const { - if(isMasterWIRE()) - return sercom->I2CM.INTFLAG.bit.SB; - else - return sercom->I2CS.INTFLAG.bit.DRDY; + return _dmaLastError; } +#endif // USE_ZERODMA -uint8_t SERCOM::readDataWIRE( void ) +#ifdef SERCOM_STRICT_PADS +bool SERCOM::registerPads(uint8_t sercomId, const PadFunc (&pads)[4], bool muxFunctionD) { - if(isMasterWIRE()) + if (sercomId >= kSercomCount) + return false; + + SercomState &state = s_states[sercomId]; + for (size_t i = 0; i < 4; ++i) { - while (sercom->I2CM.INTFLAG.bit.SB == 0) { - // Waiting complete receive - // A variety of errors in the STATUS register can set the ERROR bit in the INTFLAG register - // In that case, send a stop condition and return false. - // readDataWIRE should really be able to indicate an error (which would never be used - // because the readDataWIRE callers (in Wire.cpp) should have checked availableWIRE() first and timed it - // out if the data never showed up - if (sercom->I2CM.INTFLAG.bit.MB || sercom->I2CM.INTFLAG.bit.ERROR) { - sercom->I2CM.CTRLB.bit.CMD = 3; // Stop condition - return 0xFF; - } - } + PadFunc desired = pads[i]; + if (desired == PadFunc::None) + continue; + PadFunc existing = state.pads[i]; + if (existing != PadFunc::None && existing != desired) + return false; + } + if (state.padsConfigured && state.muxFunctionD != muxFunctionD) + return false; - return sercom->I2CM.DATA.bit.DATA ; + bool any = false; + for (size_t i = 0; i < 4; ++i) + { + PadFunc desired = pads[i]; + if (desired == PadFunc::None) + continue; + state.pads[i] = desired; + any = true; } - else + if (any) { - return sercom->I2CS.DATA.reg ; + state.padsConfigured = true; + state.muxFunctionD = muxFunctionD; } + return true; } -#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) +void SERCOM::clearPads(uint8_t sercomId) +{ + if (sercomId >= kSercomCount) + return; -static const struct { - Sercom *sercomPtr; - uint8_t id_core; - uint8_t id_slow; - IRQn_Type irq[4]; -} sercomData[] = { - { SERCOM0, SERCOM0_GCLK_ID_CORE, SERCOM0_GCLK_ID_SLOW, - SERCOM0_0_IRQn, SERCOM0_1_IRQn, SERCOM0_2_IRQn, SERCOM0_3_IRQn }, - { SERCOM1, SERCOM1_GCLK_ID_CORE, SERCOM1_GCLK_ID_SLOW, - SERCOM1_0_IRQn, SERCOM1_1_IRQn, SERCOM1_2_IRQn, SERCOM1_3_IRQn }, - { SERCOM2, SERCOM2_GCLK_ID_CORE, SERCOM2_GCLK_ID_SLOW, - SERCOM2_0_IRQn, SERCOM2_1_IRQn, SERCOM2_2_IRQn, SERCOM2_3_IRQn }, - { SERCOM3, SERCOM3_GCLK_ID_CORE, SERCOM3_GCLK_ID_SLOW, - SERCOM3_0_IRQn, SERCOM3_1_IRQn, SERCOM3_2_IRQn, SERCOM3_3_IRQn }, - { SERCOM4, SERCOM4_GCLK_ID_CORE, SERCOM4_GCLK_ID_SLOW, - SERCOM4_0_IRQn, SERCOM4_1_IRQn, SERCOM4_2_IRQn, SERCOM4_3_IRQn }, - { SERCOM5, SERCOM5_GCLK_ID_CORE, SERCOM5_GCLK_ID_SLOW, - SERCOM5_0_IRQn, SERCOM5_1_IRQn, SERCOM5_2_IRQn, SERCOM5_3_IRQn }, -#if defined(SERCOM6) - { SERCOM6, SERCOM6_GCLK_ID_CORE, SERCOM6_GCLK_ID_SLOW, - SERCOM6_0_IRQn, SERCOM6_1_IRQn, SERCOM6_2_IRQn, SERCOM6_3_IRQn }, -#endif -#if defined(SERCOM7) - { SERCOM7, SERCOM7_GCLK_ID_CORE, SERCOM7_GCLK_ID_SLOW, - SERCOM7_0_IRQn, SERCOM7_1_IRQn, SERCOM7_2_IRQn, SERCOM7_3_IRQn }, -#endif -}; + SercomState &state = s_states[sercomId]; + for (size_t i = 0; i < 4; ++i) + state.pads[i] = PadFunc::None; + state.padsConfigured = false; + state.muxFunctionD = false; +} +#endif // SERCOM_STRICT_PADS + +void SERCOM::setPending(uint8_t sercomId) +{ + if (sercomId >= kSercomCount) + return; -#else // end if SAMD51 (prob SAMD21) + PendSV::instance().setPending(PendSVChannels::sercom(sercomId)); +} -static const struct { - Sercom *sercomPtr; - uint8_t clock; - IRQn_Type irqn; -} sercomData[] = { - SERCOM0, GCM_SERCOM0_CORE, SERCOM0_IRQn, - SERCOM1, GCM_SERCOM1_CORE, SERCOM1_IRQn, - SERCOM2, GCM_SERCOM2_CORE, SERCOM2_IRQn, - SERCOM3, GCM_SERCOM3_CORE, SERCOM3_IRQn, -#if defined(SERCOM4) - SERCOM4, GCM_SERCOM4_CORE, SERCOM4_IRQn, -#endif -#if defined(SERCOM5) - SERCOM5, GCM_SERCOM5_CORE, SERCOM5_IRQn, -#endif -}; +void SERCOM::dispatchService(uint8_t sercomId, void *context) +{ + (void)context; + + sercomId = PendSVChannels::sercomIndex(sercomId); + + if (sercomId >= kSercomCount) + return; -#endif // end !SAMD51 + ServiceFn fn = s_states[sercomId].service; + SERCOM* inst = s_instances[sercomId]; + if (fn && inst) { + (inst->*fn)(); + } +} + +void SERCOM::dispatchPending(void) +{ + for (uint8_t i = 0; i < kSercomCount; ++i) + dispatchService(i, nullptr); +} int8_t SERCOM::getSercomIndex(void) { for(uint8_t i=0; i<(sizeof(sercomData) / sizeof(sercomData[0])); i++) { @@ -803,14 +2261,20 @@ int8_t SERCOM::getSercomIndex(void) { uint32_t SERCOM::getSercomFreqRef(void) { -#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || \ + defined(__SAME54__) int8_t idx = getSercomIndex(); uint8_t gen = 1; // default to GCLK1 (48 MHz) if we can't resolve if (idx >= 0) { uint8_t pch = sercomData[idx].id_core; +#if defined(__SAME53__) || defined(__SAME54__) + gen = (GCLK_REGS->GCLK_PCHCTRL[pch] & GCLK_PCHCTRL_GEN_Msk) >> + GCLK_PCHCTRL_GEN_Pos; +#else gen = GCLK->PCHCTRL[pch].bit.GEN; +#endif // __SAME53__ / __SAME54__ } switch (gen) @@ -836,12 +2300,13 @@ uint32_t SERCOM::getSercomFreqRef(void) } #else freqRef = SystemCoreClock; -#endif +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ return freqRef; } -#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || \ + defined(__SAME54__) // This is currently for overriding an SPI SERCOM's clock source only -- // NOT for UART or WIRE SERCOMs, where it will have unintended consequences. // It does not check. @@ -854,8 +2319,13 @@ void SERCOM::setClockSource(int8_t idx, SercomClockSource src, bool core) { uint8_t clk_id = core ? sercomData[idx].id_core : sercomData[idx].id_slow; +#if defined(__SAME53__) || defined(__SAME54__) + GCLK_REGS->GCLK_PCHCTRL[clk_id] &= ~GCLK_PCHCTRL_CHEN_Msk; + while (GCLK_REGS->GCLK_PCHCTRL[clk_id] & GCLK_PCHCTRL_CHEN_Msk); +#else GCLK->PCHCTRL[clk_id].bit.CHEN = 0; // Disable timer while(GCLK->PCHCTRL[clk_id].bit.CHEN); // Wait for disable +#endif // __SAME53__ / __SAME54__ if(core) clockSource = src; // Save SercomClockSource value @@ -866,40 +2336,70 @@ void SERCOM::setClockSource(int8_t idx, SercomClockSource src, bool core) { // GCLK3 = XOSC32K // GCLK4 = 12 MHz if(src == SERCOM_CLOCK_SOURCE_FCPU) { +#if defined(__SAME53__) || defined(__SAME54__) + GCLK_REGS->GCLK_PCHCTRL[clk_id] = GCLK_PCHCTRL_GEN_GCLK2 | + GCLK_PCHCTRL_CHEN_Msk; +#else GCLK->PCHCTRL[clk_id].reg = GCLK_PCHCTRL_GEN_GCLK2_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); // Guard Sercom from exceeding 100 MHz maximum +#endif // __SAME53__ / __SAME54__ if (core) freqRef = 100000000; // Save clock frequency value } else if (src == SERCOM_CLOCK_SOURCE_48M) { +#if defined(__SAME53__) || defined(__SAME54__) + GCLK_REGS->GCLK_PCHCTRL[clk_id] = GCLK_PCHCTRL_GEN_GCLK1 | + GCLK_PCHCTRL_CHEN_Msk; +#else GCLK->PCHCTRL[clk_id].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); +#endif // __SAME53__ / __SAME54__ if(core) freqRef = 48000000; } else if(src == SERCOM_CLOCK_SOURCE_100M) { +#if defined(__SAME53__) || defined(__SAME54__) + GCLK_REGS->GCLK_PCHCTRL[clk_id] = GCLK_PCHCTRL_GEN_GCLK2 | + GCLK_PCHCTRL_CHEN_Msk; +#else GCLK->PCHCTRL[clk_id].reg = GCLK_PCHCTRL_GEN_GCLK2_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); +#endif // __SAME53__ / __SAME54__ if(core) freqRef = 100000000; } else if(src == SERCOM_CLOCK_SOURCE_32K) { +#if defined(__SAME53__) || defined(__SAME54__) + GCLK_REGS->GCLK_PCHCTRL[clk_id] = GCLK_PCHCTRL_GEN_GCLK3 | + GCLK_PCHCTRL_CHEN_Msk; +#else GCLK->PCHCTRL[clk_id].reg = GCLK_PCHCTRL_GEN_GCLK3_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); +#endif // __SAME53__ / __SAME54__ if(core) freqRef = 32768; } else if(src == SERCOM_CLOCK_SOURCE_12M) { +#if defined(__SAME53__) || defined(__SAME54__) + GCLK_REGS->GCLK_PCHCTRL[clk_id] = GCLK_PCHCTRL_GEN_GCLK4 | + GCLK_PCHCTRL_CHEN_Msk; +#else GCLK->PCHCTRL[clk_id].reg = GCLK_PCHCTRL_GEN_GCLK4_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); +#endif // __SAME53__ / __SAME54__ if(core) freqRef = 12000000; } +#if defined(__SAME53__) || defined(__SAME54__) + while ((GCLK_REGS->GCLK_PCHCTRL[clk_id] & GCLK_PCHCTRL_CHEN_Msk) == 0); +#else while(!GCLK->PCHCTRL[clk_id].bit.CHEN); // Wait for clock enable +#endif // __SAME53__ / __SAME54__ } -#endif +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ void SERCOM::initClockNVIC( void ) { int8_t idx = getSercomIndex(); if(idx < 0) return; // We got a problem here -#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || \ + defined(__SAME54__) for(uint8_t i=0; i<4; i++) { NVIC_ClearPendingIRQ(sercomData[idx].irq[i]); @@ -907,9 +2407,10 @@ void SERCOM::initClockNVIC( void ) NVIC_EnableIRQ(sercomData[idx].irq[i]); } - setClockSource(idx, clockSource, true); // true = core clock + setClockSource(idx, clockSource, true); // true = core clock + setClockSource(idx, SERCOM_CLOCK_SOURCE_32K, false); // false = slow clock -#else // end if SAMD51 (prob SAMD21) +#else // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ uint8_t clockId = sercomData[idx].clock; IRQn_Type IdNvic = sercomData[idx].irqn; @@ -927,7 +2428,7 @@ void SERCOM::initClockNVIC( void ) while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); // Wait for synchronization -#endif // end !SAMD51 +#endif // __SAMD51__ / __SAME51__ || __SAME53__ / __SAME54__ getSercomFreqRef(); } diff --git a/cores/arduino/SERCOM.h b/cores/arduino/SERCOM.h index 35c90f1c4..39fa92aa0 100644 --- a/cores/arduino/SERCOM.h +++ b/cores/arduino/SERCOM.h @@ -19,7 +19,18 @@ #ifndef _SERCOM_CLASS_ #define _SERCOM_CLASS_ -#include "sam.h" +#include +#include "SERCOM_PinMux.h" +#include "SERCOM_Txn.h" +#include "RingBuffer.h" +#include + +#ifdef USE_ZERODMA +#if defined(__SAME53__) || defined(__SAME54__) +typedef dmac_descriptor_registers_t DmacDescriptor; +#endif // __SAME53__ / __SAME54__ +class Adafruit_ZeroDMA; +#endif // USE_ZERODMA // SAMD51 has configurable MAX_SPI, else use peripheral clock default. // Update: changing MAX_SPI via compiler flags is DEPRECATED, because @@ -30,11 +41,15 @@ #define SERCOM_SPI_FREQ_REF (MAX_SPI * 2) #else #define SERCOM_SPI_FREQ_REF 48000000ul -#endif +#endif // MAX_SPI // Other SERCOM peripherals always use the 48 MHz clock #define SERCOM_FREQ_REF 48000000ul #define SERCOM_NVIC_PRIORITY ((1<<__NVIC_PRIO_BITS) - 1) +#ifndef SERCOM_QUEUE_LENGTH +#define SERCOM_QUEUE_LENGTH 8 +#endif // !SERCOM_QUEUE_LENGTH + typedef enum { UART_EXT_CLOCK = 0, @@ -146,6 +161,12 @@ typedef enum WIRE_MASTER_ACT_STOP } SercomMasterCommandWire; +typedef enum +{ + WIRE_SLAVE_ACT_NO_ACTION = 0, + WIRE_SLAVE_ACT_COMPLETE = 2 +} SercomSlaveCommandWire; + typedef enum { WIRE_MASTER_ACK_ACTION = 0, @@ -168,7 +189,33 @@ typedef enum { class SERCOM { public: +#if defined(__SAME53__) || defined(__SAME54__) + SERCOM(sercom_registers_t* s) ; +#else SERCOM(Sercom* s) ; +#endif // __SAME53__ / __SAME54__ + void resetSERCOM( void ) ; + inline void enableSERCOM( void ) ; + inline void disableSERCOM( void ) ; + inline void waitSyncBusyEnable( void ) ; + inline void waitSyncBusySwrst( void ) ; + inline void waitSyncBusySysOp( void ) ; + inline void waitSyncBusyCtrlB( void ) ; +#if defined(__SAME53__) || defined(__SAME54__) + inline void disableInterrupts(uint8_t mask) { sercom->I2CM.SERCOM_INTENCLR = mask; } + inline void enableInterrupts(uint8_t mask) { sercom->I2CM.SERCOM_INTENSET = mask; } + inline uint8_t getINTFLAG( void ) const { return sercom->I2CM.SERCOM_INTFLAG; } + inline uint16_t getSTATUS( void ) const { return sercom->I2CM.SERCOM_STATUS; } + inline void clearINTFLAG(uint8_t mask = 0xFF) { sercom->I2CM.SERCOM_INTFLAG = mask; } + inline void clearStatusWIRE(uint16_t mask) { sercom->I2CM.SERCOM_STATUS = mask; } +#else + inline void disableInterrupts(uint8_t mask) { sercom->I2CM.INTENCLR.reg = mask; } + inline void enableInterrupts(uint8_t mask) { sercom->I2CM.INTENSET.reg = mask; } + inline uint8_t getINTFLAG( void ) const { return sercom->I2CM.INTFLAG.reg; } + inline uint16_t getSTATUS( void ) const { return sercom->I2CM.STATUS.reg; } + inline void clearINTFLAG(uint8_t mask = 0xFF) { sercom->I2CM.INTFLAG.reg = mask; } + inline void clearStatusWIRE(uint16_t mask) { sercom->I2CM.STATUS.reg = mask; } +#endif // __SAME53__ / __SAME54__ /* ========== UART ========== */ void initUART(SercomUartMode mode, SercomUartSampleRate sampleRate, uint32_t baudrate=0) ; @@ -176,7 +223,8 @@ class SERCOM void initPads(SercomUartTXPad txPad, SercomRXPad rxPad) ; void resetUART( void ) ; - void enableUART( void ) ; + void enableUART( void ) { enableSERCOM(); } + void disableUART( void ) { disableSERCOM(); } void flushUART( void ) ; void clearStatusUART( void ) ; bool availableDataUART( void ) ; @@ -189,15 +237,22 @@ class SERCOM int writeDataUART(uint8_t data) ; bool isUARTError() ; void acknowledgeUARTError() ; + void enableReceiveCompleteInterruptUART(); + void disableReceiveCompleteInterruptUART(); void enableDataRegisterEmptyInterruptUART(); void disableDataRegisterEmptyInterruptUART(); + bool enqueueUART(SercomTxn* txn); + bool startTransmissionUART(void); + SercomTxn* stopTransmissionUART(void); + SercomTxn* stopTransmissionUART(SercomUartError error); + void deferStopUART(SercomUartError error); /* ========== 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 enableSPI( void ) { enableSERCOM(); } + void disableSPI( void ) { disableSERCOM(); } void setDataOrderSPI(SercomDataOrder dataOrder) ; SercomDataOrder getDataOrderSPI( void ) ; void setBaudrateSPI(uint8_t divider) ; @@ -207,37 +262,114 @@ class SERCOM bool isDataRegisterEmptySPI( void ) ; bool isTransmitCompleteSPI( void ) ; bool isReceiveCompleteSPI( void ) ; + bool enqueueSPI(SercomTxn* txn); + bool startTransmissionSPI(void); + void deferStopSPI(SercomSpiError error); + SercomTxn* stopTransmissionSPI(void); + SercomTxn* stopTransmissionSPI(SercomSpiError error); + inline SercomTxn* getCurrentTxnSPI(void) { return _spi.currentTxn; } + inline const SercomTxn* getCurrentTxnSPI(void) const { return _spi.currentTxn; } + inline size_t getTxnIndexSPI(void) const { return _spi.index; } + inline size_t getTxnLengthSPI(void) const { return _spi.length; } + inline bool isActiveSPI(void) const { return _spi.active; } + inline void setTxnIndexSPI(size_t index) { _spi.index = index; } + inline void setReturnValueSPI(SercomSpiError err) { _spi.returnValue = err; } + inline bool sendDataSPI(void); + inline bool readDataSPI(void); /* ========== WIRE ========== */ - void initSlaveWIRE(uint8_t address, bool enableGeneralCall = false) ; + void initSlaveWIRE(uint8_t address, bool enableGeneralCall = false, uint8_t speed = 0x0) ; + void initSlaveWIRE(uint16_t address, bool enableGeneralCall = false, uint8_t speed = 0x0, bool enable10Bit = false) ; void initMasterWIRE(uint32_t baudrate) ; + inline void setTxnWIRE(SercomTxn* txn); + inline void setSlaveTxnWIRE(SercomTxn* txn); + inline bool isSlaveTransactionActiveWIRE(void) const { + return _wire.slaveTransactionActive; + } + inline void markSlaveTransactionActiveWIRE(void) { + _wire.slaveTransactionActive = true; + } + inline void discardIdleSlaveTransactionWIRE(void) { + if (!_wire.slaveTransactionActive && + _wire.currentTxn == _wire.slaveTxn) { + _wire.active = false; + _wire.currentTxn = nullptr; + _wire.txnIndex = 0; + _wire.txnLength = 0; + } + } + inline void setDmaWIRE(bool useDma) { _wire.useDma = useDma; } + inline bool isDmaWIRE(void) const { return _wire.useDma; } + inline void markBusReleasePendingWIRE(void) { _wire.releasePending = true; } + using WireReceiveCallback = void (*)(void* user); + using WireRequestCallback = void (*)(void* user); + void registerReceiveWIRE(WireReceiveCallback callback, void* user); + void registerRequestWIRE(WireRequestCallback callback, void* user); + void deferReceiveWIRE(void); + void deferRequestWIRE(void); + void deferReceiveCompleteWIRE(void); + SercomTxn* retireSlaveTransactionWIRE(bool reserveForFollowup); + void setSlaveWIRE( void ) ; + void setMasterWIRE( void ) ; 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); - uint32_t getSercomFreqRef(void); + void clearQueueWIRE( void ) ; + inline void enableWIRE( void ) ; + inline void disableWIRE( void ) { disableSERCOM(); } + void setBaudrateWIRE(uint32_t baudrate) ; + inline void prepareNackBitWIRE( void ) ; + inline void prepareAckBitWIRE( void ) ; + inline void prepareCommandBitsWIRE(uint8_t cmd) ; + inline void prepareSlaveCommandBitsWIRE(uint8_t cmd); + SercomTxn* startTransmissionWIRE( void ) ; + bool startTransmissionWIRE( uint8_t address, SercomWireReadWriteFlag flag ) = delete ; + SercomTxn* stopTransmissionWIRE( void ) ; + SercomTxn* stopTransmissionWIRE( SercomWireError error ) ; + bool enqueueWIRE(SercomTxn* txn); + inline bool canEnqueueWIRE(void) { return !_txnQueue.isFull(); } + bool abortWIRE(SercomWireError error = SercomWireError::MASTER_TIMEOUT); + inline bool isAbortPendingWIRE(void) const { return _wire.abortPending; } + bool serviceAbortWIRE(void); + void deferStopWIRE(SercomWireError error); + void deferBusErrorRecoveryWIRE(bool arbitrationLost, + bool commandReady); + SercomTxn* serviceBusErrorRecoveryWIRE(void); + + inline bool sendDataWIRE( void ) ; + inline bool isMasterWIRE( void ); + inline bool isSlaveWIRE( void ); + inline bool isBusIdleWIRE( void ); + inline bool isBusOwnerWIRE( void ); + inline bool isBusUnknownWIRE( void ); + inline bool isArbLostWIRE( void ); + inline bool isBusBusyWIRE( void ); + inline bool isDataReadyWIRE( void ); + inline bool isStopDetectedWIRE( void ); + inline bool isRestartDetectedWIRE( void ); + inline bool isAddressMatch( void ); + inline bool isMasterReadOperationWIRE( void ); + inline bool isRXNackReceivedWIRE( void ); + inline int availableWIRE( void ); + inline bool readDataWIRE( void ); + inline SercomTxn* getCurrentTxnWIRE(void) { return _wire.currentTxn; } + inline const SercomTxn* getCurrentTxnWIRE(void) const { return _wire.currentTxn; } + inline size_t getTxnIndexWIRE(void) const { return _wire.txnIndex; } + inline size_t getTxnLengthWIRE(void) const { return _wire.txnLength; } + inline bool isActiveWIRE(void) const { return _wire.active; } + inline const SercomWireCompletionReport& lastCompletionReportWIRE(void) const { + return _wire.lastCompletionReport; + } + + inline bool isDBGSTOP( void ) const; + inline void setDBGSTOP( bool stop ); +#if defined(__SAME53__) || defined(__SAME54__) + inline sercom_registers_t* getSercom() const { return sercom; } +#else + inline Sercom* getSercom() const { return sercom; } +#endif // __SAME53__ / __SAME54__ + int8_t getSercomIndex(void) ; + uint32_t getSercomFreqRef(void) ; + #if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) // SERCOM clock source override is only available on // SAMD51 (not 21) ... but these functions are declared @@ -252,17 +384,210 @@ class SERCOM 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; - uint32_t freqRef = 48000000ul; // Frequency corresponding to clockSource +#endif // SAMD51 vs 21 + + enum class Role : uint8_t { None = 0, UART, SPI, I2C }; + using ServiceFn = SercomTxn* (SERCOM::*)(); + + static bool claim(uint8_t sercomId, Role role); + static void release(uint8_t sercomId); + static bool registerService(uint8_t sercomId, ServiceFn fn); + static void setPending(uint8_t sercomId); + static void dispatchService(uint8_t sercomId, void *context); + static void dispatchPending(void); + + +#ifdef USE_ZERODMA + using DmaCallback = void (*)(Adafruit_ZeroDMA*); + enum class DmaStatus : uint8_t { + Ok = 0, + NotConfigured, + NullPtr, + ZeroLen, + AllocateFailed, + DescriptorFailed, + StartFailed + }; + + DmaStatus dmaInit(int8_t sercomId, uint8_t beatSize = 0); // beatSize: 0=byte (default), 1=halfword, 2=word + void dmaSetCallbacks(DmaCallback txCb, DmaCallback rxCb, + DmaCallback errorCb = nullptr); + DmaStatus dmaStartTx(const void* src, volatile void* dstReg, size_t len); + DmaStatus dmaStartRx(void* dst, volatile void* srcReg, size_t len); + DmaStatus dmaStartDuplex(const void* txSrc, void* rxDst, volatile void* txReg, volatile void* rxReg, size_t len, + const uint8_t* dummyTx = nullptr); + void dmaRelease(); + void dmaResetDescriptors(); + void dmaAbortTx(); + void dmaAbortRx(); + bool dmaTxBusy() const; + bool dmaRxBusy() const; + DmaStatus dmaLastError() const; + // DMA callbacks are protocol-owned (Wire/SPI/UART) and registered via dmaSetCallbacks(). + static inline SERCOM* findDmaOwner(Adafruit_ZeroDMA* dma, bool tx); + + // --- WIRE DMA callbacks (ISR-safe, PendSV-only completion) --- + static inline void dmaTxCallbackWIRE(Adafruit_ZeroDMA* dma); + static inline void dmaRxCallbackWIRE(Adafruit_ZeroDMA* dma); + static void dmaRxSuspendCallbackWIRE(Adafruit_ZeroDMA* dma); + static inline void dmaErrorCallbackWIRE(Adafruit_ZeroDMA* dma); + // --- SPI DMA callbacks (protocol-owned) --- + static inline void dmaTxCallbackSPI(Adafruit_ZeroDMA* dma); + static inline void dmaRxCallbackSPI(Adafruit_ZeroDMA* dma); + // --- UART DMA callbacks (protocol-owned) --- + static inline void dmaTxCallbackUART(Adafruit_ZeroDMA* dma); + static inline void dmaRxCallbackUART(Adafruit_ZeroDMA* dma); +#endif // USE_ZERODMA + +#ifdef SERCOM_STRICT_PADS + enum class PadFunc : uint8_t { + None = 0, + UartTx, + UartRx, + SpiMosi, + SpiMiso, + SpiSck, + SpiSs, + WireSda, + WireScl + }; + + static bool registerPads(uint8_t sercomId, const PadFunc (&pads)[4], bool muxFunctionD); + static void clearPads(uint8_t sercomId); +#endif // SERCOM_STRICT_PADS + + private: + bool startNextQueuedWIRE(void); +#if defined(__SAME53__) || defined(__SAME54__) + sercom_registers_t *sercom; +#else + Sercom *sercom; +#endif // __SAME53__ / __SAME54__ + uint32_t freqRef = 48000000ul; // Frequency corresponding to clockSource #if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) - SercomClockSource clockSource; -#endif - uint8_t calculateBaudrateSynchronous(uint32_t baudrate); + SercomClockSource clockSource; +#endif // __SAMD51__ / __SAME51__ || __SAME53__ / __SAME54__ + +#if defined(SERCOM_INST_NUM) && (SERCOM_INST_NUM > 0) + static constexpr size_t kSercomCount = SERCOM_INST_NUM; +#elif (defined(__SAME53__) || defined(__SAME54__)) && defined(SERCOM7_REGS) + static constexpr size_t kSercomCount = 8; +#elif (defined(__SAME53__) || defined(__SAME54__)) && defined(SERCOM5_REGS) + static constexpr size_t kSercomCount = 6; +#else + #pragma message("SERCOM_INST_NUM not defined; SERCOM support disabled.") + static constexpr size_t kSercomCount = 0; +#endif // SERCOM_INST_NUM / __SAME53__ / __SAME54__ + + struct SercomState { + Role role = Role::None; + ServiceFn service = nullptr; +#ifdef SERCOM_STRICT_PADS + PadFunc pads[4] = { PadFunc::None, PadFunc::None, PadFunc::None, PadFunc::None }; + bool padsConfigured = false; + bool muxFunctionD = false; +#endif // SERCOM_STRICT_PADS + }; + + static std::array s_states; + static std::array s_instances; + static volatile uint32_t s_pendingMask; + uint8_t calculateBaudrateSynchronous(uint32_t baudrate) ; uint32_t division(uint32_t dividend, uint32_t divisor) ; void initClockNVIC( void ) ; + void initWIRE(void) ; + + // Cached I2C master/slave configuration for fast role switching. + // This can be expanded to support additional configuration options + // as needed in the future. For now, it just provides default support + // for (hs) mode and DMA. + struct WireConfig { + uint32_t ctrla = 0x00000000; // default CTRLA value: auto ENABLE +#if defined(__SAME53__) || defined(__SAME54__) + uint32_t ctrlb = SERCOM_I2CM_CTRLB_SMEN_Msk; // default CTRLB value: SMEN +#else + uint32_t ctrlb = SERCOM_I2CM_CTRLB_SMEN; // default CTRLB value: SMEN +#endif // __SAME53__ / __SAME54__ + uint32_t baud = 0x000000FF; // default to lowest supported speed + uint32_t addr = 0x00000000; // default address no GCEN, no ADDRMASK, 7-bit address only + uint8_t masterSpeed = 0x0; // default to lowest speed + uint8_t slaveSpeed = 0x0; // default to lowest speed + bool inited = false; // whether initMaster/SlaveWIRE has been called + bool slaveConfigured = false; // return to slave mode after queued master work + bool useDma = false; // per-transaction DMA use for master/slave modes + bool active = false; // active transaction in progress + bool slaveTransactionActive = false; // AMATCH observed for cached slave descriptor + bool releasePending = false; // STOP requested; callback waits until OWNER clears + bool abortPending = false; // wait for MB/SB before issuing timeout STOP + bool busErrorRecoveryPending = false; + uint32_t busErrorRecoveryStartedUs = 0; + bool busErrorRecoveryDeadlineActive = false; + uint32_t busErrorRecoveryDeadlineStartedUs = 0; + bool busErrorRecoveryArbitrationLost = false; + bool busErrorRecoveryCommandReady = false; + SercomWireError abortError = SercomWireError::MASTER_TIMEOUT; + uint8_t retryCount = 0; // retry count for recoverable bus errors + SercomWireError returnValue = SercomWireError::SUCCESS; + SercomTxn* currentTxn = nullptr; + SercomTxn* slaveTxn = nullptr; + size_t txnIndex = 0; + size_t txnLength = 0; + size_t dmaBlockLength = 0; + SercomWireCompletionReport lastCompletionReport = {}; + } _wire; + + struct SpiConfig { + bool active = false; + bool useDma = false; + bool dmaNeedTx = false; + bool dmaNeedRx = false; + bool dmaTxDone = false; + bool dmaRxDone = false; + size_t index = 0; + size_t length = 0; + SercomTxn* currentTxn = nullptr; + SercomSpiError returnValue = SercomSpiError::SUCCESS; + } _spi; + + struct UartConfig { + bool active = false; + bool useDma = false; + bool dmaNeedTx = false; + bool dmaNeedRx = false; + bool dmaTxDone = false; + bool dmaRxDone = false; + size_t index = 0; + size_t length = 0; + SercomTxn* currentTxn = nullptr; + SercomUartError returnValue = SercomUartError::SUCCESS; + } _uart; + + RingBufferN _txnQueue; + void* _wireCallbackUser = nullptr; + WireReceiveCallback _wireReceiveCb = nullptr; + WireRequestCallback _wireRequestCb = nullptr; + bool _wireReceivePending = false; + bool _wireRequestPending = false; + +#ifdef USE_ZERODMA + Adafruit_ZeroDMA* _dmaTx = nullptr; + Adafruit_ZeroDMA* _dmaRx = nullptr; + DmacDescriptor* _dmaTxDesc = nullptr; + DmacDescriptor* _dmaRxDesc = nullptr; + DmaCallback _dmaTxCb = nullptr; + DmaCallback _dmaRxCb = nullptr; + DmaCallback _dmaErrorCb = nullptr; + uint8_t _dmaDummy = 0; + uint8_t _dmaTxTrigger = 0; + uint8_t _dmaRxTrigger = 0; + bool _dmaConfigured = false; + bool _dmaTxActive = false; + bool _dmaRxActive = false; + bool _wireRxSuspendPending = false; + DmaStatus _dmaLastError = DmaStatus::Ok; +#endif // USE_ZERODMA }; -#endif +#include "SERCOM_inline.h" + +#endif // !_SERCOM_CLASS_ diff --git a/cores/arduino/SERCOM_PinMux.h b/cores/arduino/SERCOM_PinMux.h new file mode 100644 index 000000000..8105757e9 --- /dev/null +++ b/cores/arduino/SERCOM_PinMux.h @@ -0,0 +1,39 @@ +#pragma once + +/** + * @file SERCOM_PinMux.h + * @brief SERCOM pin-route validation APIs. + * + * This header exposes small, shared declarations used by SPI/Wire to validate + * that variant-assigned pins can be routed to the selected SERCOM instance. + * + * @note Function definitions live in each library translation unit: + * - libraries/SPI/SPI.cpp + * - libraries/Wire/Wire.cpp + */ + +#include +#include + +/** @brief Shared helpers for validating SERCOM pin routing. */ +namespace sercomPinMux { + +/** + * @brief Check whether a variant pin can be used for I2C on a SERCOM instance. + * @param arduinoPin Arduino pin index into g_APinDescription. + * @param sercomIndex Zero-based SERCOM instance index. + * @return true if the pin has an I2C mapping for the requested SERCOM. + */ +bool wirePinValidForSercom(uint8_t arduinoPin, uint8_t sercomIndex); + +/** + * @brief Check whether a MOSI pin matches an SPI route for SERCOM+pad. + * @param arduinoPin Arduino pin index into g_APinDescription. + * @param sercomIndex Zero-based SERCOM instance index. + * @param mosiPad SERCOM MOSI pad index (0, 2, or 3 depending on TX pad mode). + * @return true if the pin supports the requested SERCOM/pad route. + */ +bool spiMosiPinValidForRoute(uint8_t arduinoPin, uint8_t sercomIndex, + uint8_t mosiPad); + +} // namespace sercomPinMux diff --git a/cores/arduino/SERCOM_Txn.h b/cores/arduino/SERCOM_Txn.h new file mode 100644 index 000000000..aec16dc66 --- /dev/null +++ b/cores/arduino/SERCOM_Txn.h @@ -0,0 +1,162 @@ +#ifndef _SERCOM_TXN_H_ +#define _SERCOM_TXN_H_ + +#include +#include + +// SercomTxn represents a single bus transaction that occupies one queue slot. +// For multi-phase operations (e.g., TMC2130 read phase1 then phase2, or is31fl3733 +// multi-frame sequences), callbacks can set chainNext=true to hold the queue slot +// across phases without dequeuing. This provides bus atomicity: the transaction +// remains active, preventing other queued transactions from interleaving. +// +// Example multi-phase flow: +// 1. allocateTxn() -> sets chainNext=false +// 2. Phase1: enqueueSPI(txn) -> txn occupies queue slot +// 3. Phase1 DMA completes -> onComplete() callback runs +// 4. Callback updates txPtr/rxPtr/length for phase2, sets chainNext=true +// 5. stopTransmissionSPI() sees chainNext, calls startTransmissionSPI() without dequeue +// 6. Phase2 DMA completes -> onComplete() callback runs +// 7. Callback clears chainNext (or callback already cleared it) +// 8. stopTransmissionSPI() dequeues txn, starts next queued transaction +// +// This design: +// - Avoids explicit claim/release calls (no NVIC priority dance) +// - Keeps atomicity logic in one place (the callback) +// - Allows other devices on different queue slots to proceed normally +// - Prevents queue-full failure during multi-phase chains (slot remains reserved) + +struct SercomTxn { + uint16_t config; // common + protocol-specific flags/fields + uint16_t address; // I2C addr, SPI CS/baud, UART RTS/CTS + size_t length; + const uint8_t* txPtr; + uint8_t* rxPtr; + void (*onComplete)(void* user, int status); + void* user; + bool chainNext; // callback sets true to continue transaction with updated context +}; + +// Mirrors WireDMA I2CError values for SERCOM-level reporting. +enum class SercomWireError : uint8_t +{ + SUCCESS = 0, // No error/operation successful/ACK received + DATA_TOO_LONG = 1, // Payload exceeds DMA buffer or queue slot + NACK_ON_ADDRESS = 2, // Target NACKed during address phase + NACK_ON_DATA = 3, // Target NACKed during data phase + OTHER = 4, // Generic catch-all + BUS_CONFLICT = 5, // Local transaction blocked by active bus use + QUEUE_FULL = 6, // No room in transaction queue + ARBITRATION_LOST = 7, // Lost multi-master arbitration (STATUS.ARBLOST) + BUS_ERROR = 8, // Misplaced START/STOP or illegal bus condition (STATUS.BUSERR) + BUS_STATE_UNKNOWN = 9, // BUSSTATE = 0b00 (unknown/idle state reported) + MASTER_TIMEOUT = 10, // Master timeout (STATUS.MEXTTOUT) + SLAVE_TIMEOUT = 11, // Slave timeout (STATUS.SEXTTOUT) + LENGTH_ERROR = 12, // LENERR when LEN/LENEN mismatch (STATUS.LENERR) + UNKNOWN_ERROR = 13, // Error flag set but no specific bit matched + DMA_ERROR = 14, // DMAC transfer/descriptor bus error + BUS_RELEASE_TIMEOUT = 15 // STOP issued but BUSSTATE did not return to IDLE +}; + +enum class SercomWireRole : uint8_t { + Master, + Slave, +}; + +enum class SercomWireBusDisposition : uint8_t { + Released, + LocalOwner, + OtherOwner, + Unknown, +}; + +enum class SercomWireDelivery : uint8_t { + None, + Partial, + Complete, + Ambiguous, +}; + +struct SercomWireCompletionReport { + SercomWireError error = SercomWireError::SUCCESS; + uint16_t address = 0; + uint16_t requestedLength = 0; + uint16_t transferredLength = 0; + SercomWireRole role = SercomWireRole::Master; + SercomWireBusDisposition bus = SercomWireBusDisposition::Unknown; + SercomWireDelivery delivery = SercomWireDelivery::Ambiguous; + bool read = false; +}; + +// SPI error reporting (async callbacks) +enum class SercomSpiError : uint8_t +{ + SUCCESS = 0, + BUF_OVERFLOW = 1, + UNKNOWN_ERROR = 2 +}; + +// UART error reporting (async callbacks) +enum class SercomUartError : uint8_t +{ + SUCCESS = 0, + UNKNOWN_ERROR = 1 +}; + +// I2C config flags and helpers +enum : uint16_t { + I2C_CFG_READ = 1u << 0, + I2C_CFG_STOP = 1u << 1, + I2C_CFG_CRC = 1u << 2, + I2C_CFG_10BIT = 1u << 3, + I2C_CFG_NODMA = 1u << 4, + I2C_CFG_REPLAY_SAFE = 1u << 5, +}; + +// I2C STATUS register error-clear masks (write to I2CM.STATUS or I2CS.STATUS) +// Master: LENERR|SEXTTOUT|MEXTTOUT|LOWTOUT|BUSSTATE_IDLE|ARBLOST|BUSERR +static constexpr uint16_t I2CM_STATUS_ERR_CLEAR = 0x753u; +// Slave: SEXTTOUT|LOWTOUT|COLL|BUSERR (preserves HS high-speed detection) +static constexpr uint16_t I2CS_STATUS_ERR_CLEAR = 0x243u; + +static inline uint16_t I2C_ADDR(uint16_t addr10) { return addr10 & 0x03FFu; } +static inline uint8_t I2C_ADDR7(uint16_t addr) { return (uint8_t)(addr & 0x7Fu); } + +// SPI config flags and helpers +enum : uint16_t { + SPI_CFG_READ = 1u << 0, + SPI_CFG_STOP = 1u << 1, + SPI_CFG_CRC = 1u << 2, + SPI_CFG_CPOL = 1u << 3, + SPI_CFG_CPHA = 1u << 4, + SPI_CFG_DORD = 1u << 5, + SPI_CFG_CHAR9 = 1u << 6, + SPI_CFG_CS_HOLD = 1u << 7, + SPI_CFG_DUMMY = 1u << 8, + SPI_CFG_TX_ONLY = 1u << 9, +}; + +static inline uint16_t SPI_ADDR_CS(uint8_t cs) { return (uint16_t)cs; } +static inline uint16_t SPI_ADDR_BAUD(uint8_t baud) { return (uint16_t)baud << 8; } +static inline uint8_t SPI_ADDR_GET_CS(uint16_t addr) { return (uint8_t)(addr & 0x00FFu); } +static inline uint8_t SPI_ADDR_GET_BAUD(uint16_t addr) { return (uint8_t)(addr >> 8); } + +// UART config flags and helpers +enum : uint16_t { + UART_CFG_READ = 1u << 0, + UART_CFG_STOP = 1u << 1, + UART_CFG_CRC = 1u << 2, + UART_CFG_BREAK = 1u << 3, + UART_CFG_MARK = 1u << 4, + UART_CFG_TX_ONLY = 1u << 5, + UART_CFG_RX_ONLY = 1u << 6, +}; + +static inline uint16_t UART_ADDR_RTS(uint8_t pin) { return (uint16_t)pin; } +static inline uint16_t UART_ADDR_CTS(uint8_t pin) { return (uint16_t)pin << 8; } +static inline uint8_t UART_ADDR_GET_RTS(uint16_t addr) { return (uint8_t)(addr & 0x00FFu); } +static inline uint8_t UART_ADDR_GET_CTS(uint16_t addr) { return (uint8_t)(addr >> 8); } + +static constexpr uint8_t SERCOM_PIN_NONE = 0xFFu; + +#endif diff --git a/cores/arduino/SERCOM_WireBusErrorPolicy.h b/cores/arduino/SERCOM_WireBusErrorPolicy.h new file mode 100644 index 000000000..ae465a40a --- /dev/null +++ b/cores/arduino/SERCOM_WireBusErrorPolicy.h @@ -0,0 +1,76 @@ +#ifndef SERCOM_WIRE_BUS_ERROR_POLICY_H +#define SERCOM_WIRE_BUS_ERROR_POLICY_H + +#include + +namespace simio { +namespace wire { + +enum class BusState : uint8_t { + Unknown = 0, + Idle = 1, + Owner = 2, + Busy = 3, +}; + +enum class BusErrorAction : uint8_t { + ClearSlaveWarning, + RestartQueueHead, + WaitForBusState, + WaitForArbitrationRelease, + WaitAtCommandPoint, + EstablishIdle, + ResetPeripheralAndRestart, + RetireAmbiguous, + RetireTerminal, +}; + +struct BusErrorContext { + bool master; + BusState busState; + bool arbitrationLost; + bool commandReady; + bool terminalCondition; + bool replayAllowed; + bool transactionActive; +}; + +constexpr BusErrorAction decideBusErrorAction(BusErrorContext context) { + return !context.master + ? BusErrorAction::ClearSlaveWarning + : !context.transactionActive || !context.replayAllowed + ? BusErrorAction::RetireAmbiguous + : context.terminalCondition + ? BusErrorAction::RetireTerminal + : context.busState == BusState::Busy || + context.busState == BusState::Idle + ? BusErrorAction::RestartQueueHead + : context.busState == BusState::Unknown + ? BusErrorAction::EstablishIdle + : context.arbitrationLost + ? BusErrorAction::WaitForArbitrationRelease + : context.commandReady ? BusErrorAction::WaitAtCommandPoint + : BusErrorAction::WaitForBusState; +} + +constexpr uint32_t kBusErrorRecoveryDeadlineUs = 100000u; + +constexpr bool busErrorDeadlineExpired(uint32_t startedUs, uint32_t nowUs, + bool active) { + return active && + static_cast(nowUs - startedUs) >= + kBusErrorRecoveryDeadlineUs; +} + +constexpr BusErrorAction decideBusErrorWaitAction(BusState busState, + bool timedOut) { + return busState == BusState::Busy || busState == BusState::Idle + ? BusErrorAction::RestartQueueHead + : timedOut ? BusErrorAction::ResetPeripheralAndRestart + : BusErrorAction::WaitForBusState; +} + +} // namespace wire +} // namespace simio + +#endif diff --git a/cores/arduino/SERCOM_inline.h b/cores/arduino/SERCOM_inline.h new file mode 100644 index 000000000..fcc6f3199 --- /dev/null +++ b/cores/arduino/SERCOM_inline.h @@ -0,0 +1,500 @@ +#ifndef SERCOM_INLINE_H +#define SERCOM_INLINE_H + +#ifdef __cplusplus + +inline void SERCOM::waitSyncBusyEnable( void ) +{ +#if defined(__SAME53__) || defined(__SAME54__) + while (sercom->I2CM.SERCOM_SYNCBUSY & SERCOM_I2CM_SYNCBUSY_ENABLE_Msk) ; +#else + while (sercom->I2CM.SYNCBUSY.bit.ENABLE != 0) ; +#endif // __SAME53__ / __SAME54__ +} + +inline void SERCOM::waitSyncBusySwrst( void ) +{ +#if defined(__SAME53__) || defined(__SAME54__) + while ((sercom->I2CM.SERCOM_CTRLA & SERCOM_I2CM_CTRLA_SWRST_Msk) || + (sercom->I2CM.SERCOM_SYNCBUSY & SERCOM_I2CM_SYNCBUSY_SWRST_Msk)) ; +#else + while (sercom->I2CM.CTRLA.bit.SWRST || sercom->I2CM.SYNCBUSY.bit.SWRST) ; +#endif // __SAME53__ / __SAME54__ +} + +inline void SERCOM::waitSyncBusySysOp( void ) +{ +#if defined(__SAME53__) || defined(__SAME54__) + while (sercom->I2CM.SERCOM_SYNCBUSY & SERCOM_I2CM_SYNCBUSY_SYSOP_Msk) ; +#else + while (sercom->I2CM.SYNCBUSY.bit.SYSOP != 0) ; +#endif // __SAME53__ / __SAME54__ +} + +inline void SERCOM::waitSyncBusyCtrlB( void ) +{ +#if defined(__SAME53__) || defined(__SAME54__) + while (sercom->SPIM.SERCOM_SYNCBUSY & SERCOM_SPIM_SYNCBUSY_CTRLB_Msk) ; +#else + while (sercom->SPI.SYNCBUSY.bit.CTRLB != 0) ; +#endif // __SAME53__ / __SAME54__ +} + +inline void SERCOM::enableSERCOM( void ) +{ + // UART, SPI, I2CS, and I2CM use the same enable bit +#if defined(__SAME53__) || defined(__SAME54__) + sercom->I2CM.SERCOM_CTRLA |= SERCOM_I2CM_CTRLA_ENABLE_Msk; +#else + sercom->I2CM.CTRLA.bit.ENABLE = 1; +#endif // __SAME53__ / __SAME54__ + waitSyncBusyEnable(); +} + +inline void SERCOM::disableSERCOM( void ) +{ + // UART, SPI, I2CS, and I2CM use the same enable bit +#if defined(__SAME53__) || defined(__SAME54__) + sercom->I2CM.SERCOM_CTRLA &= ~SERCOM_I2CM_CTRLA_ENABLE_Msk; +#else + sercom->I2CM.CTRLA.bit.ENABLE = 0; +#endif // __SAME53__ / __SAME54__ + waitSyncBusyEnable(); +} + +inline void SERCOM::enableWIRE( void ) +{ + enableSERCOM(); + + // Setting bus idle mode +#if defined(__SAME53__) || defined(__SAME54__) + sercom->I2CM.SERCOM_STATUS = + (sercom->I2CM.SERCOM_STATUS & ~SERCOM_I2CM_STATUS_BUSSTATE_Msk) | + SERCOM_I2CM_STATUS_BUSSTATE(WIRE_IDLE_STATE); +#else + sercom->I2CM.STATUS.bit.BUSSTATE = 1; +#endif // __SAME53__ / __SAME54__ + waitSyncBusySysOp(); +} + +inline void SERCOM::deferStopWIRE(SercomWireError error) +{ + _wire.returnValue = error; + setPending((uint8_t)getSercomIndex()); +} + +inline bool SERCOM::sendDataWIRE( void ) +{ + SercomTxn* txn = _wire.currentTxn; + if (txn == nullptr || txn->txPtr == nullptr) return false; + +#ifdef USE_ZERODMA + if (isDmaWIRE()) { + DmaStatus value = DmaStatus::StartFailed; + if (!_dmaTxActive && !_dmaRxActive) { + const size_t remaining = _wire.txnLength - _wire.txnIndex; + _wire.dmaBlockLength = + isSlaveWIRE() && remaining > 255u ? 255u : remaining; +#if defined(__SAME53__) || defined(__SAME54__) + value = dmaStartTx(txn->txPtr + _wire.txnIndex, + &sercom->I2CM.SERCOM_DATA, + _wire.dmaBlockLength); +#else + value = dmaStartTx(txn->txPtr + _wire.txnIndex, + &sercom->I2CM.DATA.reg, + _wire.dmaBlockLength); +#endif // __SAME53__ / __SAME54__ + } + return value == DmaStatus::Ok; + } +#endif // USE_ZERODMA + + // Wait for DATA to sync out of the ISR and clear MB +#if defined(__SAME53__) || defined(__SAME54__) + sercom->I2CM.SERCOM_DATA = txn->txPtr[_wire.txnIndex++]; +#else + sercom->I2CM.DATA.reg = txn->txPtr[_wire.txnIndex++]; +#endif // __SAME53__ / __SAME54__ + + // Return false when the last byte has been consumed so the caller can + // issue STOP / complete the transaction without waiting for another SB. + return (_wire.txnIndex < _wire.txnLength); +} + +inline void SERCOM::prepareCommandBitsWIRE(uint8_t cmd) +{ + if (isMasterWIRE() && cmd == WIRE_MASTER_ACT_STOP) + markBusReleasePendingWIRE(); +#if defined(__SAME53__) || defined(__SAME54__) + sercom->I2CM.SERCOM_CTRLB = + (sercom->I2CM.SERCOM_CTRLB & ~SERCOM_I2CM_CTRLB_CMD_Msk) | + SERCOM_I2CM_CTRLB_CMD(cmd); +#else + sercom->I2CM.CTRLB.bit.CMD = cmd; +#endif // __SAME53__ / __SAME54__ + if (isMasterWIRE()) + waitSyncBusySysOp(); +} + +inline void SERCOM::prepareSlaveCommandBitsWIRE(uint8_t cmd) +{ +#if defined(__SAME53__) || defined(__SAME54__) + sercom->I2CS.SERCOM_CTRLB = + (sercom->I2CS.SERCOM_CTRLB & ~SERCOM_I2CS_CTRLB_CMD_Msk) | + SERCOM_I2CS_CTRLB_CMD(cmd); +#else + sercom->I2CS.CTRLB.bit.CMD = cmd; +#endif // __SAME53__ / __SAME54__ +} + +inline bool SERCOM::readDataWIRE( void ) +{ + SercomTxn* txn = _wire.currentTxn; + if (txn == nullptr || txn->rxPtr == nullptr) return false; + +#ifdef USE_ZERODMA + if (isDmaWIRE()) { + DmaStatus value = DmaStatus::StartFailed; + if (!_dmaRxActive && !_dmaTxActive) { + const size_t remaining = _wire.txnLength - _wire.txnIndex; + _wire.dmaBlockLength = + isSlaveWIRE() && remaining > 255u ? 255u : remaining; +#if defined(__SAME53__) || defined(__SAME54__) + value = dmaStartRx(txn->rxPtr + _wire.txnIndex, + &sercom->I2CM.SERCOM_DATA, + _wire.dmaBlockLength); +#else + value = dmaStartRx(txn->rxPtr + _wire.txnIndex, + &sercom->I2CM.DATA.reg, + _wire.dmaBlockLength); +#endif // __SAME53__ / __SAME54__ + } + return value == DmaStatus::Ok; + } +#endif // USE_ZERODMA + + bool isMaster = isMasterWIRE(); + + if (isMaster) { + if (_wire.txnIndex == (_wire.txnLength - 1)) { + uint8_t cmd = txn->config & I2C_CFG_STOP ? WIRE_MASTER_ACT_STOP : WIRE_MASTER_ACT_NO_ACTION; + if (cmd == WIRE_MASTER_ACT_STOP) + markBusReleasePendingWIRE(); +#if defined(__SAME53__) || defined(__SAME54__) + sercom->I2CM.SERCOM_CTRLB = + sercom->I2CM.SERCOM_CTRLB | + SERCOM_I2CM_CTRLB_ACKACT_Msk | + SERCOM_I2CM_CTRLB_CMD(cmd); +#else + sercom->I2CM.CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT | SERCOM_I2CM_CTRLB_CMD(cmd); // NACK the last byte and send STOP if requested +#endif // __SAME53__ / __SAME54__ + } + else + prepareAckBitWIRE(); // ACK bytes otherwise for non-SCLSM mode + } + else { + // Slave mode: set ACKACT BEFORE reading DATA (SMEN auto-receives based on ACKACT) + if (_wire.txnIndex >= _wire.txnLength) + prepareNackBitWIRE(); // NACK if buffer full + else + prepareAckBitWIRE(); // ACK if room available + } + + // Read DATA register (accesses auto-trigger bus operation based on ACKACT/SMEN) +#if defined(__SAME53__) || defined(__SAME54__) + txn->rxPtr[_wire.txnIndex++] = sercom->I2CM.SERCOM_DATA; +#else + txn->rxPtr[_wire.txnIndex++] = sercom->I2CM.DATA.reg; +#endif // __SAME53__ / __SAME54__ + + return (_wire.txnIndex < _wire.txnLength); +} + +inline bool SERCOM::sendDataSPI(void) +{ + SercomTxn* txn = _spi.currentTxn; + if (txn == nullptr || txn->txPtr == nullptr) return false; + +#ifdef USE_ZERODMA + if (_spi.useDma) { + DmaStatus value = DmaStatus::StartFailed; + if (!_dmaTxActive && !_dmaRxActive) +#if defined(__SAME53__) || defined(__SAME54__) + value = dmaStartTx(txn->txPtr, &sercom->SPIM.SERCOM_DATA, _spi.length); +#else + value = dmaStartTx(txn->txPtr, &sercom->SPI.DATA.reg, _spi.length); +#endif // __SAME53__ / __SAME54__ + return value == DmaStatus::Ok; + } +#endif // USE_ZERODMA + + // Byte-by-byte: Write DATA register +#if defined(__SAME53__) || defined(__SAME54__) + sercom->SPIM.SERCOM_DATA = txn->txPtr[_spi.index++]; +#else + sercom->SPI.DATA.bit.DATA = txn->txPtr[_spi.index++]; +#endif // __SAME53__ / __SAME54__ + + // Return false when last byte consumed so caller can complete transaction + return (_spi.index < _spi.length); +} + +inline bool SERCOM::readDataSPI(void) +{ + SercomTxn* txn = _spi.currentTxn; + if (txn == nullptr || txn->rxPtr == nullptr) return false; + +#ifdef USE_ZERODMA + if (_spi.useDma) { + DmaStatus value = DmaStatus::StartFailed; + if (!_dmaRxActive && !_dmaTxActive) +#if defined(__SAME53__) || defined(__SAME54__) + value = dmaStartRx(txn->rxPtr, &sercom->SPIM.SERCOM_DATA, _spi.length); +#else + value = dmaStartRx(txn->rxPtr, &sercom->SPI.DATA.reg, _spi.length); +#endif // __SAME53__ / __SAME54__ + return value == DmaStatus::Ok; + } +#endif // USE_ZERODMA + + // Byte-by-byte: Read DATA register +#if defined(__SAME53__) || defined(__SAME54__) + txn->rxPtr[_spi.index - 1] = sercom->SPIM.SERCOM_DATA; +#else + txn->rxPtr[_spi.index - 1] = sercom->SPI.DATA.bit.DATA; +#endif // __SAME53__ / __SAME54__ + + // Return false when all bytes consumed + return (_spi.index < _spi.length); +} + +inline void SERCOM::setTxnWIRE(SercomTxn* txn) +{ + _wire.currentTxn = txn; + _wire.txnIndex = 0; + _wire.dmaBlockLength = 0; + _wire.returnValue = SercomWireError::SUCCESS; + + if (txn) + _wire.txnLength = txn->length; +#ifdef USE_ZERODMA +#if defined(__SAME53__) || defined(__SAME54__) + const bool sclsm = + (sercom->I2CM.SERCOM_CTRLA & SERCOM_I2CM_CTRLA_SCLSM_Msk) != 0; +#else + const bool sclsm = sercom->I2CM.CTRLA.bit.SCLSM; +#endif // __SAME53__ / __SAME54__ + const size_t length = txn ? txn->length : 0u; + const bool dmaEligible = length > 0u; + setDmaWIRE(dmaEligible); + (void)sclsm; +#else + _wire.useDma = false; + +#if defined(__SAME53__) || defined(__SAME54__) + if (sercom->I2CM.SERCOM_CTRLA & SERCOM_I2CM_CTRLA_SCLSM_Msk) +#else + if (sercom->I2CM.CTRLA.bit.SCLSM) +#endif // __SAME53__ / __SAME54__ + _wire.returnValue = SercomWireError::DATA_TOO_LONG; +#endif // USE_ZERODMA + if (!_wire.active) + _wire.retryCount = 0; + + _wire.active = true; +} + +inline void SERCOM::setSlaveTxnWIRE(SercomTxn* txn) +{ + _wire.slaveTxn = txn; + if (isSlaveWIRE() && !_wire.active) + setTxnWIRE(txn); +} + +#if defined(__SAME53__) || defined(__SAME54__) + +inline void SERCOM::prepareNackBitWIRE( void ) { sercom->I2CM.SERCOM_CTRLB |= SERCOM_I2CM_CTRLB_ACKACT_Msk; } +inline void SERCOM::prepareAckBitWIRE( void ) { sercom->I2CM.SERCOM_CTRLB &= ~SERCOM_I2CM_CTRLB_ACKACT_Msk; } +inline bool SERCOM::isMasterWIRE( void ) { return (sercom->I2CM.SERCOM_CTRLA & SERCOM_I2CM_CTRLA_MODE_Msk) == SERCOM_I2CM_CTRLA_MODE_I2C_MASTER; } +inline bool SERCOM::isSlaveWIRE( void ) { return (sercom->I2CS.SERCOM_CTRLA & SERCOM_I2CS_CTRLA_MODE_Msk) == SERCOM_I2CS_CTRLA_MODE_I2C_SLAVE; } +inline bool SERCOM::isBusIdleWIRE( void ) { return ((sercom->I2CM.SERCOM_STATUS & SERCOM_I2CM_STATUS_BUSSTATE_Msk) >> SERCOM_I2CM_STATUS_BUSSTATE_Pos) == WIRE_IDLE_STATE; } +inline bool SERCOM::isBusOwnerWIRE( void ) { return ((sercom->I2CM.SERCOM_STATUS & SERCOM_I2CM_STATUS_BUSSTATE_Msk) >> SERCOM_I2CM_STATUS_BUSSTATE_Pos) == WIRE_OWNER_STATE; } +inline bool SERCOM::isBusUnknownWIRE( void ) { return ((sercom->I2CM.SERCOM_STATUS & SERCOM_I2CM_STATUS_BUSSTATE_Msk) >> SERCOM_I2CM_STATUS_BUSSTATE_Pos) == WIRE_UNKNOWN_STATE; } +inline bool SERCOM::isArbLostWIRE( void ) { return (sercom->I2CM.SERCOM_STATUS & SERCOM_I2CM_STATUS_ARBLOST_Msk) != 0; } +inline bool SERCOM::isBusBusyWIRE( void ) { return ((sercom->I2CM.SERCOM_STATUS & SERCOM_I2CM_STATUS_BUSSTATE_Msk) >> SERCOM_I2CM_STATUS_BUSSTATE_Pos) == WIRE_BUSY_STATE; } +inline bool SERCOM::isDataReadyWIRE( void ) { return (sercom->I2CS.SERCOM_INTFLAG & SERCOM_I2CS_INTFLAG_DRDY_Msk) != 0; } +inline bool SERCOM::isStopDetectedWIRE( void ) { return (sercom->I2CS.SERCOM_INTFLAG & SERCOM_I2CS_INTFLAG_PREC_Msk) != 0; } +inline bool SERCOM::isRestartDetectedWIRE( void ) { return (sercom->I2CS.SERCOM_STATUS & SERCOM_I2CS_STATUS_SR_Msk) != 0; } +inline bool SERCOM::isAddressMatch( void ) { return (sercom->I2CS.SERCOM_INTFLAG & SERCOM_I2CS_INTFLAG_AMATCH_Msk) != 0; } +inline bool SERCOM::isMasterReadOperationWIRE( void ) { return (sercom->I2CS.SERCOM_STATUS & SERCOM_I2CS_STATUS_DIR_Msk) != 0; } +inline bool SERCOM::isRXNackReceivedWIRE( void ) { return (sercom->I2CM.SERCOM_STATUS & SERCOM_I2CM_STATUS_RXNACK_Msk) != 0; } +inline int SERCOM::availableWIRE( void ) { return isMasterWIRE() ? ((sercom->I2CM.SERCOM_INTFLAG & SERCOM_I2CM_INTFLAG_SB_Msk) != 0) : ((sercom->I2CS.SERCOM_INTFLAG & SERCOM_I2CS_INTFLAG_DRDY_Msk) != 0); } +inline bool SERCOM::isDBGSTOP( void ) const { return (sercom->I2CM.SERCOM_DBGCTRL & SERCOM_I2CM_DBGCTRL_DBGSTOP_Msk) != 0; } +inline void SERCOM::setDBGSTOP( bool stop ) { if (stop) sercom->I2CM.SERCOM_DBGCTRL |= SERCOM_I2CM_DBGCTRL_DBGSTOP_Msk; else sercom->I2CM.SERCOM_DBGCTRL &= ~SERCOM_I2CM_DBGCTRL_DBGSTOP_Msk; } + +#else + +inline void SERCOM::prepareNackBitWIRE( void ) { sercom->I2CM.CTRLB.bit.ACKACT = 1; } +inline void SERCOM::prepareAckBitWIRE( void ) { sercom->I2CM.CTRLB.bit.ACKACT = 0; } +inline bool SERCOM::isMasterWIRE( void ) { return sercom->I2CM.CTRLA.bit.MODE == I2C_MASTER_OPERATION; } +inline bool SERCOM::isSlaveWIRE( void ) { return sercom->I2CS.CTRLA.bit.MODE == I2C_SLAVE_OPERATION; } +inline bool SERCOM::isBusIdleWIRE( void ) { return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_IDLE_STATE; } +inline bool SERCOM::isBusOwnerWIRE( void ) { return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_OWNER_STATE; } +inline bool SERCOM::isBusUnknownWIRE( void ) { return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_UNKNOWN_STATE; } +inline bool SERCOM::isArbLostWIRE( void ) { return sercom->I2CM.STATUS.bit.ARBLOST == 1; } +inline bool SERCOM::isBusBusyWIRE( void ) { return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_BUSY_STATE; } +inline bool SERCOM::isDataReadyWIRE( void ) { return sercom->I2CS.INTFLAG.bit.DRDY; } +inline bool SERCOM::isStopDetectedWIRE( void ) { return sercom->I2CS.INTFLAG.bit.PREC; } +inline bool SERCOM::isRestartDetectedWIRE( void ) { return sercom->I2CS.STATUS.bit.SR; } +inline bool SERCOM::isAddressMatch( void ) { return sercom->I2CS.INTFLAG.bit.AMATCH; } +inline bool SERCOM::isMasterReadOperationWIRE( void ) { return sercom->I2CS.STATUS.bit.DIR; } +inline bool SERCOM::isRXNackReceivedWIRE( void ) { return sercom->I2CM.STATUS.bit.RXNACK; } +inline int SERCOM::availableWIRE( void ) { return isMasterWIRE() ? sercom->I2CM.INTFLAG.bit.SB : sercom->I2CS.INTFLAG.bit.DRDY; } +inline bool SERCOM::isDBGSTOP( void ) const { return sercom->I2CM.DBGCTRL.bit.DBGSTOP; } +inline void SERCOM::setDBGSTOP( bool stop ) { sercom->I2CM.DBGCTRL.bit.DBGSTOP = stop; } + +#endif // __SAME53__ / __SAME54__ + +#ifdef USE_ZERODMA +inline SERCOM* SERCOM::findDmaOwner(Adafruit_ZeroDMA* dma, bool tx) +{ + if (dma == nullptr) return nullptr; + + for (size_t i = 0; i < kSercomCount; ++i) + { + SERCOM* inst = s_instances[i]; + if (inst == nullptr) + continue; + if (tx) + { + if (inst->_dmaTx == dma) + return inst; + } + else + { + if (inst->_dmaRx == dma) + return inst; + } + } + + return nullptr; +} + +inline void SERCOM::dmaTxCallbackWIRE(Adafruit_ZeroDMA* dma) +{ + SERCOM* inst = findDmaOwner(dma, true); + if (!inst) return; + if (!inst->_wire.active || inst->_wire.currentTxn == nullptr || + !inst->_wire.useDma) return; + + // When using ADDR.LENEN mode, the hardware automatically generates STOP + // after ADDR.LEN bytes are transferred (datasheet §28.6.4.1.2). + // If the slave NACKs a master-write transaction before ADDR.LEN bytes, STOP + // is generated automatically and STATUS.LENERR is raised with INTFLAG.ERROR. + + inst->_dmaTxActive = false; + if (inst->isSlaveWIRE()) { + inst->_wire.txnIndex += inst->_wire.dmaBlockLength; + if (inst->_wire.txnIndex < inst->_wire.txnLength) { + if (!inst->sendDataWIRE()) + inst->abortWIRE(SercomWireError::DMA_ERROR); + } + } else { + inst->_wire.txnIndex = inst->_wire.txnLength; + inst->deferStopWIRE(SercomWireError::SUCCESS); + } +} + +inline void SERCOM::dmaRxCallbackWIRE(Adafruit_ZeroDMA* dma) +{ + SERCOM* inst = findDmaOwner(dma, false); + if (!inst) return; + if (!inst->_wire.active || inst->_wire.currentTxn == nullptr || + !inst->_wire.useDma) return; + + // When using ADDR.LENEN mode, the hardware automatically generates NACK+STOP + // after ADDR.LEN bytes are transferred (datasheet §28.6.4.1.2). + // Do NOT issue a manual STOP command - it conflicts with the automatic sequence. + // The STOP is generated by hardware, not by software CMD write. + + inst->_dmaRxActive = false; + // Transfer-complete and suspend can become pending together at an exact + // descriptor boundary. Completion owns retirement in that case; do not let + // the abandoned suspend intent suppress suspension of the next RX phase. + inst->_wireRxSuspendPending = false; + inst->_wire.txnIndex += inst->_wire.dmaBlockLength; + if (inst->isSlaveWIRE() && + inst->_wire.txnIndex < inst->_wire.txnLength) { + if (!inst->readDataWIRE()) + inst->abortWIRE(SercomWireError::DMA_ERROR); + } else { + inst->deferStopWIRE(SercomWireError::SUCCESS); + } +} + +inline void SERCOM::dmaErrorCallbackWIRE(Adafruit_ZeroDMA* dma) +{ + SERCOM* inst = findDmaOwner(dma, true); + if (!inst) + inst = findDmaOwner(dma, false); + if (!inst) return; + if (!inst->_wire.active || inst->_wire.currentTxn == nullptr || + !inst->_wire.useDma) return; + + inst->dmaAbortTx(); + inst->dmaAbortRx(); + inst->abortWIRE(SercomWireError::DMA_ERROR); +} + +inline void SERCOM::dmaTxCallbackSPI(Adafruit_ZeroDMA* dma) +{ + SERCOM* inst = findDmaOwner(dma, true); + if (!inst) return; + inst->_spi.dmaTxDone = true; + if (inst->_spi.dmaNeedRx && !inst->_spi.dmaRxDone) + return; + inst->_dmaTxActive = false; + inst->_spi.returnValue = SercomSpiError::SUCCESS; + SERCOM::setPending((uint8_t)inst->getSercomIndex()); +} + +inline void SERCOM::dmaRxCallbackSPI(Adafruit_ZeroDMA* dma) +{ + SERCOM* inst = findDmaOwner(dma, false); + if (!inst) return; + inst->_spi.dmaRxDone = true; + if (inst->_spi.dmaNeedTx && !inst->_spi.dmaTxDone) + return; + inst->_dmaRxActive = false; + inst->_spi.returnValue = SercomSpiError::SUCCESS; + SERCOM::setPending((uint8_t)inst->getSercomIndex()); +} + +inline void SERCOM::dmaTxCallbackUART(Adafruit_ZeroDMA* dma) +{ + SERCOM* inst = findDmaOwner(dma, true); + if (!inst) return; + inst->_uart.dmaTxDone = true; + if (inst->_uart.dmaNeedRx && !inst->_uart.dmaRxDone) + return; + inst->_dmaTxActive = false; + inst->_uart.returnValue = SercomUartError::SUCCESS; + SERCOM::setPending((uint8_t)inst->getSercomIndex()); +} + +inline void SERCOM::dmaRxCallbackUART(Adafruit_ZeroDMA* dma) +{ + SERCOM* inst = findDmaOwner(dma, false); + if (!inst) return; + inst->_uart.dmaRxDone = true; + if (inst->_uart.dmaNeedTx && !inst->_uart.dmaTxDone) + return; + inst->_dmaRxActive = false; + inst->_uart.returnValue = SercomUartError::SUCCESS; + SERCOM::setPending((uint8_t)inst->getSercomIndex()); +} +#endif // USE_ZERODMA + +#endif // __cplusplus + +#endif // SERCOM_INLINE_H diff --git a/cores/arduino/SercomPinMux.inc b/cores/arduino/SercomPinMux.inc new file mode 100644 index 000000000..98a7daa24 --- /dev/null +++ b/cores/arduino/SercomPinMux.inc @@ -0,0 +1,735 @@ +// Auto-generated from SAMD21/SAMD51 device tables. Do not edit manually. +// Define SERCOM_PINMUX_EMIT_I2C and/or SERCOM_PINMUX_EMIT_SPI before including. + +#ifndef SAMD21E_SERIES +#define SAMD21E_SERIES (defined(__ATSAMD21E15A__) || defined(__ATSAMD21E15B__) || defined(__ATSAMD21E15C__) || defined(__ATSAMD21E15L__) || defined(__SAMD21E15A__) || defined(__SAMD21E15B__) || defined(__SAMD21E15C__) || defined(__SAMD21E15L__) || \ + defined(__ATSAMD21E16A__) || defined(__ATSAMD21E16B__) || defined(__ATSAMD21E16C__) || defined(__ATSAMD21E16L__) || defined(__SAMD21E16A__) || defined(__SAMD21E16B__) || defined(__SAMD21E16C__) || defined(__SAMD21E16L__) || \ + defined(__ATSAMD21E17A__) || defined(__ATSAMD21E17D__) || defined(__ATSAMD21E17L__) || defined(__SAMD21E17A__) || defined(__SAMD21E17D__) || defined(__SAMD21E17L__) || \ + defined(__ATSAMD21E18A__) || defined(__SAMD21E18A__)) +#endif // SAMD21E_SERIES + +#ifndef SAMD21G_SERIES +#define SAMD21G_SERIES (defined(__ATSAMD21G15A__) || defined(__ATSAMD21G15B__) || defined(__SAMD21G15A__) || defined(__SAMD21G15B__) || \ + defined(__ATSAMD21G16A__) || defined(__ATSAMD21G16B__) || defined(__ATSAMD21G16L__) || defined(__SAMD21G16A__) || defined(__SAMD21G16B__) || defined(__SAMD21G16L__) || \ + defined(__ATSAMD21G17A__) || defined(__ATSAMD21G17D__) || defined(__ATSAMD21G17L__) || defined(__SAMD21G17A__) || defined(__SAMD21G17D__) || defined(__SAMD21G17L__) || \ + defined(__ATSAMD21G18A__) || defined(__SAMD21G18A__)) +#endif // SAMD21G_SERIES + +#ifndef SAMD21J_SERIES +#define SAMD21J_SERIES (defined(__ATSAMD21J15A__) || defined(__ATSAMD21J15B__) || defined(__SAMD21J15A__) || defined(__SAMD21J15B__) || \ + defined(__ATSAMD21J16A__) || defined(__ATSAMD21J16B__) || defined(__SAMD21J16A__) || defined(__SAMD21J16B__) || \ + defined(__ATSAMD21J17A__) || defined(__ATSAMD21J17D__) || defined(__SAMD21J17A__) || defined(__SAMD21J17D__) || \ + defined(__ATSAMD21J18A__) || defined(__SAMD21J18A__)) +#endif // SAMD21J_SERIES + +#ifndef SAMDA1_SERIES +#define SAMDA1_SERIES (defined(__ATSAMDA1E14B__) || defined(__ATSAMDA1G14B__) || defined(__ATSAMDA1J14B__) || defined(__SAMDA1E14B__) || defined(__SAMDA1G14B__) || defined(__SAMDA1J14B__) || \ + defined(__ATSAMDA1E15B__) || defined(__ATSAMDA1G15B__) || defined(__ATSAMDA1J15B__) || defined(__SAMDA1E15B__) || defined(__SAMDA1G15B__) || defined(__SAMDA1J15B__) || \ + defined(__ATSAMDA1E16B__) || defined(__ATSAMDA1G16B__) || defined(__ATSAMDA1J16B__) || defined(__SAMDA1E16B__) || defined(__SAMDA1G16B__) || defined(__SAMDA1J16B__)) +#endif // SAMDA1_SERIES + +#ifndef SAMD51_120_SERIES +#define SAMD51_120_SERIES (defined(__ATSAMD51P19A__) || defined(__ATSAMD51P20A__) || defined(__SAMD51P19A__) || defined(__SAMD51P20A__)) +#endif // SAMD51_120_SERIES + +#ifndef SAMD51_SERIES +#define SAMD51_SERIES (defined(__ATSAMD51G18A__) || defined(__ATSAMD51G19A__) || defined(__SAMD51G18A__) || defined(__SAMD51G19A__) || \ + defined(__ATSAMD51J18A__) || defined(__ATSAMD51J19A__) || defined(__ATSAMD51J20A__) || defined(__SAMD51J18A__) || defined(__SAMD51J19A__) || defined(__SAMD51J20A__) || \ + defined(__ATSAMD51N19A__) || defined(__ATSAMD51N20A__) || defined(__SAMD51N19A__) || defined(__SAMD51N20A__)) +#endif // SAMD51_SERIES + +#ifndef SAME51_SERIES +#define SAME51_SERIES (defined(__ATSAME51G18A__) || defined(__ATSAME51G19A__) || defined(__SAME51G18A__) || defined(__SAME51G19A__) || \ + defined(__ATSAME51J18A__) || defined(__ATSAME51J19A__) || defined(__ATSAME51J20A__) || defined(__SAME51J18A__) || defined(__SAME51J19A__) || defined(__SAME51J20A__) || \ + defined(__ATSAME51N19A__) || defined(__ATSAME51N20A__) || defined(__SAME51N19A__) || defined(__SAME51N20A__)) +#endif // SAME51_SERIES + +#ifndef SAME53_SERIES +#define SAME53_SERIES (defined(__ATSAME53J18A__) || defined(__ATSAME53J19A__) || defined(__ATSAME53J20A__) || defined(__SAME53J18A__) || defined(__SAME53J19A__) || defined(__SAME53J20A__) || \ + defined(__ATSAME53N19A__) || defined(__ATSAME53N20A__) || defined(__SAME53N19A__) || defined(__SAME53N20A__)) +#endif // SAME53_SERIES + +#ifndef SAME54_SERIES +#define SAME54_SERIES (defined(__ATSAME54N19A__) || defined(__ATSAME54N20A__) || defined(__SAME54N19A__) || defined(__SAME54N20A__)) +#endif // SAME54_SERIES + +#ifndef SAME54_120_SERIES +#define SAME54_120_SERIES (defined(__ATSAME54P19A__) || defined(__ATSAME54P20A__) || defined(__SAME54P19A__) || defined(__SAME54P20A__)) +#endif // SAME54_120_SERIES + +#if !defined(__SAMD51__) && !defined(__SAME51__) && !defined(__SAME53__) && !defined(__SAME54__) +#if !(SAMD21E_SERIES || SAMD21G_SERIES || SAMD21J_SERIES || SAMDA1_SERIES) +#define SAMD21E_SERIES 1 +#endif // !(SAMD21E_SERIES || SAMD21G_SERIES || SAMD21J_SERIES || SAMDA1_SERIES) +#endif // !__SAMD51__ / __SAME51__ && !__SAME53__ / __SAME54__ +#if defined(__SAMD51__) || defined(__SAME51__) +#if !(SAMD51_SERIES || SAMD51_120_SERIES || SAME51_SERIES) +#define SAMD51_SERIES 1 +#endif // !(SAMD51_SERIES || SAMD51_120_SERIES || SAME51_SERIES) +#endif // __SAMD51__ / __SAME51__ +#if defined(__SAME53__) || defined(__SAME54__) +#if !(SAME53_SERIES || SAME54_SERIES || SAME54_120_SERIES) +#define SAME54_SERIES 1 +#endif // !(SAME53_SERIES || SAME54_SERIES || SAME54_120_SERIES) +#endif // __SAME53__ / __SAME54__ + +#if defined(SERCOM_PINMUX_EMIT_I2C) +#if SAMD21E_SERIES || SAMDA1_SERIES +SERCOM_I2C_PIN('A', 8, 0, 0, 2, 0) +SERCOM_I2C_PIN('A', 9, 0, 1, 2, 1) +SERCOM_I2C_PIN('A', 16, 1, 0, 3, 0) +SERCOM_I2C_PIN('A', 17, 1, 1, 3, 1) +SERCOM_I2C_PIN('A', 22, 3, 0, 5, 0) +SERCOM_I2C_PIN('A', 23, 3, 1, 5, 1) +#endif // SAMD21E_SERIES || SAMDA1_SERIES + +#if SAMD21G_SERIES +SERCOM_I2C_PIN('A', 8, 0, 0, 2, 0) +SERCOM_I2C_PIN('A', 9, 0, 1, 2, 1) +SERCOM_I2C_PIN('A', 12, 2, 0, 4, 0) +SERCOM_I2C_PIN('A', 13, 2, 1, 4, 1) +SERCOM_I2C_PIN('A', 16, 1, 0, 3, 0) +SERCOM_I2C_PIN('A', 17, 1, 1, 3, 1) +SERCOM_I2C_PIN('A', 22, 3, 0, 5, 0) +SERCOM_I2C_PIN('A', 23, 3, 1, 5, 1) +#endif // SAMD21G_SERIES + +#if SAMD21J_SERIES +SERCOM_I2C_PIN('A', 8, 0, 0, 2, 0) +SERCOM_I2C_PIN('A', 9, 0, 1, 2, 1) +SERCOM_I2C_PIN('A', 12, 2, 0, 4, 0) +SERCOM_I2C_PIN('A', 13, 2, 1, 4, 1) +SERCOM_I2C_PIN('A', 16, 1, 0, 3, 0) +SERCOM_I2C_PIN('A', 17, 1, 1, 3, 1) +SERCOM_I2C_PIN('A', 22, 3, 0, 5, 0) +SERCOM_I2C_PIN('A', 23, 3, 1, 5, 1) +SERCOM_I2C_PIN('B', 12, 4, 0, 255, 255) +SERCOM_I2C_PIN('B', 13, 4, 1, 255, 255) +SERCOM_I2C_PIN('B', 16, 5, 0, 255, 255) +SERCOM_I2C_PIN('B', 17, 5, 1, 255, 255) +SERCOM_I2C_PIN('B', 30, 255, 255, 5, 0) +SERCOM_I2C_PIN('B', 31, 255, 255, 5, 1) +#endif // SAMD21J_SERIES + +#if SAMD51_120_SERIES || SAME54_120_SERIES +SERCOM_I2C_PIN('A', 8, 0, 0, 2, 1) +SERCOM_I2C_PIN('A', 9, 0, 1, 2, 0) +SERCOM_I2C_PIN('A', 12, 2, 0, 4, 1) +SERCOM_I2C_PIN('A', 13, 2, 1, 4, 0) +SERCOM_I2C_PIN('A', 16, 1, 0, 3, 1) +SERCOM_I2C_PIN('A', 17, 1, 1, 3, 0) +SERCOM_I2C_PIN('A', 22, 3, 0, 5, 1) +SERCOM_I2C_PIN('A', 23, 3, 1, 5, 0) +SERCOM_I2C_PIN('D', 8, 7, 0, 6, 1) +SERCOM_I2C_PIN('D', 9, 7, 1, 6, 0) +#endif // SAMD51_120_SERIES || SAME54_120_SERIES + +#if SAMD51_SERIES || SAME51_SERIES || SAME53_SERIES || SAME54_SERIES +SERCOM_I2C_PIN('A', 8, 0, 0, 2, 1) +SERCOM_I2C_PIN('A', 9, 0, 1, 2, 0) +SERCOM_I2C_PIN('A', 12, 2, 0, 4, 1) +SERCOM_I2C_PIN('A', 13, 2, 1, 4, 0) +SERCOM_I2C_PIN('A', 16, 1, 0, 3, 1) +SERCOM_I2C_PIN('A', 17, 1, 1, 3, 0) +SERCOM_I2C_PIN('A', 22, 3, 0, 5, 1) +SERCOM_I2C_PIN('A', 23, 3, 1, 5, 0) +#endif // SAMD51_SERIES || SAME51_SERIES || SAME53_SERIES || SAME54_SERIES + +#endif // SERCOM_PINMUX_EMIT_I2C + +#if defined(SERCOM_PINMUX_EMIT_SPI) +#if SAMD21E_SERIES +SERCOM_SPI_PIN('A', 0, 255, 255, 1, 0) +SERCOM_SPI_PIN('A', 4, 255, 255, 0, 0) +SERCOM_SPI_PIN('A', 6, 255, 255, 0, 2) +SERCOM_SPI_PIN('A', 7, 255, 255, 0, 3) +SERCOM_SPI_PIN('A', 8, 0, 0, 2, 0) +SERCOM_SPI_PIN('A', 10, 0, 2, 2, 2) +SERCOM_SPI_PIN('A', 11, 0, 3, 2, 3) +SERCOM_SPI_PIN('A', 12, 2, 0, 4, 0) +SERCOM_SPI_PIN('A', 14, 2, 2, 4, 2) +SERCOM_SPI_PIN('A', 15, 2, 3, 4, 3) +SERCOM_SPI_PIN('A', 16, 1, 0, 3, 0) +SERCOM_SPI_PIN('A', 18, 1, 2, 3, 2) +SERCOM_SPI_PIN('A', 19, 1, 3, 3, 3) +SERCOM_SPI_PIN('A', 20, 5, 2, 3, 2) +SERCOM_SPI_PIN('A', 21, 5, 3, 3, 3) +SERCOM_SPI_PIN('A', 22, 3, 0, 5, 0) +SERCOM_SPI_PIN('A', 24, 3, 2, 5, 2) +SERCOM_SPI_PIN('A', 25, 3, 3, 5, 3) +SERCOM_SPI_PIN('A', 30, 255, 255, 1, 2) +SERCOM_SPI_PIN('A', 31, 255, 255, 1, 3) +SERCOM_SPI_PIN('B', 0, 255, 255, 5, 2) +SERCOM_SPI_PIN('B', 1, 255, 255, 5, 3) +SERCOM_SPI_PIN('B', 2, 255, 255, 5, 0) +SERCOM_SPI_PIN('B', 8, 255, 255, 4, 0) +SERCOM_SPI_PIN('B', 10, 255, 255, 4, 2) +SERCOM_SPI_PIN('B', 11, 255, 255, 4, 3) +SERCOM_SPI_PIN('B', 12, 4, 0, 255, 255) +SERCOM_SPI_PIN('B', 14, 4, 2, 255, 255) +SERCOM_SPI_PIN('B', 15, 4, 3, 255, 255) +SERCOM_SPI_PIN('B', 16, 5, 0, 255, 255) +SERCOM_SPI_PIN('B', 22, 255, 255, 5, 2) +SERCOM_SPI_PIN('B', 23, 255, 255, 5, 3) +SERCOM_SPI_PIN('B', 30, 255, 255, 5, 0) +#endif // SAMD21E_SERIES + +#if SAMD21G_SERIES +SERCOM_SPI_PIN('A', 0, 255, 255, 1, 0) +SERCOM_SPI_PIN('A', 4, 255, 255, 0, 0) +SERCOM_SPI_PIN('A', 6, 255, 255, 0, 2) +SERCOM_SPI_PIN('A', 7, 255, 255, 0, 3) +SERCOM_SPI_PIN('A', 8, 0, 0, 2, 0) +SERCOM_SPI_PIN('A', 10, 0, 2, 2, 2) +SERCOM_SPI_PIN('A', 11, 0, 3, 2, 3) +SERCOM_SPI_PIN('A', 12, 2, 0, 4, 0) +SERCOM_SPI_PIN('A', 14, 2, 2, 4, 2) +SERCOM_SPI_PIN('A', 15, 2, 3, 4, 3) +SERCOM_SPI_PIN('A', 16, 1, 0, 3, 0) +SERCOM_SPI_PIN('A', 18, 1, 2, 3, 2) +SERCOM_SPI_PIN('A', 19, 1, 3, 3, 3) +SERCOM_SPI_PIN('A', 20, 5, 2, 3, 2) +SERCOM_SPI_PIN('A', 21, 5, 3, 3, 3) +SERCOM_SPI_PIN('A', 22, 3, 0, 5, 0) +SERCOM_SPI_PIN('A', 24, 3, 2, 5, 2) +SERCOM_SPI_PIN('A', 25, 3, 3, 5, 3) +SERCOM_SPI_PIN('A', 30, 255, 255, 1, 2) +SERCOM_SPI_PIN('A', 31, 255, 255, 1, 3) +SERCOM_SPI_PIN('B', 0, 255, 255, 5, 2) +SERCOM_SPI_PIN('B', 1, 255, 255, 5, 3) +SERCOM_SPI_PIN('B', 2, 255, 255, 5, 0) +SERCOM_SPI_PIN('B', 8, 255, 255, 4, 0) +SERCOM_SPI_PIN('B', 10, 255, 255, 4, 2) +SERCOM_SPI_PIN('B', 11, 255, 255, 4, 3) +SERCOM_SPI_PIN('B', 12, 4, 0, 255, 255) +SERCOM_SPI_PIN('B', 14, 4, 2, 255, 255) +SERCOM_SPI_PIN('B', 15, 4, 3, 255, 255) +SERCOM_SPI_PIN('B', 16, 5, 0, 255, 255) +SERCOM_SPI_PIN('B', 22, 255, 255, 5, 2) +SERCOM_SPI_PIN('B', 23, 255, 255, 5, 3) +SERCOM_SPI_PIN('B', 30, 255, 255, 5, 0) +#endif // SAMD21G_SERIES + +#if SAMD21J_SERIES +SERCOM_SPI_PIN('A', 0, 255, 255, 1, 0) +SERCOM_SPI_PIN('A', 4, 255, 255, 0, 0) +SERCOM_SPI_PIN('A', 6, 255, 255, 0, 2) +SERCOM_SPI_PIN('A', 7, 255, 255, 0, 3) +SERCOM_SPI_PIN('A', 8, 0, 0, 2, 0) +SERCOM_SPI_PIN('A', 10, 0, 2, 2, 2) +SERCOM_SPI_PIN('A', 11, 0, 3, 2, 3) +SERCOM_SPI_PIN('A', 12, 2, 0, 4, 0) +SERCOM_SPI_PIN('A', 14, 2, 2, 4, 2) +SERCOM_SPI_PIN('A', 15, 2, 3, 4, 3) +SERCOM_SPI_PIN('A', 16, 1, 0, 3, 0) +SERCOM_SPI_PIN('A', 18, 1, 2, 3, 2) +SERCOM_SPI_PIN('A', 19, 1, 3, 3, 3) +SERCOM_SPI_PIN('A', 20, 5, 2, 3, 2) +SERCOM_SPI_PIN('A', 21, 5, 3, 3, 3) +SERCOM_SPI_PIN('A', 22, 3, 0, 5, 0) +SERCOM_SPI_PIN('A', 24, 3, 2, 5, 2) +SERCOM_SPI_PIN('A', 25, 3, 3, 5, 3) +SERCOM_SPI_PIN('A', 30, 255, 255, 1, 2) +SERCOM_SPI_PIN('A', 31, 255, 255, 1, 3) +SERCOM_SPI_PIN('B', 0, 255, 255, 5, 2) +SERCOM_SPI_PIN('B', 1, 255, 255, 5, 3) +SERCOM_SPI_PIN('B', 2, 255, 255, 5, 0) +SERCOM_SPI_PIN('B', 8, 255, 255, 4, 0) +SERCOM_SPI_PIN('B', 10, 255, 255, 4, 2) +SERCOM_SPI_PIN('B', 11, 255, 255, 4, 3) +SERCOM_SPI_PIN('B', 12, 4, 0, 255, 255) +SERCOM_SPI_PIN('B', 14, 4, 2, 255, 255) +SERCOM_SPI_PIN('B', 15, 4, 3, 255, 255) +SERCOM_SPI_PIN('B', 16, 5, 0, 255, 255) +SERCOM_SPI_PIN('B', 22, 255, 255, 5, 2) +SERCOM_SPI_PIN('B', 23, 255, 255, 5, 3) +SERCOM_SPI_PIN('B', 30, 255, 255, 5, 0) +#endif // SAMD21J_SERIES + +#if SAMDA1_SERIES +SERCOM_SPI_PIN('A', 0, 255, 255, 1, 0) +SERCOM_SPI_PIN('A', 4, 255, 255, 0, 0) +SERCOM_SPI_PIN('A', 6, 255, 255, 0, 2) +SERCOM_SPI_PIN('A', 7, 255, 255, 0, 3) +SERCOM_SPI_PIN('A', 8, 0, 0, 2, 0) +SERCOM_SPI_PIN('A', 10, 0, 2, 2, 2) +SERCOM_SPI_PIN('A', 11, 0, 3, 2, 3) +SERCOM_SPI_PIN('A', 12, 2, 0, 4, 0) +SERCOM_SPI_PIN('A', 14, 2, 2, 4, 2) +SERCOM_SPI_PIN('A', 15, 2, 3, 4, 3) +SERCOM_SPI_PIN('A', 16, 1, 0, 3, 0) +SERCOM_SPI_PIN('A', 18, 1, 2, 3, 2) +SERCOM_SPI_PIN('A', 19, 1, 3, 3, 3) +SERCOM_SPI_PIN('A', 20, 5, 2, 3, 2) +SERCOM_SPI_PIN('A', 21, 5, 3, 3, 3) +SERCOM_SPI_PIN('A', 22, 3, 0, 5, 0) +SERCOM_SPI_PIN('A', 24, 3, 2, 5, 2) +SERCOM_SPI_PIN('A', 25, 3, 3, 5, 3) +SERCOM_SPI_PIN('A', 30, 255, 255, 1, 2) +SERCOM_SPI_PIN('A', 31, 255, 255, 1, 3) +SERCOM_SPI_PIN('B', 0, 255, 255, 5, 2) +SERCOM_SPI_PIN('B', 1, 255, 255, 5, 3) +SERCOM_SPI_PIN('B', 2, 255, 255, 5, 0) +SERCOM_SPI_PIN('B', 8, 255, 255, 4, 0) +SERCOM_SPI_PIN('B', 10, 255, 255, 4, 2) +SERCOM_SPI_PIN('B', 11, 255, 255, 4, 3) +SERCOM_SPI_PIN('B', 12, 4, 0, 255, 255) +SERCOM_SPI_PIN('B', 14, 4, 2, 255, 255) +SERCOM_SPI_PIN('B', 15, 4, 3, 255, 255) +SERCOM_SPI_PIN('B', 16, 5, 0, 255, 255) +SERCOM_SPI_PIN('B', 22, 255, 255, 5, 2) +SERCOM_SPI_PIN('B', 23, 255, 255, 5, 3) +SERCOM_SPI_PIN('B', 30, 255, 255, 5, 0) +#endif // SAMDA1_SERIES + +#if SAMD51_120_SERIES +SERCOM_SPI_PIN('A', 0, 255, 255, 1, 0) +SERCOM_SPI_PIN('A', 4, 255, 255, 0, 0) +SERCOM_SPI_PIN('A', 6, 255, 255, 0, 2) +SERCOM_SPI_PIN('A', 7, 255, 255, 0, 3) +SERCOM_SPI_PIN('A', 8, 0, 0, 2, 1) +SERCOM_SPI_PIN('A', 9, 0, 1, 2, 0) +SERCOM_SPI_PIN('A', 10, 0, 2, 2, 2) +SERCOM_SPI_PIN('A', 11, 0, 3, 2, 3) +SERCOM_SPI_PIN('A', 12, 2, 0, 4, 1) +SERCOM_SPI_PIN('A', 13, 2, 1, 4, 0) +SERCOM_SPI_PIN('A', 14, 2, 2, 4, 2) +SERCOM_SPI_PIN('A', 15, 2, 3, 4, 3) +SERCOM_SPI_PIN('A', 16, 1, 0, 3, 1) +SERCOM_SPI_PIN('A', 17, 1, 1, 3, 0) +SERCOM_SPI_PIN('A', 18, 1, 2, 3, 2) +SERCOM_SPI_PIN('A', 19, 1, 3, 3, 3) +SERCOM_SPI_PIN('A', 20, 5, 2, 3, 2) +SERCOM_SPI_PIN('A', 21, 5, 3, 3, 3) +SERCOM_SPI_PIN('A', 22, 3, 0, 5, 1) +SERCOM_SPI_PIN('A', 23, 3, 1, 5, 0) +SERCOM_SPI_PIN('A', 24, 3, 2, 5, 2) +SERCOM_SPI_PIN('A', 25, 3, 3, 5, 3) +SERCOM_SPI_PIN('A', 30, 7, 2, 1, 2) +SERCOM_SPI_PIN('A', 31, 7, 3, 1, 3) +SERCOM_SPI_PIN('B', 0, 255, 255, 5, 2) +SERCOM_SPI_PIN('B', 1, 255, 255, 5, 3) +SERCOM_SPI_PIN('B', 2, 255, 255, 5, 0) +SERCOM_SPI_PIN('B', 8, 255, 255, 4, 0) +SERCOM_SPI_PIN('B', 10, 255, 255, 4, 2) +SERCOM_SPI_PIN('B', 11, 255, 255, 4, 3) +SERCOM_SPI_PIN('B', 12, 4, 0, 255, 255) +SERCOM_SPI_PIN('B', 14, 4, 2, 255, 255) +SERCOM_SPI_PIN('B', 15, 4, 3, 255, 255) +SERCOM_SPI_PIN('B', 16, 5, 0, 255, 255) +SERCOM_SPI_PIN('B', 18, 5, 2, 7, 2) +SERCOM_SPI_PIN('B', 19, 5, 3, 7, 3) +SERCOM_SPI_PIN('B', 20, 3, 0, 7, 1) +SERCOM_SPI_PIN('B', 21, 3, 1, 7, 0) +SERCOM_SPI_PIN('B', 22, 1, 2, 5, 2) +SERCOM_SPI_PIN('B', 23, 1, 3, 5, 3) +SERCOM_SPI_PIN('B', 24, 0, 0, 2, 1) +SERCOM_SPI_PIN('B', 25, 0, 1, 2, 0) +SERCOM_SPI_PIN('B', 26, 2, 0, 4, 1) +SERCOM_SPI_PIN('B', 27, 2, 1, 4, 0) +SERCOM_SPI_PIN('B', 28, 2, 2, 4, 2) +SERCOM_SPI_PIN('B', 29, 2, 3, 4, 3) +SERCOM_SPI_PIN('B', 30, 7, 0, 5, 1) +SERCOM_SPI_PIN('B', 31, 7, 1, 5, 0) +SERCOM_SPI_PIN('C', 4, 6, 0, 255, 255) +SERCOM_SPI_PIN('C', 6, 6, 2, 255, 255) +SERCOM_SPI_PIN('C', 7, 6, 3, 255, 255) +SERCOM_SPI_PIN('C', 10, 6, 2, 7, 2) +SERCOM_SPI_PIN('C', 11, 6, 3, 7, 3) +SERCOM_SPI_PIN('C', 12, 7, 0, 6, 1) +SERCOM_SPI_PIN('C', 13, 7, 1, 6, 0) +SERCOM_SPI_PIN('C', 14, 7, 2, 6, 2) +SERCOM_SPI_PIN('C', 15, 7, 3, 6, 3) +SERCOM_SPI_PIN('C', 16, 6, 0, 0, 1) +SERCOM_SPI_PIN('C', 17, 6, 1, 0, 0) +SERCOM_SPI_PIN('C', 18, 6, 2, 0, 2) +SERCOM_SPI_PIN('C', 19, 6, 3, 0, 3) +SERCOM_SPI_PIN('C', 22, 1, 0, 3, 1) +SERCOM_SPI_PIN('C', 23, 1, 1, 3, 0) +SERCOM_SPI_PIN('C', 24, 0, 2, 2, 2) +SERCOM_SPI_PIN('C', 25, 0, 3, 2, 3) +SERCOM_SPI_PIN('C', 27, 1, 0, 255, 255) +SERCOM_SPI_PIN('D', 8, 7, 0, 6, 1) +SERCOM_SPI_PIN('D', 9, 7, 1, 6, 0) +SERCOM_SPI_PIN('D', 10, 7, 2, 6, 2) +SERCOM_SPI_PIN('D', 11, 7, 3, 6, 3) +SERCOM_SPI_PIN('D', 20, 1, 2, 3, 2) +SERCOM_SPI_PIN('D', 21, 1, 3, 3, 3) +#endif // SAMD51_120_SERIES + +#if SAMD51_SERIES +SERCOM_SPI_PIN('A', 0, 255, 255, 1, 0) +SERCOM_SPI_PIN('A', 4, 255, 255, 0, 0) +SERCOM_SPI_PIN('A', 6, 255, 255, 0, 2) +SERCOM_SPI_PIN('A', 7, 255, 255, 0, 3) +SERCOM_SPI_PIN('A', 8, 0, 0, 2, 1) +SERCOM_SPI_PIN('A', 9, 0, 1, 2, 0) +SERCOM_SPI_PIN('A', 10, 0, 2, 2, 2) +SERCOM_SPI_PIN('A', 11, 0, 3, 2, 3) +SERCOM_SPI_PIN('A', 12, 2, 0, 4, 1) +SERCOM_SPI_PIN('A', 13, 2, 1, 4, 0) +SERCOM_SPI_PIN('A', 14, 2, 2, 4, 2) +SERCOM_SPI_PIN('A', 15, 2, 3, 4, 3) +SERCOM_SPI_PIN('A', 16, 1, 0, 3, 1) +SERCOM_SPI_PIN('A', 17, 1, 1, 3, 0) +SERCOM_SPI_PIN('A', 18, 1, 2, 3, 2) +SERCOM_SPI_PIN('A', 19, 1, 3, 3, 3) +SERCOM_SPI_PIN('A', 20, 5, 2, 3, 2) +SERCOM_SPI_PIN('A', 21, 5, 3, 3, 3) +SERCOM_SPI_PIN('A', 22, 3, 0, 5, 1) +SERCOM_SPI_PIN('A', 23, 3, 1, 5, 0) +SERCOM_SPI_PIN('A', 24, 3, 2, 5, 2) +SERCOM_SPI_PIN('A', 25, 3, 3, 5, 3) +SERCOM_SPI_PIN('A', 30, 7, 2, 1, 2) +SERCOM_SPI_PIN('A', 31, 7, 3, 1, 3) +SERCOM_SPI_PIN('B', 0, 255, 255, 5, 2) +SERCOM_SPI_PIN('B', 1, 255, 255, 5, 3) +SERCOM_SPI_PIN('B', 2, 255, 255, 5, 0) +SERCOM_SPI_PIN('B', 8, 255, 255, 4, 0) +SERCOM_SPI_PIN('B', 10, 255, 255, 4, 2) +SERCOM_SPI_PIN('B', 11, 255, 255, 4, 3) +SERCOM_SPI_PIN('B', 12, 4, 0, 255, 255) +SERCOM_SPI_PIN('B', 14, 4, 2, 255, 255) +SERCOM_SPI_PIN('B', 15, 4, 3, 255, 255) +SERCOM_SPI_PIN('B', 16, 5, 0, 255, 255) +SERCOM_SPI_PIN('B', 18, 5, 2, 7, 2) +SERCOM_SPI_PIN('B', 19, 5, 3, 7, 3) +SERCOM_SPI_PIN('B', 20, 3, 0, 7, 1) +SERCOM_SPI_PIN('B', 21, 3, 1, 7, 0) +SERCOM_SPI_PIN('B', 22, 1, 2, 5, 2) +SERCOM_SPI_PIN('B', 23, 1, 3, 5, 3) +SERCOM_SPI_PIN('B', 24, 0, 0, 2, 1) +SERCOM_SPI_PIN('B', 25, 0, 1, 2, 0) +SERCOM_SPI_PIN('B', 26, 2, 0, 4, 1) +SERCOM_SPI_PIN('B', 27, 2, 1, 4, 0) +SERCOM_SPI_PIN('B', 28, 2, 2, 4, 2) +SERCOM_SPI_PIN('B', 29, 2, 3, 4, 3) +SERCOM_SPI_PIN('B', 30, 7, 0, 5, 1) +SERCOM_SPI_PIN('B', 31, 7, 1, 5, 0) +SERCOM_SPI_PIN('C', 4, 6, 0, 255, 255) +SERCOM_SPI_PIN('C', 6, 6, 2, 255, 255) +SERCOM_SPI_PIN('C', 7, 6, 3, 255, 255) +SERCOM_SPI_PIN('C', 10, 6, 2, 7, 2) +SERCOM_SPI_PIN('C', 11, 6, 3, 7, 3) +SERCOM_SPI_PIN('C', 12, 7, 0, 6, 1) +SERCOM_SPI_PIN('C', 13, 7, 1, 6, 0) +SERCOM_SPI_PIN('C', 14, 7, 2, 6, 2) +SERCOM_SPI_PIN('C', 15, 7, 3, 6, 3) +SERCOM_SPI_PIN('C', 16, 6, 0, 0, 1) +SERCOM_SPI_PIN('C', 17, 6, 1, 0, 0) +SERCOM_SPI_PIN('C', 18, 6, 2, 0, 2) +SERCOM_SPI_PIN('C', 19, 6, 3, 0, 3) +SERCOM_SPI_PIN('C', 22, 1, 0, 3, 1) +SERCOM_SPI_PIN('C', 23, 1, 1, 3, 0) +SERCOM_SPI_PIN('C', 24, 0, 2, 2, 2) +SERCOM_SPI_PIN('C', 25, 0, 3, 2, 3) +SERCOM_SPI_PIN('C', 27, 1, 0, 255, 255) +SERCOM_SPI_PIN('D', 8, 7, 0, 6, 1) +SERCOM_SPI_PIN('D', 9, 7, 1, 6, 0) +SERCOM_SPI_PIN('D', 10, 7, 2, 6, 2) +SERCOM_SPI_PIN('D', 11, 7, 3, 6, 3) +SERCOM_SPI_PIN('D', 20, 1, 2, 3, 2) +SERCOM_SPI_PIN('D', 21, 1, 3, 3, 3) +#endif // SAMD51_SERIES + +#if SAME51_SERIES +SERCOM_SPI_PIN('A', 0, 255, 255, 1, 0) +SERCOM_SPI_PIN('A', 4, 255, 255, 0, 0) +SERCOM_SPI_PIN('A', 6, 255, 255, 0, 2) +SERCOM_SPI_PIN('A', 7, 255, 255, 0, 3) +SERCOM_SPI_PIN('A', 8, 0, 0, 2, 1) +SERCOM_SPI_PIN('A', 9, 0, 1, 2, 0) +SERCOM_SPI_PIN('A', 10, 0, 2, 2, 2) +SERCOM_SPI_PIN('A', 11, 0, 3, 2, 3) +SERCOM_SPI_PIN('A', 12, 2, 0, 4, 1) +SERCOM_SPI_PIN('A', 13, 2, 1, 4, 0) +SERCOM_SPI_PIN('A', 14, 2, 2, 4, 2) +SERCOM_SPI_PIN('A', 15, 2, 3, 4, 3) +SERCOM_SPI_PIN('A', 16, 1, 0, 3, 1) +SERCOM_SPI_PIN('A', 17, 1, 1, 3, 0) +SERCOM_SPI_PIN('A', 18, 1, 2, 3, 2) +SERCOM_SPI_PIN('A', 19, 1, 3, 3, 3) +SERCOM_SPI_PIN('A', 20, 5, 2, 3, 2) +SERCOM_SPI_PIN('A', 21, 5, 3, 3, 3) +SERCOM_SPI_PIN('A', 22, 3, 0, 5, 1) +SERCOM_SPI_PIN('A', 23, 3, 1, 5, 0) +SERCOM_SPI_PIN('A', 24, 3, 2, 5, 2) +SERCOM_SPI_PIN('A', 25, 3, 3, 5, 3) +SERCOM_SPI_PIN('A', 30, 7, 2, 1, 2) +SERCOM_SPI_PIN('A', 31, 7, 3, 1, 3) +SERCOM_SPI_PIN('B', 0, 255, 255, 5, 2) +SERCOM_SPI_PIN('B', 1, 255, 255, 5, 3) +SERCOM_SPI_PIN('B', 2, 255, 255, 5, 0) +SERCOM_SPI_PIN('B', 8, 255, 255, 4, 0) +SERCOM_SPI_PIN('B', 10, 255, 255, 4, 2) +SERCOM_SPI_PIN('B', 11, 255, 255, 4, 3) +SERCOM_SPI_PIN('B', 12, 4, 0, 255, 255) +SERCOM_SPI_PIN('B', 14, 4, 2, 255, 255) +SERCOM_SPI_PIN('B', 15, 4, 3, 255, 255) +SERCOM_SPI_PIN('B', 16, 5, 0, 255, 255) +SERCOM_SPI_PIN('B', 18, 5, 2, 7, 2) +SERCOM_SPI_PIN('B', 19, 5, 3, 7, 3) +SERCOM_SPI_PIN('B', 20, 3, 0, 7, 1) +SERCOM_SPI_PIN('B', 21, 3, 1, 7, 0) +SERCOM_SPI_PIN('B', 22, 1, 2, 5, 2) +SERCOM_SPI_PIN('B', 23, 1, 3, 5, 3) +SERCOM_SPI_PIN('B', 24, 0, 0, 2, 1) +SERCOM_SPI_PIN('B', 25, 0, 1, 2, 0) +SERCOM_SPI_PIN('B', 26, 2, 0, 4, 1) +SERCOM_SPI_PIN('B', 27, 2, 1, 4, 0) +SERCOM_SPI_PIN('B', 28, 2, 2, 4, 2) +SERCOM_SPI_PIN('B', 29, 2, 3, 4, 3) +SERCOM_SPI_PIN('B', 30, 7, 0, 5, 1) +SERCOM_SPI_PIN('B', 31, 7, 1, 5, 0) +SERCOM_SPI_PIN('C', 4, 6, 0, 255, 255) +SERCOM_SPI_PIN('C', 6, 6, 2, 255, 255) +SERCOM_SPI_PIN('C', 7, 6, 3, 255, 255) +SERCOM_SPI_PIN('C', 10, 6, 2, 7, 2) +SERCOM_SPI_PIN('C', 11, 6, 3, 7, 3) +SERCOM_SPI_PIN('C', 12, 7, 0, 6, 1) +SERCOM_SPI_PIN('C', 13, 7, 1, 6, 0) +SERCOM_SPI_PIN('C', 14, 7, 2, 6, 2) +SERCOM_SPI_PIN('C', 15, 7, 3, 6, 3) +SERCOM_SPI_PIN('C', 16, 6, 0, 0, 1) +SERCOM_SPI_PIN('C', 17, 6, 1, 0, 0) +SERCOM_SPI_PIN('C', 18, 6, 2, 0, 2) +SERCOM_SPI_PIN('C', 19, 6, 3, 0, 3) +SERCOM_SPI_PIN('C', 22, 1, 0, 3, 1) +SERCOM_SPI_PIN('C', 23, 1, 1, 3, 0) +SERCOM_SPI_PIN('C', 24, 0, 2, 2, 2) +SERCOM_SPI_PIN('C', 25, 0, 3, 2, 3) +SERCOM_SPI_PIN('C', 27, 1, 0, 255, 255) +SERCOM_SPI_PIN('D', 8, 7, 0, 6, 1) +SERCOM_SPI_PIN('D', 9, 7, 1, 6, 0) +SERCOM_SPI_PIN('D', 10, 7, 2, 6, 2) +SERCOM_SPI_PIN('D', 11, 7, 3, 6, 3) +SERCOM_SPI_PIN('D', 20, 1, 2, 3, 2) +SERCOM_SPI_PIN('D', 21, 1, 3, 3, 3) +#endif // SAME51_SERIES + +#if SAME53_SERIES +SERCOM_SPI_PIN('A', 0, 255, 255, 1, 0) +SERCOM_SPI_PIN('A', 4, 255, 255, 0, 0) +SERCOM_SPI_PIN('A', 6, 255, 255, 0, 2) +SERCOM_SPI_PIN('A', 7, 255, 255, 0, 3) +SERCOM_SPI_PIN('A', 8, 0, 0, 2, 1) +SERCOM_SPI_PIN('A', 9, 0, 1, 2, 0) +SERCOM_SPI_PIN('A', 10, 0, 2, 2, 2) +SERCOM_SPI_PIN('A', 11, 0, 3, 2, 3) +SERCOM_SPI_PIN('A', 12, 2, 0, 4, 1) +SERCOM_SPI_PIN('A', 13, 2, 1, 4, 0) +SERCOM_SPI_PIN('A', 14, 2, 2, 4, 2) +SERCOM_SPI_PIN('A', 15, 2, 3, 4, 3) +SERCOM_SPI_PIN('A', 16, 1, 0, 3, 1) +SERCOM_SPI_PIN('A', 17, 1, 1, 3, 0) +SERCOM_SPI_PIN('A', 18, 1, 2, 3, 2) +SERCOM_SPI_PIN('A', 19, 1, 3, 3, 3) +SERCOM_SPI_PIN('A', 20, 5, 2, 3, 2) +SERCOM_SPI_PIN('A', 21, 5, 3, 3, 3) +SERCOM_SPI_PIN('A', 22, 3, 0, 5, 1) +SERCOM_SPI_PIN('A', 23, 3, 1, 5, 0) +SERCOM_SPI_PIN('A', 24, 3, 2, 5, 2) +SERCOM_SPI_PIN('A', 25, 3, 3, 5, 3) +SERCOM_SPI_PIN('A', 30, 7, 2, 1, 2) +SERCOM_SPI_PIN('A', 31, 7, 3, 1, 3) +SERCOM_SPI_PIN('B', 0, 255, 255, 5, 2) +SERCOM_SPI_PIN('B', 1, 255, 255, 5, 3) +SERCOM_SPI_PIN('B', 2, 255, 255, 5, 0) +SERCOM_SPI_PIN('B', 8, 255, 255, 4, 0) +SERCOM_SPI_PIN('B', 10, 255, 255, 4, 2) +SERCOM_SPI_PIN('B', 11, 255, 255, 4, 3) +SERCOM_SPI_PIN('B', 12, 4, 0, 255, 255) +SERCOM_SPI_PIN('B', 14, 4, 2, 255, 255) +SERCOM_SPI_PIN('B', 15, 4, 3, 255, 255) +SERCOM_SPI_PIN('B', 16, 5, 0, 255, 255) +SERCOM_SPI_PIN('B', 18, 5, 2, 7, 2) +SERCOM_SPI_PIN('B', 19, 5, 3, 7, 3) +SERCOM_SPI_PIN('B', 20, 3, 0, 7, 1) +SERCOM_SPI_PIN('B', 21, 3, 1, 7, 0) +SERCOM_SPI_PIN('B', 22, 1, 2, 5, 2) +SERCOM_SPI_PIN('B', 23, 1, 3, 5, 3) +SERCOM_SPI_PIN('B', 24, 0, 0, 2, 1) +SERCOM_SPI_PIN('B', 25, 0, 1, 2, 0) +SERCOM_SPI_PIN('B', 26, 2, 0, 4, 1) +SERCOM_SPI_PIN('B', 27, 2, 1, 4, 0) +SERCOM_SPI_PIN('B', 28, 2, 2, 4, 2) +SERCOM_SPI_PIN('B', 29, 2, 3, 4, 3) +SERCOM_SPI_PIN('B', 30, 7, 0, 5, 1) +SERCOM_SPI_PIN('B', 31, 7, 1, 5, 0) +SERCOM_SPI_PIN('C', 4, 6, 0, 255, 255) +SERCOM_SPI_PIN('C', 6, 6, 2, 255, 255) +SERCOM_SPI_PIN('C', 7, 6, 3, 255, 255) +SERCOM_SPI_PIN('C', 10, 6, 2, 7, 2) +SERCOM_SPI_PIN('C', 11, 6, 3, 7, 3) +SERCOM_SPI_PIN('C', 12, 7, 0, 6, 1) +SERCOM_SPI_PIN('C', 13, 7, 1, 6, 0) +SERCOM_SPI_PIN('C', 14, 7, 2, 6, 2) +SERCOM_SPI_PIN('C', 15, 7, 3, 6, 3) +SERCOM_SPI_PIN('C', 16, 6, 0, 0, 1) +SERCOM_SPI_PIN('C', 17, 6, 1, 0, 0) +SERCOM_SPI_PIN('C', 18, 6, 2, 0, 2) +SERCOM_SPI_PIN('C', 19, 6, 3, 0, 3) +SERCOM_SPI_PIN('C', 22, 1, 0, 3, 1) +SERCOM_SPI_PIN('C', 23, 1, 1, 3, 0) +SERCOM_SPI_PIN('C', 24, 0, 2, 2, 2) +SERCOM_SPI_PIN('C', 25, 0, 3, 2, 3) +SERCOM_SPI_PIN('C', 27, 1, 0, 255, 255) +SERCOM_SPI_PIN('D', 8, 7, 0, 6, 1) +SERCOM_SPI_PIN('D', 9, 7, 1, 6, 0) +SERCOM_SPI_PIN('D', 10, 7, 2, 6, 2) +SERCOM_SPI_PIN('D', 11, 7, 3, 6, 3) +SERCOM_SPI_PIN('D', 20, 1, 2, 3, 2) +SERCOM_SPI_PIN('D', 21, 1, 3, 3, 3) +#endif // SAME53_SERIES + +#if SAME54_SERIES +SERCOM_SPI_PIN('A', 0, 255, 255, 1, 0) +SERCOM_SPI_PIN('A', 4, 255, 255, 0, 0) +SERCOM_SPI_PIN('A', 6, 255, 255, 0, 2) +SERCOM_SPI_PIN('A', 7, 255, 255, 0, 3) +SERCOM_SPI_PIN('A', 8, 0, 0, 2, 1) +SERCOM_SPI_PIN('A', 9, 0, 1, 2, 0) +SERCOM_SPI_PIN('A', 10, 0, 2, 2, 2) +SERCOM_SPI_PIN('A', 11, 0, 3, 2, 3) +SERCOM_SPI_PIN('A', 12, 2, 0, 4, 1) +SERCOM_SPI_PIN('A', 13, 2, 1, 4, 0) +SERCOM_SPI_PIN('A', 14, 2, 2, 4, 2) +SERCOM_SPI_PIN('A', 15, 2, 3, 4, 3) +SERCOM_SPI_PIN('A', 16, 1, 0, 3, 1) +SERCOM_SPI_PIN('A', 17, 1, 1, 3, 0) +SERCOM_SPI_PIN('A', 18, 1, 2, 3, 2) +SERCOM_SPI_PIN('A', 19, 1, 3, 3, 3) +SERCOM_SPI_PIN('A', 20, 5, 2, 3, 2) +SERCOM_SPI_PIN('A', 21, 5, 3, 3, 3) +SERCOM_SPI_PIN('A', 22, 3, 0, 5, 1) +SERCOM_SPI_PIN('A', 23, 3, 1, 5, 0) +SERCOM_SPI_PIN('A', 24, 3, 2, 5, 2) +SERCOM_SPI_PIN('A', 25, 3, 3, 5, 3) +SERCOM_SPI_PIN('A', 30, 7, 2, 1, 2) +SERCOM_SPI_PIN('A', 31, 7, 3, 1, 3) +SERCOM_SPI_PIN('B', 0, 255, 255, 5, 2) +SERCOM_SPI_PIN('B', 1, 255, 255, 5, 3) +SERCOM_SPI_PIN('B', 2, 255, 255, 5, 0) +SERCOM_SPI_PIN('B', 8, 255, 255, 4, 0) +SERCOM_SPI_PIN('B', 10, 255, 255, 4, 2) +SERCOM_SPI_PIN('B', 11, 255, 255, 4, 3) +SERCOM_SPI_PIN('B', 12, 4, 0, 255, 255) +SERCOM_SPI_PIN('B', 14, 4, 2, 255, 255) +SERCOM_SPI_PIN('B', 15, 4, 3, 255, 255) +SERCOM_SPI_PIN('B', 16, 5, 0, 255, 255) +SERCOM_SPI_PIN('B', 18, 5, 2, 7, 2) +SERCOM_SPI_PIN('B', 19, 5, 3, 7, 3) +SERCOM_SPI_PIN('B', 20, 3, 0, 7, 1) +SERCOM_SPI_PIN('B', 21, 3, 1, 7, 0) +SERCOM_SPI_PIN('B', 22, 1, 2, 5, 2) +SERCOM_SPI_PIN('B', 23, 1, 3, 5, 3) +SERCOM_SPI_PIN('B', 24, 0, 0, 2, 1) +SERCOM_SPI_PIN('B', 25, 0, 1, 2, 0) +SERCOM_SPI_PIN('B', 26, 2, 0, 4, 1) +SERCOM_SPI_PIN('B', 27, 2, 1, 4, 0) +SERCOM_SPI_PIN('B', 28, 2, 2, 4, 2) +SERCOM_SPI_PIN('B', 29, 2, 3, 4, 3) +SERCOM_SPI_PIN('B', 30, 7, 0, 5, 1) +SERCOM_SPI_PIN('B', 31, 7, 1, 5, 0) +SERCOM_SPI_PIN('C', 4, 6, 0, 255, 255) +SERCOM_SPI_PIN('C', 6, 6, 2, 255, 255) +SERCOM_SPI_PIN('C', 7, 6, 3, 255, 255) +SERCOM_SPI_PIN('C', 10, 6, 2, 7, 2) +SERCOM_SPI_PIN('C', 11, 6, 3, 7, 3) +SERCOM_SPI_PIN('C', 12, 7, 0, 6, 1) +SERCOM_SPI_PIN('C', 13, 7, 1, 6, 0) +SERCOM_SPI_PIN('C', 14, 7, 2, 6, 2) +SERCOM_SPI_PIN('C', 15, 7, 3, 6, 3) +SERCOM_SPI_PIN('C', 16, 6, 0, 0, 1) +SERCOM_SPI_PIN('C', 17, 6, 1, 0, 0) +SERCOM_SPI_PIN('C', 18, 6, 2, 0, 2) +SERCOM_SPI_PIN('C', 19, 6, 3, 0, 3) +SERCOM_SPI_PIN('C', 22, 1, 0, 3, 1) +SERCOM_SPI_PIN('C', 23, 1, 1, 3, 0) +SERCOM_SPI_PIN('C', 24, 0, 2, 2, 2) +SERCOM_SPI_PIN('C', 25, 0, 3, 2, 3) +SERCOM_SPI_PIN('C', 27, 1, 0, 255, 255) +SERCOM_SPI_PIN('D', 8, 7, 0, 6, 1) +SERCOM_SPI_PIN('D', 9, 7, 1, 6, 0) +SERCOM_SPI_PIN('D', 10, 7, 2, 6, 2) +SERCOM_SPI_PIN('D', 11, 7, 3, 6, 3) +SERCOM_SPI_PIN('D', 20, 1, 2, 3, 2) +SERCOM_SPI_PIN('D', 21, 1, 3, 3, 3) +#endif // SAME54_SERIES + +#if SAME54_120_SERIES +SERCOM_SPI_PIN('A', 0, 255, 255, 1, 0) +SERCOM_SPI_PIN('A', 4, 255, 255, 0, 0) +SERCOM_SPI_PIN('A', 6, 255, 255, 0, 2) +SERCOM_SPI_PIN('A', 7, 255, 255, 0, 3) +SERCOM_SPI_PIN('A', 8, 0, 0, 2, 1) +SERCOM_SPI_PIN('A', 9, 0, 1, 2, 0) +SERCOM_SPI_PIN('A', 10, 0, 2, 2, 2) +SERCOM_SPI_PIN('A', 11, 0, 3, 2, 3) +SERCOM_SPI_PIN('A', 12, 2, 0, 4, 1) +SERCOM_SPI_PIN('A', 13, 2, 1, 4, 0) +SERCOM_SPI_PIN('A', 14, 2, 2, 4, 2) +SERCOM_SPI_PIN('A', 15, 2, 3, 4, 3) +SERCOM_SPI_PIN('A', 16, 1, 0, 3, 1) +SERCOM_SPI_PIN('A', 17, 1, 1, 3, 0) +SERCOM_SPI_PIN('A', 18, 1, 2, 3, 2) +SERCOM_SPI_PIN('A', 19, 1, 3, 3, 3) +SERCOM_SPI_PIN('A', 20, 5, 2, 3, 2) +SERCOM_SPI_PIN('A', 21, 5, 3, 3, 3) +SERCOM_SPI_PIN('A', 22, 3, 0, 5, 1) +SERCOM_SPI_PIN('A', 23, 3, 1, 5, 0) +SERCOM_SPI_PIN('A', 24, 3, 2, 5, 2) +SERCOM_SPI_PIN('A', 25, 3, 3, 5, 3) +SERCOM_SPI_PIN('A', 30, 7, 2, 1, 2) +SERCOM_SPI_PIN('A', 31, 7, 3, 1, 3) +SERCOM_SPI_PIN('B', 0, 255, 255, 5, 2) +SERCOM_SPI_PIN('B', 1, 255, 255, 5, 3) +SERCOM_SPI_PIN('B', 2, 255, 255, 5, 0) +SERCOM_SPI_PIN('B', 8, 255, 255, 4, 0) +SERCOM_SPI_PIN('B', 10, 255, 255, 4, 2) +SERCOM_SPI_PIN('B', 11, 255, 255, 4, 3) +SERCOM_SPI_PIN('B', 12, 4, 0, 255, 255) +SERCOM_SPI_PIN('B', 14, 4, 2, 255, 255) +SERCOM_SPI_PIN('B', 15, 4, 3, 255, 255) +SERCOM_SPI_PIN('B', 16, 5, 0, 255, 255) +SERCOM_SPI_PIN('B', 18, 5, 2, 7, 2) +SERCOM_SPI_PIN('B', 19, 5, 3, 7, 3) +SERCOM_SPI_PIN('B', 20, 3, 0, 7, 1) +SERCOM_SPI_PIN('B', 21, 3, 1, 7, 0) +SERCOM_SPI_PIN('B', 22, 1, 2, 5, 2) +SERCOM_SPI_PIN('B', 23, 1, 3, 5, 3) +SERCOM_SPI_PIN('B', 24, 0, 0, 2, 1) +SERCOM_SPI_PIN('B', 25, 0, 1, 2, 0) +SERCOM_SPI_PIN('B', 26, 2, 0, 4, 1) +SERCOM_SPI_PIN('B', 27, 2, 1, 4, 0) +SERCOM_SPI_PIN('B', 28, 2, 2, 4, 2) +SERCOM_SPI_PIN('B', 29, 2, 3, 4, 3) +SERCOM_SPI_PIN('B', 30, 7, 0, 5, 1) +SERCOM_SPI_PIN('B', 31, 7, 1, 5, 0) +SERCOM_SPI_PIN('C', 4, 6, 0, 255, 255) +SERCOM_SPI_PIN('C', 6, 6, 2, 255, 255) +SERCOM_SPI_PIN('C', 7, 6, 3, 255, 255) +SERCOM_SPI_PIN('C', 10, 6, 2, 7, 2) +SERCOM_SPI_PIN('C', 11, 6, 3, 7, 3) +SERCOM_SPI_PIN('C', 12, 7, 0, 6, 1) +SERCOM_SPI_PIN('C', 13, 7, 1, 6, 0) +SERCOM_SPI_PIN('C', 14, 7, 2, 6, 2) +SERCOM_SPI_PIN('C', 15, 7, 3, 6, 3) +SERCOM_SPI_PIN('C', 16, 6, 0, 0, 1) +SERCOM_SPI_PIN('C', 17, 6, 1, 0, 0) +SERCOM_SPI_PIN('C', 18, 6, 2, 0, 2) +SERCOM_SPI_PIN('C', 19, 6, 3, 0, 3) +SERCOM_SPI_PIN('C', 22, 1, 0, 3, 1) +SERCOM_SPI_PIN('C', 23, 1, 1, 3, 0) +SERCOM_SPI_PIN('C', 24, 0, 2, 2, 2) +SERCOM_SPI_PIN('C', 25, 0, 3, 2, 3) +SERCOM_SPI_PIN('C', 27, 1, 0, 255, 255) +SERCOM_SPI_PIN('D', 8, 7, 0, 6, 1) +SERCOM_SPI_PIN('D', 9, 7, 1, 6, 0) +SERCOM_SPI_PIN('D', 10, 7, 2, 6, 2) +SERCOM_SPI_PIN('D', 11, 7, 3, 6, 3) +SERCOM_SPI_PIN('D', 20, 1, 2, 3, 2) +SERCOM_SPI_PIN('D', 21, 1, 3, 3, 3) +#endif // SAME54_120_SERIES + +#endif // SERCOM_PINMUX_EMIT_SPI diff --git a/cores/arduino/Tone.cpp b/cores/arduino/Tone.cpp index b47a1a278..9e2278e51 100644 --- a/cores/arduino/Tone.cpp +++ b/cores/arduino/Tone.cpp @@ -30,14 +30,20 @@ volatile int64_t toggleCount; volatile bool toneIsActive = false; volatile bool firstTimeRunning = false; -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) #define TONE_TC TC0 #define TONE_TC_IRQn TC0_IRQn #define TONE_TC_GCLK_ID TC0_GCLK_ID #define Tone_Handler TC0_Handler #define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.SYNCBUSY.bit.ENABLE); +#elif defined(__SAME53__) || defined(__SAME54__) + #define TONE_TC TC0_REGS + #define TONE_TC_IRQn TC0_IRQn + #define TONE_TC_GCLK_ID TC0_GCLK_ID + #define Tone_Handler TC0_Handler + #define WAIT_TC16_REGS_SYNC(x) while ((x)->COUNT16.TC_SYNCBUSY); #else #define TONE_TC TC5 #define TONE_TC_IRQn TC5_IRQn @@ -49,7 +55,18 @@ volatile bool firstTimeRunning = false; #define TONE_TC_TOP 0xFFFF #define TONE_TC_CHANNEL 0 -static inline void resetTC (Tc* TCx) +#if defined(__SAME53__) || defined(__SAME54__) +static inline void resetTC(tc_registers_t *TCx) +{ + TCx->COUNT16.TC_CTRLA &= ~TC_CTRLA_ENABLE_Msk; + WAIT_TC16_REGS_SYNC(TCx) + + TCx->COUNT16.TC_CTRLA = TC_CTRLA_SWRST_Msk; + WAIT_TC16_REGS_SYNC(TCx) + while (TCx->COUNT16.TC_CTRLA & TC_CTRLA_SWRST_Msk); +} +#else +static inline void resetTC(Tc *TCx) { // Disable TCx TCx->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE; @@ -60,6 +77,7 @@ static inline void resetTC (Tc* TCx) WAIT_TC16_REGS_SYNC(TCx) while (TCx->COUNT16.CTRLA.bit.SWRST); } +#endif void toneAccurateClock (uint32_t accurateSystemCoreClockFrequency) { @@ -86,8 +104,11 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration) NVIC_SetPriority(TONE_TC_IRQn, 5); -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) GCLK->PCHCTRL[TONE_TC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); +#elif defined(__SAME53__) || defined(__SAME54__) + GCLK_REGS->GCLK_PCHCTRL[TONE_TC_GCLK_ID] = GCLK_PCHCTRL_GEN_GCLK0 | + GCLK_PCHCTRL_CHEN_Msk; #else // Enable GCLK for TC4 and TC5 (timer counter input clock) GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5)); @@ -150,24 +171,43 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration) uint16_t tmpReg = 0; tmpReg |= TC_CTRLA_MODE_COUNT16; // Set Timer counter Mode to 16 bits -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) TONE_TC->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_MFRQ; // Set TONE_TC mode as match frequency +#elif defined(__SAME53__) || defined(__SAME54__) + TONE_TC->COUNT16.TC_WAVE = TC_WAVE_WAVEGEN_MFRQ; #else tmpReg |= TC_CTRLA_WAVEGEN_MFRQ; // Set TONE_TC mode as match frequency #endif tmpReg |= prescalerConfigBits; +#if defined(__SAME53__) || defined(__SAME54__) + TONE_TC->COUNT16.TC_CTRLA |= tmpReg; +#else TONE_TC->COUNT16.CTRLA.reg |= tmpReg; +#endif WAIT_TC16_REGS_SYNC(TONE_TC) +#if defined(__SAME53__) || defined(__SAME54__) + TONE_TC->COUNT16.TC_CC[TONE_TC_CHANNEL] = (uint16_t)ccValue; +#else TONE_TC->COUNT16.CC[TONE_TC_CHANNEL].reg = (uint16_t) ccValue; +#endif WAIT_TC16_REGS_SYNC(TONE_TC) +#if defined(__SAME53__) || defined(__SAME54__) + portToggleRegister = &PORT_REGS->GROUP[g_APinDescription[outputPin].ulPort].PORT_OUTTGL; + portClearRegister = &PORT_REGS->GROUP[g_APinDescription[outputPin].ulPort].PORT_OUTCLR; +#else portToggleRegister = &(PORT->Group[g_APinDescription[outputPin].ulPort].OUTTGL.reg); portClearRegister = &(PORT->Group[g_APinDescription[outputPin].ulPort].OUTCLR.reg); +#endif portBitMask = (1ul << g_APinDescription[outputPin].ulPin); // Enable the TONE_TC interrupt request +#if defined(__SAME53__) || defined(__SAME54__) + TONE_TC->COUNT16.TC_INTENSET = TC_INTENSET_MC0_Msk; +#else TONE_TC->COUNT16.INTENSET.bit.MC0 = 1; +#endif if (outputPin != lastOutputPin) { @@ -178,7 +218,11 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration) } // Enable TONE_TC +#if defined(__SAME53__) || defined(__SAME54__) + TONE_TC->COUNT16.TC_CTRLA |= TC_CTRLA_ENABLE_Msk; +#else TONE_TC->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; +#endif WAIT_TC16_REGS_SYNC(TONE_TC) NVIC_EnableIRQ(TONE_TC_IRQn); @@ -219,7 +263,11 @@ void Tone_Handler (void) --toggleCount; // Clear the interrupt +#if defined(__SAME53__) || defined(__SAME54__) + TONE_TC->COUNT16.TC_INTFLAG = TC_INTFLAG_MC0_Msk; +#else TONE_TC->COUNT16.INTFLAG.bit.MC0 = 1; +#endif } else { diff --git a/cores/arduino/USB/SAMD21_USBDevice.cpp b/cores/arduino/USB/SAMD21_USBDevice.cpp index f45d256dc..3f976599a 100644 --- a/cores/arduino/USB/SAMD21_USBDevice.cpp +++ b/cores/arduino/USB/SAMD21_USBDevice.cpp @@ -10,14 +10,30 @@ #include "SAMD21_USBDevice.h" void USBDevice_SAMD21G18x::reset() { +#if defined(__SAME53__) || defined(__SAME54__) + usb.USB_CTRLA |= USB_CTRLA_SWRST_Msk; + memset(EP, 0, sizeof(EP)); + while (usb.USB_SYNCBUSY & (USB_SYNCBUSY_SWRST_Msk | USB_SYNCBUSY_ENABLE_Msk)) {} + usb.USB_DESCADD = (uint32_t)(&EP); +#else usb.CTRLA.bit.SWRST = 1; memset(EP, 0, sizeof(EP)); while (usb.SYNCBUSY.bit.SWRST || usb.SYNCBUSY.bit.ENABLE) {} usb.DESCADD.reg = (uint32_t)(&EP); +#endif } void USBDevice_SAMD21G18x::calibrate() { // Load Pad Calibration data from non-volatile memory +#if defined(__SAME53__) || defined(__SAME54__) + const uint32_t calibration = *(const uint32_t *)(SW0_ADDR + 4u); + uint32_t pad_transn = (calibration & FUSES_SW0_WORD_1_USB_TRANSN_Msk) >> + FUSES_SW0_WORD_1_USB_TRANSN_Pos; + uint32_t pad_transp = (calibration & FUSES_SW0_WORD_1_USB_TRANSP_Msk) >> + FUSES_SW0_WORD_1_USB_TRANSP_Pos; + uint32_t pad_trim = (calibration & FUSES_SW0_WORD_1_USB_TRIM_Msk) >> + FUSES_SW0_WORD_1_USB_TRIM_Pos; +#else uint32_t *pad_transn_p = (uint32_t *) USB_FUSES_TRANSN_ADDR; uint32_t *pad_transp_p = (uint32_t *) USB_FUSES_TRANSP_ADDR; uint32_t *pad_trim_p = (uint32_t *) USB_FUSES_TRIM_ADDR; @@ -25,6 +41,7 @@ void USBDevice_SAMD21G18x::calibrate() { uint32_t pad_transn = (*pad_transn_p & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos; uint32_t pad_transp = (*pad_transp_p & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos; uint32_t pad_trim = (*pad_trim_p & USB_FUSES_TRIM_Msk ) >> USB_FUSES_TRIM_Pos; +#endif if (pad_transn == 0x1F) // maximum value (31) pad_transn = 5; @@ -33,9 +50,15 @@ void USBDevice_SAMD21G18x::calibrate() { if (pad_trim == 0x7) // maximum value (7) pad_trim = 3; +#if defined(__SAME53__) || defined(__SAME54__) + usb.USB_PADCAL = USB_PADCAL_TRANSN(pad_transn) | + USB_PADCAL_TRANSP(pad_transp) | + USB_PADCAL_TRIM(pad_trim); +#else usb.PADCAL.bit.TRANSN = pad_transn; usb.PADCAL.bit.TRANSP = pad_transp; usb.PADCAL.bit.TRIM = pad_trim; +#endif } #endif // USE_TINYUSB diff --git a/cores/arduino/USB/SAMD21_USBDevice.h b/cores/arduino/USB/SAMD21_USBDevice.h index 00da069db..489b29151 100644 --- a/cores/arduino/USB/SAMD21_USBDevice.h +++ b/cores/arduino/USB/SAMD21_USBDevice.h @@ -29,6 +29,64 @@ typedef uint8_t ep_t; class USBDevice_SAMD21G18x { public: +#if defined(__SAME53__) || defined(__SAME54__) + USBDevice_SAMD21G18x() : usb(USB_REGS->DEVICE) { + // Empty + } + + // USB Device function mapping + // --------------------------- + + // Reset USB Device + void reset(); + + // Enable + inline void enable() { + usb.USB_CTRLA |= USB_CTRLA_ENABLE_Msk; + while (usb.USB_SYNCBUSY & USB_SYNCBUSY_ENABLE_Msk); + } + inline void disable() { + usb.USB_CTRLA &= ~USB_CTRLA_ENABLE_Msk; + while (usb.USB_SYNCBUSY & USB_SYNCBUSY_ENABLE_Msk); + } + + // USB mode (device/host) + inline void setUSBDeviceMode() { usb.USB_CTRLA &= ~USB_CTRLA_MODE_Msk; } + inline void setUSBHostMode() { usb.USB_CTRLA |= USB_CTRLA_MODE_Msk; } + + inline void runInStandby() { usb.USB_CTRLA |= USB_CTRLA_RUNSTDBY_Msk; } + inline void noRunInStandby() { usb.USB_CTRLA &= ~USB_CTRLA_RUNSTDBY_Msk; } + inline void wakeupHost() { usb.USB_CTRLB |= USB_DEVICE_CTRLB_UPRSM_Msk; } + + // USB speed + inline void setFullSpeed() { setSpeedConfiguration(USB_DEVICE_CTRLB_SPDCONF_FS_Val); } + inline void setLowSpeed() { setSpeedConfiguration(USB_DEVICE_CTRLB_SPDCONF_LS_Val); } + inline void setHiSpeed() { setFullSpeed(); } + inline void setHiSpeedTestMode() { setFullSpeed(); } + + // Authorize attach if Vbus is present + inline void attach() { usb.USB_CTRLB &= ~USB_DEVICE_CTRLB_DETACH_Msk; } + inline void detach() { usb.USB_CTRLB |= USB_DEVICE_CTRLB_DETACH_Msk; } + + // USB Interrupts + inline bool isEndOfResetInterrupt() { return usb.USB_INTFLAG & USB_DEVICE_INTFLAG_EORST_Msk; } + inline void ackEndOfResetInterrupt() { usb.USB_INTFLAG = USB_DEVICE_INTFLAG_EORST_Msk; } + inline void enableEndOfResetInterrupt() { usb.USB_INTENSET = USB_DEVICE_INTENSET_EORST_Msk; } + inline void disableEndOfResetInterrupt() { usb.USB_INTENCLR = USB_DEVICE_INTENCLR_EORST_Msk; } + + inline bool isStartOfFrameInterrupt() { return usb.USB_INTFLAG & USB_DEVICE_INTFLAG_SOF_Msk; } + inline void ackStartOfFrameInterrupt() { usb.USB_INTFLAG = USB_DEVICE_INTFLAG_SOF_Msk; } + inline void enableStartOfFrameInterrupt() { usb.USB_INTENSET = USB_DEVICE_INTENSET_SOF_Msk; } + inline void disableStartOfFrameInterrupt() { usb.USB_INTENCLR = USB_DEVICE_INTENCLR_SOF_Msk; } + + // USB Address + inline void setAddress(uint32_t addr) { usb.USB_DADD = USB_DEVICE_DADD_DADD(addr) | USB_DEVICE_DADD_ADDEN_Msk; } + inline void unsetAddress() { usb.USB_DADD = 0; } + + // Frame number + inline uint16_t frameNumber() { return (usb.USB_FNUM & USB_DEVICE_FNUM_FNUM_Msk) >> USB_DEVICE_FNUM_FNUM_Pos; } + +#else USBDevice_SAMD21G18x() : usb(USB->DEVICE) { // Empty } @@ -40,54 +98,55 @@ class USBDevice_SAMD21G18x { void reset(); // Enable - inline void enable() { + inline void enable() { usb.CTRLA.bit.ENABLE = 1; -#if defined(__SAMD51__) - while( usb.SYNCBUSY.reg & USB_SYNCBUSY_ENABLE ); //wait for sync +#if defined(__SAMD51__) || defined(__SAME51__) + while (usb.SYNCBUSY.reg & USB_SYNCBUSY_ENABLE); // Wait for sync #endif } - inline void disable() { + inline void disable() { usb.CTRLA.bit.ENABLE = 0; -#if defined(__SAMD51__) - while( usb.SYNCBUSY.reg & USB_SYNCBUSY_ENABLE ); //wait for sync +#if defined(__SAMD51__) || defined(__SAME51__) + while (usb.SYNCBUSY.reg & USB_SYNCBUSY_ENABLE); // Wait for sync #endif } // USB mode (device/host) inline void setUSBDeviceMode() { usb.CTRLA.bit.MODE = USB_CTRLA_MODE_DEVICE_Val; } - inline void setUSBHostMode() { usb.CTRLA.bit.MODE = USB_CTRLA_MODE_HOST_Val; } + inline void setUSBHostMode() { usb.CTRLA.bit.MODE = USB_CTRLA_MODE_HOST_Val; } - inline void runInStandby() { usb.CTRLA.bit.RUNSTDBY = 1; } + inline void runInStandby() { usb.CTRLA.bit.RUNSTDBY = 1; } inline void noRunInStandby() { usb.CTRLA.bit.RUNSTDBY = 0; } - inline void wakeupHost() { usb.CTRLB.bit.UPRSM = 1; } + inline void wakeupHost() { usb.CTRLB.bit.UPRSM = 1; } // USB speed - inline void setFullSpeed() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_FS_Val; } - inline void setLowSpeed() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_LS_Val; } - inline void setHiSpeed() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_HS_Val; } - inline void setHiSpeedTestMode() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_HSTM_Val; } + inline void setFullSpeed() { setSpeedConfiguration(USB_DEVICE_CTRLB_SPDCONF_FS_Val); } + inline void setLowSpeed() { setSpeedConfiguration(USB_DEVICE_CTRLB_SPDCONF_LS_Val); } + inline void setHiSpeed() { setSpeedConfiguration(USB_DEVICE_CTRLB_SPDCONF_HS_Val); } + inline void setHiSpeedTestMode() { setSpeedConfiguration(USB_DEVICE_CTRLB_SPDCONF_HSTM_Val); } // Authorize attach if Vbus is present inline void attach() { usb.CTRLB.bit.DETACH = 0; } inline void detach() { usb.CTRLB.bit.DETACH = 1; } // USB Interrupts - inline bool isEndOfResetInterrupt() { return usb.INTFLAG.bit.EORST; } - inline void ackEndOfResetInterrupt() { usb.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST; } - inline void enableEndOfResetInterrupt() { usb.INTENSET.bit.EORST = 1; } - inline void disableEndOfResetInterrupt() { usb.INTENCLR.bit.EORST = 1; } - - inline bool isStartOfFrameInterrupt() { return usb.INTFLAG.bit.SOF; } - inline void ackStartOfFrameInterrupt() { usb.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF; } - inline void enableStartOfFrameInterrupt() { usb.INTENSET.bit.SOF = 1; } + inline bool isEndOfResetInterrupt() { return usb.INTFLAG.bit.EORST; } + inline void ackEndOfResetInterrupt() { usb.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST; } + inline void enableEndOfResetInterrupt() { usb.INTENSET.bit.EORST = 1; } + inline void disableEndOfResetInterrupt() { usb.INTENCLR.bit.EORST = 1; } + + inline bool isStartOfFrameInterrupt() { return usb.INTFLAG.bit.SOF; } + inline void ackStartOfFrameInterrupt() { usb.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF; } + inline void enableStartOfFrameInterrupt() { usb.INTENSET.bit.SOF = 1; } inline void disableStartOfFrameInterrupt() { usb.INTENCLR.bit.SOF = 1; } // USB Address - inline void setAddress(uint32_t addr) { usb.DADD.bit.DADD = addr; usb.DADD.bit.ADDEN = 1; } - inline void unsetAddress() { usb.DADD.bit.DADD = 0; usb.DADD.bit.ADDEN = 0; } + inline void setAddress(uint32_t addr) { usb.DADD.bit.DADD = addr; usb.DADD.bit.ADDEN = 1; } + inline void unsetAddress() { usb.DADD.bit.DADD = 0; usb.DADD.bit.ADDEN = 0; } // Frame number inline uint16_t frameNumber() { return usb.FNUM.bit.FNUM; } +#endif // Load calibration values void calibrate(); @@ -95,6 +154,77 @@ class USBDevice_SAMD21G18x { // USB Device Endpoints function mapping // ------------------------------------- +#if defined(__SAME53__) || defined(__SAME54__) + // Config + inline void epBank0SetType(ep_t ep, uint8_t type) { + usb.DEVICE_ENDPOINT[ep].USB_EPCFG = + (usb.DEVICE_ENDPOINT[ep].USB_EPCFG & ~USB_DEVICE_EPCFG_EPTYPE0_Msk) | + USB_DEVICE_EPCFG_EPTYPE0(type); + } + inline void epBank1SetType(ep_t ep, uint8_t type) { + usb.DEVICE_ENDPOINT[ep].USB_EPCFG = + (usb.DEVICE_ENDPOINT[ep].USB_EPCFG & ~USB_DEVICE_EPCFG_EPTYPE1_Msk) | + USB_DEVICE_EPCFG_EPTYPE1(type); + } + + // Interrupts + inline uint16_t epInterruptSummary() { return usb.USB_EPINTSMRY; } + inline bool epBank0IsSetupReceived(ep_t ep) { return usb.DEVICE_ENDPOINT[ep].USB_EPINTFLAG & USB_DEVICE_EPINTFLAG_RXSTP_Msk; } + inline bool epBank0IsStalled(ep_t ep) { return usb.DEVICE_ENDPOINT[ep].USB_EPINTFLAG & USB_DEVICE_EPINTFLAG_STALL0_Msk; } + inline bool epBank1IsStalled(ep_t ep) { return usb.DEVICE_ENDPOINT[ep].USB_EPINTFLAG & USB_DEVICE_EPINTFLAG_STALL1_Msk; } + inline bool epBank0IsTransferComplete(ep_t ep) { return usb.DEVICE_ENDPOINT[ep].USB_EPINTFLAG & USB_DEVICE_EPINTFLAG_TRCPT0_Msk; } + inline bool epBank1IsTransferComplete(ep_t ep) { return usb.DEVICE_ENDPOINT[ep].USB_EPINTFLAG & USB_DEVICE_EPINTFLAG_TRCPT1_Msk; } + inline void epBank0AckSetupReceived(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPINTFLAG = USB_DEVICE_EPINTFLAG_RXSTP_Msk; } + inline void epBank0AckStalled(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPINTFLAG = USB_DEVICE_EPINTFLAG_STALL0_Msk; } + inline void epBank1AckStalled(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPINTFLAG = USB_DEVICE_EPINTFLAG_STALL1_Msk; } + inline void epBank0AckTransferComplete(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPINTFLAG = USB_DEVICE_EPINTFLAG_TRCPT0_Msk; } + inline void epBank1AckTransferComplete(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPINTFLAG = USB_DEVICE_EPINTFLAG_TRCPT1_Msk; } + inline void epBank0EnableSetupReceived(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPINTENSET = USB_DEVICE_EPINTENSET_RXSTP_Msk; } + inline void epBank0EnableStalled(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPINTENSET = USB_DEVICE_EPINTENSET_STALL0_Msk; } + inline void epBank1EnableStalled(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPINTENSET = USB_DEVICE_EPINTENSET_STALL1_Msk; } + inline void epBank0EnableTransferComplete(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPINTENSET = USB_DEVICE_EPINTENSET_TRCPT0_Msk; } + inline void epBank1EnableTransferComplete(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPINTENSET = USB_DEVICE_EPINTENSET_TRCPT1_Msk; } + inline void epBank0DisableSetupReceived(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPINTENCLR = USB_DEVICE_EPINTENCLR_RXSTP_Msk; } + inline void epBank0DisableStalled(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPINTENCLR = USB_DEVICE_EPINTENCLR_STALL0_Msk; } + inline void epBank1DisableStalled(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPINTENCLR = USB_DEVICE_EPINTENCLR_STALL1_Msk; } + inline void epBank0DisableTransferComplete(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPINTENCLR = USB_DEVICE_EPINTENCLR_TRCPT0_Msk; } + inline void epBank1DisableTransferComplete(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPINTENCLR = USB_DEVICE_EPINTENCLR_TRCPT1_Msk; } + + // Status + inline bool epBank0IsReady(ep_t ep) { return usb.DEVICE_ENDPOINT[ep].USB_EPSTATUS & USB_DEVICE_EPSTATUS_BK0RDY_Msk; } + inline bool epBank1IsReady(ep_t ep) { return usb.DEVICE_ENDPOINT[ep].USB_EPSTATUS & USB_DEVICE_EPSTATUS_BK1RDY_Msk; } + inline void epBank0SetReady(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPSTATUSSET = USB_DEVICE_EPSTATUSSET_BK0RDY_Msk; } + inline void epBank1SetReady(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPSTATUSSET = USB_DEVICE_EPSTATUSSET_BK1RDY_Msk; } + inline void epBank0ResetReady(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPSTATUSCLR = USB_DEVICE_EPSTATUSCLR_BK0RDY_Msk; } + inline void epBank1ResetReady(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPSTATUSCLR = USB_DEVICE_EPSTATUSCLR_BK1RDY_Msk; } + inline void epBank0SetStallReq(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPSTATUSSET = USB_DEVICE_EPSTATUSSET_STALLRQ0_Msk; } + inline void epBank1SetStallReq(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPSTATUSSET = USB_DEVICE_EPSTATUSSET_STALLRQ1_Msk; } + inline void epBank0ResetStallReq(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPSTATUSCLR = USB_DEVICE_EPSTATUSCLR_STALLRQ0_Msk; } + inline void epBank1ResetStallReq(ep_t ep) { usb.DEVICE_ENDPOINT[ep].USB_EPSTATUSCLR = USB_DEVICE_EPSTATUSCLR_STALLRQ1_Msk; } + + // Packet + inline uint16_t epBank0ByteCount(ep_t ep) { return (EP[ep].DEVICE_DESC_BANK[0].USB_PCKSIZE & USB_DEVICE_PCKSIZE_BYTE_COUNT_Msk) >> USB_DEVICE_PCKSIZE_BYTE_COUNT_Pos; } + inline uint16_t epBank1ByteCount(ep_t ep) { return (EP[ep].DEVICE_DESC_BANK[1].USB_PCKSIZE & USB_DEVICE_PCKSIZE_BYTE_COUNT_Msk) >> USB_DEVICE_PCKSIZE_BYTE_COUNT_Pos; } + inline void epBank0SetByteCount(ep_t ep, uint16_t bc) { EP[ep].DEVICE_DESC_BANK[0].USB_PCKSIZE = (EP[ep].DEVICE_DESC_BANK[0].USB_PCKSIZE & ~USB_DEVICE_PCKSIZE_BYTE_COUNT_Msk) | USB_DEVICE_PCKSIZE_BYTE_COUNT(bc); } + inline void epBank1SetByteCount(ep_t ep, uint16_t bc) { EP[ep].DEVICE_DESC_BANK[1].USB_PCKSIZE = (EP[ep].DEVICE_DESC_BANK[1].USB_PCKSIZE & ~USB_DEVICE_PCKSIZE_BYTE_COUNT_Msk) | USB_DEVICE_PCKSIZE_BYTE_COUNT(bc); } + inline void epBank0SetMultiPacketSize(ep_t ep, uint16_t s) { EP[ep].DEVICE_DESC_BANK[0].USB_PCKSIZE = (EP[ep].DEVICE_DESC_BANK[0].USB_PCKSIZE & ~USB_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Msk) | USB_DEVICE_PCKSIZE_MULTI_PACKET_SIZE(s); } + inline void epBank1SetMultiPacketSize(ep_t ep, uint16_t s) { EP[ep].DEVICE_DESC_BANK[1].USB_PCKSIZE = (EP[ep].DEVICE_DESC_BANK[1].USB_PCKSIZE & ~USB_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Msk) | USB_DEVICE_PCKSIZE_MULTI_PACKET_SIZE(s); } + inline void epBank0SetAddress(ep_t ep, void *addr) { EP[ep].DEVICE_DESC_BANK[0].USB_ADDR = (uint32_t)addr; } + inline void epBank1SetAddress(ep_t ep, void *addr) { EP[ep].DEVICE_DESC_BANK[1].USB_ADDR = (uint32_t)addr; } + inline void epBank0SetSize(ep_t ep, uint16_t size) { EP[ep].DEVICE_DESC_BANK[0].USB_PCKSIZE = (EP[ep].DEVICE_DESC_BANK[0].USB_PCKSIZE & ~USB_DEVICE_PCKSIZE_SIZE_Msk) | USB_DEVICE_PCKSIZE_SIZE(EP_PCKSIZE_SIZE(size)); } + inline void epBank1SetSize(ep_t ep, uint16_t size) { EP[ep].DEVICE_DESC_BANK[1].USB_PCKSIZE = (EP[ep].DEVICE_DESC_BANK[1].USB_PCKSIZE & ~USB_DEVICE_PCKSIZE_SIZE_Msk) | USB_DEVICE_PCKSIZE_SIZE(EP_PCKSIZE_SIZE(size)); } + inline uint8_t EP_PCKSIZE_SIZE(uint16_t size) { + switch (size) { + case 8: return 0; case 16: return 1; case 32: return 2; case 64: return 3; + case 128: return 4; case 256: return 5; case 512: return 6; case 1023: return 7; + default: return 0; + } + } + inline void epBank0DisableAutoZLP(ep_t ep) { EP[ep].DEVICE_DESC_BANK[0].USB_PCKSIZE &= ~USB_DEVICE_PCKSIZE_AUTO_ZLP_Msk; } + inline void epBank1DisableAutoZLP(ep_t ep) { EP[ep].DEVICE_DESC_BANK[1].USB_PCKSIZE &= ~USB_DEVICE_PCKSIZE_AUTO_ZLP_Msk; } + inline void epBank0EnableAutoZLP(ep_t ep) { EP[ep].DEVICE_DESC_BANK[0].USB_PCKSIZE |= USB_DEVICE_PCKSIZE_AUTO_ZLP_Msk; } + inline void epBank1EnableAutoZLP(ep_t ep) { EP[ep].DEVICE_DESC_BANK[1].USB_PCKSIZE |= USB_DEVICE_PCKSIZE_AUTO_ZLP_Msk; } +#else // Config inline void epBank0SetType(ep_t ep, uint8_t type) { usb.DeviceEndpoint[ep].EPCFG.bit.EPTYPE0 = type; } inline void epBank1SetType(ep_t ep, uint8_t type) { usb.DeviceEndpoint[ep].EPCFG.bit.EPTYPE1 = type; } @@ -169,13 +299,30 @@ class USBDevice_SAMD21G18x { inline void epBank1DisableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = 0; } inline void epBank0EnableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.AUTO_ZLP = 1; } inline void epBank1EnableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = 1; } - +#endif private: +#if defined(__SAME53__) || defined(__SAME54__) + inline void setSpeedConfiguration(uint8_t speed) { + usb.USB_CTRLB = (usb.USB_CTRLB & ~USB_DEVICE_CTRLB_SPDCONF_Msk) | + USB_DEVICE_CTRLB_SPDCONF(speed); + } + + // USB Device registers + usb_device_registers_t &usb; + + // Endpoints descriptors table + __attribute__((__aligned__(4))) usb_descriptor_device_registers_t EP[USB_EPT_NUM]; +#else + inline void setSpeedConfiguration(uint8_t speed) { + usb.CTRLB.bit.SPDCONF = speed; + } + // USB Device registers UsbDevice &usb; // Endpoints descriptors table __attribute__((__aligned__(4))) UsbDeviceDescriptor EP[USB_EPT_NUM]; +#endif }; /* diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index 83a3e5d32..8de67cbf2 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -54,6 +54,7 @@ static char isRemoteWakeUpEnabled = 0; static char isEndpointHalt = 0; extern void (*gpf_isr)(void); +extern "C" void USB_SetHandler(void (*new_usb_isr)(void)); // USB_Handler ISR extern "C" void UDD_Handler(void) { @@ -246,7 +247,7 @@ bool USBDeviceClass::sendDescriptor(USBSetup &setup) } else if (setup.wValueL == ISERIAL) { #ifdef PLUGGABLE_USB_ENABLED -#ifdef __SAMD51__ + #if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) #define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x008061FC) #define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x00806010) #define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x00806014) @@ -333,7 +334,7 @@ void USBDeviceClass::init() #endif /* Enable USB clock */ -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) MCLK->APBBMASK.reg |= MCLK_APBBMASK_USB; MCLK->AHBMASK.reg |= MCLK_AHBMASK_USB; @@ -347,6 +348,23 @@ void USBDeviceClass::init() GCLK->PCHCTRL[USB_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); +#elif defined(__SAME53__) || defined(__SAME54__) + MCLK_REGS->MCLK_APBBMASK |= MCLK_APBBMASK_USB_Msk; + MCLK_REGS->MCLK_AHBMASK |= MCLK_AHBMASK_USB_Msk; + + PORT_REGS->GROUP[0].PORT_PINCFG[PIN_PA24H_USB_DM] |= PORT_PINCFG_PMUXEN_Msk; + PORT_REGS->GROUP[0].PORT_PMUX[PIN_PA24H_USB_DM / 2] = + (PORT_REGS->GROUP[0].PORT_PMUX[PIN_PA24H_USB_DM / 2] & + ~(0xFu << (4u * (PIN_PA24H_USB_DM & 0x01u)))) | + (MUX_PA24H_USB_DM << (4u * (PIN_PA24H_USB_DM & 0x01u))); + PORT_REGS->GROUP[0].PORT_PINCFG[PIN_PA25H_USB_DP] |= PORT_PINCFG_PMUXEN_Msk; + PORT_REGS->GROUP[0].PORT_PMUX[PIN_PA25H_USB_DP / 2] = + (PORT_REGS->GROUP[0].PORT_PMUX[PIN_PA25H_USB_DP / 2] & + ~(0xFu << (4u * (PIN_PA25H_USB_DP & 0x01u)))) | + (MUX_PA25H_USB_DP << (4u * (PIN_PA25H_USB_DP & 0x01u))); + + GCLK_REGS->GCLK_PCHCTRL[USB_GCLK_ID] = GCLK_PCHCTRL_GEN_GCLK1 | + GCLK_PCHCTRL_CHEN_Msk; #else PM->APBBMASK.reg |= PM_APBBMASK_USB; @@ -377,7 +395,7 @@ void USBDeviceClass::init() usbd.setFullSpeed(); // Configure interrupts -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) /* Attach to the USB host */ NVIC_SetPriority(USB_0_IRQn, 0UL); NVIC_SetPriority(USB_1_IRQn, 0UL); @@ -387,6 +405,15 @@ void USBDeviceClass::init() NVIC_EnableIRQ(USB_1_IRQn); NVIC_EnableIRQ(USB_2_IRQn); NVIC_EnableIRQ(USB_3_IRQn); +#elif defined(__SAME53__) || defined(__SAME54__) + NVIC_SetPriority(USB_OTHER_IRQn, 0UL); + NVIC_SetPriority(USB_SOF_HSOF_IRQn, 0UL); + NVIC_SetPriority(USB_TRCPT0_IRQn, 0UL); + NVIC_SetPriority(USB_TRCPT1_IRQn, 0UL); + NVIC_EnableIRQ(USB_OTHER_IRQn); + NVIC_EnableIRQ(USB_SOF_HSOF_IRQn); + NVIC_EnableIRQ(USB_TRCPT0_IRQn); + NVIC_EnableIRQ(USB_TRCPT1_IRQn); #else NVIC_SetPriority((IRQn_Type) USB_IRQn, 0UL); NVIC_EnableIRQ((IRQn_Type) USB_IRQn); @@ -422,9 +449,7 @@ void USBDeviceClass::setAddress(uint32_t addr) // Wait for transfer to complete while (!usbd.epBank1IsTransferComplete(0)) {} - // Set USB address to addr - USB->DEVICE.DADD.bit.DADD = addr; // Address - USB->DEVICE.DADD.bit.ADDEN = 1; // Enable + usbd.setAddress(addr); } bool USBDeviceClass::detach() @@ -568,19 +593,15 @@ void USBDeviceClass::flush(uint32_t ep) void USBDeviceClass::stall(uint32_t ep) { - // TODO: test - // TODO: use .bit. notation - - // Stall endpoint - USB->DEVICE.DeviceEndpoint[ep].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ(2); + usbd.epBank1SetStallReq(ep); } bool USBDeviceClass::connected() { // Count frame numbers - uint8_t f = USB->DEVICE.FNUM.bit.FNUM; + uint16_t f = usbd.frameNumber(); //delay(3); - return f != USB->DEVICE.FNUM.bit.FNUM; + return f != usbd.frameNumber(); } diff --git a/cores/arduino/USB/samd21_host.c b/cores/arduino/USB/samd21_host.c index 7d59f9c45..8a7c54355 100644 --- a/cores/arduino/USB/samd21_host.c +++ b/cores/arduino/USB/samd21_host.c @@ -17,6 +17,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #ifndef USE_TINYUSB #include @@ -27,7 +29,6 @@ #include "variant.h" #include "USB_host.h" #include "samd21_host.h" -#include "sam.h" #include "wiring_digital.h" #include "wiring_private.h" @@ -40,10 +41,198 @@ // Handle UOTGHS Host driver state static uhd_vbus_state_t uhd_state = UHD_STATE_NO_VBUS; +#if defined(__SAME53__) || defined(__SAME54__) +__attribute__((__aligned__(4))) volatile usb_descriptor_host_registers_t usb_pipe_table[USB_EPT_NUM]; +#else // __SAME53__ / __SAME54__ __attribute__((__aligned__(4))) volatile UsbHostDescriptor usb_pipe_table[USB_EPT_NUM]; +#endif // __SAME53__ / __SAME54__ extern void (*gpf_isr)(void); +#if defined(__SAME53__) || defined(__SAME54__) + +void UHD_Init(void) +{ + const uint32_t calibration = *(const uint32_t *)(SW0_ADDR + 4u); + uint32_t pad_transn = (calibration & FUSES_SW0_WORD_1_USB_TRANSN_Msk) >> FUSES_SW0_WORD_1_USB_TRANSN_Pos; + uint32_t pad_transp = (calibration & FUSES_SW0_WORD_1_USB_TRANSP_Msk) >> FUSES_SW0_WORD_1_USB_TRANSP_Pos; + uint32_t pad_trim = (calibration & FUSES_SW0_WORD_1_USB_TRIM_Msk) >> FUSES_SW0_WORD_1_USB_TRIM_Pos; + + USB_SetHandler(&UHD_Handler); + MCLK_REGS->MCLK_APBBMASK |= MCLK_APBBMASK_USB_Msk; + pinPeripheral(PIN_USB_DM, PIO_COM); + pinPeripheral(PIN_USB_DP, PIO_COM); + GCLK_REGS->GCLK_PCHCTRL[USB_GCLK_ID] = GCLK_PCHCTRL_GEN_GCLK1 | GCLK_PCHCTRL_CHEN_Msk; + + USB_REGS->HOST.USB_CTRLA = USB_CTRLA_SWRST_Msk; + while (USB_REGS->HOST.USB_SYNCBUSY & USB_SYNCBUSY_SWRST_Msk); + USB_REGS->HOST.USB_CTRLA = USB_CTRLA_MODE_Msk | USB_CTRLA_RUNSTDBY_Msk; + + if (pad_transn == 0x1f) pad_transn = 5; + if (pad_transp == 0x1f) pad_transp = 29; + if (pad_trim == 0x7) pad_trim = 3; + USB_REGS->HOST.USB_PADCAL = USB_PADCAL_TRANSN(pad_transn) | + USB_PADCAL_TRANSP(pad_transp) | + USB_PADCAL_TRIM(pad_trim); + USB_REGS->HOST.USB_DESCADD = (uint32_t)&usb_pipe_table[0]; + USB_REGS->HOST.USB_CTRLB &= ~USB_HOST_CTRLB_SPDCONF_Msk; + memset((void *)usb_pipe_table, 0, sizeof(usb_pipe_table)); + uhd_state = UHD_STATE_NO_VBUS; + USB_REGS->HOST.USB_CTRLA |= USB_CTRLA_ENABLE_Msk; + while (USB_REGS->HOST.USB_SYNCBUSY & USB_SYNCBUSY_ENABLE_Msk); + + pinMode(PIN_USB_HOST_ENABLE, OUTPUT); + digitalWrite(PIN_USB_HOST_ENABLE, HIGH); + USB_REGS->HOST.USB_INTENSET = USB_HOST_INTENSET_DCONN_Msk | + USB_HOST_INTENSET_WAKEUP_Msk | + USB_HOST_INTENSET_DDISC_Msk; + USB_REGS->HOST.USB_CTRLB |= USB_HOST_CTRLB_VBUSOK_Msk; + + NVIC_SetPriority(USB_OTHER_IRQn, 0UL); + NVIC_SetPriority(USB_SOF_HSOF_IRQn, 0UL); + NVIC_SetPriority(USB_TRCPT0_IRQn, 0UL); + NVIC_SetPriority(USB_TRCPT1_IRQn, 0UL); + NVIC_EnableIRQ(USB_OTHER_IRQn); + NVIC_EnableIRQ(USB_SOF_HSOF_IRQn); + NVIC_EnableIRQ(USB_TRCPT0_IRQn); + NVIC_EnableIRQ(USB_TRCPT1_IRQn); +} + +void UHD_Handler(void) +{ + if ((USB_REGS->HOST.USB_CTRLA & USB_CTRLA_MODE_Msk) == 0) return; + + uint16_t flags = USB_REGS->HOST.USB_INTFLAG; + if (flags & USB_HOST_INTFLAG_HSOF_Msk) { + USB_REGS->HOST.USB_INTFLAG = USB_HOST_INTFLAG_HSOF_Msk; + uhd_state = UHD_STATE_CONNECTED; + } else if (flags & USB_HOST_INTFLAG_RST_Msk) { + USB_REGS->HOST.USB_INTFLAG = USB_HOST_INTFLAG_RST_Msk; + uhd_state = UHD_STATE_DISCONNECTED; + } else if (flags & USB_HOST_INTFLAG_UPRSM_Msk) { + USB_REGS->HOST.USB_INTFLAG = USB_HOST_INTFLAG_UPRSM_Msk; + uhd_state = UHD_STATE_DISCONNECTED; + } else if (flags & USB_HOST_INTFLAG_DNRSM_Msk) { + USB_REGS->HOST.USB_INTFLAG = USB_HOST_INTFLAG_DNRSM_Msk; + uhd_state = UHD_STATE_DISCONNECTED; + } else if (flags & USB_HOST_INTFLAG_WAKEUP_Msk) { + USB_REGS->HOST.USB_INTFLAG = USB_HOST_INTFLAG_WAKEUP_Msk; + uhd_state = UHD_STATE_CONNECTED; + } else if (flags & USB_HOST_INTFLAG_RAMACER_Msk) { + USB_REGS->HOST.USB_INTFLAG = USB_HOST_INTFLAG_RAMACER_Msk; + uhd_state = UHD_STATE_DISCONNECTED; + } else if (flags & USB_HOST_INTFLAG_DCONN_Msk) { + USB_REGS->HOST.USB_INTFLAG = USB_HOST_INTFLAG_DCONN_Msk | USB_HOST_INTFLAG_DDISC_Msk; + USB_REGS->HOST.USB_INTENCLR = USB_HOST_INTENCLR_DCONN_Msk; + USB_REGS->HOST.USB_INTENSET = USB_HOST_INTENSET_DDISC_Msk; + uhd_state = UHD_STATE_CONNECTED; + } else if (flags & USB_HOST_INTFLAG_DDISC_Msk) { + USB_REGS->HOST.USB_INTFLAG = USB_HOST_INTFLAG_DDISC_Msk | USB_HOST_INTFLAG_DCONN_Msk; + USB_REGS->HOST.USB_INTENCLR = USB_HOST_INTENCLR_DDISC_Msk; + USB_REGS->HOST.USB_INTENSET = USB_HOST_INTENSET_DCONN_Msk; + uhd_state = UHD_STATE_DISCONNECTED; + } +} + +uhd_vbus_state_t UHD_GetVBUSState(void) +{ + return uhd_state; +} + +uint32_t UHD_Pipe0_Alloc(uint32_t ul_add, uint32_t ul_ep_size) +{ + (void)ul_add; + (void)ul_ep_size; + uint32_t size = (USB_REGS->HOST.USB_STATUS & USB_HOST_STATUS_SPEED_Msk) ? + USB_PCKSIZE_SIZE_8_BYTES : USB_PCKSIZE_SIZE_64_BYTES; + USB_REGS->HOST.HOST_PIPE[0].USB_PCFG = USB_HOST_PCFG_PTYPE(1); + usb_pipe_table[0].HOST_DESC_BANK[0].USB_CTRL_PIPE = USB_HOST_CTRL_PIPE_PEPNUM(0); + usb_pipe_table[0].HOST_DESC_BANK[0].USB_PCKSIZE = USB_HOST_PCKSIZE_SIZE(size); + return 0; +} + +uint32_t UHD_Pipe_Alloc(uint32_t ul_dev_addr, uint32_t ul_dev_ep, uint32_t ul_type, + uint32_t ul_dir, uint32_t ul_maxsize, uint32_t ul_interval, uint32_t ul_nb_bank) +{ + usb_host_pipe_registers_t *pipe = &USB_REGS->HOST.HOST_PIPE[ul_dev_ep]; + pipe->USB_PCFG = USB_HOST_PCFG_BK(ul_nb_bank) | ul_type | + USB_HOST_PCFG_PTOKEN((ul_dir & USB_EP_DIR_IN) ? 1 : 2); + pipe->USB_BINTERVAL = ul_interval; + if (ul_dir & USB_EP_DIR_IN) pipe->USB_PSTATUSSET = USB_HOST_PSTATUSSET_BK0RDY_Msk; + else pipe->USB_PSTATUSCLR = USB_HOST_PSTATUSCLR_BK0RDY_Msk; + + ul_maxsize = (USB_REGS->HOST.USB_STATUS & USB_HOST_STATUS_SPEED_Msk) ? + USB_PCKSIZE_SIZE_8_BYTES : USB_PCKSIZE_SIZE_64_BYTES; + memset((void *)&usb_pipe_table[ul_dev_ep], 0, sizeof(usb_pipe_table[ul_dev_ep])); + usb_pipe_table[ul_dev_ep].HOST_DESC_BANK[0].USB_CTRL_PIPE = + USB_HOST_CTRL_PIPE_PDADDR(ul_dev_addr) | USB_HOST_CTRL_PIPE_PEPNUM(ul_dev_ep); + usb_pipe_table[ul_dev_ep].HOST_DESC_BANK[0].USB_PCKSIZE = USB_HOST_PCKSIZE_SIZE(ul_maxsize); + return 1; +} + +void UHD_Pipe_CountZero(uint32_t ul_pipe) +{ + usb_pipe_table[ul_pipe].HOST_DESC_BANK[0].USB_PCKSIZE &= ~USB_HOST_PCKSIZE_BYTE_COUNT_Msk; +} + +void UHD_Pipe_Free(uint32_t ul_pipe) +{ + USB_REGS->HOST.HOST_PIPE[ul_pipe].USB_PSTATUSSET = USB_HOST_PSTATUSSET_PFREEZE_Msk; +} + +uint32_t UHD_Pipe_Read(uint32_t pipe_num, uint32_t buf_size, uint8_t *buf) +{ + usb_host_pipe_registers_t *pipe = &USB_REGS->HOST.HOST_PIPE[pipe_num]; + if ((pipe->USB_PCFG & USB_HOST_PCFG_PTYPE_Msk) == USB_HOST_PTYPE_DIS) return 0; + volatile usb_host_desc_bank_registers_t *bank = &usb_pipe_table[pipe_num].HOST_DESC_BANK[0]; + bank->USB_ADDR = (uint32_t)buf; + bank->USB_PCKSIZE = (bank->USB_PCKSIZE & ~(USB_HOST_PCKSIZE_BYTE_COUNT_Msk | + USB_HOST_PCKSIZE_MULTI_PACKET_SIZE_Msk)) | + USB_HOST_PCKSIZE_MULTI_PACKET_SIZE(buf_size); + pipe->USB_PCFG = (pipe->USB_PCFG & ~USB_HOST_PCFG_PTOKEN_Msk) | USB_HOST_PCFG_PTOKEN(1); + pipe->USB_PSTATUSCLR = USB_HOST_PSTATUSCLR_BK0RDY_Msk | USB_HOST_PSTATUSCLR_PFREEZE_Msk; + return buf_size; +} + +void UHD_Pipe_Write(uint32_t ul_pipe, uint32_t ul_size, uint8_t *buf) +{ + volatile usb_host_desc_bank_registers_t *bank = &usb_pipe_table[ul_pipe].HOST_DESC_BANK[0]; + bank->USB_ADDR = (uint32_t)buf; + bank->USB_PCKSIZE = (bank->USB_PCKSIZE & ~(USB_HOST_PCKSIZE_BYTE_COUNT_Msk | + USB_HOST_PCKSIZE_MULTI_PACKET_SIZE_Msk)) | + USB_HOST_PCKSIZE_BYTE_COUNT(ul_size); +} + +void UHD_Pipe_Send(uint32_t ul_pipe, uint32_t ul_token_type) +{ + usb_host_pipe_registers_t *pipe = &USB_REGS->HOST.HOST_PIPE[ul_pipe]; + pipe->USB_PCFG = (pipe->USB_PCFG & ~USB_HOST_PCFG_PTOKEN_Msk) | + USB_HOST_PCFG_PTOKEN(ul_token_type); + if (ul_token_type == USB_HOST_PCFG_PTOKEN_SETUP) { + pipe->USB_PINTFLAG = USB_HOST_PINTFLAG_TXSTP_Msk; + pipe->USB_PSTATUSSET = USB_HOST_PSTATUSSET_BK0RDY_Msk; + } else if (ul_token_type == USB_HOST_PCFG_PTOKEN_IN) { + pipe->USB_PSTATUSCLR = USB_HOST_PSTATUSCLR_BK0RDY_Msk; + } else { + pipe->USB_PINTFLAG = USB_HOST_PINTFLAG_TRCPT1_Msk; + pipe->USB_PSTATUSSET = USB_HOST_PSTATUSSET_BK0RDY_Msk; + } + pipe->USB_PSTATUSCLR = USB_HOST_PSTATUSCLR_PFREEZE_Msk; +} + +uint32_t UHD_Pipe_Is_Transfer_Complete(uint32_t ul_pipe, uint32_t ul_token_type) +{ + usb_host_pipe_registers_t *pipe = &USB_REGS->HOST.HOST_PIPE[ul_pipe]; + uint8_t completion = (ul_token_type == USB_HOST_PCFG_PTOKEN_SETUP) ? + USB_HOST_PINTFLAG_TXSTP_Msk : USB_HOST_PINTFLAG_TRCPT1_Msk; + if ((pipe->USB_PINTFLAG & completion) == 0) return 0; + pipe->USB_PINTFLAG = completion; + pipe->USB_PSTATUSSET = USB_HOST_PSTATUSSET_PFREEZE_Msk; + return 1; +} + +#else // __SAME53__ / __SAME54__ + // NVM Software Calibration Area Mapping // USB TRANSN calibration value. Should be written to the USB PADCAL register. @@ -68,11 +257,11 @@ void UHD_Init(void) USB_SetHandler(&UHD_Handler); /* Enable USB clock */ -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) MCLK->APBBMASK.reg |= MCLK_APBBMASK_USB; #else PM->APBBMASK.reg |= PM_APBBMASK_USB; -#endif +#endif // __SAMD51__ / __SAME51__ /* Set up the USB DP/DM pins */ pinPeripheral( PIN_USB_DM, PIO_COM ); @@ -89,7 +278,7 @@ void UHD_Init(void) * Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference) */ -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) GCLK->PCHCTRL[USB_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); #else GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(6) | // Generic Clock Multiplexer 6 @@ -100,7 +289,7 @@ void UHD_Init(void) { /* Wait for synchronization */ } -#endif +#endif // __SAMD51__ / __SAME51__ /* Reset */ USB->HOST.CTRLA.bit.SWRST = 1; @@ -116,11 +305,11 @@ void UHD_Init(void) /* Load Pad Calibration */ -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) pad_transn = (*((uint32_t *)(NVMCTRL_SW0) // Non-Volatile Memory Controller #else pad_transn = (*((uint32_t *)(NVMCTRL_OTP4) // Non-Volatile Memory Controller -#endif +#endif // __SAMD51__ / __SAME51__ + (NVM_USB_PAD_TRANSN_POS / 32)) >> (NVM_USB_PAD_TRANSN_POS % 32)) @@ -133,11 +322,11 @@ void UHD_Init(void) USB->HOST.PADCAL.bit.TRANSN = pad_transn; -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) pad_transp = (*((uint32_t *)(NVMCTRL_SW0) #else pad_transp = (*((uint32_t *)(NVMCTRL_OTP4) -#endif +#endif // __SAMD51__ / __SAME51__ + (NVM_USB_PAD_TRANSP_POS / 32)) >> (NVM_USB_PAD_TRANSP_POS % 32)) & ((1 << NVM_USB_PAD_TRANSP_SIZE) - 1); @@ -149,11 +338,11 @@ void UHD_Init(void) USB->HOST.PADCAL.bit.TRANSP = pad_transp; -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) pad_trim = (*((uint32_t *)(NVMCTRL_SW0) #else pad_trim = (*((uint32_t *)(NVMCTRL_OTP4) -#endif +#endif // __SAMD51__ / __SAME51__ + (NVM_USB_PAD_TRIM_POS / 32)) >> (NVM_USB_PAD_TRIM_POS % 32)) & ((1 << NVM_USB_PAD_TRIM_SIZE) - 1); @@ -189,7 +378,7 @@ void UHD_Init(void) USB->HOST.CTRLB.bit.VBUSOK = 1; // Configure interrupts -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) NVIC_SetPriority((IRQn_Type)USB_0_IRQn, 0UL); NVIC_SetPriority((IRQn_Type)USB_1_IRQn, 0UL); NVIC_SetPriority((IRQn_Type)USB_2_IRQn, 0UL); @@ -202,7 +391,7 @@ void UHD_Init(void) #else NVIC_SetPriority((IRQn_Type)USB_IRQn, 0UL); NVIC_EnableIRQ((IRQn_Type)USB_IRQn); -#endif +#endif // __SAMD51__ / __SAME51__ } @@ -545,6 +734,8 @@ uint32_t UHD_Pipe_Is_Transfer_Complete(uint32_t ul_pipe, uint32_t ul_token_type) return 0; } +#endif // __SAME53__ / __SAME54__ + @@ -555,4 +746,4 @@ uint32_t UHD_Pipe_Is_Transfer_Complete(uint32_t ul_pipe, uint32_t ul_token_type) #endif // HOST_DEFINED -#endif // USE_TINYUSB +#endif // !USE_TINYUSB diff --git a/cores/arduino/USB/samd21_host.h b/cores/arduino/USB/samd21_host.h index d2d9c9e09..804a17716 100644 --- a/cores/arduino/USB/samd21_host.h +++ b/cores/arduino/USB/samd21_host.h @@ -23,7 +23,11 @@ extern "C" { #endif +#if defined(__SAME53__) || defined(__SAME54__) +extern __attribute__((__aligned__(4))) volatile usb_descriptor_host_registers_t usb_pipe_table[USB_EPT_NUM]; +#else extern __attribute__((__aligned__(4))) volatile UsbHostDescriptor usb_pipe_table[USB_EPT_NUM]; +#endif #define USB_EP_DIR_IN 0x80 // USB_SETUP_DEVICE_TO_HOST #define USB_EP_DIR_OUT 0x00 // USB_SETUP_HOST_TO_DEVICE @@ -41,9 +45,15 @@ extern __attribute__((__aligned__(4))) volatile UsbHostDescriptor usb_pipe_table #define USB_HOST_PCFG_PTOKEN_IN USB_HOST_PCFG_PTOKEN(0x1) #define USB_HOST_PCFG_PTOKEN_OUT USB_HOST_PCFG_PTOKEN(0x2) +#if defined(__SAME53__) || defined(__SAME54__) +#define USB_ERRORFLOW USB_HOST_STATUS_BK_ERRORFLOW_Msk +#define USB_ERRORTIMEOUT USB_HOST_STATUS_PIPE_TOUTER_Msk +#define USB_ERROR_DATATOGGLE USB_HOST_STATUS_PIPE_DTGLER_Msk +#else #define USB_ERRORFLOW USB_HOST_STATUS_BK_ERRORFLOW #define USB_ERRORTIMEOUT USB_HOST_STATUS_PIPE_TOUTER #define USB_ERROR_DATATOGGLE USB_HOST_STATUS_PIPE_DTGLER +#endif #define USB_PCKSIZE_SIZE_8_BYTES 0 #define USB_PCKSIZE_SIZE_16_BYTES 1 @@ -55,6 +65,9 @@ extern __attribute__((__aligned__(4))) volatile UsbHostDescriptor usb_pipe_table #define USB_PCKSIZE_SIZE_1023_BYTES_FS 7 #define USB_PCKSIZE_SIZE_1024_BYTES_HS 7 +#if defined(__SAME53__) || defined(__SAME54__) +// SAME53/E54 host operations use the native register structures directly in samd21_host.c. +#else #define USB_HOST_DTGL(p) (USB->HOST.HostPipe[p].PSTATUS.reg & USB_HOST_PSTATUS_DTGL)>>USB_HOST_PSTATUS_DTGL_Pos // USB host connection/disconnection monitoring @@ -121,6 +134,7 @@ extern __attribute__((__aligned__(4))) volatile UsbHostDescriptor usb_pipe_table // Force full speed mode #define uhd_force_full_speed() USB->HOST.CTRLB.reg &= ~USB_HOST_CTRLB_SPDCONF_Msk +#endif #ifdef __cplusplus } diff --git a/cores/arduino/Uart.cpp b/cores/arduino/Uart.cpp index dd797da4d..8724c49ee 100644 --- a/cores/arduino/Uart.cpp +++ b/cores/arduino/Uart.cpp @@ -24,6 +24,90 @@ #define NO_CTS_PIN 255 #define RTS_RX_THRESHOLD 10 +// Default SERCOM ISR symbols are derived from PERIPH_SERIAL* routing. +// Variants may override SERIAL*_IT_HANDLER* macros when split vectors need +// custom ownership. +#define UART_SERCOM_INDEX_sercom0 0 +#define UART_SERCOM_INDEX_sercom1 1 +#define UART_SERCOM_INDEX_sercom2 2 +#define UART_SERCOM_INDEX_sercom3 3 +#define UART_SERCOM_INDEX_sercom4 4 +#define UART_SERCOM_INDEX_sercom5 5 +#if defined(SERCOM6) || defined(SERCOM6_REGS) +#define UART_SERCOM_INDEX_sercom6 6 +#endif // SERCOM6 || SERCOM6_REGS +#if defined(SERCOM7) || defined(SERCOM7_REGS) +#define UART_SERCOM_INDEX_sercom7 7 +#endif // SERCOM7 || SERCOM7_REGS + +#define UART_SERCOM_INDEX(token) UART_SERCOM_INDEX_##token +#define UART_SERCOM_HANDLER_FROM_INDEX(idx) \ + UART_SERCOM_HANDLER_FROM_INDEX_2(idx) +#define UART_SERCOM_HANDLER_FROM_INDEX_2(idx) SERCOM##idx##_Handler +#define UART_SERCOM_HANDLER_FROM_TOKEN(token) \ + UART_SERCOM_HANDLER_FROM_INDEX(UART_SERCOM_INDEX(token)) + +#define UART_SERCOM_HANDLER0_FROM_INDEX(idx) \ + UART_SERCOM_HANDLER0_FROM_INDEX_2(idx) +#define UART_SERCOM_HANDLER0_FROM_INDEX_2(idx) SERCOM##idx##_0_Handler +#define UART_SERCOM_HANDLER1_FROM_INDEX(idx) \ + UART_SERCOM_HANDLER1_FROM_INDEX_2(idx) +#define UART_SERCOM_HANDLER1_FROM_INDEX_2(idx) SERCOM##idx##_1_Handler +#define UART_SERCOM_HANDLER2_FROM_INDEX(idx) \ + UART_SERCOM_HANDLER2_FROM_INDEX_2(idx) +#define UART_SERCOM_HANDLER2_FROM_INDEX_2(idx) SERCOM##idx##_2_Handler +#define UART_SERCOM_HANDLER3_FROM_INDEX(idx) \ + UART_SERCOM_HANDLER3_FROM_INDEX_2(idx) +#define UART_SERCOM_HANDLER3_FROM_INDEX_2(idx) SERCOM##idx##_3_Handler +#define UART_SERCOM_HANDLER_OTHER_FROM_INDEX(idx) \ + UART_SERCOM_HANDLER_OTHER_FROM_INDEX_2(idx) +#define UART_SERCOM_HANDLER_OTHER_FROM_INDEX_2(idx) SERCOM##idx##_OTHER_Handler + +#define UART_SERCOM_HANDLER0_FROM_TOKEN(token) \ + UART_SERCOM_HANDLER0_FROM_INDEX(UART_SERCOM_INDEX(token)) +#define UART_SERCOM_HANDLER1_FROM_TOKEN(token) \ + UART_SERCOM_HANDLER1_FROM_INDEX(UART_SERCOM_INDEX(token)) +#define UART_SERCOM_HANDLER2_FROM_TOKEN(token) \ + UART_SERCOM_HANDLER2_FROM_INDEX(UART_SERCOM_INDEX(token)) +#define UART_SERCOM_HANDLER3_FROM_TOKEN(token) \ + UART_SERCOM_HANDLER3_FROM_INDEX(UART_SERCOM_INDEX(token)) +#define UART_SERCOM_HANDLER_OTHER_FROM_TOKEN(token) \ + UART_SERCOM_HANDLER_OTHER_FROM_INDEX(UART_SERCOM_INDEX(token)) + +#define UART_DEFINE_SINGLE_HANDLER(handler, instance) \ + void handler(void) { instance.IrqHandler(); } + +#define UART_DEFINE_SAMD51_E51_HANDLERS(handler0, handler1, handler2, \ + handler3, instance) \ + void handler0(void) { instance.IrqHandler(); } \ + void handler1(void) { instance.IrqHandler(); } \ + void handler2(void) { instance.IrqHandler(); } \ + void handler3(void) { instance.IrqHandler(); } + +#define UART_DEFINE_SAME53_E54_HANDLERS(handler0, handler1, handler2, \ + handlerOther, instance) \ + void handler0(void) { instance.IrqHandler(); } \ + void handler1(void) { instance.IrqHandler(); } \ + void handler2(void) { instance.IrqHandler(); } \ + void handlerOther(void) { instance.IrqHandler(); } + +#if defined(__SAMD51__) || defined(__SAME51__) +#define UART_DEFINE_SERCOM_HANDLERS(prefix, instance) \ + UART_DEFINE_SAMD51_E51_HANDLERS(prefix##_IT_HANDLER_0, \ + prefix##_IT_HANDLER_1, \ + prefix##_IT_HANDLER_2, \ + prefix##_IT_HANDLER_3, instance) +#elif defined(__SAME53__) || defined(__SAME54__) +#define UART_DEFINE_SERCOM_HANDLERS(prefix, instance) \ + UART_DEFINE_SAME53_E54_HANDLERS(prefix##_IT_HANDLER_0, \ + prefix##_IT_HANDLER_1, \ + prefix##_IT_HANDLER_2, \ + prefix##_IT_HANDLER_OTHER, instance) +#else +#define UART_DEFINE_SERCOM_HANDLERS(prefix, instance) \ + UART_DEFINE_SINGLE_HANDLER(prefix##_IT_HANDLER, instance) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ + Uart::Uart(SERCOM *_s, uint8_t _pinRX, uint8_t _pinTX, SercomRXPad _padRX, SercomUartTXPad _padTX) : Uart(_s, _pinRX, _pinTX, _padRX, _padTX, NO_RTS_PIN, NO_CTS_PIN) { @@ -38,6 +122,7 @@ Uart::Uart(SERCOM *_s, uint8_t _pinRX, uint8_t _pinTX, SercomRXPad _padRX, Serco uc_padTX = _padTX; uc_pinRTS = _pinRTS; uc_pinCTS = _pinCTS; + txnPoolHead = 0; } void Uart::begin(unsigned long baudrate) @@ -50,7 +135,7 @@ void Uart::begin(unsigned long baudrate, uint16_t config) pinPeripheral(uc_pinRX, g_APinDescription[uc_pinRX].ulPinType); pinPeripheral(uc_pinTX, g_APinDescription[uc_pinTX].ulPinType); - if (uc_padTX == UART_TX_RTS_CTS_PAD_0_2_3) { + if (uc_padTX == UART_TX_RTS_CTS_PAD_0_2_3) { if (uc_pinCTS != NO_CTS_PIN) { pinPeripheral(uc_pinCTS, g_APinDescription[uc_pinCTS].ulPinType); } @@ -60,8 +145,13 @@ void Uart::begin(unsigned long baudrate, uint16_t config) pinMode(uc_pinRTS, OUTPUT); EPortType rtsPort = g_APinDescription[uc_pinRTS].ulPort; +#if defined(__SAME53__) || defined(__SAME54__) + pul_outsetRTS = &PORT_REGS->GROUP[rtsPort].PORT_OUTSET; + pul_outclrRTS = &PORT_REGS->GROUP[rtsPort].PORT_OUTCLR; +#else pul_outsetRTS = &PORT->Group[rtsPort].OUTSET.reg; pul_outclrRTS = &PORT->Group[rtsPort].OUTCLR.reg; +#endif // __SAME53__ / __SAME54__ ul_pinMaskRTS = (1ul << g_APinDescription[uc_pinRTS].ulPin); *pul_outclrRTS = ul_pinMaskRTS; @@ -190,6 +280,138 @@ size_t Uart::write(const uint8_t data) return 1; } +size_t Uart::write(const uint8_t* buffer, size_t size, + void (*onComplete)(void* user, int status), + void* user) +{ + if (buffer == nullptr || size == 0) + return 0; + + if (onComplete == nullptr) { + // Synchronous path: block until complete +#ifdef USE_ZERODMA + SercomTxn* txn = allocateTxn(); + txn->txPtr = buffer; + txn->rxPtr = nullptr; + txn->length = size; + txn->onComplete = &Uart::onTxnComplete; + txn->user = this; + txnDone = false; + txnStatus = 0; + + if (sercom->enqueueUART(txn)) { + while (!txnDone) ; + return size; + } +#endif // USE_ZERODMA + // Fallback: byte-by-byte + for (size_t i = 0; i < size; ++i) + write(buffer[i]); + return size; + } else { + // Asynchronous path: enqueue and return immediately +#ifdef USE_ZERODMA + SercomTxn* txn = allocateTxn(); + txn->txPtr = buffer; + txn->rxPtr = nullptr; + txn->length = size; + txn->onComplete = onComplete; + txn->user = user; + txnDone = false; + txnStatus = 0; + + if (!sercom->enqueueUART(txn)) + return 0; + + return size; +#else + (void)onComplete; + (void)user; + for (size_t i = 0; i < size; ++i) + write(buffer[i]); + return size; +#endif // USE_ZERODMA + } +} + +size_t Uart::read(uint8_t* buffer, size_t size, void (*onComplete)(void* user, int status), void* user) +{ + if (buffer == nullptr || size == 0) + return 0; + + if (onComplete == nullptr) { + // Synchronous path: read from ring buffer + size_t readCount = 0; + while (readCount < size) { + int c = read(); + if (c >= 0) + buffer[readCount++] = static_cast(c); + } + return readCount; + } + +#ifdef USE_ZERODMA + // Asynchronous path: use DMA + pendingRxCb = onComplete; + pendingRxUser = user; + rxExternalActive = true; + + // Disable RXC interrupt; DMA takes over + sercom->disableReceiveCompleteInterruptUART(); + + SercomTxn* txn = allocateTxn(); + txn->txPtr = nullptr; + txn->rxPtr = buffer; + txn->length = size; + txn->onComplete = &Uart::onTxnComplete; + txn->user = this; + txnDone = false; + txnStatus = 0; + + if (!sercom->enqueueUART(txn)) { + // Enqueue failed; restore RXC interrupt and clear pending state + sercom->enableReceiveCompleteInterruptUART(); + rxExternalActive = false; + pendingRxCb = nullptr; + pendingRxUser = nullptr; + return 0; + } + + return size; +#else + (void)onComplete; + (void)user; + return 0; +#endif // USE_ZERODMA +} + +SercomTxn* Uart::allocateTxn() { + // Simple round-robin allocation from pool + SercomTxn* txn = &txnPool[txnPoolHead]; + txnPoolHead = (txnPoolHead + 1) % TXN_POOL_SIZE; + return txn; +} + +void Uart::onTxnComplete(void* user, int status) +{ + if (!user) + return; + Uart* self = static_cast(user); + self->txnStatus = status; + self->txnDone = true; + if (self->rxExternalActive) { + self->rxExternalActive = false; + self->sercom->enableReceiveCompleteInterruptUART(); + if (self->pendingRxCb) { + void (*cb)(void*, int) = self->pendingRxCb; + void* cbUser = self->pendingRxUser; + self->pendingRxCb = nullptr; + self->pendingRxUser = nullptr; + cb(cbUser, status); + } + } +} + SercomNumberStopBit Uart::extractNbStopBit(uint16_t config) { switch(config & HARDSER_STOP_BIT_MASK) @@ -238,3 +460,148 @@ SercomParityMode Uart::extractParity(uint16_t config) return SERCOM_ODD_PARITY; } } + +#if defined(PERIPH_SERIAL) && !defined(UART_VARIANT_OWNS_SERIAL) +Uart Serial(&PERIPH_SERIAL, PIN_SERIAL_RX, PIN_SERIAL_TX, PAD_SERIAL_RX, + PAD_SERIAL_TX); +#ifndef SERIAL_IT_HANDLER +#define SERIAL_IT_HANDLER UART_SERCOM_HANDLER_FROM_TOKEN(PERIPH_SERIAL) +#endif // !SERIAL_IT_HANDLER +#ifndef SERIAL_IT_HANDLER_0 +#define SERIAL_IT_HANDLER_0 UART_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_SERIAL) +#define SERIAL_IT_HANDLER_1 UART_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_SERIAL) +#define SERIAL_IT_HANDLER_2 UART_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_SERIAL) +#if defined(__SAMD51__) || defined(__SAME51__) +#define SERIAL_IT_HANDLER_3 UART_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_SERIAL) +#elif defined(__SAME53__) || defined(__SAME54__) +#define SERIAL_IT_HANDLER_OTHER UART_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_SERIAL) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !SERIAL_IT_HANDLER_0 +UART_DEFINE_SERCOM_HANDLERS(SERIAL, Serial) +#endif // PERIPH_SERIAL && !UART_VARIANT_OWNS_SERIAL + +#if defined(PERIPH_SERIAL_UART) && !defined(UART_VARIANT_OWNS_SERIAL_UART) +Uart SerialUART(&PERIPH_SERIAL_UART, PIN_SERIAL_UART_RX, PIN_SERIAL_UART_TX, + PAD_SERIAL_UART_RX, PAD_SERIAL_UART_TX); +#ifndef SERIAL_UART_IT_HANDLER +#define SERIAL_UART_IT_HANDLER UART_SERCOM_HANDLER_FROM_TOKEN(PERIPH_SERIAL_UART) +#endif // !SERIAL_UART_IT_HANDLER +#ifndef SERIAL_UART_IT_HANDLER_0 +#define SERIAL_UART_IT_HANDLER_0 UART_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_SERIAL_UART) +#define SERIAL_UART_IT_HANDLER_1 UART_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_SERIAL_UART) +#define SERIAL_UART_IT_HANDLER_2 UART_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_SERIAL_UART) +#if defined(__SAMD51__) || defined(__SAME51__) +#define SERIAL_UART_IT_HANDLER_3 UART_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_SERIAL_UART) +#elif defined(__SAME53__) || defined(__SAME54__) +#define SERIAL_UART_IT_HANDLER_OTHER UART_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_SERIAL_UART) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !SERIAL_UART_IT_HANDLER_0 +UART_DEFINE_SERCOM_HANDLERS(SERIAL_UART, SerialUART) +#endif // PERIPH_SERIAL_UART && !UART_VARIANT_OWNS_SERIAL_UART + +#if defined(PERIPH_SERIAL1) && !defined(UART_VARIANT_OWNS_SERIAL1) +#ifdef PIN_SERIAL1_RTS +Uart Serial1(&PERIPH_SERIAL1, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, + PAD_SERIAL1_TX, PIN_SERIAL1_RTS, PIN_SERIAL1_CTS); +#else +Uart Serial1(&PERIPH_SERIAL1, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, + PAD_SERIAL1_TX); +#endif + +#ifndef SERIAL1_IT_HANDLER +#define SERIAL1_IT_HANDLER UART_SERCOM_HANDLER_FROM_TOKEN(PERIPH_SERIAL1) +#endif // !SERIAL1_IT_HANDLER +#ifndef SERIAL1_IT_HANDLER_0 +#define SERIAL1_IT_HANDLER_0 UART_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_SERIAL1) +#define SERIAL1_IT_HANDLER_1 UART_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_SERIAL1) +#define SERIAL1_IT_HANDLER_2 UART_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_SERIAL1) +#if defined(__SAMD51__) || defined(__SAME51__) +#define SERIAL1_IT_HANDLER_3 UART_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_SERIAL1) +#elif defined(__SAME53__) || defined(__SAME54__) +#define SERIAL1_IT_HANDLER_OTHER UART_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_SERIAL1) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !SERIAL1_IT_HANDLER_0 +UART_DEFINE_SERCOM_HANDLERS(SERIAL1, Serial1) +#endif // PERIPH_SERIAL1 && !UART_VARIANT_OWNS_SERIAL1 + +#if defined(PERIPH_SERIAL2) && !defined(UART_VARIANT_OWNS_SERIAL2) +#ifdef PIN_SERIAL2_RTS +Uart Serial2(&PERIPH_SERIAL2, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, + PAD_SERIAL2_TX, PIN_SERIAL2_RTS, PIN_SERIAL2_CTS); +#else +Uart Serial2(&PERIPH_SERIAL2, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, + PAD_SERIAL2_TX); +#endif + +#ifndef SERIAL2_IT_HANDLER +#define SERIAL2_IT_HANDLER UART_SERCOM_HANDLER_FROM_TOKEN(PERIPH_SERIAL2) +#endif // !SERIAL2_IT_HANDLER +#ifndef SERIAL2_IT_HANDLER_0 +#define SERIAL2_IT_HANDLER_0 UART_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_SERIAL2) +#define SERIAL2_IT_HANDLER_1 UART_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_SERIAL2) +#define SERIAL2_IT_HANDLER_2 UART_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_SERIAL2) +#if defined(__SAMD51__) || defined(__SAME51__) +#define SERIAL2_IT_HANDLER_3 UART_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_SERIAL2) +#elif defined(__SAME53__) || defined(__SAME54__) +#define SERIAL2_IT_HANDLER_OTHER UART_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_SERIAL2) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !SERIAL2_IT_HANDLER_0 +UART_DEFINE_SERCOM_HANDLERS(SERIAL2, Serial2) +#endif // PERIPH_SERIAL2 && !UART_VARIANT_OWNS_SERIAL2 + +#if defined(PERIPH_SERIAL3) && !defined(UART_VARIANT_OWNS_SERIAL3) +Uart Serial3(&PERIPH_SERIAL3, PIN_SERIAL3_RX, PIN_SERIAL3_TX, PAD_SERIAL3_RX, + PAD_SERIAL3_TX); +#ifndef SERIAL3_IT_HANDLER +#define SERIAL3_IT_HANDLER UART_SERCOM_HANDLER_FROM_TOKEN(PERIPH_SERIAL3) +#endif // !SERIAL3_IT_HANDLER +#ifndef SERIAL3_IT_HANDLER_0 +#define SERIAL3_IT_HANDLER_0 UART_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_SERIAL3) +#define SERIAL3_IT_HANDLER_1 UART_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_SERIAL3) +#define SERIAL3_IT_HANDLER_2 UART_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_SERIAL3) +#if defined(__SAMD51__) || defined(__SAME51__) +#define SERIAL3_IT_HANDLER_3 UART_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_SERIAL3) +#elif defined(__SAME53__) || defined(__SAME54__) +#define SERIAL3_IT_HANDLER_OTHER UART_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_SERIAL3) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !SERIAL3_IT_HANDLER_0 +UART_DEFINE_SERCOM_HANDLERS(SERIAL3, Serial3) +#endif // PERIPH_SERIAL3 && !UART_VARIANT_OWNS_SERIAL3 + +#if defined(PERIPH_SERIAL4) && !defined(UART_VARIANT_OWNS_SERIAL4) +Uart Serial4(&PERIPH_SERIAL4, PIN_SERIAL4_RX, PIN_SERIAL4_TX, PAD_SERIAL4_RX, + PAD_SERIAL4_TX); +#ifndef SERIAL4_IT_HANDLER +#define SERIAL4_IT_HANDLER UART_SERCOM_HANDLER_FROM_TOKEN(PERIPH_SERIAL4) +#endif // !SERIAL4_IT_HANDLER +#ifndef SERIAL4_IT_HANDLER_0 +#define SERIAL4_IT_HANDLER_0 UART_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_SERIAL4) +#define SERIAL4_IT_HANDLER_1 UART_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_SERIAL4) +#define SERIAL4_IT_HANDLER_2 UART_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_SERIAL4) +#if defined(__SAMD51__) || defined(__SAME51__) +#define SERIAL4_IT_HANDLER_3 UART_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_SERIAL4) +#elif defined(__SAME53__) || defined(__SAME54__) +#define SERIAL4_IT_HANDLER_OTHER UART_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_SERIAL4) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !SERIAL4_IT_HANDLER_0 +UART_DEFINE_SERCOM_HANDLERS(SERIAL4, Serial4) +#endif // PERIPH_SERIAL4 && !UART_VARIANT_OWNS_SERIAL4 + +#if defined(PERIPH_SERIAL5) && !defined(UART_VARIANT_OWNS_SERIAL5) +Uart Serial5(&PERIPH_SERIAL5, PIN_SERIAL_RX, PIN_SERIAL_TX, PAD_SERIAL_RX, + PAD_SERIAL_TX); +#ifndef SERIAL5_IT_HANDLER +#define SERIAL5_IT_HANDLER UART_SERCOM_HANDLER_FROM_TOKEN(PERIPH_SERIAL5) +#endif // !SERIAL5_IT_HANDLER +#ifndef SERIAL5_IT_HANDLER_0 +#define SERIAL5_IT_HANDLER_0 UART_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_SERIAL5) +#define SERIAL5_IT_HANDLER_1 UART_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_SERIAL5) +#define SERIAL5_IT_HANDLER_2 UART_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_SERIAL5) +#if defined(__SAMD51__) || defined(__SAME51__) +#define SERIAL5_IT_HANDLER_3 UART_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_SERIAL5) +#elif defined(__SAME53__) || defined(__SAME54__) +#define SERIAL5_IT_HANDLER_OTHER UART_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_SERIAL5) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !SERIAL5_IT_HANDLER_0 +UART_DEFINE_SERCOM_HANDLERS(SERIAL5, Serial5) +#endif // PERIPH_SERIAL5 && !UART_VARIANT_OWNS_SERIAL5 diff --git a/cores/arduino/Uart.h b/cores/arduino/Uart.h index 8f80ea9ce..cebf72dec 100644 --- a/cores/arduino/Uart.h +++ b/cores/arduino/Uart.h @@ -36,14 +36,25 @@ class Uart : public HardwareSerial int availableForWrite(); int peek(); int read(); + size_t read(uint8_t* buffer, size_t size, + void (*onComplete)(void* user, int status) = nullptr, + void* user = nullptr); void flush(); size_t write(const uint8_t data); + // If onComplete is nullptr, blocks (sync); otherwise enqueues and returns (async) + // Transparently uses DMA when available, falls back to byte-by-byte otherwise + size_t write(const uint8_t* buffer, size_t size, + void (*onComplete)(void* user, int status) = nullptr, + void* user = nullptr); using Print::write; // pull in write(str) and write(buf, size) from Print void IrqHandler(); operator bool() { return true; } + // Accessor for SERCOM peripheral (for direct async transaction enqueuing) + SERCOM* getSercom(void) const { return sercom; } + private: SERCOM *sercom; RingBuffer rxBuffer; @@ -59,6 +70,20 @@ class Uart : public HardwareSerial uint32_t ul_pinMaskRTS; uint8_t uc_pinCTS; + volatile bool txnDone = false; + volatile int txnStatus = 0; + + // Transaction pool for async operations (matches SERCOM queue depth) + static constexpr size_t TXN_POOL_SIZE = 8; + SercomTxn txnPool[TXN_POOL_SIZE]; + uint8_t txnPoolHead = 0; + + SercomTxn* allocateTxn(); + static void onTxnComplete(void* user, int status); + bool rxExternalActive = false; + void (*pendingRxCb)(void* user, int status) = nullptr; + void* pendingRxUser = nullptr; + SercomNumberStopBit extractNbStopBit(uint16_t config); SercomUartCharSize extractCharSize(uint16_t config); SercomParityMode extractParity(uint16_t config); diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index 85b744673..500551a18 100644 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -34,7 +34,7 @@ static void __initialize() memset(ISRcallback, 0, sizeof(ISRcallback)); nints = 0; -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) ///EIC MCLK is enabled by default for (uint32_t i = 0; i <= 15; i++) // EIC_0_IRQn = 12 ... EIC_15_IRQn = 27 { @@ -46,6 +46,19 @@ static void __initialize() } GCLK->PCHCTRL[EIC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK2_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); +#elif defined(__SAME53__) || defined(__SAME54__) + // EIC MCLK is enabled by default. + for (uint32_t i = 0; i <= 15; i++) + { + IRQn_Type irqn = (IRQn_Type)(EIC_EXTINT_0_IRQn + i); + NVIC_DisableIRQ(irqn); + NVIC_ClearPendingIRQ(irqn); + NVIC_SetPriority(irqn, 0); + NVIC_EnableIRQ(irqn); + } + + GCLK_REGS->GCLK_PCHCTRL[EIC_GCLK_ID] = GCLK_PCHCTRL_GEN_GCLK2 | + GCLK_PCHCTRL_CHEN_Msk; #else NVIC_DisableIRQ(EIC_IRQn); NVIC_ClearPendingIRQ(EIC_IRQn); @@ -63,9 +76,12 @@ static void __initialize() */ // Enable EIC -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) EIC->CTRLA.bit.ENABLE = 1; while (EIC->SYNCBUSY.bit.ENABLE == 1) { } +#elif defined(__SAME53__) || defined(__SAME54__) + EIC_REGS->EIC_CTRLA |= EIC_CTRLA_ENABLE_Msk; + while (EIC_REGS->EIC_SYNCBUSY & EIC_SYNCBUSY_ENABLE_Msk) { } #else EIC->CTRL.bit.ENABLE = 1; while (EIC->STATUS.bit.SYNCBUSY == 1) { } @@ -95,7 +111,7 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) } uint32_t inMask = (1UL << in); // Enable wakeup capability on pin in case being used during sleep - #if defined(__SAMD51__) + #if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) //I believe this is done automatically #else EIC->WAKEUP.reg |= (1 << in); @@ -107,29 +123,45 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) if (callback) { if (in == EXTERNAL_INT_NMI) { + uint8_t sense; +#if defined(__SAME53__) || defined(__SAME54__) + EIC_REGS->EIC_NMIFLAG = EIC_NMIFLAG_NMI_Msk; +#else EIC->NMIFLAG.bit.NMI = 1; // Clear flag +#endif switch (mode) { case LOW: - EIC->NMICTRL.bit.NMISENSE = EIC_NMICTRL_NMISENSE_LOW; + sense = EIC_NMICTRL_NMISENSE_LOW_Val; break; case HIGH: - EIC->NMICTRL.bit.NMISENSE = EIC_NMICTRL_NMISENSE_HIGH; + sense = EIC_NMICTRL_NMISENSE_HIGH_Val; break; case CHANGE: - EIC->NMICTRL.bit.NMISENSE = EIC_NMICTRL_NMISENSE_BOTH; + sense = EIC_NMICTRL_NMISENSE_BOTH_Val; break; case FALLING: - EIC->NMICTRL.bit.NMISENSE = EIC_NMICTRL_NMISENSE_FALL; + sense = EIC_NMICTRL_NMISENSE_FALL_Val; break; case RISING: - EIC->NMICTRL.bit.NMISENSE = EIC_NMICTRL_NMISENSE_RISE; + sense = EIC_NMICTRL_NMISENSE_RISE_Val; break; + + default: + return; } +#if defined(__SAME53__) || defined(__SAME54__) + EIC_REGS->EIC_NMICTRL = + (EIC_REGS->EIC_NMICTRL & ~EIC_NMICTRL_NMISENSE_Msk) | + EIC_NMICTRL_NMISENSE(sense); +#else + EIC->NMICTRL.bit.NMISENSE = sense; +#endif + // Assign callback to interrupt ISRcallback[EXTERNAL_INT_NMI] = callback; @@ -164,42 +196,49 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) pos = in << 2; } - #if defined (__SAMD51__) - EIC->CTRLA.bit.ENABLE = 0; - while (EIC->SYNCBUSY.bit.ENABLE == 1) { } - #endif - - EIC->CONFIG[config].reg &=~ (EIC_CONFIG_SENSE0_Msk << pos); // Reset sense mode, important when changing trigger mode during runtime + uint8_t sense; switch (mode) { - case LOW: - EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_LOW_Val << pos; - break; - - case HIGH: - EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_HIGH_Val << pos; - break; - - case CHANGE: - EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_BOTH_Val << pos; - break; + case LOW: sense = EIC_CONFIG_SENSE0_LOW_Val; break; + case HIGH: sense = EIC_CONFIG_SENSE0_HIGH_Val; break; + case CHANGE: sense = EIC_CONFIG_SENSE0_BOTH_Val; break; + case FALLING: sense = EIC_CONFIG_SENSE0_FALL_Val; break; + case RISING: sense = EIC_CONFIG_SENSE0_RISE_Val; break; + default: return; + } - case FALLING: - EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_FALL_Val << pos; - break; + #if defined(__SAMD51__) || defined(__SAME51__) + EIC->CTRLA.bit.ENABLE = 0; + while (EIC->SYNCBUSY.bit.ENABLE == 1) { } + #elif defined(__SAME53__) || defined(__SAME54__) + EIC_REGS->EIC_CTRLA &= ~EIC_CTRLA_ENABLE_Msk; + while (EIC_REGS->EIC_SYNCBUSY & EIC_SYNCBUSY_ENABLE_Msk) { } + #endif - case RISING: - EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_RISE_Val << pos; - break; - } +#if defined(__SAME53__) || defined(__SAME54__) + EIC_REGS->EIC_CONFIG[config] = + (EIC_REGS->EIC_CONFIG[config] & ~(EIC_CONFIG_SENSE0_Msk << pos)) | + ((uint32_t)sense << pos); +#else + EIC->CONFIG[config].reg = + (EIC->CONFIG[config].reg & ~(EIC_CONFIG_SENSE0_Msk << pos)) | + ((uint32_t)sense << pos); +#endif } // Enable the interrupt +#if defined(__SAME53__) || defined(__SAME54__) + EIC_REGS->EIC_INTENSET = EIC_INTENSET_EXTINT(1 << in); +#else EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << in); +#endif } - #if defined (__SAMD51__) + #if defined(__SAMD51__) || defined(__SAME51__) EIC->CTRLA.bit.ENABLE = 1; while (EIC->SYNCBUSY.bit.ENABLE == 1) { } + #elif defined(__SAME53__) || defined(__SAME54__) + EIC_REGS->EIC_CTRLA |= EIC_CTRLA_ENABLE_Msk; + while (EIC_REGS->EIC_SYNCBUSY & EIC_SYNCBUSY_ENABLE_Msk) { } #endif } @@ -216,12 +255,20 @@ void detachInterrupt(uint32_t pin) if (in == NOT_AN_INTERRUPT) return; if(in == EXTERNAL_INT_NMI) { +#if defined(__SAME53__) || defined(__SAME54__) + EIC_REGS->EIC_NMICTRL &= ~EIC_NMICTRL_NMISENSE_Msk; +#else EIC->NMICTRL.bit.NMISENSE = 0; // Turn off detection +#endif } else { +#if defined(__SAME53__) || defined(__SAME54__) + EIC_REGS->EIC_INTENCLR = EIC_INTENCLR_EXTINT(1 << in); +#else EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT(1 << in); +#endif // Disable wakeup capability on pin during sleep -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) //I believe this is done automatically #else // Disable wakeup capability on pin during sleep @@ -249,7 +296,7 @@ void detachInterrupt(uint32_t pin) /* * External Interrupt Controller NVIC Interrupt Handler */ -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) void InterruptHandler(uint32_t unused_i) { (void)unused_i; @@ -259,16 +306,25 @@ void InterruptHandler(uint32_t unused_i) // Loop over all enabled interrupts in the list for (uint32_t i=0; iEIC_INTFLAG & ISRlist[i]) != 0) + #else if ((EIC->INTFLAG.reg & ISRlist[i]) != 0) + #endif { // Call the callback function ISRcallback[i](); // Clear the interrupt + #if defined(__SAME53__) || defined(__SAME54__) + EIC_REGS->EIC_INTFLAG = ISRlist[i]; + #else EIC->INTFLAG.reg = ISRlist[i]; + #endif } } } +#if defined(__SAMD51__) || defined(__SAME51__) void EIC_0_Handler(void) { InterruptHandler(EXTERNAL_INT_0); @@ -348,6 +404,24 @@ void EIC_15_Handler(void) { InterruptHandler(EXTERNAL_INT_15); } +#elif defined(__SAME53__) || defined(__SAME54__) +void EIC_EXTINT_0_Handler(void) { InterruptHandler(EXTERNAL_INT_0); } +void EIC_EXTINT_1_Handler(void) { InterruptHandler(EXTERNAL_INT_1); } +void EIC_EXTINT_2_Handler(void) { InterruptHandler(EXTERNAL_INT_2); } +void EIC_EXTINT_3_Handler(void) { InterruptHandler(EXTERNAL_INT_3); } +void EIC_EXTINT_4_Handler(void) { InterruptHandler(EXTERNAL_INT_4); } +void EIC_EXTINT_5_Handler(void) { InterruptHandler(EXTERNAL_INT_5); } +void EIC_EXTINT_6_Handler(void) { InterruptHandler(EXTERNAL_INT_6); } +void EIC_EXTINT_7_Handler(void) { InterruptHandler(EXTERNAL_INT_7); } +void EIC_EXTINT_8_Handler(void) { InterruptHandler(EXTERNAL_INT_8); } +void EIC_EXTINT_9_Handler(void) { InterruptHandler(EXTERNAL_INT_9); } +void EIC_EXTINT_10_Handler(void) { InterruptHandler(EXTERNAL_INT_10); } +void EIC_EXTINT_11_Handler(void) { InterruptHandler(EXTERNAL_INT_11); } +void EIC_EXTINT_12_Handler(void) { InterruptHandler(EXTERNAL_INT_12); } +void EIC_EXTINT_13_Handler(void) { InterruptHandler(EXTERNAL_INT_13); } +void EIC_EXTINT_14_Handler(void) { InterruptHandler(EXTERNAL_INT_14); } +void EIC_EXTINT_15_Handler(void) { InterruptHandler(EXTERNAL_INT_15); } +#endif #else void EIC_Handler(void) diff --git a/cores/arduino/WVariant.h b/cores/arduino/WVariant.h index cb7202d84..6ad36040d 100644 --- a/cores/arduino/WVariant.h +++ b/cores/arduino/WVariant.h @@ -20,9 +20,26 @@ #pragma once #include -#include "sam.h" +#include #include +#if defined(__SAMD51__) || defined(__SAME51__) +enum { + ARDUINO_TCC_INSTANCE_COUNT = TCC_INST_NUM, + ARDUINO_TC_INSTANCE_COUNT = TC_INST_NUM, +}; +#elif defined(__SAME53__) || defined(__SAME54__) +enum { + ARDUINO_TCC_INSTANCE_COUNT = 5, + ARDUINO_TC_INSTANCE_COUNT = 8, +}; +#else +enum { + ARDUINO_TCC_INSTANCE_COUNT = TCC_INST_NUM, + ARDUINO_TC_INSTANCE_COUNT = TC_INST_NUM, +}; +#endif + #ifdef __cplusplus extern "C" { #endif @@ -39,18 +56,30 @@ typedef enum _EAnalogChannel ADC_Channel5=5, ADC_Channel6=6, ADC_Channel7=7, -#if defined __SAMD21J18A__ || defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) ADC_Channel8=8, ADC_Channel9=9, -#endif // __SAMD21J18A__ +#else + #if defined(__SAMD21J18A__) + ADC_Channel8=8, + ADC_Channel9=9, + #endif +#endif ADC_Channel10=10, ADC_Channel11=11, -#if defined __SAMD21J18A__ || defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) ADC_Channel12=12, ADC_Channel13=13, ADC_Channel14=14, ADC_Channel15=15, -#endif // __SAMD21J18A__ +#else + #if defined(__SAMD21J18A__) + ADC_Channel12=12, + ADC_Channel13=13, + ADC_Channel14=14, + ADC_Channel15=15, + #endif +#endif ADC_Channel16=16, ADC_Channel17=17, ADC_Channel18=18, @@ -61,7 +90,7 @@ typedef enum _EAnalogChannel ADC_Channel_PTAT=0x1C, } EAnalogChannel ; -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) #if defined(__SAMD51G19A__) || defined(__SAME51G19A__) @@ -136,7 +165,7 @@ typedef enum _ETCChannel TC7_CH1 = (12<<8)|(1), } ETCChannel ; -#elif defined(__SAME53N20A__) || defined(__SAME53N19A__) || defined(__SAME54P20A__) || defined(__SAME54P19A__) || defined(__SAME54N20A__) || defined(__SAME54N19A__) || defined(__SAMD51P20A__) || defined(__SAMD51P19A__) || defined(__SAMD51N20A__) || defined(__SAMD51N19A__) || defined(__SAME51N20A__) || defined(__SAME51N19A__) +#else typedef enum _ETCChannel { @@ -179,7 +208,7 @@ typedef enum _ETCChannel #endif typedef ETCChannel EPWMChannel; -extern const uint32_t GCLK_CLKCTRL_IDs[TCC_INST_NUM+TC_INST_NUM]; +extern const uint32_t GCLK_CLKCTRL_IDs[ARDUINO_TCC_INSTANCE_COUNT + ARDUINO_TC_INSTANCE_COUNT]; #define NOT_ON_PWM NOT_ON_TIMER @@ -254,7 +283,7 @@ typedef enum _EPWMChannel #endif -extern const void* g_apTCInstances[TCC_INST_NUM+TC_INST_NUM] ; +extern const void* g_apTCInstances[ARDUINO_TCC_INSTANCE_COUNT + ARDUINO_TC_INSTANCE_COUNT] ; #define GetTCNumber( x ) ( (x) >> 8 ) #define GetTCChannelNumber( x ) ( (x) & 0xff ) @@ -307,7 +336,7 @@ typedef enum _EPioType PIO_SERCOM_ALT, /* The pin is controlled by the associated signal of peripheral D. */ PIO_TIMER, /* The pin is controlled by the associated signal of peripheral E. */ PIO_TIMER_ALT, /* The pin is controlled by the associated signal of peripheral F. */ -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) PIO_TCC_PDEC, /* The pin is controlled by the associated signal of peripheral G. */ PIO_COM, /* The pin is controlled by the associated signal of peripheral H. */ PIO_SDHC, /* The pin is controlled by the associated signal of peripheral I. */ @@ -341,7 +370,7 @@ typedef enum _EPioType #define PIN_ATTR_EXTINT (1UL<<6) #define PIN_ATTR_ANALOG_ALT (1UL<<7) -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) // these correspond to the mux table #define PIN_ATTR_PWM_E (1UL<<3) #define PIN_ATTR_PWM_F (1UL<<8) diff --git a/cores/arduino/cortex_handlers.c b/cores/arduino/cortex_handlers.c index 953d1a6e1..2f3c670b8 100644 --- a/cores/arduino/cortex_handlers.c +++ b/cores/arduino/cortex_handlers.c @@ -35,7 +35,7 @@ void Dummy_Handler(void) for (;;) { } } -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) /* Cortex-M4 processor handlers */ void Reset_Handler ( void ); @@ -62,6 +62,7 @@ void SUPC_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Han void SUPC_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void WDT_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void RTC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#if defined(__SAMD51__) || defined(__SAME51__) void EIC_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void EIC_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void EIC_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); @@ -78,6 +79,25 @@ void EIC_12_Handler ( void ) __attribute__ ((weak, alias("Dummy_Han void EIC_13_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void EIC_14_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void EIC_15_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#elif defined(__SAME53__) || defined(__SAME54__) +void EIC_EXTINT_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_EXTINT_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_EXTINT_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_EXTINT_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_EXTINT_4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_EXTINT_5_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_EXTINT_6_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_EXTINT_7_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_EXTINT_8_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_EXTINT_9_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_EXTINT_10_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_EXTINT_11_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_EXTINT_12_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_EXTINT_13_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_EXTINT_14_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_EXTINT_15_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#else +#endif void FREQM_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void NVMCTRL_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void NVMCTRL_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); @@ -85,7 +105,11 @@ void DMAC_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Han void DMAC_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void DMAC_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void DMAC_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#if defined(__SAME53__) || defined(__SAME54__) +void DMAC_OTHER_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#else void DMAC_4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#endif void EVSYS_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void EVSYS_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void EVSYS_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); @@ -98,41 +122,89 @@ void RAMECC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Han void SERCOM0_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM0_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM0_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#if defined(__SAMD51__) || defined(__SAME51__) void SERCOM0_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#elif defined(__SAME53__) || defined(__SAME54__) +void SERCOM0_OTHER_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#else +#endif void SERCOM1_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM1_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM1_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#if defined(__SAMD51__) || defined(__SAME51__) void SERCOM1_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#elif defined(__SAME53__) || defined(__SAME54__) +void SERCOM1_OTHER_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#else +#endif void SERCOM2_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM2_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM2_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#if defined(__SAMD51__) || defined(__SAME51__) void SERCOM2_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#elif defined(__SAME53__) || defined(__SAME54__) +void SERCOM2_OTHER_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#else +#endif void SERCOM3_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM3_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM3_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#if defined(__SAMD51__) || defined(__SAME51__) void SERCOM3_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#elif defined(__SAME53__) || defined(__SAME54__) +void SERCOM3_OTHER_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#else +#endif void SERCOM4_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM4_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM4_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#if defined(__SAMD51__) || defined(__SAME51__) void SERCOM4_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#elif defined(__SAME53__) || defined(__SAME54__) +void SERCOM4_OTHER_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#else +#endif void SERCOM5_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM5_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM5_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#if defined(__SAMD51__) || defined(__SAME51__) void SERCOM5_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#elif defined(__SAME53__) || defined(__SAME54__) +void SERCOM5_OTHER_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#else +#endif void SERCOM6_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM6_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM6_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#if defined(__SAMD51__) || defined(__SAME51__) void SERCOM6_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#elif defined(__SAME53__) || defined(__SAME54__) +void SERCOM6_OTHER_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#else +#endif void SERCOM7_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM7_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM7_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#if defined(__SAMD51__) || defined(__SAME51__) void SERCOM7_3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#elif defined(__SAME53__) || defined(__SAME54__) +void SERCOM7_OTHER_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#else +#endif void CAN0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void CAN1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#if defined(__SAMD51__) || defined(__SAME51__) void USB_0_Handler ( void ) __attribute__ ((weak)); void USB_1_Handler ( void ) __attribute__ ((weak)); void USB_2_Handler ( void ) __attribute__ ((weak)); void USB_3_Handler ( void ) __attribute__ ((weak)); +#elif defined(__SAME53__) || defined(__SAME54__) +void USB_OTHER_Handler ( void ) __attribute__ ((weak)); +void USB_SOF_HSOF_Handler ( void ) __attribute__ ((weak)); +void USB_TRCPT0_Handler ( void ) __attribute__ ((weak)); +void USB_TRCPT1_Handler ( void ) __attribute__ ((weak)); +#else +#endif void GMAC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void TCC0_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void TCC0_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); @@ -167,10 +239,17 @@ void TC7_Handler ( void ) __attribute__ ((weak, alias("Dummy_Han void PDEC_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void PDEC_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void PDEC_2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#if defined(__SAME53__) || defined(__SAME54__) +void ADC0_OTHER_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void ADC0_RESRDY_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void ADC1_OTHER_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void ADC1_RESRDY_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#else void ADC0_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void ADC0_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void ADC1_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void ADC1_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +#endif void AC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void DAC_0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); void DAC_1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); @@ -232,6 +311,7 @@ __attribute__ ((section(".isr_vector"))) const DeviceVectors exception_table = (void*) SUPC_1_Handler, /* 9 Supply Controller IRQ 1 */ (void*) WDT_Handler, /* 10 Watchdog Timer */ (void*) RTC_Handler, /* 11 Real-Time Counter */ +#if defined(__SAMD51__) || defined(__SAME51__) (void*) EIC_0_Handler, /* 12 External Interrupt Controller IRQ 0 */ (void*) EIC_1_Handler, /* 13 External Interrupt Controller IRQ 1 */ (void*) EIC_2_Handler, /* 14 External Interrupt Controller IRQ 2 */ @@ -248,6 +328,25 @@ __attribute__ ((section(".isr_vector"))) const DeviceVectors exception_table = (void*) EIC_13_Handler, /* 25 External Interrupt Controller IRQ 13 */ (void*) EIC_14_Handler, /* 26 External Interrupt Controller IRQ 14 */ (void*) EIC_15_Handler, /* 27 External Interrupt Controller IRQ 15 */ +#elif defined(__SAME53__) || defined(__SAME54__) + (void*) EIC_EXTINT_0_Handler, /* 12 External Interrupt Controller IRQ 0 */ + (void*) EIC_EXTINT_1_Handler, /* 13 External Interrupt Controller IRQ 1 */ + (void*) EIC_EXTINT_2_Handler, /* 14 External Interrupt Controller IRQ 2 */ + (void*) EIC_EXTINT_3_Handler, /* 15 External Interrupt Controller IRQ 3 */ + (void*) EIC_EXTINT_4_Handler, /* 16 External Interrupt Controller IRQ 4 */ + (void*) EIC_EXTINT_5_Handler, /* 17 External Interrupt Controller IRQ 5 */ + (void*) EIC_EXTINT_6_Handler, /* 18 External Interrupt Controller IRQ 6 */ + (void*) EIC_EXTINT_7_Handler, /* 19 External Interrupt Controller IRQ 7 */ + (void*) EIC_EXTINT_8_Handler, /* 20 External Interrupt Controller IRQ 8 */ + (void*) EIC_EXTINT_9_Handler, /* 21 External Interrupt Controller IRQ 9 */ + (void*) EIC_EXTINT_10_Handler, /* 22 External Interrupt Controller IRQ 10 */ + (void*) EIC_EXTINT_11_Handler, /* 23 External Interrupt Controller IRQ 11 */ + (void*) EIC_EXTINT_12_Handler, /* 24 External Interrupt Controller IRQ 12 */ + (void*) EIC_EXTINT_13_Handler, /* 25 External Interrupt Controller IRQ 13 */ + (void*) EIC_EXTINT_14_Handler, /* 26 External Interrupt Controller IRQ 14 */ + (void*) EIC_EXTINT_15_Handler, /* 27 External Interrupt Controller IRQ 15 */ +#else +#endif (void*) FREQM_Handler, /* 28 Frequency Meter */ (void*) NVMCTRL_0_Handler, /* 29 Non-Volatile Memory Controller IRQ 0 */ (void*) NVMCTRL_1_Handler, /* 30 Non-Volatile Memory Controller IRQ 1 */ @@ -255,7 +354,11 @@ __attribute__ ((section(".isr_vector"))) const DeviceVectors exception_table = (void*) DMAC_1_Handler, /* 32 Direct Memory Access Controller IRQ 1 */ (void*) DMAC_2_Handler, /* 33 Direct Memory Access Controller IRQ 2 */ (void*) DMAC_3_Handler, /* 34 Direct Memory Access Controller IRQ 3 */ +#if defined(__SAME53__) || defined(__SAME54__) + (void*) DMAC_OTHER_Handler, /* 35 Direct Memory Access Controller other IRQ */ +#else (void*) DMAC_4_Handler, /* 35 Direct Memory Access Controller IRQ 4 */ +#endif (void*) EVSYS_0_Handler, /* 36 Event System Interface IRQ 0 */ (void*) EVSYS_1_Handler, /* 37 Event System Interface IRQ 1 */ (void*) EVSYS_2_Handler, /* 38 Event System Interface IRQ 2 */ @@ -269,41 +372,89 @@ __attribute__ ((section(".isr_vector"))) const DeviceVectors exception_table = (void*) SERCOM0_0_Handler, /* 46 Serial Communication Interface 0 IRQ 0 */ (void*) SERCOM0_1_Handler, /* 47 Serial Communication Interface 0 IRQ 1 */ (void*) SERCOM0_2_Handler, /* 48 Serial Communication Interface 0 IRQ 2 */ +#if defined(__SAMD51__) || defined(__SAME51__) (void*) SERCOM0_3_Handler, /* 49 Serial Communication Interface 0 IRQ 3 */ +#elif defined(__SAME53__) || defined(__SAME54__) + (void*) SERCOM0_OTHER_Handler, /* Serial Communication Interface 0 other IRQ */ +#else +#endif (void*) SERCOM1_0_Handler, /* 50 Serial Communication Interface 1 IRQ 0 */ (void*) SERCOM1_1_Handler, /* 51 Serial Communication Interface 1 IRQ 1 */ (void*) SERCOM1_2_Handler, /* 52 Serial Communication Interface 1 IRQ 2 */ +#if defined(__SAMD51__) || defined(__SAME51__) (void*) SERCOM1_3_Handler, /* 53 Serial Communication Interface 1 IRQ 3 */ +#elif defined(__SAME53__) || defined(__SAME54__) + (void*) SERCOM1_OTHER_Handler, /* Serial Communication Interface 1 other IRQ */ +#else +#endif (void*) SERCOM2_0_Handler, /* 54 Serial Communication Interface 2 IRQ 0 */ (void*) SERCOM2_1_Handler, /* 55 Serial Communication Interface 2 IRQ 1 */ (void*) SERCOM2_2_Handler, /* 56 Serial Communication Interface 2 IRQ 2 */ +#if defined(__SAMD51__) || defined(__SAME51__) (void*) SERCOM2_3_Handler, /* 57 Serial Communication Interface 2 IRQ 3 */ +#elif defined(__SAME53__) || defined(__SAME54__) + (void*) SERCOM2_OTHER_Handler, /* Serial Communication Interface 2 other IRQ */ +#else +#endif (void*) SERCOM3_0_Handler, /* 58 Serial Communication Interface 3 IRQ 0 */ (void*) SERCOM3_1_Handler, /* 59 Serial Communication Interface 3 IRQ 1 */ (void*) SERCOM3_2_Handler, /* 60 Serial Communication Interface 3 IRQ 2 */ +#if defined(__SAMD51__) || defined(__SAME51__) (void*) SERCOM3_3_Handler, /* 61 Serial Communication Interface 3 IRQ 3 */ +#elif defined(__SAME53__) || defined(__SAME54__) + (void*) SERCOM3_OTHER_Handler, /* Serial Communication Interface 3 other IRQ */ +#else +#endif (void*) SERCOM4_0_Handler, /* 62 Serial Communication Interface 4 IRQ 0 */ (void*) SERCOM4_1_Handler, /* 63 Serial Communication Interface 4 IRQ 1 */ (void*) SERCOM4_2_Handler, /* 64 Serial Communication Interface 4 IRQ 2 */ +#if defined(__SAMD51__) || defined(__SAME51__) (void*) SERCOM4_3_Handler, /* 65 Serial Communication Interface 4 IRQ 3 */ +#elif defined(__SAME53__) || defined(__SAME54__) + (void*) SERCOM4_OTHER_Handler, /* Serial Communication Interface 4 other IRQ */ +#else +#endif (void*) SERCOM5_0_Handler, /* 66 Serial Communication Interface 5 IRQ 0 */ (void*) SERCOM5_1_Handler, /* 67 Serial Communication Interface 5 IRQ 1 */ (void*) SERCOM5_2_Handler, /* 68 Serial Communication Interface 5 IRQ 2 */ +#if defined(__SAMD51__) || defined(__SAME51__) (void*) SERCOM5_3_Handler, /* 69 Serial Communication Interface 5 IRQ 3 */ +#elif defined(__SAME53__) || defined(__SAME54__) + (void*) SERCOM5_OTHER_Handler, /* Serial Communication Interface 5 other IRQ */ +#else +#endif (void*) SERCOM6_0_Handler, /* 70 Serial Communication Interface 6 IRQ 0 */ (void*) SERCOM6_1_Handler, /* 71 Serial Communication Interface 6 IRQ 1 */ (void*) SERCOM6_2_Handler, /* 72 Serial Communication Interface 6 IRQ 2 */ +#if defined(__SAMD51__) || defined(__SAME51__) (void*) SERCOM6_3_Handler, /* 73 Serial Communication Interface 6 IRQ 3 */ +#elif defined(__SAME53__) || defined(__SAME54__) + (void*) SERCOM6_OTHER_Handler, /* Serial Communication Interface 6 other IRQ */ +#else +#endif (void*) SERCOM7_0_Handler, /* 74 Serial Communication Interface 7 IRQ 0 */ (void*) SERCOM7_1_Handler, /* 75 Serial Communication Interface 7 IRQ 1 */ (void*) SERCOM7_2_Handler, /* 76 Serial Communication Interface 7 IRQ 2 */ +#if defined(__SAMD51__) || defined(__SAME51__) (void*) SERCOM7_3_Handler, /* 77 Serial Communication Interface 7 IRQ 3 */ +#elif defined(__SAME53__) || defined(__SAME54__) + (void*) SERCOM7_OTHER_Handler, /* Serial Communication Interface 7 other IRQ */ +#else +#endif (void*) CAN0_Handler, /* 78 Control Area Network 0 (SAM E5x) */ (void*) CAN1_Handler, /* 79 Control Area Network 0 (SAM E5x) */ +#if defined(__SAMD51__) || defined(__SAME51__) (void*) USB_0_Handler, /* 80 Universal Serial Bus IRQ 0 */ (void*) USB_1_Handler, /* 81 Universal Serial Bus IRQ 1 */ (void*) USB_2_Handler, /* 82 Universal Serial Bus IRQ 2 */ (void*) USB_3_Handler, /* 83 Universal Serial Bus IRQ 3 */ +#elif defined(__SAME53__) || defined(__SAME54__) + (void*) USB_OTHER_Handler, /* 80 Universal Serial Bus other IRQ */ + (void*) USB_SOF_HSOF_Handler, /* 81 Universal Serial Bus SOF/HSOF IRQ */ + (void*) USB_TRCPT0_Handler, /* 82 Universal Serial Bus transfer complete 0 IRQ */ + (void*) USB_TRCPT1_Handler, /* 83 Universal Serial Bus transfer complete 1 IRQ */ +#else +#endif (void*) GMAC_Handler, /* 84 Ethernet MAC */ (void*) TCC0_0_Handler, /* 85 Timer Counter Control 0 IRQ 0 */ (void*) TCC0_1_Handler, /* 86 Timer Counter Control 0 IRQ 1 */ @@ -338,10 +489,17 @@ __attribute__ ((section(".isr_vector"))) const DeviceVectors exception_table = (void*) PDEC_0_Handler, /* 115 Quadrature Decodeur IRQ 0 */ (void*) PDEC_1_Handler, /* 116 Quadrature Decodeur IRQ 1 */ (void*) PDEC_2_Handler, /* 117 Quadrature Decodeur IRQ 2 */ +#if defined(__SAME53__) || defined(__SAME54__) + (void*) ADC0_OTHER_Handler, /* 118 Analog Digital Converter 0 other IRQ */ + (void*) ADC0_RESRDY_Handler, /* 119 Analog Digital Converter 0 result-ready IRQ */ + (void*) ADC1_OTHER_Handler, /* 120 Analog Digital Converter 1 other IRQ */ + (void*) ADC1_RESRDY_Handler, /* 121 Analog Digital Converter 1 result-ready IRQ */ +#else (void*) ADC0_0_Handler, /* 118 Analog Digital Converter 0 IRQ 0 */ (void*) ADC0_1_Handler, /* 119 Analog Digital Converter 0 IRQ 1 */ (void*) ADC1_0_Handler, /* 120 Analog Digital Converter 1 IRQ 0 */ (void*) ADC1_1_Handler, /* 121 Analog Digital Converter 1 IRQ 1 */ +#endif (void*) AC_Handler, /* 122 Analog Comparators */ (void*) DAC_0_Handler, /* 123 Digital-to-Analog Converter IRQ 0 */ (void*) DAC_1_Handler, /* 124 Digital-to-Analog Converter IRQ 1 */ @@ -465,6 +623,7 @@ __attribute__ ((section(".isr_vector"))) const DeviceVectors exception_table = #endif extern int main(void); +extern void SystemInit(void); /* This is called on processor reset to initialize the device and call main() */ void Reset_Handler(void) @@ -486,7 +645,8 @@ void Reset_Handler(void) *pDest = 0; } -#if defined(__FPU_USED) && defined(__SAMD51__) +#if defined(__FPU_USED) && \ + (defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__)) /* Enable FPU */ SCB->CPACR |= (0xFu << 20); __DSB(); @@ -513,32 +673,26 @@ void SysTick_Handler(void) static void (*usb_isr)(void) = NULL; -#if defined(__SAMD51__) -void USB_0_Handler(void) -{ - if (usb_isr) - usb_isr(); -} -void USB_1_Handler(void) +static void dispatchUSBInterrupt(void) { if (usb_isr) - usb_isr(); -} -void USB_2_Handler(void) -{ - if (usb_isr) - usb_isr(); -} -void USB_3_Handler(void) -{ - if (usb_isr) - usb_isr(); + usb_isr(); } + +#if defined(__SAMD51__) || defined(__SAME51__) +void USB_0_Handler(void) { dispatchUSBInterrupt(); } +void USB_1_Handler(void) { dispatchUSBInterrupt(); } +void USB_2_Handler(void) { dispatchUSBInterrupt(); } +void USB_3_Handler(void) { dispatchUSBInterrupt(); } +#elif defined(__SAME53__) || defined(__SAME54__) +void USB_OTHER_Handler(void) { dispatchUSBInterrupt(); } +void USB_SOF_HSOF_Handler(void) { dispatchUSBInterrupt(); } +void USB_TRCPT0_Handler(void) { dispatchUSBInterrupt(); } +void USB_TRCPT1_Handler(void) { dispatchUSBInterrupt(); } #else void USB_Handler(void) { - if (usb_isr) - usb_isr(); + dispatchUSBInterrupt(); } #endif diff --git a/cores/arduino/pulse.c b/cores/arduino/pulse.c index 6ead704dd..194ae3028 100644 --- a/cores/arduino/pulse.c +++ b/cores/arduino/pulse.c @@ -34,14 +34,18 @@ uint32_t pulseIn(uint32_t pin, uint32_t state, uint32_t timeout) uint32_t bit = 1 << p.ulPin; uint32_t stateMask = state ? bit : 0; -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) /* * The SAMD51 is fast enough to use really obvious code (similar to * what was used to produce pulse_asm.S, but using micros() for timing. * No assembly required, no conversion of loop counts to times (which is * worrisome in the presence of cache.) */ - const volatile uint32_t *port = &(PORT->Group[p.ulPort].IN.reg); +#if defined(__SAME53__) || defined(__SAME54__) + const volatile uint32_t *port = &PORT_REGS->GROUP[p.ulPort].PORT_IN; +#else + const volatile uint32_t *port = &PORT->Group[p.ulPort].IN.reg; +#endif uint32_t usCallStart; // microseconds at start of call, for timeout. uint32_t usPulseStart; // microseconds at start of measured pulse. usCallStart = usPulseStart = micros(); @@ -80,4 +84,3 @@ uint32_t pulseIn(uint32_t pin, uint32_t state, uint32_t timeout) return 0; #endif // SAMD51 } - diff --git a/cores/arduino/startup.c b/cores/arduino/startup.c index 676844091..a0f1caf88 100644 --- a/cores/arduino/startup.c +++ b/cores/arduino/startup.c @@ -17,15 +17,17 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "sam.h" +#include #include "variant.h" #include +extern uint32_t SystemCoreClock; + // Constants for Clock generators #define GENERIC_CLOCK_GENERATOR_MAIN (0u) -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) #define GENERIC_CLOCK_GENERATOR_XOSC32K (3u) #define GENERIC_CLOCK_GENERATOR_48M (1u) #define GENERIC_CLOCK_GENERATOR_48M_SYNC GCLK_SYNCBUSY_GENCTRL1 @@ -40,6 +42,16 @@ #define GENERIC_CLOCK_GENERATOR_1M (5u) //#define CRYSTALLESS +#elif defined(__SAME53__) || defined(__SAME54__) +#define GENERIC_CLOCK_GENERATOR_XOSC32K (3u) +#define GENERIC_CLOCK_GENERATOR_48M (1u) +#define GENERIC_CLOCK_GENERATOR_48M_SYNC GCLK_SYNCBUSY_GENCTRL_Msk +#define GENERIC_CLOCK_GENERATOR_100M (2u) +#define GENERIC_CLOCK_GENERATOR_100M_SYNC GCLK_SYNCBUSY_GENCTRL_Msk +#define GENERIC_CLOCK_GENERATOR_12M (4u) +#define GENERIC_CLOCK_GENERATOR_12M_SYNC GCLK_SYNCBUSY_GENCTRL_Msk +#define GENERIC_CLOCK_GENERATOR_1M (5u) + #else #define GENERIC_CLOCK_GENERATOR_XOSC32K (1u) @@ -55,7 +67,7 @@ void SystemInit( void ) { //***************** SAMD51 ************************// -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) NVMCTRL->CTRLA.reg |= NVMCTRL_CTRLA_RWS(0); #ifndef CRYSTALLESS @@ -109,14 +121,32 @@ void SystemInit( void ) /* Wait for synchronization */ } - /* DFLL Configuration in Open Loop mode */ + /* DFLL Configuration */ OSCCTRL->DFLLCTRLA.reg = 0; - //GCLK->PCHCTRL[OSCCTRL_GCLK_ID_DFLL48].reg = (1 << GCLK_PCHCTRL_CHEN_Pos) | GCLK_PCHCTRL_GEN(GCLK_PCHCTRL_GEN_GCLK3_Val); + +#ifndef CRYSTALLESS + /* + * D5x/E5x USB clock: XOSC32K -> GCLK3 -> DFLL48M closed loop. + * 32768 Hz * 1465 = 48.00512 MHz (+106.7 ppm), within the USB + * full-speed device requirement of 48 MHz +/-0.25%. + */ + GCLK->PCHCTRL[OSCCTRL_GCLK_ID_DFLL48].reg = + (1 << GCLK_PCHCTRL_CHEN_Pos) | + GCLK_PCHCTRL_GEN(GCLK_PCHCTRL_GEN_GCLK3_Val); + while ((GCLK->PCHCTRL[OSCCTRL_GCLK_ID_DFLL48].reg & + GCLK_PCHCTRL_CHEN) == 0) { + /* Wait for the DFLL reference channel to become active. */ + } +#endif // !CRYSTALLESS OSCCTRL->DFLLMUL.reg = OSCCTRL_DFLLMUL_CSTEP( 0x1 ) | OSCCTRL_DFLLMUL_FSTEP( 0x1 ) | +#ifndef CRYSTALLESS + OSCCTRL_DFLLMUL_MUL( 1465 ); +#else OSCCTRL_DFLLMUL_MUL( 0 ); +#endif // !CRYSTALLESS while ( OSCCTRL->DFLLSYNC.reg & OSCCTRL_DFLLSYNC_DFLLMUL ) { @@ -138,8 +168,13 @@ void SystemInit( void ) OSCCTRL->DFLLVAL.reg = OSCCTRL->DFLLVAL.reg; while( OSCCTRL->DFLLSYNC.bit.DFLLVAL ); +#ifndef CRYSTALLESS OSCCTRL->DFLLCTRLB.reg = OSCCTRL_DFLLCTRLB_WAITLOCK | - OSCCTRL_DFLLCTRLB_CCDIS | OSCCTRL_DFLLCTRLB_USBCRM ; + OSCCTRL_DFLLCTRLB_CCDIS | OSCCTRL_DFLLCTRLB_MODE; +#else + OSCCTRL->DFLLCTRLB.reg = OSCCTRL_DFLLCTRLB_WAITLOCK | + OSCCTRL_DFLLCTRLB_CCDIS | OSCCTRL_DFLLCTRLB_USBCRM; +#endif // !CRYSTALLESS while ( !OSCCTRL->STATUS.bit.DFLLRDY ) { @@ -303,7 +338,129 @@ void SystemInit( void ) | USB_PADCAL_TRANSP(usbtransp); //*************** END SAMD51 *************************// - + +#elif defined(__SAME53__) || defined(__SAME54__) + NVMCTRL_REGS->NVMCTRL_CTRLA |= NVMCTRL_CTRLA_RWS(0); + +#ifndef CRYSTALLESS + OSC32KCTRL_REGS->OSC32KCTRL_XOSC32K = + OSC32KCTRL_XOSC32K_ENABLE_Msk | OSC32KCTRL_XOSC32K_EN1K_Msk | + OSC32KCTRL_XOSC32K_EN32K_Msk | OSC32KCTRL_XOSC32K_CGM_XT | + OSC32KCTRL_XOSC32K_XTALEN_Msk; + while ((OSC32KCTRL_REGS->OSC32KCTRL_STATUS & OSC32KCTRL_STATUS_XOSC32KRDY_Msk) == 0); +#endif + + GCLK_REGS->GCLK_CTRLA = GCLK_CTRLA_SWRST_Msk; + while (GCLK_REGS->GCLK_SYNCBUSY & GCLK_SYNCBUSY_SWRST_Msk); + +#ifndef CRYSTALLESS + GCLK_REGS->GCLK_GENCTRL[GENERIC_CLOCK_GENERATOR_XOSC32K] = + GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_GENEN_Msk; +#else + GCLK_REGS->GCLK_GENCTRL[GENERIC_CLOCK_GENERATOR_XOSC32K] = + GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_GENEN_Msk; +#endif + while (GCLK_REGS->GCLK_SYNCBUSY & GCLK_SYNCBUSY_GENCTRL_Msk); + + GCLK_REGS->GCLK_GENCTRL[GENERIC_CLOCK_GENERATOR_MAIN] = + GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_GENEN_Msk; + while (GCLK_REGS->GCLK_SYNCBUSY & GCLK_SYNCBUSY_GENCTRL_Msk); + + OSCCTRL_REGS->OSCCTRL_DFLLCTRLA = 0; +#ifndef CRYSTALLESS + /* + * D5x/E5x USB clock: XOSC32K -> GCLK3 -> DFLL48M closed loop. + * 32768 Hz * 1465 = 48.00512 MHz (+106.7 ppm), within the USB + * full-speed device requirement of 48 MHz +/-0.25%. + */ + GCLK_REGS->GCLK_PCHCTRL[OSCCTRL_GCLK_ID_DFLL48] = + GCLK_PCHCTRL_GEN_GCLK3 | GCLK_PCHCTRL_CHEN_Msk; + while ((GCLK_REGS->GCLK_PCHCTRL[OSCCTRL_GCLK_ID_DFLL48] & + GCLK_PCHCTRL_CHEN_Msk) == 0); +#endif // !CRYSTALLESS + + OSCCTRL_REGS->OSCCTRL_DFLLMUL = OSCCTRL_DFLLMUL_CSTEP(1) | + OSCCTRL_DFLLMUL_FSTEP(1) | +#ifndef CRYSTALLESS + OSCCTRL_DFLLMUL_MUL(1465); +#else + OSCCTRL_DFLLMUL_MUL(0); +#endif // !CRYSTALLESS + while (OSCCTRL_REGS->OSCCTRL_DFLLSYNC & OSCCTRL_DFLLSYNC_DFLLMUL_Msk); + + OSCCTRL_REGS->OSCCTRL_DFLLCTRLB = 0; + while (OSCCTRL_REGS->OSCCTRL_DFLLSYNC & OSCCTRL_DFLLSYNC_DFLLCTRLB_Msk); + + OSCCTRL_REGS->OSCCTRL_DFLLCTRLA = OSCCTRL_DFLLCTRLA_ENABLE_Msk; + while (OSCCTRL_REGS->OSCCTRL_DFLLSYNC & OSCCTRL_DFLLSYNC_ENABLE_Msk); + + OSCCTRL_REGS->OSCCTRL_DFLLVAL = OSCCTRL_REGS->OSCCTRL_DFLLVAL; + while (OSCCTRL_REGS->OSCCTRL_DFLLSYNC & OSCCTRL_DFLLSYNC_DFLLVAL_Msk); + +#ifndef CRYSTALLESS + OSCCTRL_REGS->OSCCTRL_DFLLCTRLB = OSCCTRL_DFLLCTRLB_WAITLOCK_Msk | + OSCCTRL_DFLLCTRLB_CCDIS_Msk | + OSCCTRL_DFLLCTRLB_MODE_Msk; +#else + OSCCTRL_REGS->OSCCTRL_DFLLCTRLB = OSCCTRL_DFLLCTRLB_WAITLOCK_Msk | + OSCCTRL_DFLLCTRLB_CCDIS_Msk | + OSCCTRL_DFLLCTRLB_USBCRM_Msk; +#endif // !CRYSTALLESS + while ((OSCCTRL_REGS->OSCCTRL_STATUS & OSCCTRL_STATUS_DFLLRDY_Msk) == 0); + + GCLK_REGS->GCLK_GENCTRL[GENERIC_CLOCK_GENERATOR_1M] = + GCLK_GENCTRL_SRC_DFLL | GCLK_GENCTRL_GENEN_Msk | GCLK_GENCTRL_DIV(48); + while (GCLK_REGS->GCLK_SYNCBUSY & GCLK_SYNCBUSY_GENCTRL_Msk); + + GCLK_REGS->GCLK_PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0] = + GCLK_PCHCTRL_GEN_GCLK5 | GCLK_PCHCTRL_CHEN_Msk; + OSCCTRL_REGS->DPLL[0].OSCCTRL_DPLLRATIO = + OSCCTRL_DPLLRATIO_LDRFRAC(0) | OSCCTRL_DPLLRATIO_LDR((F_CPU - 500000) / 1000000); + while (OSCCTRL_REGS->DPLL[0].OSCCTRL_DPLLSYNCBUSY & OSCCTRL_DPLLSYNCBUSY_DPLLRATIO_Msk); + OSCCTRL_REGS->DPLL[0].OSCCTRL_DPLLCTRLB = + OSCCTRL_DPLLCTRLB_REFCLK_GCLK | OSCCTRL_DPLLCTRLB_LBYPASS_Msk; + OSCCTRL_REGS->DPLL[0].OSCCTRL_DPLLCTRLA = OSCCTRL_DPLLCTRLA_ENABLE_Msk; + while ((OSCCTRL_REGS->DPLL[0].OSCCTRL_DPLLSTATUS & + (OSCCTRL_DPLLSTATUS_CLKRDY_Msk | OSCCTRL_DPLLSTATUS_LOCK_Msk)) != + (OSCCTRL_DPLLSTATUS_CLKRDY_Msk | OSCCTRL_DPLLSTATUS_LOCK_Msk)); + + GCLK_REGS->GCLK_PCHCTRL[OSCCTRL_GCLK_ID_FDPLL1] = + GCLK_PCHCTRL_GEN_GCLK5 | GCLK_PCHCTRL_CHEN_Msk; + OSCCTRL_REGS->DPLL[1].OSCCTRL_DPLLRATIO = + OSCCTRL_DPLLRATIO_LDRFRAC(0) | OSCCTRL_DPLLRATIO_LDR(99); + while (OSCCTRL_REGS->DPLL[1].OSCCTRL_DPLLSYNCBUSY & OSCCTRL_DPLLSYNCBUSY_DPLLRATIO_Msk); + OSCCTRL_REGS->DPLL[1].OSCCTRL_DPLLCTRLB = + OSCCTRL_DPLLCTRLB_REFCLK_GCLK | OSCCTRL_DPLLCTRLB_LBYPASS_Msk; + OSCCTRL_REGS->DPLL[1].OSCCTRL_DPLLCTRLA = OSCCTRL_DPLLCTRLA_ENABLE_Msk; + while ((OSCCTRL_REGS->DPLL[1].OSCCTRL_DPLLSTATUS & + (OSCCTRL_DPLLSTATUS_CLKRDY_Msk | OSCCTRL_DPLLSTATUS_LOCK_Msk)) != + (OSCCTRL_DPLLSTATUS_CLKRDY_Msk | OSCCTRL_DPLLSTATUS_LOCK_Msk)); + + GCLK_REGS->GCLK_GENCTRL[GENERIC_CLOCK_GENERATOR_48M] = + GCLK_GENCTRL_SRC_DFLL | GCLK_GENCTRL_IDC_Msk | GCLK_GENCTRL_GENEN_Msk; + while (GCLK_REGS->GCLK_SYNCBUSY & GENERIC_CLOCK_GENERATOR_48M_SYNC); + + GCLK_REGS->GCLK_GENCTRL[GENERIC_CLOCK_GENERATOR_100M] = + GCLK_GENCTRL_SRC_DPLL1 | GCLK_GENCTRL_IDC_Msk | GCLK_GENCTRL_GENEN_Msk; + while (GCLK_REGS->GCLK_SYNCBUSY & GENERIC_CLOCK_GENERATOR_100M_SYNC); + + GCLK_REGS->GCLK_GENCTRL[GENERIC_CLOCK_GENERATOR_12M] = + GCLK_GENCTRL_SRC_DFLL | GCLK_GENCTRL_IDC_Msk | GCLK_GENCTRL_DIV(4) | + GCLK_GENCTRL_GENEN_Msk; + while (GCLK_REGS->GCLK_SYNCBUSY & GENERIC_CLOCK_GENERATOR_12M_SYNC); + + GCLK_REGS->GCLK_GENCTRL[GENERIC_CLOCK_GENERATOR_MAIN] = + GCLK_GENCTRL_SRC_DPLL0 | GCLK_GENCTRL_IDC_Msk | GCLK_GENCTRL_GENEN_Msk; + while (GCLK_REGS->GCLK_SYNCBUSY & GCLK_SYNCBUSY_GENCTRL_Msk); + + MCLK_REGS->MCLK_CPUDIV = MCLK_CPUDIV_DIV_DIV1; + SUPC_REGS->SUPC_VREG &= ~SUPC_VREG_SEL_Msk; + + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + + SystemCoreClock = F_CPU; + #else //********************** SAMD21 *********************// diff --git a/cores/arduino/wiring.c b/cores/arduino/wiring.c index ad6c7982d..5635c81d3 100644 --- a/cores/arduino/wiring.c +++ b/cores/arduino/wiring.c @@ -24,7 +24,7 @@ extern "C" { #endif -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) uint32_t SystemCoreClock=F_CPU; #else /* @@ -77,7 +77,7 @@ void init( void ) // // Clock EIC for I/O interrupts // PM->APBAMASK.reg |= PM_APBAMASK_EIC ; -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) MCLK->APBAMASK.reg |= MCLK_APBAMASK_SERCOM0 | MCLK_APBAMASK_SERCOM1 | MCLK_APBAMASK_TC0 | MCLK_APBAMASK_TC1; MCLK->APBBMASK.reg |= MCLK_APBBMASK_SERCOM2 | MCLK_APBBMASK_SERCOM3 | MCLK_APBBMASK_TCC0 | MCLK_APBBMASK_TCC1 | MCLK_APBBMASK_TC3 | MCLK_APBBMASK_TC2; @@ -87,6 +87,20 @@ void init( void ) MCLK->APBDMASK.reg |= MCLK_APBDMASK_DAC | MCLK_APBDMASK_SERCOM4 | MCLK_APBDMASK_SERCOM5 | MCLK_APBDMASK_ADC0 | MCLK_APBDMASK_ADC1 | MCLK_APBDMASK_TCC4 | MCLK_APBDMASK_TC6 | MCLK_APBDMASK_TC7 | MCLK_APBDMASK_SERCOM6 | MCLK_APBDMASK_SERCOM7; +#elif defined(__SAME53__) || defined(__SAME54__) + MCLK_REGS->MCLK_APBAMASK |= MCLK_APBAMASK_SERCOM0_Msk | MCLK_APBAMASK_SERCOM1_Msk | + MCLK_APBAMASK_TC0_Msk | MCLK_APBAMASK_TC1_Msk; + MCLK_REGS->MCLK_APBBMASK |= MCLK_APBBMASK_SERCOM2_Msk | MCLK_APBBMASK_SERCOM3_Msk | + MCLK_APBBMASK_TCC0_Msk | MCLK_APBBMASK_TCC1_Msk | + MCLK_APBBMASK_TC2_Msk | MCLK_APBBMASK_TC3_Msk; + MCLK_REGS->MCLK_APBCMASK |= MCLK_APBCMASK_TCC2_Msk | MCLK_APBCMASK_TCC3_Msk | + MCLK_APBCMASK_TC4_Msk | MCLK_APBCMASK_TC5_Msk; + MCLK_REGS->MCLK_APBDMASK |= MCLK_APBDMASK_DAC_Msk | MCLK_APBDMASK_SERCOM4_Msk | + MCLK_APBDMASK_SERCOM5_Msk | MCLK_APBDMASK_ADC0_Msk | + MCLK_APBDMASK_ADC1_Msk | MCLK_APBDMASK_TCC4_Msk | + MCLK_APBDMASK_TC6_Msk | MCLK_APBDMASK_TC7_Msk | + MCLK_APBDMASK_SERCOM6_Msk | MCLK_APBDMASK_SERCOM7_Msk; + #else // Clock SERCOM for Serial PM->APBCMASK.reg |= PM_APBCMASK_SERCOM0 | PM_APBCMASK_SERCOM1 | PM_APBCMASK_SERCOM2 | PM_APBCMASK_SERCOM3 | PM_APBCMASK_SERCOM4 | PM_APBCMASK_SERCOM5 ; @@ -114,7 +128,7 @@ void init( void ) // Initialize Analog Controller // Setting clock -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) //set to 1/(1/(48000000/32) * 6) = 250000 SPS GCLK->PCHCTRL[ADC0_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); //use clock generator 1 (48Mhz) GCLK->PCHCTRL[ADC1_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); //use clock generator 1 (48Mhz) @@ -156,6 +170,46 @@ void init( void ) DAC->DACCTRL[0].bit.REFRESH = 2; DAC->DACCTRL[1].bit.REFRESH = 2; +#elif defined(__SAME53__) || defined(__SAME54__) + GCLK_REGS->GCLK_PCHCTRL[ADC0_GCLK_ID] = GCLK_PCHCTRL_GEN_GCLK1 | + GCLK_PCHCTRL_CHEN_Msk; + GCLK_REGS->GCLK_PCHCTRL[ADC1_GCLK_ID] = GCLK_PCHCTRL_GEN_GCLK1 | + GCLK_PCHCTRL_CHEN_Msk; + + adc_registers_t *adcs[] = {ADC0_REGS, ADC1_REGS}; + for (uint32_t i = 0; i < 2; i++) { + adcs[i]->ADC_CTRLA = (adcs[i]->ADC_CTRLA & ~ADC_CTRLA_PRESCALER_Msk) | + ADC_CTRLA_PRESCALER_DIV32; + adcs[i]->ADC_CTRLB = (adcs[i]->ADC_CTRLB & ~ADC_CTRLB_RESSEL_Msk) | + ADC_CTRLB_RESSEL_10BIT; + while (adcs[i]->ADC_SYNCBUSY & ADC_SYNCBUSY_CTRLB_Msk); + + adcs[i]->ADC_SAMPCTRL = ADC_SAMPCTRL_SAMPLEN(5); + while (adcs[i]->ADC_SYNCBUSY & ADC_SYNCBUSY_SAMPCTRL_Msk); + + adcs[i]->ADC_INPUTCTRL = ADC_INPUTCTRL_MUXNEG_GND; + while (adcs[i]->ADC_SYNCBUSY & ADC_SYNCBUSY_INPUTCTRL_Msk); + + adcs[i]->ADC_AVGCTRL = ADC_AVGCTRL_SAMPLENUM_1 | ADC_AVGCTRL_ADJRES(0); + while (adcs[i]->ADC_SYNCBUSY & ADC_SYNCBUSY_AVGCTRL_Msk); + } + + analogReference(AR_DEFAULT); + + GCLK_REGS->GCLK_PCHCTRL[DAC_GCLK_ID] = GCLK_PCHCTRL_GEN_GCLK4 | + GCLK_PCHCTRL_CHEN_Msk; + while ((GCLK_REGS->GCLK_PCHCTRL[DAC_GCLK_ID] & GCLK_PCHCTRL_CHEN_Msk) == 0); + + while (DAC_REGS->DAC_SYNCBUSY & DAC_SYNCBUSY_SWRST_Msk); + DAC_REGS->DAC_CTRLA |= DAC_CTRLA_SWRST_Msk; + while (DAC_REGS->DAC_SYNCBUSY & DAC_SYNCBUSY_SWRST_Msk); + + DAC_REGS->DAC_CTRLB = DAC_CTRLB_REFSEL_VREFPU; + DAC_REGS->DAC_DACCTRL[0] = + (DAC_REGS->DAC_DACCTRL[0] & ~DAC_DACCTRL_REFRESH_Msk) | DAC_DACCTRL_REFRESH(2); + DAC_REGS->DAC_DACCTRL[1] = + (DAC_REGS->DAC_DACCTRL[1] & ~DAC_DACCTRL_REFRESH_Msk) | DAC_DACCTRL_REFRESH(2); + #else //set to 1/(1/(48000000/32) * 6) = 250000 SPS @@ -197,7 +251,7 @@ void init( void ) #endif -#endif //SAMD51 +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ / SAMD21 } #ifdef __cplusplus diff --git a/cores/arduino/wiring_analog.c b/cores/arduino/wiring_analog.c index 40f5a6424..7b051718a 100644 --- a/cores/arduino/wiring_analog.c +++ b/cores/arduino/wiring_analog.c @@ -24,10 +24,18 @@ extern "C" { #endif +#if (defined(__SAMD51__) || defined(__SAME51__)) && !defined(ARDUINO_SAMD51_E51) +#define ARDUINO_SAMD51_E51 +#endif + +#if (defined(__SAME53__) || defined(__SAME54__)) && !defined(ARDUINO_SAME53_E54) +#define ARDUINO_SAME53_E54 +#endif + static int _readResolution = 10; static int _ADCResolution = 10; -#if defined(__SAMD51__) +#if defined(ARDUINO_SAMD51_E51) || defined(ARDUINO_SAME53_E54) static int _writeResolution = 12; static int _dacResolution = 12; #else @@ -36,7 +44,7 @@ static int _writeResolution = 8; #endif -#if !defined(__SAMD51__) +#if !defined(ARDUINO_SAMD51_E51) && !defined(ARDUINO_SAME53_E54) // Wait for synchronization of registers between the clock domains static __inline__ void syncADC() __attribute__((always_inline, unused)); static void syncADC() { @@ -45,7 +53,7 @@ static void syncADC() { } // ATSAMR, for example, doesn't have a DAC -#ifdef DAC +#if defined(DAC) || defined(DAC_REGS) // Wait for synchronization of registers between the clock domains static __inline__ void syncDAC() __attribute__((always_inline, unused)); static void syncDAC() { @@ -73,7 +81,7 @@ static bool dacEnabled[2]; void analogReadResolution(int res) { _readResolution = res; -#if defined(__SAMD51__) +#if defined(ARDUINO_SAMD51_E51) if (res > 10) { ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_12BIT_Val; @@ -92,6 +100,23 @@ void analogReadResolution(int res) while(ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB); //wait for sync while(ADC1->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB); //wait for sync +#elif defined(ARDUINO_SAME53_E54) + uint32_t resolution; + if (res > 10) { + resolution = ADC_CTRLB_RESSEL_12BIT; + _ADCResolution = 12; + } else if (res > 8) { + resolution = ADC_CTRLB_RESSEL_10BIT; + _ADCResolution = 10; + } else { + resolution = ADC_CTRLB_RESSEL_8BIT; + _ADCResolution = 8; + } + + ADC0_REGS->ADC_CTRLB = (ADC0_REGS->ADC_CTRLB & ~ADC_CTRLB_RESSEL_Msk) | resolution; + ADC1_REGS->ADC_CTRLB = (ADC1_REGS->ADC_CTRLB & ~ADC_CTRLB_RESSEL_Msk) | resolution; + while (ADC0_REGS->ADC_SYNCBUSY & ADC_SYNCBUSY_CTRLB_Msk); + while (ADC1_REGS->ADC_SYNCBUSY & ADC_SYNCBUSY_CTRLB_Msk); #else if (res > 10) { @@ -133,7 +158,7 @@ static inline uint32_t mapResolution(uint32_t value, uint32_t from, uint32_t to) */ void analogReference(eAnalogReference mode) { -#if defined(__SAMD51__) + #if defined(ARDUINO_SAMD51_E51) while(ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_REFCTRL); //wait for sync while(ADC1->SYNCBUSY.reg & ADC_SYNCBUSY_REFCTRL); //wait for sync @@ -223,7 +248,34 @@ void analogReference(eAnalogReference mode) ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; // break; } - + +#elif defined(ARDUINO_SAME53_E54) + uint32_t reference = ADC_REFCTRL_REFSEL_INTVCC1; + uint32_t vref = SUPC_REGS->SUPC_VREF; + + switch (mode) + { + case AR_INTERNAL1V0: vref = (vref & ~SUPC_VREF_SEL_Msk) | SUPC_VREF_SEL_1V0; reference = ADC_REFCTRL_REFSEL_INTREF; break; + case AR_INTERNAL1V1: vref = (vref & ~SUPC_VREF_SEL_Msk) | SUPC_VREF_SEL_1V1; reference = ADC_REFCTRL_REFSEL_INTREF; break; + case AR_INTERNAL1V2: vref = (vref & ~SUPC_VREF_SEL_Msk) | SUPC_VREF_SEL_1V2; reference = ADC_REFCTRL_REFSEL_INTREF; break; + case AR_INTERNAL1V25: vref = (vref & ~SUPC_VREF_SEL_Msk) | SUPC_VREF_SEL_1V25; reference = ADC_REFCTRL_REFSEL_INTREF; break; + case AR_INTERNAL2V0: vref = (vref & ~SUPC_VREF_SEL_Msk) | SUPC_VREF_SEL_2V0; reference = ADC_REFCTRL_REFSEL_INTREF; break; + case AR_INTERNAL2V2: vref = (vref & ~SUPC_VREF_SEL_Msk) | SUPC_VREF_SEL_2V2; reference = ADC_REFCTRL_REFSEL_INTREF; break; + case AR_INTERNAL2V4: vref = (vref & ~SUPC_VREF_SEL_Msk) | SUPC_VREF_SEL_2V4; reference = ADC_REFCTRL_REFSEL_INTREF; break; + case AR_INTERNAL2V5: vref = (vref & ~SUPC_VREF_SEL_Msk) | SUPC_VREF_SEL_2V5; reference = ADC_REFCTRL_REFSEL_INTREF; break; + case AR_EXTERNAL: reference = ADC_REFCTRL_REFSEL_AREFA; break; + case AR_INTERNAL1V65: reference = ADC_REFCTRL_REFSEL_INTVCC0; break; + case AR_DEFAULT: + default: break; + } + + if (reference == ADC_REFCTRL_REFSEL_INTREF) { + SUPC_REGS->SUPC_VREF = vref | SUPC_VREF_VREFOE_Msk; + } + ADC0_REGS->ADC_REFCTRL = reference; + ADC1_REGS->ADC_REFCTRL = reference; + while (ADC0_REGS->ADC_SYNCBUSY & ADC_SYNCBUSY_REFCTRL_Msk); + while (ADC1_REGS->ADC_SYNCBUSY & ADC_SYNCBUSY_REFCTRL_Msk); #else syncADC(); switch (mode) @@ -277,9 +329,9 @@ uint32_t analogRead(uint32_t pin) pinPeripheral(pin, PIO_ANALOG); //ATSAMR, for example, doesn't have a DAC -#ifdef DAC +#if defined(DAC) || defined(DAC_REGS) - #if defined(__SAMD51__) + #if defined(ARDUINO_SAMD51_E51) if (pin == PIN_DAC0 || pin == PIN_DAC1) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled uint8_t channel = (pin == PIN_DAC0 ? 0 : 1); @@ -297,19 +349,28 @@ uint32_t analogRead(uint32_t pin) } while (DAC->SYNCBUSY.bit.ENABLE); - #else - if (pin == PIN_DAC0) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled - syncDAC(); - - DAC->CTRLA.bit.ENABLE = 0x00; // Disable DAC - //DAC->CTRLB.bit.EOEN = 0x00; // The DAC output is turned off. - syncDAC(); - #endif + #elif defined(ARDUINO_SAME53_E54) + if (pin == PIN_DAC0) { + if (dacEnabled[0]) { + dacEnabled[0] = false; + while (DAC_REGS->DAC_SYNCBUSY & (DAC_SYNCBUSY_ENABLE_Msk | DAC_SYNCBUSY_SWRST_Msk)); + DAC_REGS->DAC_CTRLA &= ~DAC_CTRLA_ENABLE_Msk; + while (DAC_REGS->DAC_SYNCBUSY & DAC_SYNCBUSY_ENABLE_Msk); + DAC_REGS->DAC_DACCTRL[0] &= ~DAC_DACCTRL_ENABLE_Msk; + DAC_REGS->DAC_CTRLA |= DAC_CTRLA_ENABLE_Msk; + } + while (DAC_REGS->DAC_SYNCBUSY & DAC_SYNCBUSY_ENABLE_Msk); + #else + if (pin == PIN_DAC0) { + syncDAC(); + DAC->CTRLA.bit.ENABLE = 0x00; + syncDAC(); + #endif } #endif -#if defined(__SAMD51__) +#if defined(ARDUINO_SAMD51_E51) Adc *adc; if(g_APinDescription[pin].ulPinAttribute & PIN_ATTR_ANALOG) adc = ADC0; else if(g_APinDescription[pin].ulPinAttribute & PIN_ATTR_ANALOG_ALT) adc = ADC1; @@ -352,6 +413,32 @@ uint32_t analogRead(uint32_t pin) adc->CTRLA.bit.ENABLE = 0x00; // Disable ADC while( adc->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync +#elif defined(ARDUINO_SAME53_E54) + adc_registers_t *adc; + if (g_APinDescription[pin].ulPinAttribute & PIN_ATTR_ANALOG) adc = ADC0_REGS; + else if (g_APinDescription[pin].ulPinAttribute & PIN_ATTR_ANALOG_ALT) adc = ADC1_REGS; + else return 0; + + while (adc->ADC_SYNCBUSY & ADC_SYNCBUSY_INPUTCTRL_Msk); + adc->ADC_INPUTCTRL = + (adc->ADC_INPUTCTRL & ~ADC_INPUTCTRL_MUXPOS_Msk) | + ADC_INPUTCTRL_MUXPOS(g_APinDescription[pin].ulADCChannelNumber); + + while (adc->ADC_SYNCBUSY & ADC_SYNCBUSY_ENABLE_Msk); + adc->ADC_CTRLA |= ADC_CTRLA_ENABLE_Msk; + while (adc->ADC_SYNCBUSY & ADC_SYNCBUSY_ENABLE_Msk); + + adc->ADC_SWTRIG = ADC_SWTRIG_START_Msk; + while ((adc->ADC_INTFLAG & ADC_INTFLAG_RESRDY_Msk) == 0); + adc->ADC_INTFLAG = ADC_INTFLAG_RESRDY_Msk; + + adc->ADC_SWTRIG = ADC_SWTRIG_START_Msk; + while ((adc->ADC_INTFLAG & ADC_INTFLAG_RESRDY_Msk) == 0); + valueRead = adc->ADC_RESULT; + + while (adc->ADC_SYNCBUSY & ADC_SYNCBUSY_ENABLE_Msk); + adc->ADC_CTRLA &= ~ADC_CTRLA_ENABLE_Msk; + while (adc->ADC_SYNCBUSY & ADC_SYNCBUSY_ENABLE_Msk); #else syncADC(); ADC->INPUTCTRL.bit.MUXPOS = g_APinDescription[pin].ulADCChannelNumber; // Selection for the positive ADC input @@ -408,17 +495,19 @@ void analogWrite(uint32_t pin, uint32_t value) uint32_t attr = pinDesc.ulPinAttribute; // ATSAMR, for example, doesn't have a DAC -#ifdef DAC +#if defined(DAC) || defined(DAC_REGS) if ((attr & PIN_ATTR_ANALOG) == PIN_ATTR_ANALOG) { // DAC handling code -#if defined(__SAMD51__) +#if defined(ARDUINO_SAMD51_E51) if (pin == PIN_DAC0 || pin == PIN_DAC1) { // 2 DACs on A0 (PA02) and A1 (PA05) +#elif defined(ARDUINO_SAME53_E54) + if (pin == PIN_DAC0) { #else if (pin == PIN_DAC0) { // Only 1 DAC on A0 (PA02) #endif -#if defined(__SAMD51__) +#if defined(ARDUINO_SAMD51_E51) value = mapResolution(value, _writeResolution, _dacResolution); @@ -473,25 +562,41 @@ void analogWrite(uint32_t pin, uint32_t value) DAC->DATA[1].reg = value; // DAC on 10 bits. } +#elif defined(ARDUINO_SAME53_E54) + value = mapResolution(value, _writeResolution, _dacResolution); + uint8_t channel = 0; + pinPeripheral(pin, PIO_ANALOG); + + if (!dacEnabled[channel]) { + dacEnabled[channel] = true; + while (DAC_REGS->DAC_SYNCBUSY & (DAC_SYNCBUSY_ENABLE_Msk | DAC_SYNCBUSY_SWRST_Msk)); + DAC_REGS->DAC_CTRLA &= ~DAC_CTRLA_ENABLE_Msk; + while (DAC_REGS->DAC_SYNCBUSY & DAC_SYNCBUSY_ENABLE_Msk); + DAC_REGS->DAC_DACCTRL[channel] |= DAC_DACCTRL_ENABLE_Msk; + DAC_REGS->DAC_CTRLA |= DAC_CTRLA_ENABLE_Msk; + } + while ((DAC_REGS->DAC_STATUS & (DAC_STATUS_READY0_Msk << channel)) == 0); + while (DAC_REGS->DAC_SYNCBUSY & (DAC_SYNCBUSY_DATA0_Msk << channel)); + DAC_REGS->DAC_DATA[channel] = value; #else syncDAC(); DAC->DATA.reg = value & 0x3FF; // DAC on 10 bits. syncDAC(); DAC->CTRLA.bit.ENABLE = 0x01; // Enable DAC syncDAC(); -#endif // __SAMD51__ +#endif return; } } #endif // DAC -#if defined(__SAMD51__) +#if defined(ARDUINO_SAMD51_E51) if(attr & (PIN_ATTR_PWM_E|PIN_ATTR_PWM_F|PIN_ATTR_PWM_G)){ uint32_t tcNum = GetTCNumber(pinDesc.ulPWMChannel); uint8_t tcChannel = GetTCChannelNumber(pinDesc.ulPWMChannel); - static bool tcEnabled[TCC_INST_NUM+TC_INST_NUM]; + static bool tcEnabled[ARDUINO_TCC_INSTANCE_COUNT + ARDUINO_TC_INSTANCE_COUNT]; if(attr & PIN_ATTR_PWM_E) pinPeripheral(pin, PIO_TIMER); @@ -505,7 +610,7 @@ void analogWrite(uint32_t pin, uint32_t value) GCLK->PCHCTRL[GCLK_CLKCTRL_IDs[tcNum]].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); //use clock generator 0 // Set PORT - if (tcNum >= TCC_INST_NUM) { + if (tcNum >= ARDUINO_TCC_INSTANCE_COUNT) { // -- Configure TC Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel); @@ -560,7 +665,7 @@ void analogWrite(uint32_t pin, uint32_t value) } } else { - if (tcNum >= TCC_INST_NUM) { + if (tcNum >= ARDUINO_TCC_INSTANCE_COUNT) { Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel); TCx->COUNT8.CC[tcChannel].reg = (uint8_t) value; while (TCx->COUNT8.SYNCBUSY.bit.CC0 || TCx->COUNT8.SYNCBUSY.bit.CC1); @@ -577,7 +682,63 @@ void analogWrite(uint32_t pin, uint32_t value) return; } - + +#elif defined(ARDUINO_SAME53_E54) + if (attr & (PIN_ATTR_PWM_E | PIN_ATTR_PWM_F | PIN_ATTR_PWM_G)) { + uint32_t tcNum = GetTCNumber(pinDesc.ulPWMChannel); + uint8_t tcChannel = GetTCChannelNumber(pinDesc.ulPWMChannel); + static bool tcEnabled[ARDUINO_TCC_INSTANCE_COUNT + ARDUINO_TC_INSTANCE_COUNT]; + + if (attr & PIN_ATTR_PWM_E) pinPeripheral(pin, PIO_TIMER); + else if (attr & PIN_ATTR_PWM_F) pinPeripheral(pin, PIO_TIMER_ALT); + else pinPeripheral(pin, PIO_TCC_PDEC); + + if (!tcEnabled[tcNum]) { + tcEnabled[tcNum] = true; + GCLK_REGS->GCLK_PCHCTRL[GCLK_CLKCTRL_IDs[tcNum]] = + GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN_Msk; + + if (tcNum >= ARDUINO_TCC_INSTANCE_COUNT) { + tc_registers_t *TCx = (tc_registers_t *)GetTC(pinDesc.ulPWMChannel); + TCx->COUNT8.TC_CTRLA = TC_CTRLA_SWRST_Msk; + while (TCx->COUNT8.TC_SYNCBUSY & TC_SYNCBUSY_SWRST_Msk); + TCx->COUNT8.TC_CTRLA = TC_CTRLA_MODE_COUNT8 | TC_CTRLA_PRESCALER_DIV256; + TCx->COUNT8.TC_WAVE = TC_WAVE_WAVEGEN_NPWM; + TCx->COUNT8.TC_CC[tcChannel] = (uint8_t)value; + while (TCx->COUNT8.TC_SYNCBUSY & (TC_SYNCBUSY_CC0_Msk << tcChannel)); + TCx->COUNT8.TC_PER = 0xff; + while (TCx->COUNT8.TC_SYNCBUSY & TC_SYNCBUSY_PER_Msk); + TCx->COUNT8.TC_CTRLA |= TC_CTRLA_ENABLE_Msk; + while (TCx->COUNT8.TC_SYNCBUSY & TC_SYNCBUSY_ENABLE_Msk); + } else { + tcc_registers_t *TCCx = (tcc_registers_t *)GetTC(pinDesc.ulPWMChannel); + TCCx->TCC_CTRLA = TCC_CTRLA_SWRST_Msk; + while (TCCx->TCC_SYNCBUSY & TCC_SYNCBUSY_SWRST_Msk); + TCCx->TCC_CTRLA = TCC_CTRLA_PRESCALER_DIV256 | TCC_CTRLA_PRESCSYNC_GCLK; + TCCx->TCC_WAVE = TCC_WAVE_WAVEGEN_NPWM; + while (TCCx->TCC_SYNCBUSY & TCC_SYNCBUSY_WAVE_Msk); + TCCx->TCC_CC[tcChannel] = value; + while (TCCx->TCC_SYNCBUSY & (TCC_SYNCBUSY_CC0_Msk << tcChannel)); + TCCx->TCC_PER = 0xff; + while (TCCx->TCC_SYNCBUSY & TCC_SYNCBUSY_PER_Msk); + TCCx->TCC_CTRLA |= TCC_CTRLA_ENABLE_Msk; + while (TCCx->TCC_SYNCBUSY & TCC_SYNCBUSY_ENABLE_Msk); + } + } else if (tcNum >= ARDUINO_TCC_INSTANCE_COUNT) { + tc_registers_t *TCx = (tc_registers_t *)GetTC(pinDesc.ulPWMChannel); + TCx->COUNT8.TC_CC[tcChannel] = (uint8_t)value; + while (TCx->COUNT8.TC_SYNCBUSY & (TC_SYNCBUSY_CC0_Msk << tcChannel)); + } else { + tcc_registers_t *TCCx = (tcc_registers_t *)GetTC(pinDesc.ulPWMChannel); + while (TCCx->TCC_SYNCBUSY & TCC_SYNCBUSY_CTRLB_Msk); + TCCx->TCC_CCBUF[tcChannel] = value; + while (TCCx->TCC_SYNCBUSY & (TCC_SYNCBUSY_CC0_Msk << tcChannel)); + TCCx->TCC_CTRLBCLR = TCC_CTRLBCLR_LUPD_Msk; + while (TCCx->TCC_SYNCBUSY & TCC_SYNCBUSY_CTRLB_Msk); + } + + return; + } #else if ((attr & PIN_ATTR_PWM) == PIN_ATTR_PWM) @@ -586,7 +747,7 @@ void analogWrite(uint32_t pin, uint32_t value) uint32_t tcNum = GetTCNumber(pinDesc.ulPWMChannel); uint8_t tcChannel = GetTCChannelNumber(pinDesc.ulPWMChannel); - static bool tcEnabled[TCC_INST_NUM+TC_INST_NUM]; + static bool tcEnabled[ARDUINO_TCC_INSTANCE_COUNT + ARDUINO_TC_INSTANCE_COUNT]; if (attr & PIN_ATTR_TIMER) { #if !(ARDUINO_SAMD_VARIANT_COMPLIANCE >= 10603) @@ -622,7 +783,7 @@ void analogWrite(uint32_t pin, uint32_t value) while (GCLK->STATUS.bit.SYNCBUSY == 1); // Set PORT - if (tcNum >= TCC_INST_NUM) { + if (tcNum >= ARDUINO_TCC_INSTANCE_COUNT) { // -- Configure TC Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel); // Disable TCx @@ -657,7 +818,7 @@ void analogWrite(uint32_t pin, uint32_t value) syncTCC(TCCx); } } else { - if (tcNum >= TCC_INST_NUM) { + if (tcNum >= ARDUINO_TCC_INSTANCE_COUNT) { Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel); TCx->COUNT16.CC[tcChannel].reg = (uint32_t) value; syncTC_16(TCx); diff --git a/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c index c62fdebfb..cad4df32d 100644 --- a/cores/arduino/wiring_digital.c +++ b/cores/arduino/wiring_digital.c @@ -22,6 +22,67 @@ extern "C" { #endif +#if defined(__SAME53__) || defined(__SAME54__) +void pinMode(uint32_t ulPin, uint32_t ulMode) +{ + if (g_APinDescription[ulPin].ulPinType == PIO_NOT_A_PIN) return; + + port_group_registers_t *group = &PORT_REGS->GROUP[g_APinDescription[ulPin].ulPort]; + uint32_t pin = g_APinDescription[ulPin].ulPin; + uint32_t pinMask = 1UL << pin; + + switch (ulMode) + { + case INPUT: + group->PORT_PINCFG[pin] = PORT_PINCFG_INEN_Msk; + group->PORT_DIRCLR = pinMask; + break; + case INPUT_PULLUP: + group->PORT_PINCFG[pin] = PORT_PINCFG_INEN_Msk | PORT_PINCFG_PULLEN_Msk; + group->PORT_DIRCLR = pinMask; + group->PORT_OUTSET = pinMask; + break; + case INPUT_PULLDOWN: + group->PORT_PINCFG[pin] = PORT_PINCFG_INEN_Msk | PORT_PINCFG_PULLEN_Msk; + group->PORT_DIRCLR = pinMask; + group->PORT_OUTCLR = pinMask; + break; + case OUTPUT: + group->PORT_PINCFG[pin] = PORT_PINCFG_INEN_Msk | PORT_PINCFG_DRVSTR_Msk; + group->PORT_DIRSET = pinMask; + break; + default: + break; + } +} + +void digitalWrite(uint32_t ulPin, uint32_t ulVal) +{ + if (g_APinDescription[ulPin].ulPinType == PIO_NOT_A_PIN) return; + + port_group_registers_t *group = &PORT_REGS->GROUP[g_APinDescription[ulPin].ulPort]; + uint32_t pin = g_APinDescription[ulPin].ulPin; + uint32_t pinMask = 1UL << pin; + + if ((group->PORT_DIRSET & pinMask) == 0) { + if (ulVal == LOW) group->PORT_PINCFG[pin] &= ~PORT_PINCFG_PULLEN_Msk; + else group->PORT_PINCFG[pin] |= PORT_PINCFG_PULLEN_Msk; + } + + if (ulVal == LOW) group->PORT_OUTCLR = pinMask; + else group->PORT_OUTSET = pinMask; +} + +int digitalRead(uint32_t ulPin) +{ + if (g_APinDescription[ulPin].ulPinType == PIO_NOT_A_PIN) return LOW; + + port_group_registers_t *group = &PORT_REGS->GROUP[g_APinDescription[ulPin].ulPort]; + uint32_t pinMask = 1UL << g_APinDescription[ulPin].ulPin; + return (group->PORT_IN & pinMask) ? HIGH : LOW; +} + +#else void pinMode( uint32_t ulPin, uint32_t ulMode ) { // Handle the case the pin isn't usable as PIO @@ -121,8 +182,8 @@ int digitalRead( uint32_t ulPin ) return LOW ; } +#endif #ifdef __cplusplus } #endif - diff --git a/cores/arduino/wiring_private.c b/cores/arduino/wiring_private.c index 954f854af..f9708fe11 100644 --- a/cores/arduino/wiring_private.c +++ b/cores/arduino/wiring_private.c @@ -68,7 +68,7 @@ int pinPeripheral( uint32_t ulPin, EPioType ulPeripheral ) case PIO_TIMER: case PIO_TIMER_ALT: case PIO_EXTINT: -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) case PIO_TCC_PDEC: case PIO_COM: case PIO_SDHC: @@ -81,6 +81,7 @@ int pinPeripheral( uint32_t ulPin, EPioType ulPeripheral ) case PIO_COM: case PIO_AC_CLK: #endif + { #if 0 // Is the pio pin in the lower 16 ones? // The WRCONFIG register allows update of only 16 pin max out of 32 @@ -97,6 +98,19 @@ int pinPeripheral( uint32_t ulPin, EPioType ulPeripheral ) PORT_WRCONFIG_WRPINCFG | PORT_WRCONFIG_PINMASK( g_APinDescription[ulPin].ulPin - 16 ) ; } +#else +#if defined(__SAME53__) || defined(__SAME54__) + port_group_registers_t *group = &PORT_REGS->GROUP[g_APinDescription[ulPin].ulPort]; + uint32_t pin = g_APinDescription[ulPin].ulPin; + uint32_t pmux = group->PORT_PMUX[pin >> 1]; + + if (pin & 1) { + pmux = (pmux & PORT_PMUX_PMUXE_Msk) | PORT_PMUX_PMUXO(ulPeripheral); + } else { + pmux = (pmux & PORT_PMUX_PMUXO_Msk) | PORT_PMUX_PMUXE(ulPeripheral); + } + group->PORT_PMUX[pin >> 1] = pmux; + group->PORT_PINCFG[pin] |= PORT_PINCFG_PMUXEN_Msk | PORT_PINCFG_INEN_Msk | PORT_PINCFG_DRVSTR_Msk; #else if ( g_APinDescription[ulPin].ulPin & 1 ) // is pin odd? { @@ -118,6 +132,8 @@ int pinPeripheral( uint32_t ulPin, EPioType ulPeripheral ) PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN | PORT_PINCFG_DRVSTR ; // Enable port mux } #endif +#endif + } break ; case PIO_NOT_A_PIN: @@ -127,4 +143,3 @@ int pinPeripheral( uint32_t ulPin, EPioType ulPeripheral ) return 0l ; } - diff --git a/cores/arduino/wiring_private.h b/cores/arduino/wiring_private.h index ce64e2def..639de7b89 100644 --- a/cores/arduino/wiring_private.h +++ b/cores/arduino/wiring_private.h @@ -27,7 +27,7 @@ extern "C" { #endif // Includes Atmel CMSIS -#include "sam.h" +#include #include "wiring_constants.h" diff --git a/extras/wirepinmux/SAMD21_Device_I2C_Config.csv b/extras/wirepinmux/SAMD21_Device_I2C_Config.csv new file mode 100644 index 000000000..91ec36e5d --- /dev/null +++ b/extras/wirepinmux/SAMD21_Device_I2C_Config.csv @@ -0,0 +1,161 @@ +Device,Pin Count,Variant,I2C Pins,SERCOM Configs +SAMD21E14,32,base,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E14A,32,A,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E14B,32,B,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E14C,32,C,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E14D,32,D,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E14L,32,L,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E15,32,base,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E15A,32,A,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E15B,32,B,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E15C,32,C,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E15D,32,D,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E15L,32,L,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E16,32,base,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E16A,32,A,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E16B,32,B,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E16C,32,C,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E16D,32,D,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E16L,32,L,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E17,32,base,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E17A,32,A,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E17B,32,B,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E17C,32,C,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E17D,32,D,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E17L,32,L,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E18,32,base,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E18A,32,A,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E18B,32,B,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E18C,32,C,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E18D,32,D,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21E18L,32,L,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G14,48,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G14A,48,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G14B,48,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G14C,48,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G14D,48,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G14L,48,L,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G15,48,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G15A,48,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G15B,48,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G15C,48,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G15D,48,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G15L,48,L,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G16,48,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G16A,48,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G16B,48,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G16C,48,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G16D,48,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G16L,48,L,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G17,48,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G17A,48,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G17B,48,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G17C,48,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G17D,48,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G17L,48,L,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G18,48,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G18A,48,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G18B,48,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G18C,48,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G18D,48,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21G18L,48,L,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMD21J14,64,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J14A,64,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J14B,64,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J14C,64,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J14D,64,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J15,64,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J15A,64,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J15B,64,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J15C,64,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J15D,64,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J16,64,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J16A,64,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J16B,64,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J16C,64,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J16D,64,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J17,64,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J17A,64,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J17B,64,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J17C,64,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J17D,64,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J18,64,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J18A,64,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J18B,64,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J18C,64,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMD21J18D,64,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1E14,32,base,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E14A,32,A,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E14B,32,B,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E14C,32,C,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E14D,32,D,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E15,32,base,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E15A,32,A,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E15B,32,B,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E15C,32,C,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E15D,32,D,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E16,32,base,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E16A,32,A,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E16B,32,B,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E16C,32,C,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E16D,32,D,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E17,32,base,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E17A,32,A,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E17B,32,B,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E17C,32,C,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E17D,32,D,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E18,32,base,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E18A,32,A,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E18B,32,B,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E18C,32,C,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1E18D,32,D,"PA08,PA09,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G14,48,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G14A,48,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G14B,48,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G14C,48,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G14D,48,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G15,48,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G15A,48,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G15B,48,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G15C,48,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G15D,48,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G16,48,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G16A,48,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G16B,48,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G16C,48,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G16D,48,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G17,48,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G17A,48,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G17B,48,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G17C,48,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G17D,48,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G18,48,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G18A,48,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G18B,48,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G18C,48,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1G18D,48,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]" +SAMDA1J14,64,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J14A,64,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J14B,64,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J14C,64,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J14D,64,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J15,64,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J15A,64,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J15B,64,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J15C,64,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J15D,64,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J16,64,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J16A,64,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J16B,64,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J16C,64,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J16D,64,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J17,64,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J17A,64,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J17B,64,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J17C,64,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J17D,64,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J18,64,base,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J18A,64,A,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J18B,64,B,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J18C,64,C,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" +SAMDA1J18D,64,D,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PB12,PB13,PB16,PB17,PB30,PB31","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[0]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[1]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[0]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[1]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[0]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[1]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[0]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[1]]|PB12:[SERCOM4/PAD[0]]|PB13:[SERCOM4/PAD[1]]|PB16:[SERCOM5/PAD[0]]|PB17:[SERCOM5/PAD[1]]|PB30:[SERCOM5/PAD[0]]|PB31:[SERCOM5/PAD[1]]" diff --git a/extras/wirepinmux/SAMD21_Table_2-1.csv b/extras/wirepinmux/SAMD21_Table_2-1.csv new file mode 100644 index 000000000..050df920d --- /dev/null +++ b/extras/wirepinmux/SAMD21_Table_2-1.csv @@ -0,0 +1,31 @@ +Table 2-1. SAM D21 E/G/J and SAM D21 EL/GL Product Family Features,,,,,,,,,,,,,,,,,,,,,, +,,,,,Oscillators,,Peripherals,,,,,,,,,,,,Analog,,, +Device,Program Memory (KB),Data Memory (KB),Pins,Packages,Internal,External,USB,SERCOM,TC-Waveform /PWM Output/Capture Input Channels per TCx Instance,TCC,Waveform /PWM Output Channels per TCCx Instance,I2S,DMA Channels,RTC,WDT,Event System (Channels),External Interrupt Lines,I/O Pins,ADC Channels,Analog Comparator,DAC,"PTC (Mutual/Self-capacitance Channels)""" +ATSAMD21E15A,32,4,32,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,4,"3-2",3,"8/4/2",Y,12,Y,Y,12,16,26,10,2,Y,"60/6" +ATSAMD21E16A,64,8,32,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,4,"3-2",3,"8/4/2",Y,12,Y,Y,12,16,26,10,2,Y,"60/6" +ATSAMD21E17A,128,16,32,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,4,"3-2",3,"8/4/2",Y,12,Y,Y,12,16,26,10,2,Y,"60/6" +ATSAMD21E18A,256,32,32,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,4,"3-2",3,"8/4/2",Y,12,Y,Y,12,16,26,10,2,Y,"60/6" +ATSAMD21E15B,32,4,32,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,4,"3-2",3,"8/4/2",Y,12,Y,Y,12,16,26,10,2,Y,"60/6" +ATSAMD21E16B,64,8,32,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,4,"3-2",3,"8/4/2",Y,12,Y,Y,12,16,26,10,2,Y,"60/6" +ATSAMD21E15C,32,4,35,WLCSP,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,4,"3-2",3,"8/4/2",Y,12,Y,Y,12,16,26,10,2,Y,"60/6" +ATSAMD21E16C,64,8,35,WLCSP,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,4,"3-2",3,"8/4/2",Y,12,Y,Y,12,16,26,10,2,Y,"60/6" +ATSAMD21G15A,32,4,48,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,6,"3-2",3,"8/4/2",Y,12,Y,Y,12,16,38,14,2,Y,"120/10" +ATSAMD21G16A,64,8,48,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,6,"3-2",3,"8/4/2",Y,12,Y,Y,12,16,38,14,2,Y,"120/10" +ATSAMD21G17A,128,16,48,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,6,"3-2",3,"8/4/2",Y,12,Y,Y,12,16,38,14,2,Y,"120/10" +ATSAMD21G18A,256,32,48,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,6,"3-2",3,"8/4/2",Y,12,Y,Y,12,16,38,14,2,Y,"120/10" +ATSAMD21G15B,32,4,48,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,6,"3-2",3,"8/4/2",Y,12,Y,Y,12,16,38,14,2,Y,"120/10" +ATSAMD21G16B,64,8,48,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,6,"3-2",3,"8/4/2",Y,12,Y,Y,12,16,38,14,2,Y,"120/10" +ATSAMD21J15A,32,4,64,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,6,"5-2",3,"8/4/2",Y,12,Y,Y,12,16,52,20,2,Y,"256/16" +ATSAMD21J16A,64,8,64,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,6,"5-2",3,"8/4/2",Y,12,Y,Y,12,16,52,20,2,Y,"256/16" +ATSAMD21J17A,128,16,64,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,6,"5-2",3,"8/4/2",Y,12,Y,Y,12,16,52,20,2,Y,"256/16" +ATSAMD21J18A,256,32,64,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,6,"5-2",3,"8/4/2",Y,12,Y,Y,12,16,52,20,2,Y,"256/16" +ATSAMD21J15B,32,4,64,TQFP/QFN/UFBGA,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,6,"5-2",3,"8/4/2",Y,12,Y,Y,12,16,52,20,2,Y,"256/16" +ATSAMD21J16B,64,8,64,TQFP/QFN/UFBGA,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,6,"5-2",3,"8/4/2",Y,12,Y,Y,12,16,52,20,2,Y,"256/16" +ATSAMD21E15L,32,4,32,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC,N,4,"3-2",3,"6/4/2",N,12,Y,Y,12,16,26,14,4,Y,N +ATSAMD21E16L,64,8,32,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC,N,4,"3-2",3,"6/4/2",N,12,Y,Y,12,16,26,14,4,Y,N +ATSAMD21G16L,64,8,48,QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC,Y,6,"5-2",3,"8/4/2",N,12,Y,Y,12,16,38,18,4,Y,N +ATSAMD21E17D,128,16,32,TQFP/QFN/WLCSP,OSC32K/OSCULP32K/OSC8M/DFLL48M,XOSC32K/XOSC,Y,4,"3-2",4,"6/4/2/6",Y,12,Y,Y,12,16,26,10,2,Y,"30/6" +ATSAMD21G17D,128,16,48,QFN/TQFP,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,6,"3-2",4,"8/4/2/8",Y,12,Y,Y,12,16,38,14,2,Y,"120/10" +ATSAMD21J17D,128,16,64,QFN/TQFP/UFBGA,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,Y,6,"5-2",4,"8/4/2/8",Y,12,Y,Y,12,16,52,20,2,Y,"256/16" +ATSAMD21E17L,128,16,32,QFN/TQFP,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC,N,4,"3-2",4,"6/4/2/6",N,12,Y,Y,12,16,26,14,4,Y,N +ATSAMD21G17L,128,16,48,QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC,N,6,"5-2",4,"8/4/2/8",N,12,Y,Y,12,16,38,18,4,Y,N \ No newline at end of file diff --git a/extras/wirepinmux/SAMD21_Table_2-2.csv b/extras/wirepinmux/SAMD21_Table_2-2.csv new file mode 100644 index 000000000..06081a952 --- /dev/null +++ b/extras/wirepinmux/SAMD21_Table_2-2.csv @@ -0,0 +1,11 @@ +Table 2-2. SAM DA1,E/G/J Product Family Features,,,,,,,,,,,,,,,,,,,,, +Device,Program Memory (KB),Data Memory (KB),Pins,Packages,Internal,External,USB,SERCOM,TC-Waveform/PWM Output/Capture Input Channels per TCx Instance,TCC,Waveform/PWM Output Channels per TCCx Instance,I2S,DMA Channels,RTC,WDT,EventSystem (Channels),External Interrupt Lines,I/O Pins,ADC Channels,2,1,PTC (Mutual/Self-capacitance Channels) +ATSAMDA1E14B,16,4,32,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,1,4,"3-2",3,"6/4/2",1,12,Y,Y,12,16,26,10,2,1,"60/6" +ATSAMDA1E15B,32,4,32,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,1,4,"3-2",3,"6/4/2",1,12,Y,Y,12,16,26,10,2,1,"60/6" +ATSAMDA1E16B,64,8,32,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,1,4,"3-2",3,"6/4/2",1,12,Y,Y,12,16,26,10,2,1,"60/6" +ATSAMDA1G14B,16,4,48,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,1,6,"3-2",3,"8/4/2",1,12,Y,Y,12,16,38,14,2,1,"120/10" +ATSAMDA1G15B,32,4,48,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,1,6,"3-2",3,"8/4/2",1,12,Y,Y,12,16,38,14,2,1,"120/10" +ATSAMDA1G16B,64,8,48,TQFP/QFN,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,1,6,"3-2",3,"8/4/2",1,12,Y,Y,12,16,38,14,2,1,"120/10" +ATSAMDA1J14B,16,4,64,TQFP,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,1,6,"5-2",3,"8/4/2",1,12,Y,Y,12,16,52,20,2,1,"256/16" +ATSAMDA1J15B,32,4,64,TQFP,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,1,6,"5-2",3,"8/4/2",1,12,Y,Y,12,16,52,20,2,1,"256/16" +ATSAMDA1J16B,64,8,64,TQFP,OSC32K/OSCULP32K/OSC8M/DFLL48M/FDPLL96M,XOSC32K/XOSC,1,6,"5-2",3,"8/4/2",1,12,Y,Y,12,16,52,20,2,1,"256/16" \ No newline at end of file diff --git a/extras/wirepinmux/SAMD21_Table_7-1.csv b/extras/wirepinmux/SAMD21_Table_7-1.csv new file mode 100644 index 000000000..c50b4113f --- /dev/null +++ b/extras/wirepinmux/SAMD21_Table_7-1.csv @@ -0,0 +1,53 @@ +SAMD2xE,SAMD2xG,SAMD2xJ,I/O Pin,Supply,A,B1,B2,B3,B4,B5,C,D,E,F,G,H +1,1,1,PA00,VDDANA,EXTINT[0],,,,,,,SERCOM1/PAD[0],TCC2/WO[0],,, +2,2,2,PA01,VDDANA,EXTINT[1],,,,,,,SERCOM1/PAD[1],TCC2/WO[1],,, +3,3,3,PA02,VDDANA,EXTINT[2],,AIN[0],,Y[0],VOUT,,,,TCC3/WO[0],, +4,4,4,PA03,VDDANA,EXTINT[3],ADC/VREFA DAC/VREFA,AIN[1],,Y[1],,,,,TCC3/WO[1],, +,,5,PB04,VDDANA,EXTINT[4],,AIN[12],,Y[10],,,,,,, +,,6,PB05,VDDANA,EXTINT[5],,AIN[13],,Y[11],,,,,,, +,,9,PB06,VDDANA,EXTINT[6],,AIN[14],,Y[12],,,,,,, +,,10,PB07,VDDANA,EXTINT[7],,AIN[15],,Y[13],,,,,,, +,7,11,PB08,VDDANA,EXTINT[8],,AIN[2],,Y[14],,,SERCOM4/PAD[0],TC4/WO[0],TCC3/WO[6],, +,8,12,PB09,VDDANA,EXTINT[9],,AIN[3],,Y[15],,,SERCOM4/PAD[1],TC4/WO[1],TCC3/WO[7],, +5,9,13,PA04,VDDANA,EXTINT[4],ADC/VREFB,AIN[4],AIN[0],Y[2],,,SERCOM0/PAD[0],TCC0/WO[0],TCC3/WO[2],, +6,10,14,PA05,VDDANA,EXTINT[5],,AIN[5],AIN[1],Y[3],,,SERCOM0/PAD[1],TCC0/WO[1],TCC3/WO[3],, +7,11,15,PA06,VDDANA,EXTINT[6],,AIN[6],AIN[2],Y[4],,,SERCOM0/PAD[2],TCC1/WO[0],TCC3/WO[4],, +8,12,16,PA07,VDDANA,EXTINT[7],,AIN[7],AIN[3],Y[5],,,SERCOM0/PAD[3],TCC1/WO[1],TCC3/WO[5],I2S/SD[0], +11,13,17,PA08,VDDIO,NMI,,AIN[16],,X[0],,SERCOM0/PAD[0],SERCOM2/PAD[0],TCC0/WO[0],TCC1/WO[2],I2S/SD[1], +12,14,18,PA09,VDDIO,EXTINT[9],,AIN[17],,X[1],,SERCOM0/PAD[1],SERCOM2/PAD[1],TCC0/WO[1],TCC1/WO[3],I2S/MCK[0], +13,15,19,PA10,VDDIO,EXTINT[10],,AIN[18],,X[2],,SERCOM0/PAD[2],SERCOM2/PAD[2],TCC1/WO[0],TCC0/WO[2],I2S/SCK[0],GCLK_IO[4] +14,16,20,PA11,VDDIO,EXTINT[11],,AIN[19],,X[3],,SERCOM0/PAD[3],SERCOM2/PAD[3],TCC1/WO[1],TCC0/WO[3],I2S/FS[0],GCLK_IO[5] +,19,23,PB10,VDDIO,EXTINT[10],,,,,,,SERCOM4/PAD[2],TC5/WO[0],TCC0/WO[4],I2S/MCK[1],GCLK_IO[4] +,20,24,PB11,VDDIO,EXTINT[11],,,,,,,SERCOM4/PAD[3],TC5/WO[1],TCC0/WO[5],I2S/SCK[1],GCLK_IO[5] +,,25,PB12,VDDIO,EXTINT[12],,,,X[12],,SERCOM4/PAD[0],,TC4/WO[0],TCC0/WO[6],I2S/FS[1],GCLK_IO[6] +,,26,PB13,VDDIO,EXTINT[13],,,,X[13],,SERCOM4/PAD[1],,TC4/WO[1],TCC0/WO[7],,GCLK_IO[7] +,,27,PB14,VDDIO,EXTINT[14],,,,X[14],,SERCOM4/PAD[2],,TC5/WO[0],,,GCLK_IO[0] +,,28,PB15,VDDIO,EXTINT[15],,,,X[15],,SERCOM4/PAD[3],,TC5/WO[1],,,GCLK_IO[1] +,21,29,PA12,VDDIO,EXTINT[12],,,,,,SERCOM2/PAD[0],SERCOM4/PAD[0],TCC2/WO[0],TCC0/WO[6],,AC/CMP[0] +,22,30,PA13,VDDIO,EXTINT[13],,,,,,SERCOM2/PAD[1],SERCOM4/PAD[1],TCC2/WO[1],TCC0/WO[7],,AC/CMP[1] +15,23,31,PA14,VDDIO,EXTINT[14],,,,,,SERCOM2/PAD[2],SERCOM4/PAD[2],TC3/WO[0],TCC0/WO[4],,GCLK_IO[0] +16,24,32,PA15,VDDIO,EXTINT[15],,,,,,SERCOM2/PAD[3],SERCOM4/PAD[3],TC3/WO[1],TCC0/WO[5],,GCLK_IO[1] +17,25,35,PA16,VDDIO,EXTINT[0],,,,X[4],,SERCOM1/PAD[0],SERCOM3/PAD[0],TCC2/WO[0],TCC0/WO[6],,GCLK_IO[2] +18,26,36,PA17,VDDIO,EXTINT[1],,,,X[5],,SERCOM1/PAD[1],SERCOM3/PAD[1],TCC2/WO[1],TCC0/WO[7],,GCLK_IO[3] +19,27,37,PA18,VDDIO,EXTINT[2],,,,X[6],,SERCOM1/PAD[2],SERCOM3/PAD[2],TC3/WO[0],TCC0/WO[2],,AC/CMP[0] +20,28,38,PA19,VDDIO,EXTINT[3],,,,X[7],,SERCOM1/PAD[3],SERCOM3/PAD[3],TC3/WO[1],TCC0/WO[3],I2S/SD[0],AC/CMP[1] +,,39,PB16,VDDIO,EXTINT[0],,,,,,SERCOM5/PAD[0],,TC6/WO[0],TCC0/WO[4],I2S/SD[1],GCLK_IO[2] +,,40,PB17,VDDIO,EXTINT[1],,,,,,SERCOM5/PAD[1],,TC6/WO[1],TCC0/WO[5],I2S/MCK[0],GCLK_IO[3] +,29,41,PA20,VDDIO,EXTINT[4],,,,X[8],,SERCOM5/PAD[2],SERCOM3/PAD[2],TC7/WO[0],TCC0/WO[6],I2S/SCK[0],GCLK_IO[4] +,30,42,PA21,VDDIO,EXTINT[5],,,,X[9],,SERCOM5/PAD[3],SERCOM3/PAD[3],TC7/WO[1],TCC0/WO[7],I2S/FS[0],GCLK_IO[5] +21,31,43,PA22,VDDIO,EXTINT[6],,,,X[10],,SERCOM3/PAD[0],SERCOM5/PAD[0],TC4/WO[0],TCC0/WO[4],,GCLK_IO[6] +22,32,44,PA23,VDDIO,EXTINT[7],,,,X[11],,SERCOM3/PAD[1],SERCOM5/PAD[1],TC4/WO[1],TCC0/WO[5],USB/SOF 1kHz,GCLK_IO[7] +23,33,45,PA24,VDDIO,EXTINT[12],,,,,,SERCOM3/PAD[2],SERCOM5/PAD[2],TC5/WO[0],TCC1/WO[2],USB/DM, +24,34,46,PA25,VDDIO,EXTINT[13],,,,,,SERCOM3/PAD[3],SERCOM5/PAD[3],TC5/WO[1],TCC1/WO[3],USB/DP, +,37,49,PB22,VDDIO,EXTINT[6],,,,,,,SERCOM5/PAD[2],TC7/WO[0],TCC3/WO[0],,GCLK_IO[0] +,38,50,PB23,VDDIO,EXTINT[7],,,,,,,SERCOM5/PAD[3],TC7/WO[1],TCC3/WO[1],,GCLK_IO[1] +25,39,51,PA27,VDDIO,EXTINT[15],,,,,,,,,TCC3/WO[6],,GCLK_IO[0] +27,41,53,PA28,VDDIO,EXTINT[8],,,,,,,,,TCC3/WO[7],,GCLK_IO[0] +31,45,57,PA30,VDDIO,EXTINT[10],,,,,,,SERCOM1/PAD[2],TCC1/WO[0],TCC3/WO[4],SWCLK,GCLK_IO[0] +32,46,58,PA31,VDDIO,EXTINT[11],,,,,,,SERCOM1/PAD[3],TCC1/WO[1],TCC3/WO[5],SWDIO, +,,59,PB30,VDDIO,EXTINT[14],,,,,,,SERCOM5/PAD[0],TCC0/WO[0],TCC1/WO[2],, +,,60,PB31,VDDIO,EXTINT[15],,,,,,,SERCOM5/PAD[1],TCC0/WO[1],TCC1/WO[3],, +,,61,PB00,VDDANA,EXTINT[0],,AIN[8],,Y[6],,,SERCOM5/PAD[2],TC7/WO[0],,, +,,62,PB01,VDDANA,EXTINT[1],,AIN[9],,Y[7],,,SERCOM5/PAD[3],TC7/WO[1],,, +,47,63,PB02,VDDANA,EXTINT[2],,AIN[10],,Y[8],,,SERCOM5/PAD[0],TC6/WO[0],TCC3/WO[2],, +,48,64,PB03,VDDANA,EXTINT[3],,AIN[11],,Y[9],,,SERCOM5/PAD[1],TC6/WO[1],TCC3/WO[3],, \ No newline at end of file diff --git a/extras/wirepinmux/SAMD21_Table_7-2.csv b/extras/wirepinmux/SAMD21_Table_7-2.csv new file mode 100644 index 000000000..c24707fae --- /dev/null +++ b/extras/wirepinmux/SAMD21_Table_7-2.csv @@ -0,0 +1,39 @@ +SAMD21ExL,SAMD21GxL,I/O Pin,Supply,A,B1,B2,B3,B4,B5,C,D,E,F,G,H +1,1,PA02,VDDANA,EXTINT[2],,AIN[0],,,VOUT,,,,TCC3/WO[0],, +2,2,PA03,VDDANA,EXTINT[3],DAC/VREFA,AIN[1],,,,,,,TCC3/WO[1],, +3,3,PB04,VDDANA,EXTINT[4],,AIN[12],,AIN[0],,,,,,, +4,4,PB05,VDDANA,EXTINT[5],,AIN[13],,AIN[1],,,,,,, +,7,PB08,VDDANA,EXTINT[8],,AIN[2],,,,,SERCOM4/PAD[0],TC4/WO[0],TCC3/WO[6],, +,8,PB09,VDDANA,EXTINT[9],,AIN[3],,,,,SERCOM4/PAD[1],TC4/WO[1],TCC3/WO[7],, +5,9,PA04,VDDANA,EXTINT[4],ADC/VREFB,AIN[4],AIN[0],,,,SERCOM0/PAD[0],TCC0/WO[0],TCC3/WO[2],, +6,10,PA05,VDDANA,EXTINT[5],,AIN[5],AIN[1],,,,SERCOM0/PAD[1],TCC0/WO[1],TCC3/WO[3],, +7,11,PA06,VDDANA,EXTINT[6],,AIN[6],AIN[2],,,,SERCOM0/PAD[2],TCC1/WO[0],TCC3/WO[4],, +8,12,PA07,VDDANA,EXTINT[7],,AIN[7],AIN[3],,,,SERCOM0/PAD[3],TCC1/WO[1],TCC3/WO[5],, +11,13,PA08,VDDIO,NMI,,AIN[16],,,,SERCOM0/PAD[0],SERCOM2/PAD[0],TCC0/WO[0],TCC1/WO[2],, +12,14,PA09,VDDIO,EXTINT[9],,AIN[17],,,,SERCOM0/PAD[1],SERCOM2/PAD[1],TCC0/WO[1],TCC1/WO[3],, +13,15,PA10,VDDIO,EXTINT[10],,AIN[18],,,,SERCOM0/PAD[2],SERCOM2/PAD[2],TCC1/WO[0],TCC0/WO[2],,GCLK_IO[4] +14,16,PA11,VDDIO,EXTINT[11],,AIN[19],,,,SERCOM0/PAD[3],SERCOM2/PAD[3],TCC1/WO[1],TCC0/WO[3],,GCLK_IO[5] +,19,PB10,VDDIO,EXTINT[10],,,,,,,SERCOM4/PAD[2],TC5/WO[0],TCC0/WO[4],,GCLK_IO[4] +,20,PB11,VDDIO,EXTINT[11],,,,,,,SERCOM4/PAD[3],TC5/WO[1],TCC0/WO[5],,GCLK_IO[5] +,21,PA12,VDDIO,EXTINT[12],,,,,,SERCOM2/PAD[0],SERCOM4/PAD[0],TCC2/WO[0],TCC0/WO[6],,AC/CMP[0] +,22,PA13,VDDIO,EXTINT[13],,,,,,SERCOM2/PAD[1],SERCOM4/PAD[1],TCC2/WO[1],TCC0/WO[7],,AC/CMP[1] +15,23,PA14,VDDIO,EXTINT[14],,,,,,SERCOM2/PAD[2],SERCOM4/PAD[2],TC3/WO[0],TCC0/WO[4],,GCLK_IO[0] +16,24,PA15,VDDIO,EXTINT[15],,,,,,SERCOM2/PAD[3],SERCOM4/PAD[3],TC3/WO[1],TCC0/WO[5],,GCLK_IO[1] +17,25,PA16,VDDIO,EXTINT[0],,,,,,SERCOM1/PAD[0],SERCOM3/PAD[0],TCC2/WO[0],TCC0/WO[6],,GCLK_IO[2] +18,26,PA17,VDDIO,EXTINT[1],,,,,,SERCOM1/PAD[1],SERCOM3/PAD[1],TCC2/WO[1],TCC0/WO[7],,GCLK_IO[3] +19,27,PA18,VDDIO,EXTINT[2],,,,,,SERCOM1/PAD[2],SERCOM3/PAD[2],TC3/WO[0],TCC0/WO[2],,AC/CMP[0] +20,28,PA19,VDDIO,EXTINT[3],,,,,,SERCOM1/PAD[3],SERCOM3/PAD[3],TC3/WO[1],TCC0/WO[3],,AC/CMP[1] +,29,PA20,VDDIO,EXTINT[4],,,,,,SERCOM5/PAD[2],SERCOM3/PAD[2],TC7/WO[0],TCC0/WO[6],,GCLK_IO[4] +,30,PA21,VDDIO,EXTINT[5],,,,,,SERCOM5/PAD[3],SERCOM3/PAD[3],TC7/WO[1],TCC0/WO[7],,GCLK_IO[5] +21,31,PA22,VDDIO,EXTINT[6],,,,,,SERCOM3/PAD[0],SERCOM5/PAD[0],TC4/WO[0],TCC0/WO[4],,GCLK_IO[6] +22,32,PA23,VDDIO,EXTINT[7],,,,,,SERCOM3/PAD[1],SERCOM5/PAD[1],TC4/WO[1],TCC0/WO[5],,GCLK_IO[7] +23,33,PA24,VDDIO,EXTINT[12],,,,,,SERCOM3/PAD[2],SERCOM5/PAD[2],TC5/WO[0],TCC1/WO[2],,AC1/CMP[0] +24,34,PA25,VDDIO,EXTINT[13],,,,,,SERCOM3/PAD[3],SERCOM5/PAD[3],TC5/WO[1],TCC1/WO[3],,AC1/CMP[1] +,37,PA27,VDDIO,EXTINT[15],,,,,,,,,TCC3/WO[6],,GCLK_IO[0] +,39,PA28,VDDIO,EXTINT[8],,,,,,,,,TCC3/WO[7],,GCLK_IO[0] +29,43,PA30,VDDIO,EXTINT[10],,,,,,,SERCOM1/PAD[2],TCC1/WO[0],TCC3/WO[4],SWCLK,GCLK_IO[0] +30,44,PA31,VDDIO,EXTINT[11],,,,,,,SERCOM1/PAD[3],TCC1/WO[1],TCC3/WO[5],SWDIO, +,45,PB00,,,,AIN[8],,,,,,,,, +,46,PB01,,,,AIN[9],,,,,,,,, +31,47,PB02,VDDANA,EXTINT[2],,AIN[10],,AIN[2],,,SERCOM5/PAD[0],TC6/WO[0],TCC3/WO[2],, +32,48,PB03,VDDANA,EXTINT[3],,AIN[11],,AIN[3],,,SERCOM5/PAD[1],TC6/WO[1],TCC3/WO[3],, \ No newline at end of file diff --git a/extras/wirepinmux/SAMD21_Table_7-5.csv b/extras/wirepinmux/SAMD21_Table_7-5.csv new file mode 100644 index 000000000..3b0f7183e --- /dev/null +++ b/extras/wirepinmux/SAMD21_Table_7-5.csv @@ -0,0 +1,4 @@ +Device,I/O Pin +32, PA08, PA09, PA16, PA17, PA22, PA23 +48, PA08, PA09, PA12, PA13, PA16, PA17, PA22, PA23 +64, PA08, PA09, PA12, PA13, PA16, PA17, PA22, PA23, PB12, PB13, PB16, PB17, PB30, PB31 \ No newline at end of file diff --git a/extras/wirepinmux/SAMD51_Device_I2C_Config.csv b/extras/wirepinmux/SAMD51_Device_I2C_Config.csv new file mode 100644 index 000000000..93ab09455 --- /dev/null +++ b/extras/wirepinmux/SAMD51_Device_I2C_Config.csv @@ -0,0 +1,26 @@ +Device,Pin Count,I2C Pins,SERCOM Configs +SAMD51G18,48,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAMD51G19,48,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAMD51J18,64,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAMD51J19,64,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAMD51J20,64,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAMD51N19,100,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAMD51N20,100,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAMD51P19,120,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PD08,PD09","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]|PD08:[SERCOM7/PAD[0],SERCOM6/PAD[1]]|PD09:[SERCOM7/PAD[1],SERCOM6/PAD[0]]" +SAMD51P20,120,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PD08,PD09","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]|PD08:[SERCOM7/PAD[0],SERCOM6/PAD[1]]|PD09:[SERCOM7/PAD[1],SERCOM6/PAD[0]]" +SAME51G18,48,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAME51G19,48,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAME51J18,64,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAME51J19,64,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAME51J20,64,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAME51N19,100,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAME51N20,100,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAME53J18,64,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAME53J19,64,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAME53J20,64,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAME53N19,100,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAME53N20,100,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAME54N19,100,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAME54N20,100,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]" +SAME54P19,120,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PD08,PD09","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]|PD08:[SERCOM7/PAD[0],SERCOM6/PAD[1]]|PD09:[SERCOM7/PAD[1],SERCOM6/PAD[0]]" +SAME54P20,120,"PA08,PA09,PA12,PA13,PA16,PA17,PA22,PA23,PD08,PD09","PA08:[SERCOM0/PAD[0],SERCOM2/PAD[1]]|PA09:[SERCOM0/PAD[1],SERCOM2/PAD[0]]|PA12:[SERCOM2/PAD[0],SERCOM4/PAD[1]]|PA13:[SERCOM2/PAD[1],SERCOM4/PAD[0]]|PA16:[SERCOM1/PAD[0],SERCOM3/PAD[1]]|PA17:[SERCOM1/PAD[1],SERCOM3/PAD[0]]|PA22:[SERCOM3/PAD[0],SERCOM5/PAD[1]]|PA23:[SERCOM3/PAD[1],SERCOM5/PAD[0]]|PD08:[SERCOM7/PAD[0],SERCOM6/PAD[1]]|PD09:[SERCOM7/PAD[1],SERCOM6/PAD[0]]" diff --git a/extras/wirepinmux/SAMD51_Table_1-1.csv b/extras/wirepinmux/SAMD51_Table_1-1.csv new file mode 100644 index 000000000..78e57a570 --- /dev/null +++ b/extras/wirepinmux/SAMD51_Table_1-1.csv @@ -0,0 +1,14 @@ +Table 1-1. SAM E53/E54 Family Features with Ethernet,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,Peripherals,,,,,,,,,,,,,,,,,,,Analog,,,,,Security,,,, +Device,Flash (KB),SRAM (KB) / Backup RAM (KB),Pins,Packages,Ethernet Controller,CAN-FD,SERCOM,TC/Compare,TCC (24-bit/16-bit),I2S,USB,QSPI,SDHC,DMA Channels,PCC (data size),CCL,Position Decoder,RTC,WDT,Frequency Measurement,Event System (Channels),External Interrupt Lines,I/O Pins,ADC (Channels ADC0/ADC1),Analog Comparators (Channels),DAC (Channels),PTC (Mutual/Self-capacitance Channels),Temperature Sensor,AES,TRNG,Public Key Cryptography (PUKCC),Integrity Check Monitor,Tamper Pins +SAME53N20,1024,256 / 8,100,TQFP,Y,N,8,"8/2","2/3",Y,Y,Y,2,32,14,4,Y,Y,Y,Y,32,16,81,"16/12",4,2,"256/32",Y,Y,Y,Y,Y,5 +SAME53N19,512,192 / 8,100,TQFP,Y,N,8,"8/2","2/3",Y,Y,Y,2,32,14,4,Y,Y,Y,Y,32,16,81,"16/12",4,2,"256/32",Y,Y,Y,Y,Y,5 +SAME53J20,1024,256 / 8,64,"TQFP,VQFN",Y,N,6,"6/2","2/3",Y,Y,Y,1,32,10,4,Y,Y,Y,Y,32,16,51,"16/8",4,2,"256/32",Y,Y,Y,Y,Y,3 +SAME53J19,512,192 / 8,64,"TQFP,VQFN",Y,N,6,"6/2","2/3",Y,Y,Y,1,32,10,4,Y,Y,Y,Y,32,16,51,"16/8",4,2,"256/32",Y,Y,Y,Y,Y,3 +SAME53J18,256,128 / 8,64,"TQFP,VQFN",Y,N,6,"6/2","2/3",Y,Y,Y,1,32,10,4,Y,Y,Y,Y,32,16,51,"16/8",4,2,"256/32",Y,Y,Y,Y,Y,3 +SAME54P20,1024,256 / 8,128,TQFP,Y,Y,8,"8/2","2/3",Y,Y,Y,2,32,14,4,Y,Y,Y,Y,32,16,99,"16/16",4,2,"256/32",Y,Y,Y,Y,Y,5 +SAME54P20,1024,256 / 8,120,TFBGA,Y,Y,8,"8/2","2/3",Y,Y,Y,2,32,14,4,Y,Y,Y,Y,32,16,99,"16/16",4,2,"256/32",Y,Y,Y,Y,Y,5 +SAME54P19,512,192 / 8,128,TQFP,Y,Y,8,"8/2","2/3",Y,Y,Y,2,32,14,4,Y,Y,Y,Y,32,16,99,"16/16",4,2,"256/32",Y,Y,Y,Y,Y,5 +SAME54P19,512,192 / 8,120,TFBGA,Y,Y,8,"8/2","2/3",Y,Y,Y,2,32,14,4,Y,Y,Y,Y,32,16,99,"16/16",4,2,"256/32",Y,Y,Y,Y,Y,5 +SAME54N20,1024,256 / 8,100,TQFP,Y,Y,8,"8/2","2/3",Y,Y,Y,2,32,14,4,Y,Y,Y,Y,32,16,81,"16/12",4,2,"256/32",Y,Y,Y,Y,Y,5 +SAME54N19,512,192 / 8,100,TQFP,Y,Y,8,"8/2","2/3",Y,Y,Y,2,32,14,4,Y,Y,Y,Y,32,16,81,"16/12",4,2,"256/32",Y,Y,Y,Y,Y,5 \ No newline at end of file diff --git a/extras/wirepinmux/SAMD51_Table_1-2.csv b/extras/wirepinmux/SAMD51_Table_1-2.csv new file mode 100644 index 000000000..881339354 --- /dev/null +++ b/extras/wirepinmux/SAMD51_Table_1-2.csv @@ -0,0 +1,21 @@ +Table 1-2. SAM D51/E51 Family Features without Ethernet,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,Peripherals,,,,,,,,,,,,,,,,,,Analog,,,,,Security,,,, +Device,Flash (KB),SRAM (KB) / Backup RAM (KB),Pins,Packages,CAN-FD,SERCOM,TC/Compare,TCC (24-bit/16-bit),I2S,USB,QSPI,SDHC,DMA Channels,PCC (data size),CCL,Position Decoder,RTC,WDT,Frequency Measurement,Event System (Channels),External Interrupt Lines,I/O Pins,ADC (Channels ADC0/ADC1),Analog Comparators (Channels),DAC (Channels),PTC (Mutual/Self-capacitance Channels),Temperature Sensor,AES,TRNG,Public Key Cryptography (PUKCC),Integrity Check Monitor,Tamper Pins +SAMD51P20,1024,256,128,TQFP,N,8,"8/2","2/3",Y,Y,Y,2,32,14,4,Y,Y,Y,Y,32,16,99,"16/16",4,2,256/32,Y,Y,Y,Y,Y,5 +SAMD51P20,1024,256,120,TFBGA,N,8,"8/2","2/3",Y,Y,Y,2,32,14,4,Y,Y,Y,Y,32,16,99,"16/16",4,2,256/32,Y,Y,Y,Y,Y,5 +SAMD51P19,512,192,128,TQFP,N,8,"8/2","2/3",Y,Y,Y,2,32,14,4,Y,Y,Y,Y,32,16,99,"16/16",4,2,256/32,Y,Y,Y,Y,Y,5 +SAMD51P19,512,192,120,TFBGA,N,8,"8/2","2/3",Y,Y,Y,2,32,14,4,Y,Y,Y,Y,32,16,99,"16/16",4,2,256/32,Y,Y,Y,Y,Y,5 +SAMD51N20,1024,256,100,TQFP,N,8,"8/2","2/3",Y,Y,Y,2,32,14,4,Y,Y,Y,Y,32,16,81,"16/12",4,2,256/32,Y,Y,Y,Y,Y,5 +SAMD51N19,512,192,100,TQFP,N,8,"8/2","2/3",Y,Y,Y,2,32,14,4,Y,Y,Y,Y,32,16,81,"16/12",4,2,256/32,Y,Y,Y,Y,Y,5 +SAMD51J20,1024,256,64,"TQFP,VQFN,WLCSP",N,6,"6/2","2/3",Y,Y,Y,1,32,10,4,Y,Y,Y,Y,32,16,51,"16/8",4,2,256/32,Y,Y,Y,Y,Y,3 +SAMD51J19,512,192,64,"TQFP,VQFN,WLCSP",N,6,"6/2","2/3",Y,Y,Y,1,32,10,4,Y,Y,Y,Y,32,16,51,"16/8",4,2,256/32,Y,Y,Y,Y,Y,3 +SAMD51J18,256,128,64,"TQFP,VQFN",N,6,"6/2","2/3",Y,Y,Y,1,32,10,4,Y,Y,Y,Y,32,16,51,"16/8",4,2,256/32,Y,Y,Y,Y,Y,3 +SAMD51G19,512,192,48,VQFN,N,6,"4/2","2/1",N,Y,Y,1,32,10,4,Y,Y,Y,Y,32,16,37,"16/4",4,2,121/22,Y,Y,Y,Y,Y,2 +SAMD51G18,256,128,48,VQFN,N,6,"4/2","2/1",N,Y,Y,1,32,10,4,Y,Y,Y,Y,32,16,37,"16/4",4,2,121/22,Y,Y,Y,Y,Y,2 +SAME51N20,1024,256,100,TQFP,Y,8,"8/2","2/3",Y,Y,Y,1,32,14,4,Y,Y,Y,Y,32,16,81,"16/12",4,2,256/32,Y,Y,Y,Y,Y,5 +SAME51N19,512,192,100,TQFP,Y,8,"8/2","2/3",Y,Y,Y,1,32,14,4,Y,Y,Y,Y,32,16,81,"16/12",4,2,256/32,Y,Y,Y,Y,Y,5 +SAME51J20,1024,256,64,"TQFP,VQFN",Y,6,"6/2","2/3",Y,Y,Y,1,32,10,4,Y,Y,Y,Y,32,16,51,"16/8",4,2,256/32,Y,Y,Y,Y,Y,3 +SAME51J19,512,192,64,"TQFP,VQFN",Y,6,"6/2","2/3",Y,Y,Y,1,32,10,4,Y,Y,Y,Y,32,16,51,"16/8",4,2,256/32,Y,Y,Y,Y,Y,3 +SAME51J18,256,128,64,"TQFP,VQFN",Y,6,"6/2","2/3",Y,Y,Y,1,32,10,4,Y,Y,Y,Y,32,16,51,"16/8",4,2,256/32,Y,Y,Y,Y,Y,3 +SAME51G18,256,128,48,VQFN,Y,6,"4/2","2/1",N,Y,Y,1,32,10,4,Y,Y,Y,Y,32,16,37,"16/4",4,2,121/22,Y,Y,Y,Y,Y,2 +SAME51G19,512,192,48,VQFN,Y,6,"4/2","2/1",N,Y,Y,1,32,10,4,Y,Y,Y,Y,32,16,37,"16/4",4,2,121/22,Y,Y,Y,Y,Y,2 \ No newline at end of file diff --git a/extras/wirepinmux/SAMD51_Table_6-1.csv b/extras/wirepinmux/SAMD51_Table_6-1.csv new file mode 100644 index 000000000..15969cb2f --- /dev/null +++ b/extras/wirepinmux/SAMD51_Table_6-1.csv @@ -0,0 +1,101 @@ +48,64,100,120,128,Pad Name,A,B1,B2,B3,B4,B5,B6,C,D,E,F,G,H,I,J,K,L,M,N +48,64/C6,100,B2,128,PB03,EIC/EXTINT[3],-,ADC0/AIN[15],-,-,-,X21/Y21,-,SERCOM5/PAD[1],TC6/WO[1],-,-,-,-,-,-,-,-,- +1,01/B8,1,A1,1,PA00,EIC/EXTINT[0],-,-,-,-,-,,-,SERCOM1/PAD[0],TC2/WO[0],-,-,-,-,-,-,-,-,- +2,02/C8,2,B1,2,PA01,EIC/EXTINT[1],-,-,-,-,-,,-,SERCOM1/PAD[1],TC2/WO[1],-,-,-,-,-,-,-,-,- +,,3,C1,3,PC00,EIC/EXTINT[0],-,-,ADC1/AIN[10],-,-,,-,-,-,-,-,-,-,-,-,-,-,- +,,4,C2,4,PC01,EIC/EXTINT[1],-,-,ADC1/AIN[11],-,-,,-,-,-,-,-,-,-,-,-,-,-,- +,,5,D1,7,PC02,EIC/EXTINT[2],-,-,ADC1/AIN[4],-,-,,-,-,-,-,-,-,-,-,-,-,-,- +,,6,E2,8,PC03,EIC/EXTINT[3],-,-,ADC1/AIN[5],-,-,,-,-,-,-,-,-,-,-,-,-,-,- +3,03/C7,7,E1,9,PA02,EIC/EXTINT[2],-,ADC0/AIN[0],-,-,DAC/VOUT[0],,-,-,-,-,-,-,-,-,-,-,-,- +4,04/D6,8,F2,10,PA03,EIC/EXTINT[3],ANAREF/VREFA,ADC0/AIN[1],-,-,-,X0/Y0,-,-,-,-,-,-,-,-,-,-,-,- +,05/D7,9,F1,11,PB04,EIC/EXTINT[4],-,-,ADC1/AIN[6],-,-,X22/Y22,-,-,-,-,-,-,-,-,-,-,-,- +,06/D8,10,G1,12,PB05,EIC/EXTINT[5],-,-,ADC1/AIN[7],-,-,X23/Y23,-,-,-,-,-,-,-,-,-,-,-,- +,,-,G2,13,PD00,EIC/EXTINT[0],-,-,ADC1/AIN[14],-,-,,-,-,-,-,-,-,-,-,-,-,-,- +,,-,H1,16,PD01,EIC/EXTINT[1],-,-,ADC1/AIN[15],-,-,,-,-,-,-,-,-,-,-,-,-,-,- +,09/E7,13,H2,17,PB06,EIC/EXTINT[6],-,-,ADC1/AIN[8],-,-,X24/Y24,-,-,-,-,-,-,-,-,-,-,-,CCL/IN[6] +,10/E6,14,J1,18,PB07,EIC/EXTINT[7],-,-,ADC1/AIN[9],-,-,X25/Y25,-,-,-,-,-,-,-,-,-,-,-,CCL/IN[7] +7,11/F5,15,J2,19,PB08,EIC/EXTINT[8],-,ADC0/AIN[2],ADC1/AIN[0],-,-,X1/Y1,-,SERCOM4/PAD[0],TC4/WO[0],-,-,-,-,-,-,-,-,CCL/IN[8] +8,12/F8,16,K1,20,PB09,EIC/EXTINT[9],-,ADC0/AIN[3],ADC1/AIN[1],-,-,X2/Y2,-,SERCOM4/PAD[1],TC4/WO[1],-,-,-,-,-,-,-,-,CCL/OUT[2] +9,13/F7,17,K2,21,PA04,EIC/EXTINT[4],ANAREF/VREFB,ADC0/AIN[4],-,AC/AIN[0],-,X3/Y3,-,SERCOM0/PAD[0],TC0/WO[0],-,-,-,-,-,-,-,-,CCL/IN[0] +10,14/F6,18,L1,22,PA05,EIC/EXTINT[5],-,ADC0/AIN[5],-,AC/AIN[1],DAC/VOUT[1],,-,SERCOM0/PAD[1],TC0/WO[1],-,-,-,-,-,-,-,-,CCL/IN[1] +11,15/G7,19,L2,23,PA06,EIC/EXTINT[6],ANAREF/VREFC,ADC0/AIN[6],-,AC/AIN[2],-,X4/Y4,-,SERCOM0/PAD[2],TC1/WO[0],-,-,-,SDHC0/SDCD,-,-,-,-,CCL/IN[2] +12,16/G8,20,M1,24,PA07,EIC/EXTINT[7],-,ADC0/AIN[7],-,AC/AIN[3],-,X5/Y5,-,SERCOM0/PAD[3],TC1/WO[1],-,-,-,SDHC0/SDWP,-,-,-,-,CCL/OUT[0] +,,-,N1,27,PC04,EIC/EXTINT[4],-,-,-,-,-,,SERCOM6/PAD[0],-,-,TCC0/WO[0],-,-,-,-,-,-,-,- +,,21,N2,28,PC05,EIC/EXTINT[5],-,-,-,-,-,,SERCOM6/PAD[1],-,-,-,-,-,-,-,-,-,-,- +,,22,P1,29,PC06,EIC/EXTINT[6],-,-,-,-,-,,SERCOM6/PAD[2],-,-,-,-,-,SDHC0/SDCD,-,-,-,-,- +,,23,P2,30,PC07,EIC/EXTINT[9],-,-,-,-,-,,SERCOM6/PAD[3],-,-,-,-,-,SDHC0/SDWP,-,-,-,-,- +13,17/H8,26,R1,33,PA08,EIC/NMI,-,ADC0/AIN[8],ADC1/AIN[2],-,-,X6/Y6,SERCOM0/PAD[0],SERCOM2/PAD[1],TC0/WO[0],TCC0/WO[0],TCC1/WO[4],QSPI/DATA[0],SDHC0/SDCMD,I2S/MCK[0],-,-,-,CCL/IN[3] +14,18/G6,27,P3,34,PA09,EIC/EXTINT[9],-,ADC0/AIN[9],ADC1/AIN[3],-,-,X7/Y7,SERCOM0/PAD[1],SERCOM2/PAD[0],TC0/WO[1],TCC0/WO[1],TCC1/WO[5],QSPI/DATA[1],SDHC0/SDDAT[0],I2S/FS[0],-,-,-,CCL/IN[4] +15,19/H7,28,R2,35,PA10,EIC/EXTINT[10],-,ADC0/-AIN[10],,-,-,X8/Y8,SERCOM0/PAD[2],SERCOM2/PAD[2],TC1/WO[0],TCC0/WO[2],TCC1/WO[6],QSPI/DATA[2],SDHC0/SDDAT[1],I2S/SCK[0],-,-,GCLK/IO[4],CCL/IN[5] +16,20/G5,29,P4,36,PA11,EIC/EXTINT[11],-,ADC0/-AIN[11],,-,-,X9/Y9,SERCOM0/PAD[3],SERCOM2/PAD[3],TC1/WO[1],TCC0/WO[3],TCC1/WO[7],QSPI/DATA[3],SDHC0/SDDAT[2],I2S/SDO,-,-,GCLK/IO[5],CCL/OUT[1] +19,23/H6,32,R3,39,PB10,EIC/EXTINT[10],-,-,-,-,-,,-,SERCOM4/PAD[2],TC5/WO[0],TCC0/WO[4],TCC1/WO[0],QSPI/SCK,SDHC0/SDDAT[3],I2S/SDI,-,-,GCLK/IO[4],CCL/IN[11] +20,24/G4,33,P5,40,PB11,EIC/EXTINT[11],-,-,-,-,-,,-,SERCOM4/PAD[3],TC5/WO[1],TCC0/WO[5],TCC1/WO[1],QSPI/CS,SDHC0/SDCK,I2S/FS[1],-,-,GCLK/IO[5],CCL/OUT[1] +,25/H5,34,R4,41,PB12,EIC/EXTINT[12],-,-,-,-,-,X26/Y26,SERCOM4/PAD[0],-,TC4/WO[0],TCC3/WO[0],TCC0/WO[0],CAN1/TX,SDHC0/SDCD,I2S/SCK[1],-,-,GCLK/IO[6],- +,26/H4,35,P6,42,PB13,EIC/EXTINT[13],-,-,-,-,-,X27/Y27,SERCOM4/PAD[1],-,TC4/WO[1],TCC3/WO[1],TCC0/WO[1],CAN1/RX,SDHC0/SDWP,I2S/MCK[1],-,-,GCLK/IO[7],- +,27/G3,36,R5,43,PB14,EIC/EXTINT[14],-,-,-,-,-,X28/Y28,SERCOM4/PAD[2],-,TC5/WO[0],TCC4/WO[0],TCC0/WO[2],CAN1/TX,-,-,PCC/DATA[8],GMAC/GMDC,GCLK/IO[0],CCL/IN[9] +,28/H3,37,P7,44,PB15,EIC/EXTINT[15],-,-,-,-,-,X29/Y29,SERCOM4/PAD[3],-,TC5/WO[1],TCC4/WO[1],TCC0/WO[3],CAN1/RX,-,-,PCC/DATA[9],GMAC/GMDIO,GCLK/IO[1],CCL/IN[10] +,,-,R6,47,PD08,EIC/EXTINT[3],-,-,-,-,-,,SERCOM7/PAD[0],SERCOM6/PAD[1],-,TCC0/WO[1],-,-,-,-,-,-,-,- +,,-,P8,48,PD09,EIC/EXTINT[4],-,-,-,-,-,,SERCOM7/PAD[1],SERCOM6/PAD[0],-,TCC0/WO[2],-,-,-,-,-,-,-,- +,,-,R7,49,PD10,EIC/EXTINT[5],-,-,-,-,-,,SERCOM7/PAD[2],SERCOM6/PAD[2],-,TCC0/WO[3],-,-,-,-,-,-,-,- +,,-,P9,50,PD11,EIC/EXTINT[6],-,-,-,-,-,,SERCOM7/PAD[3],SERCOM6/PAD[3],-,TCC0/WO[4],-,-,-,-,-,-,-,- +,,-,R8,51,PD12,EIC/EXTINT[7],-,-,-,-,-,,-,-,-,TCC0/WO[5],-,-,-,-,-,-,-,- +,,40,P10,52,PC10,EIC/EXTINT[10],-,-,-,-,-,,SERCOM6/PAD[2],SERCOM7/PAD[2],-,TCC0/WO[0],TCC1/WO[4],-,-,-,-,-,-,- +,,41,R9,55,PC11,EIC/EXTINT[11],-,-,-,-,-,,SERCOM6/PAD[3],SERCOM7/PAD[3],-,TCC0/WO[1],TCC1/WO[5],-,-,-,-,GMAC/GMDC,-,- +,,42,R10,56,PC12,EIC/EXTINT[12],-,-,-,-,-,,SERCOM7/PAD[0],SERCOM6/PAD[1],-,TCC0/WO[2],TCC1/WO[6],-,-,-,PCC/DATA[10],GMAC/GMDIO,-,- +,,43,P11,57,PC13,EIC/EXTINT[13],-,-,-,-,-,,SERCOM7/PAD[1],SERCOM6/PAD[0],-,TCC0/WO[3],TCC1/WO[7],-,-,-,PCC/DATA[11],-,-,- +,,44,R11,58,PC14,EIC/EXTINT[14],-,-,-,-,-,,SERCOM7/PAD[2],SERCOM6/PAD[2],-,TCC0/WO[4],TCC1/WO[0],-,-,-,PCC/DATA[12],GMAC/GRX[3],-,- +,,45,P12,59,PC15,EIC/EXTINT[15],-,-,-,-,-,,SERCOM7/PAD[3],SERCOM6/PAD[3],-,TCC0/WO[5],TCC1/WO[1],-,-,-,PCC/DATA[13],GMAC/GRX[2],-,- +21,29/F2,46,R12,60,PA12,EIC/EXTINT[12],-,-,-,-,-,,SERCOM2/PAD[0],SERCOM4/PAD[1],TC2/WO[0],TCC0/WO[6],TCC1/WO[2],-,SDHC0/SDCD,-,PCC/DEN1,GMAC/GRX[1],AC/CMP[0],- +22,30/G2,47,P13,61,PA13,EIC/EXTINT[13],-,-,-,-,-,,SERCOM2/PAD[1],SERCOM4/PAD[0],TC2/WO[1],TCC0/WO[7],TCC1/WO[3],-,SDHC0/SDWP,-,PCC/DEN2,GMAC/GRX[0],AC/CMP[1],- +23,31/H1,48,R13,62,PA14,EIC/EXTINT[14],-,-,-,-,-,,SERCOM2/PAD[2],SERCOM4/PAD[2],TC3/WO[0],TCC2/WO[0],TCC1/WO[2],-,-,-,PCC/CLK,GMAC/GTXCK,GCLK/IO[0],- +24,32/H2,49,R14,63,PA15,EIC/EXTINT[15],-,-,-,-,-,,SERCOM2/PAD[3],SERCOM4/PAD[3],TC3/WO[1],TCC2/WO[1],TCC1/WO[3],-,-,-,-,GMAC/GRXER,GCLK/IO[1],- +25,35/G1,52,R15,66,PA16,EIC/EXTINT[0],-,-,-,-,-,X10/Y10,SERCOM1/PAD[0],SERCOM3/PAD[1],TC2/WO[0],TCC1/WO[0],TCC0/WO[4],-,-,-,PCC/DATA[0],GMAC/GCRS/GRXDV(6),GCLK/IO[2],CCL/IN[0] +26,36/F1,53,P14,67,PA17,EIC/EXTINT[1],-,-,-,-,-,X11/Y11,SERCOM1/PAD[1],SERCOM3/PAD[0],TC2/WO[1],TCC1/WO[1],TCC0/WO[5],-,-,-,PCC/DATA[1],GMAC/GTXEN,GCLK/IO[3],CCL/IN[1] +27,37/E1,54,P15,68,PA18,EIC/EXTINT[2],-,-,-,-,-,X12/Y12,SERCOM1/PAD[2],SERCOM3/PAD[2],TC3/WO[0],TCC1/WO[2],TCC0/WO[6],-,-,-,PCC/DATA[2],GMAC/GTX[0],AC/CMP[0],CCL/IN[2] +28,38/E2,55,N14,69,PA19,EIC/EXTINT[3],-,-,-,-,-,X13/Y13,SERCOM1/PAD[3],SERCOM3/PAD[3],TC3/WO[1],TCC1/WO[3],TCC0/WO[7],-,-,-,PCC/DATA[3],GMAC/GTX[1],AC/CMP[1],CCL/OUT[0] +,,56,N15,70,PC16,EIC/EXTINT[0],-,-,-,-,-,,SERCOM6/PAD[0],SERCOM0/PAD[1],-,TCC0/WO[0],PDEC/PDEC[0],-,-,-,-,GMAC/GTX[2],-,- +,,57,M14,71,PC17,EIC/EXTINT[1],-,-,-,-,-,,SERCOM6/PAD[1],SERCOM0/PAD[0],-,TCC0/WO[1],PDEC/PDEC[1],-,-,-,-,GMAC/GTX[3],-,- +,,58,M15,72,PC18,EIC/EXTINT[2],-,-,-,-,-,,SERCOM6/PAD[2],SERCOM0/PAD[2],-,TCC0/WO[2],PDEC/PDEC[2],-,-,-,-,GMAC/GRXCK,-,- +,,59,L14,73,PC19,EIC/EXTINT[3],-,-,-,-,-,,SERCOM6/PAD[3],SERCOM0/PAD[3],-,TCC0/WO[3],-,-,-,-,-,GMAC/GTXER,-,- +,,60,L15,74,PC20,EIC/EXTINT[4],-,-,-,-,-,,-,-,-,TCC0/WO[4],-,-,SDHC1/SDCD,-,-,GMAC/GRXDV,-,CCL/IN[9] +,,61,K14,75,PC21,EIC/EXTINT[5],-,-,-,-,-,,-,-,-,TCC0/WO[5],-,-,SDHC1/SDWP,-,-,GMAC/GCOL,-,CCL/IN[10] +,,-,K15,76,PC22,EIC/EXTINT[6],-,-,-,-,-,,SERCOM1/PAD[0],SERCOM3/PAD[1],-,TCC0/WO[6],-,-,-,-,-,GMAC/GMDC,-,- +,,-,J14,77,PC23,EIC/EXTINT[7],-,-,-,-,-,,SERCOM1/PAD[1],SERCOM3/PAD[0],-,TCC0/WO[7],-,-,-,-,-,GMAC/GMDIO,-,- +,,-,J15,80,PD20,EIC/EXTINT[10],-,-,-,-,-,,SERCOM1/PAD[2],SERCOM3/PAD[2],-,TCC1/WO[0],-,-,SDHC1/SDCD,-,-,-,-,- +,,-,H14,81,PD21,EIC/EXTINT[11],-,-,-,-,-,,SERCOM1/PAD[3],SERCOM3/PAD[3],-,TCC1/WO[1],-,-,SDHC1/SDWP,-,-,-,-,- +,39/D4,64,H15,82,PB16,EIC/EXTINT[0],-,-,-,-,-,,SERCOM5/PAD[0],-,TC6/WO[0],TCC3/WO[0],TCC0/WO[4],-,SDHC1/SDCD,I2S/SCK[0],-,-,GCLK/IO[2],CCL/IN[11] +,40/D1,65,G15,83,PB17,EIC/EXTINT[1],-,-,-,-,-,,SERCOM5/PAD[1],-,TC6/WO[1],TCC3/WO[1],TCC0/WO[5],-,SDHC1/SDWP,I2S/MCK[0],-,-,GCLK/IO[3],CCL/OUT[3] +,,66,G14,84,PB18,EIC/EXTINT[2],-,-,-,-,-,,SERCOM5/PAD[2],SERCOM7/PAD[2],-,TCC1/WO[0],PDEC/PDEC[0],-,SDHC1/SDDAT[0],-,-,-,GCLK/IO[4],- +,,67,F15,85,PB19,EIC/EXTINT[3],-,-,-,-,-,,SERCOM5/PAD[3],SERCOM7/PAD[3],-,TCC1/WO[1],PDEC/PDEC[1],-,SDHC1/SDDAT[1],-,-,-,GCLK/IO[5],- +,,68,F14,86,PB20,EIC/EXTINT[4],-,-,-,-,-,,SERCOM3/PAD[0],SERCOM7/PAD[1],-,TCC1/WO[2],PDEC/PDEC[2],-,SDHC1/SDDAT[2],-,-,-,GCLK/IO[6],- +,,69,E15,87,PB21,EIC/EXTINT[5],-,-,-,-,-,,SERCOM3/PAD[1],SERCOM7/PAD[0],-,TCC1/WO[3],-,-,SDHC1/SDDAT[3],-,-,-,GCLK/IO[7],- +29,41/D2,70,E14,88,PA20,EIC/EXTINT[4],-,-,-,-,-,X14/Y14,SERCOM5/PAD[2],SERCOM3/PAD[2],TC7/WO[0],TCC1/WO[4],TCC0/WO[0],-,SDHC1/SDCMD,I2S/FS[0],PCC/DATA[4],GMAC/GMDC,-,- +30,42/D3,71,D15,89,PA21,EIC/EXTINT[5],-,-,-,-,-,X15/Y15,SERCOM5/PAD[3],SERCOM3/PAD[3],TC7/WO[1],TCC1/WO[5],TCC0/WO[1],-,SDHC1/SDCK,I2S/SDO,PCC/DATA[5],GMAC/GMDIO,-,- +31,43/C1,72,D14,92,PA22,EIC/EXTINT[6],-,-,-,-,-,X16/Y16,SERCOM3/PAD[0],SERCOM5/PAD[1],TC4/WO[0],TCC1/WO[6],TCC0/WO[2],-,CAN0/TX,I2S/SDI,PCC/DATA[6],-,-,CCL/IN[6] +32,44/C2,73,C14,93,PA23,EIC/EXTINT[7],-,-,-,-,-,X17/Y17,SERCOM3/PAD[1],SERCOM5/PAD[0],TC4/WO[1],TCC1/WO[7],TCC0/WO[3],USB/SOF_1KHZ,CAN0/RX,I2S/FS[1],PCC/DATA[7],-,-,CCL/IN[7] +33,45/B1,74,C15,94,PA24,EIC/EXTINT[8],-,-,-,-,-,,SERCOM3/PAD[2],SERCOM5/PAD[2],TC5/WO[0],TCC2/WO[2],PDEC/PDEC[0],USB/DM,CAN0/TX,-,-,-,-,CCL/IN[8] +34,46/A1,75,B15,95,PA25,EIC/EXTINT[9],-,-,-,-,-,,SERCOM3/PAD[3],SERCOM5/PAD[3],TC5/WO[1],-,PDEC/PDEC[1],USB/DP,CAN0/RX,-,-,-,-,CCL/OUT[2] +37,49/A2,78,A15,98,PB22,EIC/EXTINT[6],-,-,-,-,-,,SERCOM1/PAD[2],SERCOM5/PAD[2],TC7/WO[0],-,PDEC/PDEC[2],USB/SOF_1KHZ,-,-,-,-,GCLK/IO[0],CCL/IN[0] +38,50/A3,79,A14,99,PB23,EIC/EXTINT[7],-,-,-,-,-,,SERCOM1/PAD[3],SERCOM5/PAD[3],TC7/WO[1],-,PDEC/PDEC[0],-,-,-,-,-,GCLK/IO[1],CCL/OUT[0] +,,80,B14,100,PB24,EIC/EXTINT[8],-,-,-,-,-,,SERCOM0/PAD[0],SERCOM2/PAD[1],-,-,PDEC/PDEC[1],-,-,-,-,-,AC/CMP[0],- +,,81,B13,101,PB25,EIC/EXTINT[9],-,-,-,-,-,,SERCOM0/PAD[1],SERCOM2/PAD[0],-,-,PDEC/PDEC[2],-,-,-,-,-,AC/CMP[1],- +,,-,A13,102,PB26,EIC/EXTINT[12],-,-,-,-,-,,SERCOM2/PAD[0],SERCOM4/PAD[1],-,TCC1/WO[2],-,-,-,-,-,-,-,- +,,-,B12,103,PB27,EIC/EXTINT[13],-,-,-,-,-,,SERCOM2/PAD[1],SERCOM4/PAD[0],-,TCC1/WO[3],-,-,-,-,-,-,-,- +,,-,A12,104,PB28,EIC/EXTINT[14],-,-,-,-,-,,SERCOM2/PAD[2],SERCOM4/PAD[2],-,TCC1/WO[4],-,-,-,I2S/SCK[1],-,-,-,- +,,-,B11,105,PB29,EIC/EXTINT[15],-,-,-,-,-,,SERCOM2/PAD[3],SERCOM4/PAD[3],-,TCC1/WO[5],-,-,-,I2S/MCK[1],-,-,-,- +,,82,A11,108,PC24,EIC/EXTINT[8],-,-,-,-,-,,SERCOM0/PAD[2],SERCOM2/PAD[2],-,-,-,CORTEX_CM4/TRACEDATA[3],-,-,-,-,-,- +,,83,B10,109,PC25,EIC/EXTINT[9],-,-,-,-,-,,SERCOM0/PAD[3],SERCOM2/PAD[3],-,-,-,CORTEX_CM4/TRACEDATA[2],-,-,-,-,-,- +,,84,A10,110,PC26,EIC/EXTINT[10],-,-,-,-,-,,-,-,-,-,-,CORTEX_CM4/TRACEDATA[1],-,-,-,-,-,- +,,85,A9,111,PC27,EIC/EXTINT[11],-,-,-,-,-,,SERCOM1/PAD[0],-,-,-,-,CORTEX_CM4/TRACECLK,-,-,-,-,CORTEX_M4/SWO,CCL/IN[4] +,,86,B9,112,PC28,EIC/EXTINT[12],-,-,-,-,-,,SERCOM1/PAD[1],-,-,-,-,CORTEX_CM4/TRACEDATA[0],-,-,-,-,-,CCL/IN[5] +39,51/B3,87,B8,113,PA27,EIC/EXTINT[11],-,-,-,-,-,X18/Y18,-,-,-,-,-,-,-,-,-,GCLK/IO[1],-, +40,52/B4,88,A8,114,RESET_N,-,-,-,-,-,-,,-,-,-,-,-,-,-,-,-,-,-,- +45,57/C5,93,B7,119,PA30,EIC/EXTINT[14],-,-,-,-,-,X19/Y19,SERCOM7/PAD[2],SERCOM1/PAD[2],TC6/WO[0],TCC2/WO[0],-,CORTEX_CM4/SWCLK,-,-,-,-,GCLK/IO[0],CCL/IN[3] +46,58/D5,94,B6,120,PA31,EIC/EXTINT[15],-,-,-,-,-,,SERCOM7/PAD[3],SERCOM1/PAD[3],TC6/WO[1],TCC2/WO[1],--,CORTEX_CM4/SWDIO,-,-,-,-,-,CCL/OUT[1] +,59/A6,95,A5,121,PB30,EIC/EXTINT[14],-,-,-,-,-,,SERCOM7/PAD[0],SERCOM5/PAD[1],TC0/WO[0],TCC4/WO[0],TCC0/WO[6],CORTEX_CM4/SWO,-,-,-,-,-,- +,60/B6,96,B5,122,PB31,EIC/EXTINT[15],-,-,-,-,-,,SERCOM7/PAD[1],SERCOM5/PAD[0],TC0/WO[1],TCC4/WO[1],TCC0/WO[7],,-,-,-,-,-,- +,,-,A4,123,PC30,EIC/EXTINT[14],-,-,ADC1/AIN[12],-,-,,-,-,-,-,-,-,-,-,-,-,-,- +,,-,B4,124,PC31,EIC/EXTINT[15],-,-,ADC1/AIN[13],-,-,,-,-,-,-,-,-,-,-,-,-,-,- +,61/A7,97,A3,125,PB00,EIC/EXTINT[0],-,ADC0/AIN[12],-,-,-,X30/Y30,-,SERCOM5/PAD[2],TC7/WO[0],-,-,-,-,-,-,-,-,CCL/IN[1] +,62/B7,98,B3,126,PB01,EIC/EXTINT[1],-,ADC0/AIN[13],-,-,-,X31/Y31,-,SERCOM5/PAD[3],TC7/WO[1],-,-,-,-,-,-,-,-,CCL/IN[2] +47,63/A8,99,A2,127,PB02,EIC/EXTINT[2],-,ADC0/AIN[14],-,-,-,X20/Y20,-,SERCOM5/PAD[0],TC6/WO[0],TCC2/WO[2],-,-,-,-,-,-,-,CCL/OUT[0] \ No newline at end of file diff --git a/extras/wirepinmux/SAMD51_Table_6-8.csv b/extras/wirepinmux/SAMD51_Table_6-8.csv new file mode 100644 index 000000000..a13b7c6bc --- /dev/null +++ b/extras/wirepinmux/SAMD51_Table_6-8.csv @@ -0,0 +1,10 @@ +Device,Supply,I/O Pin +128,VDDIOB, PA08, PA09 +128,VDDIO,PA12, PA13, PA16, PA17, PA22, PA23, PD08, PD09 +120,VDDIOB, PA08, PA09 +120,VDDIO, PA12, PA13, PA16, PA17, PA22, PA23, PD08, PD09 +100,VDDIOB, PA08, PA09 +100,VDDIO, PA12, PA13, PA16, PA17, PA22, PA23 +64,VDDIOB, PA08, PA09 +64,VDDIO, PA12, PA13, PA16, PA17, PA22, PA23 +48,VDDIO, PA08, PA09, PA12, PA13, PA16, PA17, PA22, PA23 \ No newline at end of file diff --git a/libraries/Adafruit_TinyUSB_Arduino b/libraries/Adafruit_TinyUSB_Arduino index 3e5369cd4..057f6734f 160000 --- a/libraries/Adafruit_TinyUSB_Arduino +++ b/libraries/Adafruit_TinyUSB_Arduino @@ -1 +1 @@ -Subproject commit 3e5369cd4720c63d9caf31db6ca4c18ce7bcd0b7 +Subproject commit 057f6734f589680072de3a467b3b4051e57f3a9e diff --git a/libraries/Adafruit_ZeroDMA b/libraries/Adafruit_ZeroDMA index 5b48867c1..25e92a081 160000 --- a/libraries/Adafruit_ZeroDMA +++ b/libraries/Adafruit_ZeroDMA @@ -1 +1 @@ -Subproject commit 5b48867c1d3015ec63cd8f31def45f5a2d8e49bd +Subproject commit 25e92a0811b364a068989c43788727c18803fc77 diff --git a/libraries/SPI/SPI.cpp b/libraries/SPI/SPI.cpp index 0393752d7..9a58be417 100644 --- a/libraries/SPI/SPI.cpp +++ b/libraries/SPI/SPI.cpp @@ -25,14 +25,147 @@ #ifdef USE_TINYUSB // For Serial when selecting TinyUSB #include -#endif +#endif // USE_TINYUSB #define SPI_IMODE_NONE 0 #define SPI_IMODE_EXTINT 1 #define SPI_IMODE_GLOBAL 2 +// Default SERCOM ISR symbols are derived from PERIPH_SPI* routing. +// Variants may override the SPI*_IT_HANDLER* macros when split vectors need +// custom ownership. +#define SPI_SERCOM_INDEX_sercom0 0 +#define SPI_SERCOM_INDEX_sercom1 1 +#define SPI_SERCOM_INDEX_sercom2 2 +#define SPI_SERCOM_INDEX_sercom3 3 +#define SPI_SERCOM_INDEX_sercom4 4 +#define SPI_SERCOM_INDEX_sercom5 5 +#if defined(SERCOM6) || defined(SERCOM6_REGS) +#define SPI_SERCOM_INDEX_sercom6 6 +#endif // SERCOM6 || SERCOM6_REGS +#if defined(SERCOM7) || defined(SERCOM7_REGS) +#define SPI_SERCOM_INDEX_sercom7 7 +#endif // SERCOM7 || SERCOM7_REGS + +#define SPI_SERCOM_INDEX(token) SPI_SERCOM_INDEX_##token +#define SPI_SERCOM_HANDLER_FROM_INDEX(idx) SPI_SERCOM_HANDLER_FROM_INDEX_2(idx) +#define SPI_SERCOM_HANDLER_FROM_INDEX_2(idx) SERCOM##idx##_Handler +#define SPI_SERCOM_HANDLER_FROM_TOKEN(token) \ + SPI_SERCOM_HANDLER_FROM_INDEX(SPI_SERCOM_INDEX(token)) + +#define SPI_SERCOM_HANDLER0_FROM_INDEX(idx) \ + SPI_SERCOM_HANDLER0_FROM_INDEX_2(idx) +#define SPI_SERCOM_HANDLER0_FROM_INDEX_2(idx) SERCOM##idx##_0_Handler +#define SPI_SERCOM_HANDLER1_FROM_INDEX(idx) \ + SPI_SERCOM_HANDLER1_FROM_INDEX_2(idx) +#define SPI_SERCOM_HANDLER1_FROM_INDEX_2(idx) SERCOM##idx##_1_Handler +#define SPI_SERCOM_HANDLER2_FROM_INDEX(idx) \ + SPI_SERCOM_HANDLER2_FROM_INDEX_2(idx) +#define SPI_SERCOM_HANDLER2_FROM_INDEX_2(idx) SERCOM##idx##_2_Handler +#define SPI_SERCOM_HANDLER3_FROM_INDEX(idx) \ + SPI_SERCOM_HANDLER3_FROM_INDEX_2(idx) +#define SPI_SERCOM_HANDLER3_FROM_INDEX_2(idx) SERCOM##idx##_3_Handler +#define SPI_SERCOM_HANDLER_OTHER_FROM_INDEX(idx) \ + SPI_SERCOM_HANDLER_OTHER_FROM_INDEX_2(idx) +#define SPI_SERCOM_HANDLER_OTHER_FROM_INDEX_2(idx) SERCOM##idx##_OTHER_Handler + +#define SPI_SERCOM_HANDLER0_FROM_TOKEN(token) \ + SPI_SERCOM_HANDLER0_FROM_INDEX(SPI_SERCOM_INDEX(token)) +#define SPI_SERCOM_HANDLER1_FROM_TOKEN(token) \ + SPI_SERCOM_HANDLER1_FROM_INDEX(SPI_SERCOM_INDEX(token)) +#define SPI_SERCOM_HANDLER2_FROM_TOKEN(token) \ + SPI_SERCOM_HANDLER2_FROM_INDEX(SPI_SERCOM_INDEX(token)) +#define SPI_SERCOM_HANDLER3_FROM_TOKEN(token) \ + SPI_SERCOM_HANDLER3_FROM_INDEX(SPI_SERCOM_INDEX(token)) +#define SPI_SERCOM_HANDLER_OTHER_FROM_TOKEN(token) \ + SPI_SERCOM_HANDLER_OTHER_FROM_INDEX(SPI_SERCOM_INDEX(token)) + +#define SPI_DEFINE_SINGLE_HANDLER(handler, instance) \ + void handler(void) __attribute__((weak)); \ + void handler(void) { instance.onService(); } + +#define SPI_DEFINE_SAMD51_E51_HANDLERS(handler0, handler1, handler2, handler3, \ + instance) \ + void handler0(void) __attribute__((weak)); \ + void handler1(void) __attribute__((weak)); \ + void handler2(void) __attribute__((weak)); \ + void handler3(void) __attribute__((weak)); \ + void handler0(void) { instance.onService(); } \ + void handler1(void) { instance.onService(); } \ + void handler2(void) { instance.onService(); } \ + void handler3(void) { instance.onService(); } + +#define SPI_DEFINE_SAME53_E54_HANDLERS(handler0, handler1, handler2, \ + handlerOther, instance) \ + void handler0(void) __attribute__((weak)); \ + void handler1(void) __attribute__((weak)); \ + void handler2(void) __attribute__((weak)); \ + void handlerOther(void) __attribute__((weak)); \ + void handler0(void) { instance.onService(); } \ + void handler1(void) { instance.onService(); } \ + void handler2(void) { instance.onService(); } \ + void handlerOther(void) { instance.onService(); } + +#if defined(__SAMD51__) || defined(__SAME51__) +#define SPI_DEFINE_SERCOM_HANDLERS(prefix, instance, periph) \ + SPI_DEFINE_SAMD51_E51_HANDLERS(prefix##_IT_HANDLER_0, \ + prefix##_IT_HANDLER_1, \ + prefix##_IT_HANDLER_2, \ + prefix##_IT_HANDLER_3, instance) +#elif defined(__SAME53__) || defined(__SAME54__) +#define SPI_DEFINE_SERCOM_HANDLERS(prefix, instance, periph) \ + SPI_DEFINE_SAME53_E54_HANDLERS(prefix##_IT_HANDLER_0, \ + prefix##_IT_HANDLER_1, \ + prefix##_IT_HANDLER_2, \ + prefix##_IT_HANDLER_OTHER, instance) +#else +#define SPI_DEFINE_SERCOM_HANDLERS(prefix, instance, periph) \ + SPI_DEFINE_SINGLE_HANDLER(prefix##_IT_HANDLER, instance) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ + const SPISettings DEFAULT_SPI_SETTINGS = SPISettings(); +namespace sercomPinMux { +bool spiMosiPinValidForRoute(uint8_t arduinoPin, uint8_t sercomIndex, + uint8_t mosiPad) { + if (arduinoPin >= PINS_COUNT || mosiPad > 3) + return false; + + const char portLetter = + static_cast('A' + g_APinDescription[arduinoPin].ulPort); + const uint8_t portPin = + static_cast(g_APinDescription[arduinoPin].ulPin); + +#define SERCOM_PINMUX_EMIT_SPI 1 +#define SERCOM_SPI_PIN(PORT_LETTER, PORT_PIN, S0, P0, S1, P1) \ + if ((portLetter == (PORT_LETTER)) && (portPin == (PORT_PIN)) && \ + (((S0) == sercomIndex && (P0) == mosiPad) || \ + ((S1) == sercomIndex && (P1) == mosiPad))) \ + return true; +#include +#undef SERCOM_SPI_PIN +#undef SERCOM_PINMUX_EMIT_SPI + + return false; +} +} // namespace sercomPinMux + +namespace { +static uint8_t spiMosiPadFromTxPad(SercomSpiTXPad txPad) { + switch (txPad) { + case SPI_PAD_0_SCK_1: + case SPI_PAD_0_SCK_3: + return 0; + case SPI_PAD_2_SCK_3: + return 2; + case SPI_PAD_3_SCK_1: + return 3; + default: + return 255; + } +} +} // namespace + SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI, SercomSpiTXPad PadTx, SercomRXPad PadRx) { initialized = false; @@ -47,9 +180,12 @@ SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint // SERCOM pads _padTx=PadTx; _padRx=PadRx; + + // Transaction pool initialization + txnPoolHead = 0; } -void SPIClass::begin() +bool SPIClass::begin() { if(!initialized) { interruptMode = SPI_IMODE_NONE; @@ -58,16 +194,22 @@ void SPIClass::begin() initialized = true; } - if(!use_dma) { - dmaAllocate(); - } +#ifdef USE_ZERODMA + _p_sercom->dmaInit(_p_sercom->getSercomIndex()); +#endif // USE_ZERODMA // PIO init + const uint8_t sercomIndex = static_cast(_p_sercom->getSercomIndex()); + const uint8_t mosiPad = spiMosiPadFromTxPad(_padTx); + if (!sercomPinMux::spiMosiPinValidForRoute(_uc_pinMosi, sercomIndex, mosiPad)) + return false; + pinPeripheral(_uc_pinMiso, g_APinDescription[_uc_pinMiso].ulPinType); pinPeripheral(_uc_pinSCK, g_APinDescription[_uc_pinSCK].ulPinType); pinPeripheral(_uc_pinMosi, g_APinDescription[_uc_pinMosi].ulPinType); config(DEFAULT_SPI_SETTINGS); + return true; } void SPIClass::config(SPISettings settings) @@ -95,7 +237,7 @@ static inline unsigned char __interruptsStatus(void) // See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/CHDBIBGJ.html return (__get_PRIMASK() ? 0 : 1); } -#endif +#endif // !interruptsStatus void SPIClass::usingInterrupt(int interruptNumber) { @@ -146,8 +288,13 @@ void SPIClass::beginTransaction(SPISettings settings) interruptSave = interruptsStatus(); noInterrupts(); } - else if (interruptMode & SPI_IMODE_EXTINT) + else if (interruptMode & SPI_IMODE_EXTINT) { +#if defined(__SAME53__) || defined(__SAME54__) + EIC_REGS->EIC_INTENCLR = EIC_INTENCLR_EXTINT(interruptMask); +#else EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT(interruptMask); +#endif // __SAME53__ / __SAME54__ + } } config(settings); @@ -162,8 +309,13 @@ void SPIClass::endTransaction(void) if (interruptSave) interrupts(); } - else if (interruptMode & SPI_IMODE_EXTINT) + else if (interruptMode & SPI_IMODE_EXTINT) { +#if defined(__SAME53__) || defined(__SAME54__) + EIC_REGS->EIC_INTENSET = EIC_INTENSET_EXTINT(interruptMask); +#else EIC->INTENSET.reg = EIC_INTENSET_EXTINT(interruptMask); +#endif // __SAME53__ / __SAME54__ + } } } @@ -240,131 +392,8 @@ void SPIClass::transfer(void *buf, size_t count) } } -// DMA-based SPI transfer() function --------------------------------------- - -// IMPORTANT: references to 65535 throughout the DMA code are INTENTIONAL. -// DO NOT try to 'fix' by changing to 65536, or large transfers will fail! -// The BTCNT value of a DMA descriptor is an unsigned 16-bit value with a -// max of 65535. Larger transfers are handled by linked descriptors. - -// Pointer to SPIClass object, one per DMA channel. This allows the -// DMA callback (which has to exist outside the class context) to have -// a reference back to the originating SPIClass object. -static SPIClass *spiPtr[DMAC_CH_NUM] = { 0 }; // Legit inits list to NULL - -void SPIClass::dmaCallback(Adafruit_ZeroDMA *dma) { - // dmaCallback() receives an Adafruit_ZeroDMA object. From this we can get - // a channel number (0 to DMAC_CH_NUM-1, always unique per ZeroDMA object), - // then locate the originating SPIClass object using array lookup, setting - // the dma_busy element 'false' to indicate end of transfer. Doesn't matter - // if it's a read or write transfer...both channels get pointers to it. - spiPtr[dma->getChannel()]->dma_busy = false; -} - -// For read-only and read+write transfers, a callback is assigned only -// to the read channel to indicate end-of-transfer, and the write channel's -// callback is assigned to this nonsense function (for reasons I'm not -// entirely sure of, setting the callback to NULL doesn't work). -static void dmaDoNothingCallback(Adafruit_ZeroDMA *dma) { (void)dma; } - -// This could've gone in begin(), but for the sake of organization... -void SPIClass::dmaAllocate(void) { - // In order to support fully non-blocking SPI transfers, DMA descriptor - // lists must be created for the input and/or output data. Rather than - // do this dynamically with every transfer, the lists are allocated once - // on SPI init. Maximum list size is finite and knowable -- transfers to - // or from RAM or from flash memory will never exceed the corresponding - // memory size (if they do, you have bigger problems). Descriptors - // aren't large and there's usually only a handful to a dozen, so this - // isn't an excessive burden in exchange for big non-blocking transfers. - uint32_t maxWriteBytes = FLASH_SIZE; // Writes can't exceed all of flash -#if defined(__SAMD51__) - uint32_t maxReadBytes = HSRAM_SIZE; // Reads can't exceed all of RAM -#else - uint32_t maxReadBytes = HMCRAMC0_SIZE; -#endif - if(maxReadBytes > maxWriteBytes) { // I don't think any SAMD devices - maxWriteBytes = maxReadBytes; // have RAM > flash, but just in case - } - - // VITAL to alloc read channel first, assigns it a higher DMA priority! - if(readChannel.allocate() == DMA_STATUS_OK) { - if(writeChannel.allocate() == DMA_STATUS_OK) { - - // Both DMA channels (read and write) allocated successfully, - // set up transfer triggers and other basics... - - // readChannel callback only needs to be set up once. - // Unlike the write callback which may get switched on or off, - // read callback stays put. In certain cases the read DMA job - // just isn't started and the callback is a non-issue then. - readChannel.setTrigger(getDMAC_ID_RX()); - readChannel.setAction(DMA_TRIGGER_ACTON_BEAT); - readChannel.setCallback(dmaCallback); - spiPtr[readChannel.getChannel()] = this; - - writeChannel.setTrigger(getDMAC_ID_TX()); - writeChannel.setAction(DMA_TRIGGER_ACTON_BEAT); - spiPtr[writeChannel.getChannel()] = this; - - // One descriptor per channel has already been allocated - // in Adafruit_ZeroDMA, this just gets pointers to them... - firstReadDescriptor = readChannel.addDescriptor( - (void *)getDataRegister(), // Source address (SPI data reg) - NULL, // Dest address (set later) - 0, // Count (set later) - DMA_BEAT_SIZE_BYTE, // Bytes/hwords/words - false, // Don't increment source address - true); // Increment dest address - firstWriteDescriptor = writeChannel.addDescriptor( - NULL, // Source address (set later) - (void *)getDataRegister(), // Dest (SPI data register) - 0, // Count (set later) - DMA_BEAT_SIZE_BYTE, // Bytes/hwords/words - true, // Increment source address - false); // Don't increment dest address - // This is the number of EXTRA descriptors beyond the first. - int numReadDescriptors = ((maxReadBytes + 65534) / 65535) - 1; - int numWriteDescriptors = ((maxWriteBytes + 65534) / 65535) - 1; - int totalDescriptors = numReadDescriptors + numWriteDescriptors; - - if(totalDescriptors <= 0) { // Don't need extra descriptors, - use_dma = true; // channels are allocated, we're good. - } else { // Else allocate extra descriptor lists... - // Although DMA descriptors are technically a linked list, we just - // allocate a chunk all at once, and finesse the pointers later. - if((extraReadDescriptors = (DmacDescriptor *)malloc( - totalDescriptors * sizeof(DmacDescriptor)))) { - use_dma = true; // Everything allocated successfully - extraWriteDescriptors = &extraReadDescriptors[numReadDescriptors]; - - // Initialize descriptors (copy from first ones) - // cast to void* to suppress warning: with no trivial copy-assignment [-Wclass-memaccess] - for(int i=0; i 65535) { // Limit each descriptor - bytesThisDescriptor = 65535; // to 65535 (not 65536) bytes - } - rDesc->BTCNT.reg = wDesc->BTCNT.reg = bytesThisDescriptor; - if(rxbuf) { // Read-only or read+write - // Auto-inc addresses in DMA descriptors must point to END of data. - // Buf pointers would advance at end of loop anyway, do it now... - rxbuf8 += bytesThisDescriptor; - rDesc->DSTADDR.reg = (uint32_t)rxbuf8; - } - if(txbuf) { // Write-only or read+write - txbuf8 += bytesThisDescriptor; // Same as above - wDesc->SRCADDR.reg = (uint32_t)txbuf8; - wDesc->BTCTRL.bit.SRCINC = 1; // Increment source pointer - } else { // Read-only requires dummy write - wDesc->SRCADDR.reg = (uint32_t)&dum; - wDesc->BTCTRL.bit.SRCINC = 0; // Don't increment source pointer - } - count -= bytesThisDescriptor; - if(count) { // Still more data? - // Link to next descriptors. Extra descriptors are IN ADDITION - // to first, so it's safe and correct that descIdx starts at 0. - rDesc->DESCADDR.reg = (uint32_t)&extraReadDescriptors[descIdx]; - wDesc->DESCADDR.reg = (uint32_t)&extraWriteDescriptors[descIdx]; - rDesc = &extraReadDescriptors[descIdx]; // Update pointers to - wDesc = &extraWriteDescriptors[descIdx]; // next descriptors - descIdx++; - // A write-only transfer doesn't use the read descriptor list, but - // it's quicker to build it (full of nonsense) anyway than to check. - } else { // No more data, end descriptor linked lists - rDesc->DESCADDR.reg = wDesc->DESCADDR.reg = 0; - } - } + SercomTxn* txn = allocateTxn(); + txn->txPtr = static_cast(txbuf); + txn->rxPtr = static_cast(rxbuf); + txn->length = count; + txn->onComplete = onComplete ? onComplete : &SPIClass::onTxnComplete; + txn->user = onComplete ? user : this; + txn->chainNext = false; + txnDone = false; + txnStatus = 0; + + if (!_p_sercom->enqueueSPI(txn)) { + if (onComplete) + onComplete(user, static_cast(SercomSpiError::UNKNOWN_ERROR)); + return; + } - // Set up DMA transfer job(s) ------------------------------------------ + if (!onComplete && block) { + while (!txnDone) ; + } +} - if(rxbuf) { // Read+write or read-only - // End-of-read callback is already set up, disable write CB, start job - writeChannel.setCallback(dmaDoNothingCallback); - readChannel.startJob(); - } else { // Write-only, use end-of-write callback - writeChannel.setCallback(dmaCallback); - } +void SPIClass::onService(void) +{ + // SPI interrupt service handler - moved from SERCOM::serviceSPI() + if (!_p_sercom->isActiveSPI() || _p_sercom->getCurrentTxnSPI() == nullptr) + return; - // Run DMA jobs, blocking if requested --------------------------------- + uint8_t flags = _p_sercom->getINTFLAG(); - dma_busy = true; - writeChannel.startJob(); // All xfers, even read-only, need write job. - if(block) { // If blocking transfer requested, - while(dma_busy); // wait for job to finish - } +#if defined(__SAME53__) || defined(__SAME54__) + const bool isError = flags & SERCOM_SPIM_INTFLAG_ERROR_Msk; + const bool isRxc = flags & SERCOM_SPIM_INTFLAG_RXC_Msk; + const bool isDre = flags & SERCOM_SPIM_INTFLAG_DRE_Msk; + const uint8_t disableDoneMask = SERCOM_SPIM_INTENCLR_DRE_Msk | + SERCOM_SPIM_INTENCLR_RXC_Msk | + SERCOM_SPIM_INTENCLR_ERROR_Msk; + const uint8_t disableDreMask = SERCOM_SPIM_INTENCLR_DRE_Msk; +#else + const bool isError = flags & SERCOM_SPI_INTFLAG_ERROR; + const bool isRxc = flags & SERCOM_SPI_INTFLAG_RXC; + const bool isDre = flags & SERCOM_SPI_INTFLAG_DRE; + const uint8_t disableDoneMask = SERCOM_SPI_INTENCLR_DRE | + SERCOM_SPI_INTENCLR_RXC | + SERCOM_SPI_INTENCLR_ERROR; + const uint8_t disableDreMask = SERCOM_SPI_INTENCLR_DRE; +#endif // __SAME53__ / __SAME54__ + + if (isError) + { + _p_sercom->setReturnValueSPI(SercomSpiError::BUF_OVERFLOW); + _p_sercom->clearINTFLAG(); + _p_sercom->deferStopSPI(SercomSpiError::BUF_OVERFLOW); + return; + } - } else { // NON-DMA FALLBACK --------------------------------------------- - - if(txbuf8) { - if(rxbuf8) { // Write + read simultaneously - while(count--) { - *rxbuf8++ = _p_sercom->transferDataSPI(*txbuf8++); - } - } else { // Write only - while(count--) { - (void)_p_sercom->transferDataSPI(*txbuf8++); - } - } - } else { // Read only - while(count--) { - *rxbuf8++ = _p_sercom->transferDataSPI(0xFF); - } + if (isRxc) { + // Read completes after write, so read previous byte + bool hasMore = _p_sercom->readDataSPI(); + + if (!hasMore) { + _p_sercom->disableInterrupts(disableDoneMask); + _p_sercom->setReturnValueSPI(SercomSpiError::SUCCESS); + _p_sercom->deferStopSPI(SercomSpiError::SUCCESS); + return; } + } - } // end non-DMA + if (isDre) { + bool hasMore = _p_sercom->sendDataSPI(); + if (!hasMore) + _p_sercom->disableInterrupts(disableDreMask); + } } -// Waits for a prior in-background DMA transfer to complete. +SercomTxn* SPIClass::allocateTxn() { + // Simple round-robin allocation from pool + SercomTxn* txn = &txnPool[txnPoolHead]; + txnPoolHead = (txnPoolHead + 1) % TXN_POOL_SIZE; + return txn; +} + +void SPIClass::onTxnComplete(void* user, int status) +{ + if (!user) + return; + SPIClass* self = static_cast(user); + self->txnStatus = status; + self->txnDone = true; +} + +// Waits for a prior in-background transfer to complete. void SPIClass::waitForTransfer(void) { - while(dma_busy); + while(!txnDone); } /* returns the current DMA transfer status to allow non-blocking polling */ bool SPIClass::isBusy(void) { - return dma_busy; + return !txnDone; } @@ -481,90 +512,169 @@ void SPIClass::detachInterrupt() { // Should be disableInterrupt() } -// SPI DMA lookup works on both SAMD21 and SAMD51 - -static const struct { - volatile uint32_t *data_reg; - int dmac_id_tx; - int dmac_id_rx; -} sercomData[] = { - { &SERCOM0->SPI.DATA.reg, SERCOM0_DMAC_ID_TX, SERCOM0_DMAC_ID_RX }, - { &SERCOM1->SPI.DATA.reg, SERCOM1_DMAC_ID_TX, SERCOM1_DMAC_ID_RX }, - { &SERCOM2->SPI.DATA.reg, SERCOM2_DMAC_ID_TX, SERCOM2_DMAC_ID_RX }, - { &SERCOM3->SPI.DATA.reg, SERCOM3_DMAC_ID_TX, SERCOM3_DMAC_ID_RX }, -#if defined(SERCOM4) - { &SERCOM4->SPI.DATA.reg, SERCOM4_DMAC_ID_TX, SERCOM4_DMAC_ID_RX }, -#endif -#if defined(SERCOM5) - { &SERCOM5->SPI.DATA.reg, SERCOM5_DMAC_ID_TX, SERCOM5_DMAC_ID_RX }, -#endif -#if defined(SERCOM6) - { &SERCOM6->SPI.DATA.reg, SERCOM6_DMAC_ID_TX, SERCOM6_DMAC_ID_RX }, -#endif -#if defined(SERCOM7) - { &SERCOM7->SPI.DATA.reg, SERCOM7_DMAC_ID_TX, SERCOM7_DMAC_ID_RX }, -#endif -}; - -volatile uint32_t *SPIClass::getDataRegister(void) { - int8_t idx = _p_sercom->getSercomIndex(); - return (idx >= 0) ? sercomData[idx].data_reg: NULL; -} - -int SPIClass::getDMAC_ID_TX(void) { - int8_t idx = _p_sercom->getSercomIndex(); - return (idx >= 0) ? sercomData[idx].dmac_id_tx : -1; -} - -int SPIClass::getDMAC_ID_RX(void) { - int8_t idx = _p_sercom->getSercomIndex(); - return (idx >= 0) ? sercomData[idx].dmac_id_rx : -1; -} - -#if defined(__SAMD51__) - -// Set the SPI device's SERCOM clock CORE and SLOW clock sources. -// SercomClockSource values are an enumeration in SERCOM.h. -// This works on SAMD51 only. On SAMD21, a dummy function is declared -// in SPI.h which compiles to nothing, so user code doesn't need to check -// and conditionally compile lines for different architectures. -void SPIClass::setClockSource(SercomClockSource clk) { - int8_t idx = _p_sercom->getSercomIndex(); - _p_sercom->setClockSource(idx, clk, true); // true = set core clock - _p_sercom->setClockSource(idx, clk, false); // false = set slow clock -} - -#endif // end __SAMD51__ - #if SPI_INTERFACES_COUNT > 0 - /* In case new variant doesn't define these macros, - * we put here the ones for Arduino Zero. - * - * These values should be different on some variants! - * - * The SPI PAD values can be found in cores/arduino/SERCOM.h: - * - SercomSpiTXPad - * - SercomRXPad - */ - #ifndef PERIPH_SPI - #define PERIPH_SPI sercom4 - #define PAD_SPI_TX SPI_PAD_2_SCK_3 - #define PAD_SPI_RX SERCOM_RX_PAD_0 - #endif // PERIPH_SPI - SPIClass SPI (&PERIPH_SPI, PIN_SPI_MISO, PIN_SPI_SCK, PIN_SPI_MOSI, PAD_SPI_TX, PAD_SPI_RX); -#endif +/* In case new variant doesn't define these macros, + * we put here the ones for Arduino Zero. + * + * These values should be different on some variants! + * + * The SPI PAD values can be found in cores/arduino/SERCOM.h: + * - SercomSpiTXPad + * - SercomRXPad + */ +#ifndef PERIPH_SPI +#define PERIPH_SPI sercom4 +#define PAD_SPI_TX SPI_PAD_2_SCK_3 +#define PAD_SPI_RX SERCOM_RX_PAD_0 +#endif // PERIPH_SPI + +SPIClass SPI(&PERIPH_SPI, PIN_SPI_MISO, PIN_SPI_SCK, PIN_SPI_MOSI, PAD_SPI_TX, + PAD_SPI_RX); +#ifndef SPI_IT_HANDLER +#define SPI_IT_HANDLER SPI_SERCOM_HANDLER_FROM_TOKEN(PERIPH_SPI) +#endif // !SPI_IT_HANDLER +#ifndef SPI_IT_HANDLER_0 +#define SPI_IT_HANDLER_0 SPI_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_SPI) +#define SPI_IT_HANDLER_1 SPI_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_SPI) +#define SPI_IT_HANDLER_2 SPI_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_SPI) +#if defined(__SAMD51__) || defined(__SAME51__) +#define SPI_IT_HANDLER_3 SPI_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_SPI) +#elif defined(__SAME53__) || defined(__SAME54__) +#define SPI_IT_HANDLER_OTHER SPI_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_SPI) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !SPI_IT_HANDLER_0 +SPI_DEFINE_SERCOM_HANDLERS(SPI, SPI, PERIPH_SPI) +#endif // SPI_INTERFACES_COUNT > 0 + #if SPI_INTERFACES_COUNT > 1 - SPIClass SPI1(&PERIPH_SPI1, PIN_SPI1_MISO, PIN_SPI1_SCK, PIN_SPI1_MOSI, PAD_SPI1_TX, PAD_SPI1_RX); -#endif +SPIClass SPI1(&PERIPH_SPI1, PIN_SPI1_MISO, PIN_SPI1_SCK, PIN_SPI1_MOSI, + PAD_SPI1_TX, PAD_SPI1_RX); +#ifndef SPI1_IT_HANDLER +#define SPI1_IT_HANDLER SPI_SERCOM_HANDLER_FROM_TOKEN(PERIPH_SPI1) +#endif // !SPI1_IT_HANDLER +#ifndef SPI1_IT_HANDLER_0 +#define SPI1_IT_HANDLER_0 SPI_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_SPI1) +#define SPI1_IT_HANDLER_1 SPI_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_SPI1) +#define SPI1_IT_HANDLER_2 SPI_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_SPI1) +#if defined(__SAMD51__) || defined(__SAME51__) +#define SPI1_IT_HANDLER_3 SPI_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_SPI1) +#elif defined(__SAME53__) || defined(__SAME54__) +#define SPI1_IT_HANDLER_OTHER SPI_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_SPI1) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !SPI1_IT_HANDLER_0 +SPI_DEFINE_SERCOM_HANDLERS(SPI1, SPI1, PERIPH_SPI1) +#endif // SPI_INTERFACES_COUNT > 1 + #if SPI_INTERFACES_COUNT > 2 - SPIClass SPI2(&PERIPH_SPI2, PIN_SPI2_MISO, PIN_SPI2_SCK, PIN_SPI2_MOSI, PAD_SPI2_TX, PAD_SPI2_RX); -#endif +SPIClass SPI2(&PERIPH_SPI2, PIN_SPI2_MISO, PIN_SPI2_SCK, PIN_SPI2_MOSI, + PAD_SPI2_TX, PAD_SPI2_RX); +#ifndef SPI2_IT_HANDLER +#define SPI2_IT_HANDLER SPI_SERCOM_HANDLER_FROM_TOKEN(PERIPH_SPI2) +#endif // !SPI2_IT_HANDLER +#ifndef SPI2_IT_HANDLER_0 +#define SPI2_IT_HANDLER_0 SPI_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_SPI2) +#define SPI2_IT_HANDLER_1 SPI_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_SPI2) +#define SPI2_IT_HANDLER_2 SPI_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_SPI2) +#if defined(__SAMD51__) || defined(__SAME51__) +#define SPI2_IT_HANDLER_3 SPI_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_SPI2) +#elif defined(__SAME53__) || defined(__SAME54__) +#define SPI2_IT_HANDLER_OTHER SPI_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_SPI2) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !SPI2_IT_HANDLER_0 +SPI_DEFINE_SERCOM_HANDLERS(SPI2, SPI2, PERIPH_SPI2) +#endif // SPI_INTERFACES_COUNT > 2 + #if SPI_INTERFACES_COUNT > 3 - SPIClass SPI3(&PERIPH_SPI3, PIN_SPI3_MISO, PIN_SPI3_SCK, PIN_SPI3_MOSI, PAD_SPI3_TX, PAD_SPI3_RX); -#endif +SPIClass SPI3(&PERIPH_SPI3, PIN_SPI3_MISO, PIN_SPI3_SCK, PIN_SPI3_MOSI, + PAD_SPI3_TX, PAD_SPI3_RX); +#ifndef SPI3_IT_HANDLER +#define SPI3_IT_HANDLER SPI_SERCOM_HANDLER_FROM_TOKEN(PERIPH_SPI3) +#endif // !SPI3_IT_HANDLER +#ifndef SPI3_IT_HANDLER_0 +#define SPI3_IT_HANDLER_0 SPI_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_SPI3) +#define SPI3_IT_HANDLER_1 SPI_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_SPI3) +#define SPI3_IT_HANDLER_2 SPI_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_SPI3) +#if defined(__SAMD51__) || defined(__SAME51__) +#define SPI3_IT_HANDLER_3 SPI_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_SPI3) +#elif defined(__SAME53__) || defined(__SAME54__) +#define SPI3_IT_HANDLER_OTHER SPI_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_SPI3) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !SPI3_IT_HANDLER_0 +SPI_DEFINE_SERCOM_HANDLERS(SPI3, SPI3, PERIPH_SPI3) +#endif // SPI_INTERFACES_COUNT > 3 + #if SPI_INTERFACES_COUNT > 4 - SPIClass SPI4(&PERIPH_SPI4, PIN_SPI4_MISO, PIN_SPI4_SCK, PIN_SPI4_MOSI, PAD_SPI4_TX, PAD_SPI4_RX); -#endif +SPIClass SPI4(&PERIPH_SPI4, PIN_SPI4_MISO, PIN_SPI4_SCK, PIN_SPI4_MOSI, + PAD_SPI4_TX, PAD_SPI4_RX); +#ifndef SPI4_IT_HANDLER +#define SPI4_IT_HANDLER SPI_SERCOM_HANDLER_FROM_TOKEN(PERIPH_SPI4) +#endif // !SPI4_IT_HANDLER +#ifndef SPI4_IT_HANDLER_0 +#define SPI4_IT_HANDLER_0 SPI_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_SPI4) +#define SPI4_IT_HANDLER_1 SPI_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_SPI4) +#define SPI4_IT_HANDLER_2 SPI_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_SPI4) +#if defined(__SAMD51__) || defined(__SAME51__) +#define SPI4_IT_HANDLER_3 SPI_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_SPI4) +#elif defined(__SAME53__) || defined(__SAME54__) +#define SPI4_IT_HANDLER_OTHER SPI_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_SPI4) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !SPI4_IT_HANDLER_0 +SPI_DEFINE_SERCOM_HANDLERS(SPI4, SPI4, PERIPH_SPI4) +#endif // SPI_INTERFACES_COUNT > 4 + #if SPI_INTERFACES_COUNT > 5 - SPIClass SPI5(&PERIPH_SPI5, PIN_SPI5_MISO, PIN_SPI5_SCK, PIN_SPI5_MOSI, PAD_SPI5_TX, PAD_SPI5_RX); -#endif +SPIClass SPI5(&PERIPH_SPI5, PIN_SPI5_MISO, PIN_SPI5_SCK, PIN_SPI5_MOSI, + PAD_SPI5_TX, PAD_SPI5_RX); +#ifndef SPI5_IT_HANDLER +#define SPI5_IT_HANDLER SPI_SERCOM_HANDLER_FROM_TOKEN(PERIPH_SPI5) +#endif // !SPI5_IT_HANDLER +#ifndef SPI5_IT_HANDLER_0 +#define SPI5_IT_HANDLER_0 SPI_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_SPI5) +#define SPI5_IT_HANDLER_1 SPI_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_SPI5) +#define SPI5_IT_HANDLER_2 SPI_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_SPI5) +#if defined(__SAMD51__) || defined(__SAME51__) +#define SPI5_IT_HANDLER_3 SPI_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_SPI5) +#elif defined(__SAME53__) || defined(__SAME54__) +#define SPI5_IT_HANDLER_OTHER SPI_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_SPI5) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !SPI5_IT_HANDLER_0 +SPI_DEFINE_SERCOM_HANDLERS(SPI5, SPI5, PERIPH_SPI5) +#endif // SPI_INTERFACES_COUNT > 5 + +#if SPI_INTERFACES_COUNT > 6 +SPIClass SPI6(&PERIPH_SPI6, PIN_SPI6_MISO, PIN_SPI6_SCK, PIN_SPI6_MOSI, + PAD_SPI6_TX, PAD_SPI6_RX); +#ifndef SPI6_IT_HANDLER +#define SPI6_IT_HANDLER SPI_SERCOM_HANDLER_FROM_TOKEN(PERIPH_SPI6) +#endif // !SPI6_IT_HANDLER +#ifndef SPI6_IT_HANDLER_0 +#define SPI6_IT_HANDLER_0 SPI_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_SPI6) +#define SPI6_IT_HANDLER_1 SPI_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_SPI6) +#define SPI6_IT_HANDLER_2 SPI_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_SPI6) +#if defined(__SAMD51__) || defined(__SAME51__) +#define SPI6_IT_HANDLER_3 SPI_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_SPI6) +#elif defined(__SAME53__) || defined(__SAME54__) +#define SPI6_IT_HANDLER_OTHER SPI_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_SPI6) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !SPI6_IT_HANDLER_0 +SPI_DEFINE_SERCOM_HANDLERS(SPI6, SPI6, PERIPH_SPI6) +#endif // SPI_INTERFACES_COUNT > 6 + +#if SPI_INTERFACES_COUNT > 7 +SPIClass SPI7(&PERIPH_SPI7, PIN_SPI7_MISO, PIN_SPI7_SCK, PIN_SPI7_MOSI, + PAD_SPI7_TX, PAD_SPI7_RX); +#ifndef SPI7_IT_HANDLER +#define SPI7_IT_HANDLER SPI_SERCOM_HANDLER_FROM_TOKEN(PERIPH_SPI7) +#endif // !SPI7_IT_HANDLER +#ifndef SPI7_IT_HANDLER_0 +#define SPI7_IT_HANDLER_0 SPI_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_SPI7) +#define SPI7_IT_HANDLER_1 SPI_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_SPI7) +#define SPI7_IT_HANDLER_2 SPI_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_SPI7) +#if defined(__SAMD51__) || defined(__SAME51__) +#define SPI7_IT_HANDLER_3 SPI_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_SPI7) +#elif defined(__SAME53__) || defined(__SAME54__) +#define SPI7_IT_HANDLER_OTHER SPI_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_SPI7) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !SPI7_IT_HANDLER_0 +SPI_DEFINE_SERCOM_HANDLERS(SPI7, SPI7, PERIPH_SPI7) +#endif // SPI_INTERFACES_COUNT > 7 diff --git a/libraries/SPI/SPI.h b/libraries/SPI/SPI.h index 7c719f695..1f1390b73 100644 --- a/libraries/SPI/SPI.h +++ b/libraries/SPI/SPI.h @@ -21,7 +21,7 @@ #define _SPI_H_INCLUDED #include -#include +#include "SERCOM.h" // SPI_HAS_TRANSACTION means SPI has // - beginTransaction() @@ -38,28 +38,28 @@ #define SPI_MODE2 0x03 #define SPI_MODE3 0x01 -#if defined(__SAMD51__) - // 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). Use the setClockSource() - // function instead. This is left here for compatibility with interim code. - #if !defined(MAX_SPI) - #define MAX_SPI 24000000 - #endif - #define SPI_MIN_CLOCK_DIVIDER 1 +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) +// 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). Configure SERCOM clock source +// directly via the SERCOM API instead. This is left here for compatibility. +#if !defined(MAX_SPI) +#define MAX_SPI 24000000 +#endif // !MAX_SPI +#define SPI_MIN_CLOCK_DIVIDER 1 #else - // The datasheet specifies a typical SPI SCK period (tSCK) of 42 ns, - // see "Table 36-48. SPI Timing Characteristics and Requirements", - // which translates into a maximum SPI clock of 23.8 MHz. - // We'll permit use of 24 MHz SPI even though this is slightly out - // of spec. Given how clock dividers work, the next "sensible" - // threshold would be a substantial drop down to 12 MHz. - #if !defined(MAX_SPI) - #define MAX_SPI 24000000 - #endif - #define SPI_MIN_CLOCK_DIVIDER (uint8_t)(1 + ((F_CPU - 1) / MAX_SPI)) -#endif +// The datasheet specifies a typical SPI SCK period (tSCK) of 42 ns, +// see "Table 36-48. SPI Timing Characteristics and Requirements", +// which translates into a maximum SPI clock of 23.8 MHz. +// We'll permit use of 24 MHz SPI even though this is slightly out +// of spec. Given how clock dividers work, the next "sensible" +// threshold would be a substantial drop down to 12 MHz. +#if !defined(MAX_SPI) +#define MAX_SPI 24000000 +#endif // !MAX_SPI +#define SPI_MIN_CLOCK_DIVIDER (uint8_t)(1 + ((F_CPU - 1) / MAX_SPI)) +#endif // __SAMD51__ / __SAME51__ || __SAME53__ / __SAME54__ class SPISettings { public: @@ -80,11 +80,11 @@ class SPISettings { } void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) __attribute__((__always_inline__)) { -#if defined(__SAMD51__) +#if defined(__SAMD51__) || defined(__SAME51__) || defined(__SAME53__) || defined(__SAME54__) this->clockFreq = clock; // Clipping handled in SERCOM.cpp #else this->clockFreq = clock >= MAX_SPI ? MAX_SPI : clock; -#endif +#endif // __SAMD51__ / __SAME51__ || __SAME53__ / __SAME54__ this->bitOrder = (bitOrder == MSBFIRST ? MSB_FIRST : LSB_FIRST); @@ -118,9 +118,13 @@ class SPIClass { uint16_t transfer16(uint16_t data); void transfer(void *buf, size_t count); void transfer(const void* txbuf, void* rxbuf, size_t count, - bool block = true); + bool block = true, + void (*onComplete)(void* user, int status) = nullptr, + void* user = nullptr); + void onService(void); void waitForTransfer(void); bool isBusy(void); + SERCOM* getSercom(void) const { return _p_sercom; } // Transaction Functions void usingInterrupt(int interruptNumber); @@ -132,27 +136,13 @@ class SPIClass { void attachInterrupt(); void detachInterrupt(); - void begin(); + bool begin(); void end(); void setBitOrder(BitOrder order); void setDataMode(uint8_t uc_mode); void setClockDivider(uint8_t uc_div); - // SERCOM lookup functions are available on both SAMD51 and 21. - volatile uint32_t *getDataRegister(void); - int getDMAC_ID_TX(void); - int getDMAC_ID_RX(void); - uint8_t getSercomIndex(void) { return _p_sercom->getSercomIndex(); }; -#if defined(__SAMD51__) - // SERCOM clock source override is available only on SAMD51. - void setClockSource(SercomClockSource clk); -#else - // On SAMD21, this compiles to nothing, so user code doesn't need to - // check and conditionally compile lines for different architectures. - void setClockSource(SercomClockSource clk) { (void)clk; }; -#endif // end __SAMD51__ - private: void config(SPISettings settings); @@ -169,46 +159,51 @@ class SPIClass { char interruptSave; uint32_t interruptMask; - // transfer(txbuf, rxbuf, count, block) uses DMA when possible - Adafruit_ZeroDMA readChannel; - Adafruit_ZeroDMA writeChannel; - DmacDescriptor *firstReadDescriptor = NULL; // List entry point - DmacDescriptor *firstWriteDescriptor = NULL; - DmacDescriptor *extraReadDescriptors = NULL; // Add'l descriptors - DmacDescriptor *extraWriteDescriptors = NULL; - bool use_dma = false; // true on successful alloc - volatile bool dma_busy = false; - void dmaAllocate(void); - static void dmaCallback(Adafruit_ZeroDMA *dma); + volatile bool txnDone = false; + volatile int txnStatus = 0; + + // Transaction pool for async operations (matches SERCOM queue depth) + static constexpr size_t TXN_POOL_SIZE = 8; + SercomTxn txnPool[TXN_POOL_SIZE]; + uint8_t txnPoolHead; + + SercomTxn* allocateTxn(); + static void onTxnComplete(void* user, int status); }; #if SPI_INTERFACES_COUNT > 0 extern SPIClass SPI; -#endif +#endif // SPI_INTERFACES_COUNT > 0 #if SPI_INTERFACES_COUNT > 1 extern SPIClass SPI1; -#endif +#endif // SPI_INTERFACES_COUNT > 1 #if SPI_INTERFACES_COUNT > 2 extern SPIClass SPI2; -#endif +#endif // SPI_INTERFACES_COUNT > 2 #if SPI_INTERFACES_COUNT > 3 extern SPIClass SPI3; -#endif +#endif // SPI_INTERFACES_COUNT > 3 #if SPI_INTERFACES_COUNT > 4 extern SPIClass SPI4; -#endif +#endif // SPI_INTERFACES_COUNT > 4 #if SPI_INTERFACES_COUNT > 5 extern SPIClass SPI5; -#endif - -// For compatibility with sketches designed for AVR @ 16 MHz -// New programs should use SPI.beginTransaction to set the SPI clock -#define SPI_CLOCK_DIV2 (MAX_SPI * 2 / 8000000) -#define SPI_CLOCK_DIV4 (MAX_SPI * 2 / 4000000) -#define SPI_CLOCK_DIV8 (MAX_SPI * 2 / 2000000) -#define SPI_CLOCK_DIV16 (MAX_SPI * 2 / 1000000) -#define SPI_CLOCK_DIV32 (MAX_SPI * 2 / 500000) -#define SPI_CLOCK_DIV64 (MAX_SPI * 2 / 250000) +#endif // SPI_INTERFACES_COUNT > 5 +#if SPI_INTERFACES_COUNT > 6 + extern SPIClass SPI6; +#endif // SPI_INTERFACES_COUNT > 6 +#if SPI_INTERFACES_COUNT > 7 + extern SPIClass SPI7; +#endif // SPI_INTERFACES_COUNT > 7 + + // For compatibility with sketches designed for AVR @ 16 MHz + // New programs should use SPI.beginTransaction to set the SPI clock +#define SPI_CLOCK_DIV2 (MAX_SPI * 2 / 8000000) +#define SPI_CLOCK_DIV4 (MAX_SPI * 2 / 4000000) +#define SPI_CLOCK_DIV8 (MAX_SPI * 2 / 2000000) +#define SPI_CLOCK_DIV16 (MAX_SPI * 2 / 1000000) +#define SPI_CLOCK_DIV32 (MAX_SPI * 2 / 500000) +#define SPI_CLOCK_DIV64 (MAX_SPI * 2 / 250000) #define SPI_CLOCK_DIV128 (MAX_SPI * 2 / 125000) -#endif +#endif // _SPI_H_INCLUDED diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp index da9732c59..b69c223a1 100644 --- a/libraries/Wire/Wire.cpp +++ b/libraries/Wire/Wire.cpp @@ -27,175 +27,459 @@ extern "C" { #ifdef USE_TINYUSB // For Serial when selecting TinyUSB #include -#endif +#endif // USE_TINYUSB #include "Wire.h" +// Default SERCOM ISR symbols are derived from PERIPH_WIRE* routing. +// Variants may override WIRE*_IT_HANDLER* macros when split vectors need +// custom ownership. +#define WIRE_SERCOM_INDEX_sercom0 0 +#define WIRE_SERCOM_INDEX_sercom1 1 +#define WIRE_SERCOM_INDEX_sercom2 2 +#define WIRE_SERCOM_INDEX_sercom3 3 +#define WIRE_SERCOM_INDEX_sercom4 4 +#define WIRE_SERCOM_INDEX_sercom5 5 +#if defined(SERCOM6) || defined(SERCOM6_REGS) +#define WIRE_SERCOM_INDEX_sercom6 6 +#endif // SERCOM6 || SERCOM6_REGS +#if defined(SERCOM7) || defined(SERCOM7_REGS) +#define WIRE_SERCOM_INDEX_sercom7 7 +#endif // SERCOM7 || SERCOM7_REGS + +#define WIRE_SERCOM_INDEX(token) WIRE_SERCOM_INDEX_##token +#define WIRE_SERCOM_HANDLER_FROM_INDEX(idx) \ + WIRE_SERCOM_HANDLER_FROM_INDEX_2(idx) +#define WIRE_SERCOM_HANDLER_FROM_INDEX_2(idx) SERCOM##idx##_Handler +#define WIRE_SERCOM_HANDLER_FROM_TOKEN(token) \ + WIRE_SERCOM_HANDLER_FROM_INDEX(WIRE_SERCOM_INDEX(token)) + +#define WIRE_SERCOM_HANDLER0_FROM_INDEX(idx) \ + WIRE_SERCOM_HANDLER0_FROM_INDEX_2(idx) +#define WIRE_SERCOM_HANDLER0_FROM_INDEX_2(idx) SERCOM##idx##_0_Handler +#define WIRE_SERCOM_HANDLER1_FROM_INDEX(idx) \ + WIRE_SERCOM_HANDLER1_FROM_INDEX_2(idx) +#define WIRE_SERCOM_HANDLER1_FROM_INDEX_2(idx) SERCOM##idx##_1_Handler +#define WIRE_SERCOM_HANDLER2_FROM_INDEX(idx) \ + WIRE_SERCOM_HANDLER2_FROM_INDEX_2(idx) +#define WIRE_SERCOM_HANDLER2_FROM_INDEX_2(idx) SERCOM##idx##_2_Handler +#define WIRE_SERCOM_HANDLER3_FROM_INDEX(idx) \ + WIRE_SERCOM_HANDLER3_FROM_INDEX_2(idx) +#define WIRE_SERCOM_HANDLER3_FROM_INDEX_2(idx) SERCOM##idx##_3_Handler +#define WIRE_SERCOM_HANDLER_OTHER_FROM_INDEX(idx) \ + WIRE_SERCOM_HANDLER_OTHER_FROM_INDEX_2(idx) +#define WIRE_SERCOM_HANDLER_OTHER_FROM_INDEX_2(idx) SERCOM##idx##_OTHER_Handler + +#define WIRE_SERCOM_HANDLER0_FROM_TOKEN(token) \ + WIRE_SERCOM_HANDLER0_FROM_INDEX(WIRE_SERCOM_INDEX(token)) +#define WIRE_SERCOM_HANDLER1_FROM_TOKEN(token) \ + WIRE_SERCOM_HANDLER1_FROM_INDEX(WIRE_SERCOM_INDEX(token)) +#define WIRE_SERCOM_HANDLER2_FROM_TOKEN(token) \ + WIRE_SERCOM_HANDLER2_FROM_INDEX(WIRE_SERCOM_INDEX(token)) +#define WIRE_SERCOM_HANDLER3_FROM_TOKEN(token) \ + WIRE_SERCOM_HANDLER3_FROM_INDEX(WIRE_SERCOM_INDEX(token)) +#define WIRE_SERCOM_HANDLER_OTHER_FROM_TOKEN(token) \ + WIRE_SERCOM_HANDLER_OTHER_FROM_INDEX(WIRE_SERCOM_INDEX(token)) + + +#define WIRE_DEFINE_SINGLE_HANDLER(handler, instance) \ + void handler(void) { \ + instance.onService(); \ + } + +#if defined(__SAMD51__) || defined(__SAME51__) +#define WIRE_DEFINE_SAMD51_E51_HANDLERS(handler0, handler1, handler2, \ + handler3, instance) \ + void handler0(void) { \ + instance.onService(); \ + } \ + void handler1(void) { \ + instance.onService(); \ + } \ + void handler2(void) { \ + instance.onService(); \ + } \ + void handler3(void) { \ + instance.onService(); \ + } + +#define WIRE_DEFINE_SERCOM_HANDLERS(prefix, instance) \ + WIRE_DEFINE_SAMD51_E51_HANDLERS( \ + prefix##_IT_HANDLER_0, prefix##_IT_HANDLER_1, prefix##_IT_HANDLER_2, \ + prefix##_IT_HANDLER_3, instance) +#elif defined(__SAME53__) || defined(__SAME54__) +#define WIRE_DEFINE_SAME53_E54_HANDLERS(handler0, handler1, handler2, \ + handlerOther, instance) \ + void handler0(void) { \ + instance.onService(); \ + } \ + void handler1(void) { \ + instance.onService(); \ + } \ + void handler2(void) { \ + instance.onService(); \ + } \ + void handlerOther(void) { \ + instance.onService(); \ + } + +#define WIRE_DEFINE_SERCOM_HANDLERS(prefix, instance) \ + WIRE_DEFINE_SAME53_E54_HANDLERS(prefix##_IT_HANDLER_0, \ + prefix##_IT_HANDLER_1, \ + prefix##_IT_HANDLER_2, \ + prefix##_IT_HANDLER_OTHER, instance) +#else +#define WIRE_DEFINE_SERCOM_HANDLERS(prefix, instance) \ + WIRE_DEFINE_SINGLE_HANDLER(prefix##_IT_HANDLER, instance) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ + +namespace sercomPinMux { +bool wirePinValidForSercom(uint8_t arduinoPin, uint8_t sercomIndex) { + if (arduinoPin >= PINS_COUNT) + return false; + + const char portLetter = + static_cast('A' + g_APinDescription[arduinoPin].ulPort); + const uint8_t portPin = + static_cast(g_APinDescription[arduinoPin].ulPin); + +#define SERCOM_PINMUX_EMIT_I2C 1 +#define SERCOM_I2C_PIN(PORT_LETTER, PORT_PIN, S0, P0, S1, P1) \ + if ((portLetter == (PORT_LETTER)) && (portPin == (PORT_PIN)) && \ + (((S0) == sercomIndex) || ((S1) == sercomIndex))) \ + return true; +#include +#undef SERCOM_I2C_PIN +#undef SERCOM_PINMUX_EMIT_I2C + + return false; +} +} // namespace sercomPinMux + TwoWire::TwoWire(SERCOM * s, uint8_t pinSDA, uint8_t pinSCL) { this->sercom = s; this->_uc_pinSDA=pinSDA; this->_uc_pinSCL=pinSCL; transmissionBegun = false; + rxLength = 0; + rxIndex = 0; + masterIndex = 0; + awaitingAddressAck = false; + txnDone = false; + txnStatus = 0; + rxBufferPtr = rxBuffer; + rxBufferCapacity = WIRE_BUFFER_LENGTH; + txBufferCapacity = WIRE_BUFFER_LENGTH; + onRequestCallback = nullptr; + onReceiveCallback = nullptr; + onReceiveResultCallback = nullptr; + requestCompletionCallback = nullptr; + requestCompletionUser = nullptr; + txnPoolHead = 0; } -void TwoWire::begin(void) { +bool TwoWire::begin(void) { //Master Mode - sercom->initMasterWIRE(TWI_CLOCK); - sercom->enableWIRE(); + const uint8_t sercomIndex = static_cast(sercom->getSercomIndex()); + if (!sercomPinMux::wirePinValidForSercom(_uc_pinSDA, sercomIndex) || + !sercomPinMux::wirePinValidForSercom(_uc_pinSCL, sercomIndex)) + return false; pinPeripheral(_uc_pinSDA, g_APinDescription[_uc_pinSDA].ulPinType); pinPeripheral(_uc_pinSCL, g_APinDescription[_uc_pinSCL].ulPinType); + + sercom->initMasterWIRE(TWI_CLOCK); + sercom->enableWIRE(); + return true; } -void TwoWire::begin(uint8_t address, bool enableGeneralCall) { +bool TwoWire::begin(uint16_t address, bool enableGeneralCall, uint8_t speed, + bool enable10Bit) { //Slave mode - sercom->initSlaveWIRE(address, enableGeneralCall); - sercom->enableWIRE(); + const uint8_t sercomIndex = static_cast(sercom->getSercomIndex()); + if (!sercomPinMux::wirePinValidForSercom(_uc_pinSDA, sercomIndex) || + !sercomPinMux::wirePinValidForSercom(_uc_pinSCL, sercomIndex)) + return false; pinPeripheral(_uc_pinSDA, g_APinDescription[_uc_pinSDA].ulPinType); pinPeripheral(_uc_pinSCL, g_APinDescription[_uc_pinSCL].ulPinType); + + sercom->initSlaveWIRE(address, enableGeneralCall, speed, enable10Bit); + sercom->enableWIRE(); + sercom->registerReceiveWIRE(&TwoWire::onDeferredReceive, this); + sercom->registerRequestWIRE(&TwoWire::onDeferredRequest, this); + prepareSlaveReceive(); + return true; +} + +bool TwoWire::begin(uint8_t address, bool enableGeneralCall) { + return begin(static_cast(address), enableGeneralCall); } void TwoWire::setClock(uint32_t baudrate) { - sercom->disableWIRE(); - sercom->initMasterWIRE(baudrate); - sercom->enableWIRE(); + sercom->setBaudrateWIRE(baudrate); } void TwoWire::end() { - sercom->disableWIRE(); + sercom->resetWIRE(); // SWRST: resets hardware + clears state + drains queue +} + +bool TwoWire::abortTransmission(int status) { + return sercom->abortWIRE(static_cast(status)); } -uint8_t TwoWire::requestFrom(uint8_t address, size_t quantity, bool stopBit) +uint8_t TwoWire::requestFrom(uint8_t address, size_t quantity, bool stopBit, uint8_t* rxBuffer, + void (*onComplete)(void* user, int status), void* user, + bool replaySafe) { if(quantity == 0) - { return 0; + if (!sercom->canEnqueueWIRE()) + return 0; + + loader = SercomTxn{}; + + if (rxBuffer != nullptr) { + loader.rxPtr = rxBuffer; + loader.length = quantity; + } else { + loader.rxPtr = this->rxBuffer; + loader.length = ( quantity > WIRE_BUFFER_LENGTH) ? WIRE_BUFFER_LENGTH : quantity; } - size_t byteRead = 0; + loader.config = I2C_CFG_READ | (stopBit ? I2C_CFG_STOP : 0) | + (replaySafe ? I2C_CFG_REPLAY_SAFE : 0); + loader.address = address; + + // Allocate fresh transaction from pool and copy loader data + SercomTxn* txn = allocateTxn(); + *txn = loader; + txn->chainNext = false; + + // For caller callbacks, pass txn as user so callback can access + // txn->rxPtr/length directly. + if (onComplete) { + txn->onComplete = onComplete; + txn->user = (user == nullptr) ? txn : user; + } else { + txn->onComplete = &TwoWire::onTxnComplete; + txn->user = this; + } - rxBuffer.clear(); + awaitingAddressAck = true; + txnDone = false; - if(sercom->startTransmissionWIRE(address, WIRE_READ_FLAG)) - { - // Read first data - rxBuffer.store_char(sercom->readDataWIRE()); - - // Connected to slave - for (byteRead = 1; byteRead < quantity; ++byteRead) - { - sercom->prepareAckBitWIRE(); // Prepare Acknowledge - sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_READ); // Prepare the ACK command for the slave - rxBuffer.store_char(sercom->readDataWIRE()); // Read data and send the ACK - } - sercom->prepareNackBitWIRE(); // Prepare NACK to stop slave transmission - //sercom->readDataWIRE(); // Clear data register to send NACK + // Enqueue the pool transaction, not the loader + if (!sercom->enqueueWIRE(txn)) + return 0; - if (stopBit) - { - sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); // Send Stop - } + if (!onComplete) { + while (!txnDone) + yield(); + + if (txnStatus != static_cast(SercomWireError::SUCCESS)) + return 0; + + rxBufferPtr = loader.rxPtr; + rxLength = loader.length; + rxIndex = 0; + return rxLength; } - return byteRead; + return loader.length; } -uint8_t TwoWire::requestFrom(uint8_t address, size_t quantity) -{ - return requestFrom(address, quantity, true); +SercomTxn* TwoWire::allocateTxn() { + // Simple round-robin allocation from pool + SercomTxn* txn = &txnPool[txnPoolHead]; + txnPoolHead = (txnPoolHead + 1) % TXN_POOL_SIZE; + *txn = SercomTxn{}; // Clear the transaction + return txn; } -void TwoWire::beginTransmission(uint8_t address) { - // save address of target and clear buffer - txAddress = address; - txBuffer.clear(); +void TwoWire::freeTxn(SercomTxn* txn) { + // Transactions are freed when removed from SERCOM queue + // Pool allocation is round-robin, so no explicit free needed + (void)txn; +} +void TwoWire::beginTransmission(uint8_t address) { + // Initialize loader as staging area for building transaction + loader = SercomTxn{}; + loader.txPtr = nullptr; + loader.address = address; + txBufferCapacity = WIRE_BUFFER_LENGTH; transmissionBegun = true; } +void TwoWire::setTransactionReplaySafe(bool replaySafe) { + if (replaySafe) + loader.config |= I2C_CFG_REPLAY_SAFE; + else + loader.config &= ~I2C_CFG_REPLAY_SAFE; +} + // Errors: // 0 : Success // 1 : Data too long // 2 : NACK on transmit of address // 3 : NACK on transmit of data // 4 : Other error -uint8_t TwoWire::endTransmission(bool stopBit) -{ +uint8_t TwoWire::endTransmission(bool stopBit, + void (*onComplete)(void *user, int status), + void *user) { transmissionBegun = false ; - // Start I2C transmission - if ( !sercom->startTransmissionWIRE( txAddress, WIRE_WRITE_FLAG ) ) - { - sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); - return 2 ; // Address error + if (!sercom->canEnqueueWIRE()) { + if (onComplete) + return static_cast(SercomWireError::QUEUE_FULL); + return 4; } - // Send all buffer - while( txBuffer.available() ) - { - // Trying to send data - if ( !sercom->sendDataMasterWIRE( txBuffer.read_char() ) ) - { - sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); - return 3 ; // Nack or error + // Allocate a fresh transaction from the pool and copy staged data from loader + SercomTxn* txn = allocateTxn(); + *txn = loader; // Copy staged transaction data + txn->chainNext = false; + + // Set parameters that weren't known during beginTransmission/write + txn->config = (loader.config & I2C_CFG_REPLAY_SAFE) | + (stopBit ? I2C_CFG_STOP : 0); + if (onComplete) { + txn->onComplete = onComplete; + txn->user = (user == nullptr) ? txn : user; + } else { + txn->onComplete = &TwoWire::onTxnComplete; + txn->user = this; + } + + awaitingAddressAck = true; + txnDone = false; + + // Enqueue the pool transaction, not the loader + if (!sercom->enqueueWIRE(txn)) { + if (onComplete) + return static_cast(SercomWireError::QUEUE_FULL); + return 4; + } + + if (!onComplete) { + while (!txnDone) + yield(); + + SercomWireError err = static_cast(txnStatus); + switch (err) { + case SercomWireError::SUCCESS: + return 0; + case SercomWireError::DATA_TOO_LONG: + return 1; + case SercomWireError::NACK_ON_ADDRESS: + return 2; + case SercomWireError::NACK_ON_DATA: + return 3; + default: + return 4; } } - - if (stopBit) - { - sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); - } return 0; } -uint8_t TwoWire::endTransmission() -{ - return endTransmission(true); -} - size_t TwoWire::write(uint8_t ucData) { - // No writing, without begun transmission or a full buffer - if ( !transmissionBegun || txBuffer.isFull() ) - { - return 0 ; - } + if (!transmissionBegun) + return 0; - txBuffer.store_char( ucData ) ; + // Check buffer full + if (loader.length >= txBufferCapacity) + return 0; + + // Initialize to internal buffer if first write + if (loader.txPtr == nullptr) + loader.txPtr = txBuffer; - return 1 ; + // Append to current buffer (internal or external) + if (loader.txPtr == txBuffer) + txBuffer[loader.length++] = ucData; + else + const_cast(loader.txPtr)[loader.length++] = ucData; + + return 1; } -size_t TwoWire::write(const uint8_t *data, size_t quantity) +size_t TwoWire::write(const uint8_t *data, size_t quantity, bool setExternal) { - //Try to store all data - for(size_t i = 0; i < quantity; ++i) - { - //Return the number of data stored, when the buffer is full (if write return 0) - if(!write(data[i])) - return i; + if (!transmissionBegun) + return 0; + + if (quantity == 0) + return 0; + + // External path: require external buffer (zero-copy) + if (setExternal) { + if (loader.txPtr == nullptr) { + loader.txPtr = data; + txBufferCapacity = quantity; // Treat quantity as both length and capacity + loader.length = quantity; + return quantity; + } + + // Prevent switching from internal buffer to external mid-transaction + if (loader.txPtr == txBuffer) + return 0; + } + + // Sync path: prefer internal buffer unless it overflows + if (loader.txPtr == nullptr) { + if (quantity <= WIRE_BUFFER_LENGTH) { + loader.txPtr = txBuffer; + txBufferCapacity = WIRE_BUFFER_LENGTH; + memcpy(txBuffer, data, quantity); + loader.length = quantity; + return quantity; + } + + // Large write: require external buffer + loader.txPtr = data; + txBufferCapacity = quantity; + loader.length = quantity; + return quantity; } - //All data stored + // Appending to existing buffer + size_t available = txBufferCapacity - loader.length; + if (quantity > available) + quantity = available; + + if (quantity == 0) + return 0; + + if (loader.txPtr == txBuffer) + memcpy(txBuffer + loader.length, data, quantity); + else + memcpy(const_cast(loader.txPtr) + loader.length, data, quantity); + + loader.length += quantity; return quantity; } int TwoWire::available(void) { - return rxBuffer.available(); + return (rxLength > rxIndex) ? (int)(rxLength - rxIndex) : 0; } int TwoWire::read(void) { - return rxBuffer.read_char(); + if (rxIndex >= rxLength) + return -1; + return rxBufferPtr[rxIndex++]; } int TwoWire::peek(void) { - return rxBuffer.peek(); + if (rxIndex >= rxLength) + return -1; + return rxBufferPtr[rxIndex]; } void TwoWire::flush(void) @@ -207,74 +491,158 @@ void TwoWire::flush(void) void TwoWire::onReceive(void(*function)(int)) { onReceiveCallback = function; + onReceive(static_cast(nullptr)); +} + +void TwoWire::onReceive(void (*function)(SercomWireError, int)) { + onReceiveResultCallback = function; } void TwoWire::onRequest(void(*function)(void)) { + onRequest(function, nullptr, nullptr); +} + +void TwoWire::onRequest(void (*function)(void), RequestCompletion completion, + void *user) { onRequestCallback = function; + requestCompletionCallback = completion; + requestCompletionUser = user; } -void TwoWire::onService(void) +void TwoWire::setRxBuffer(uint8_t* buffer, size_t length) { - if ( sercom->isSlaveWIRE() ) + if (buffer == nullptr || length == 0) { - if(sercom->isStopDetectedWIRE() || - (sercom->isAddressMatch() && sercom->isRestartDetectedWIRE() && !sercom->isMasterReadOperationWIRE())) //Stop or Restart detected - { - sercom->prepareAckBitWIRE(); - sercom->prepareCommandBitsWire(0x03); - - //Calling onReceiveCallback, if exists - if(onReceiveCallback) - { - onReceiveCallback(available()); - } - - rxBuffer.clear(); - } - else if(sercom->isAddressMatch()) //Address Match - { - sercom->prepareAckBitWIRE(); - sercom->prepareCommandBitsWire(0x03); - - if(sercom->isMasterReadOperationWIRE()) //Is a request ? - { - txBuffer.clear(); - - transmissionBegun = true; - - //Calling onRequestCallback, if exists - if(onRequestCallback) - { - onRequestCallback(); - } - } - } - else if(sercom->isDataReadyWIRE()) - { - if (sercom->isMasterReadOperationWIRE()) - { - uint8_t c = 0xff; - - if( txBuffer.available() ) { - c = txBuffer.read_char(); - } - - transmissionBegun = sercom->sendDataSlaveWIRE(c); - } else { //Received data - if (rxBuffer.isFull()) { - sercom->prepareNackBitWIRE(); - } else { - //Store data - rxBuffer.store_char(sercom->readDataWIRE()); - - sercom->prepareAckBitWIRE(); - } - - sercom->prepareCommandBitsWire(0x03); - } - } + clearRxBuffer(); + return; + } + rxBufferPtr = buffer; + rxBufferCapacity = length; +} + +void TwoWire::setTxBuffer(uint8_t* buffer, size_t length) +{ + if (buffer == nullptr || length == 0) { + loader.txPtr = nullptr; + txBufferCapacity = WIRE_BUFFER_LENGTH; + loader.length = 0; + return; } + + loader.txPtr = buffer; + txBufferCapacity = length; + loader.length = 0; +} + +void TwoWire::clearRxBuffer(void) +{ + if (rxBufferPtr && rxBufferCapacity > 0) + memset(rxBufferPtr, 0, rxBufferCapacity); + rxLength = 0; + rxIndex = 0; +} + +void TwoWire::resetRxBuffer(void) +{ + rxBufferPtr = rxBuffer; + rxBufferCapacity = WIRE_BUFFER_LENGTH; + clearRxBuffer(); +} + +uint8_t* TwoWire::getRxBuffer(void) +{ + return rxBufferPtr; +} + +size_t TwoWire::getRxLength(void) const +{ + return rxLength; +} + +void TwoWire::onTxnComplete(void* user, int status) +{ + if (!user) + return; + TwoWire* self = static_cast(user); + self->txnStatus = status; + self->txnDone = true; +} + +void TwoWire::prepareSlaveReceive() { + rxLength = 0; + rxIndex = 0; + slaveTxn = SercomTxn{}; + slaveTxn.rxPtr = rxBufferPtr; + slaveTxn.length = rxBufferCapacity; + slaveTxn.config = 0; + slaveTxn.onComplete = &TwoWire::onSlaveReceiveComplete; + slaveTxn.user = this; + sercom->setSlaveTxnWIRE(&slaveTxn); +} + +void TwoWire::onDeferredReceive(void *user) { + if (!user) + return; + TwoWire *self = static_cast(user); + self->prepareSlaveReceive(); + self->sercom->setTxnWIRE(&self->slaveTxn); + self->sercom->markSlaveTransactionActiveWIRE(); + if (!self->sercom->startTransmissionWIRE()) { + self->sercom->deferStopWIRE(SercomWireError::DMA_ERROR); + return; + } +} + +void TwoWire::onDeferredRequest(void *user) { + if (!user) + return; + TwoWire *self = static_cast(user); + self->loader = SercomTxn{}; + self->transmissionBegun = true; + if (self->onRequestCallback) + self->onRequestCallback(); + self->transmissionBegun = false; + if (self->loader.txPtr == nullptr || self->loader.length == 0) { + if (self->requestCompletionCallback) + self->requestCompletionCallback(self->requestCompletionUser, + SercomWireError::SUCCESS); + return; + } + self->slaveTxn = self->loader; + self->slaveTxn.config |= I2C_CFG_READ; + self->slaveTxn.onComplete = &TwoWire::onSlaveRequestComplete; + self->slaveTxn.user = self; + self->sercom->setTxnWIRE(&self->slaveTxn); + self->sercom->markSlaveTransactionActiveWIRE(); + if (!self->sercom->startTransmissionWIRE()) { + self->sercom->deferStopWIRE(SercomWireError::DMA_ERROR); + return; + } +} + +void TwoWire::onSlaveReceiveComplete(void *user, int status) { + if (!user) + return; + TwoWire *self = static_cast(user); + const SercomWireError error = static_cast(status); + const int received = static_cast(self->sercom->getTxnIndexWIRE()); + self->rxLength = received; + self->rxIndex = 0; + if (error == SercomWireError::SUCCESS && self->onReceiveCallback) + self->onReceiveCallback(received); + if (self->onReceiveResultCallback) + self->onReceiveResultCallback(error, received); +} + +void TwoWire::onSlaveRequestComplete(void *user, int status) { + if (!user) + return; + TwoWire *self = static_cast(user); + if (self->requestCompletionCallback) + self->requestCompletionCallback(self->requestCompletionUser, + static_cast(status)); + self->prepareSlaveReceive(); } #if WIRE_INTERFACES_COUNT > 0 @@ -287,92 +655,114 @@ void TwoWire::onService(void) #define PERIPH_WIRE sercom3 #define WIRE_IT_HANDLER SERCOM3_Handler #endif // PERIPH_WIRE - TwoWire Wire(&PERIPH_WIRE, PIN_WIRE_SDA, PIN_WIRE_SCL); - - void WIRE_IT_HANDLER(void) { - Wire.onService(); - } - - #if defined(__SAMD51__) - void WIRE_IT_HANDLER_0(void) { Wire.onService(); } - void WIRE_IT_HANDLER_1(void) { Wire.onService(); } - void WIRE_IT_HANDLER_2(void) { Wire.onService(); } - void WIRE_IT_HANDLER_3(void) { Wire.onService(); } - #endif // __SAMD51__ -#endif +TwoWire Wire(&PERIPH_WIRE, PIN_WIRE_SDA, PIN_WIRE_SCL); +#ifndef WIRE_IT_HANDLER +#define WIRE_IT_HANDLER WIRE_SERCOM_HANDLER_FROM_TOKEN(PERIPH_WIRE) +#endif // !WIRE_IT_HANDLER +#ifndef WIRE_IT_HANDLER_0 +#define WIRE_IT_HANDLER_0 WIRE_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_WIRE) +#define WIRE_IT_HANDLER_1 WIRE_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_WIRE) +#define WIRE_IT_HANDLER_2 WIRE_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_WIRE) +#if defined(__SAMD51__) || defined(__SAME51__) +#define WIRE_IT_HANDLER_3 WIRE_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_WIRE) +#elif defined(__SAME53__) || defined(__SAME54__) +#define WIRE_IT_HANDLER_OTHER WIRE_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_WIRE) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !WIRE_IT_HANDLER_0 +WIRE_DEFINE_SERCOM_HANDLERS(WIRE, Wire) +#endif // WIRE_INTERFACES_COUNT > 0 #if WIRE_INTERFACES_COUNT > 1 TwoWire Wire1(&PERIPH_WIRE1, PIN_WIRE1_SDA, PIN_WIRE1_SCL); - - void WIRE1_IT_HANDLER(void) { - Wire1.onService(); - } - - #if defined(__SAMD51__) - void WIRE1_IT_HANDLER_0(void) { Wire1.onService(); } - void WIRE1_IT_HANDLER_1(void) { Wire1.onService(); } - void WIRE1_IT_HANDLER_2(void) { Wire1.onService(); } - void WIRE1_IT_HANDLER_3(void) { Wire1.onService(); } - #endif // __SAMD51__ -#endif + #ifndef WIRE1_IT_HANDLER +#define WIRE1_IT_HANDLER WIRE_SERCOM_HANDLER_FROM_TOKEN(PERIPH_WIRE1) +#endif // !WIRE1_IT_HANDLER +#ifndef WIRE1_IT_HANDLER_0 +#define WIRE1_IT_HANDLER_0 WIRE_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_WIRE1) +#define WIRE1_IT_HANDLER_1 WIRE_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_WIRE1) +#define WIRE1_IT_HANDLER_2 WIRE_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_WIRE1) +#if defined(__SAMD51__) || defined(__SAME51__) +#define WIRE1_IT_HANDLER_3 WIRE_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_WIRE1) +#elif defined(__SAME53__) || defined(__SAME54__) +#define WIRE1_IT_HANDLER_OTHER \ + WIRE_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_WIRE1) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !WIRE1_IT_HANDLER_0 + WIRE_DEFINE_SERCOM_HANDLERS(WIRE1, Wire1) +#endif // WIRE_INTERFACES_COUNT > 1 #if WIRE_INTERFACES_COUNT > 2 TwoWire Wire2(&PERIPH_WIRE2, PIN_WIRE2_SDA, PIN_WIRE2_SCL); - - void WIRE2_IT_HANDLER(void) { - Wire2.onService(); - } - - #if defined(__SAMD51__) - void WIRE2_IT_HANDLER_0(void) { Wire2.onService(); } - void WIRE2_IT_HANDLER_1(void) { Wire2.onService(); } - void WIRE2_IT_HANDLER_2(void) { Wire2.onService(); } - void WIRE2_IT_HANDLER_3(void) { Wire2.onService(); } - #endif // __SAMD51__ -#endif + #ifndef WIRE2_IT_HANDLER +#define WIRE2_IT_HANDLER WIRE_SERCOM_HANDLER_FROM_TOKEN(PERIPH_WIRE2) +#endif // !WIRE2_IT_HANDLER +#ifndef WIRE2_IT_HANDLER_0 +#define WIRE2_IT_HANDLER_0 WIRE_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_WIRE2) +#define WIRE2_IT_HANDLER_1 WIRE_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_WIRE2) +#define WIRE2_IT_HANDLER_2 WIRE_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_WIRE2) +#if defined(__SAMD51__) || defined(__SAME51__) +#define WIRE2_IT_HANDLER_3 WIRE_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_WIRE2) +#elif defined(__SAME53__) || defined(__SAME54__) +#define WIRE2_IT_HANDLER_OTHER \ + WIRE_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_WIRE2) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !WIRE2_IT_HANDLER_0 + WIRE_DEFINE_SERCOM_HANDLERS(WIRE2, Wire2) +#endif // WIRE_INTERFACES_COUNT > 2 #if WIRE_INTERFACES_COUNT > 3 TwoWire Wire3(&PERIPH_WIRE3, PIN_WIRE3_SDA, PIN_WIRE3_SCL); - - void WIRE3_IT_HANDLER(void) { - Wire3.onService(); - } - - #if defined(__SAMD51__) - void WIRE3_IT_HANDLER_0(void) { Wire3.onService(); } - void WIRE3_IT_HANDLER_1(void) { Wire3.onService(); } - void WIRE3_IT_HANDLER_2(void) { Wire3.onService(); } - void WIRE3_IT_HANDLER_3(void) { Wire3.onService(); } - #endif // __SAMD51__ -#endif + #ifndef WIRE3_IT_HANDLER +#define WIRE3_IT_HANDLER WIRE_SERCOM_HANDLER_FROM_TOKEN(PERIPH_WIRE3) +#endif // !WIRE3_IT_HANDLER +#ifndef WIRE3_IT_HANDLER_0 +#define WIRE3_IT_HANDLER_0 WIRE_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_WIRE3) +#define WIRE3_IT_HANDLER_1 WIRE_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_WIRE3) +#define WIRE3_IT_HANDLER_2 WIRE_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_WIRE3) +#if defined(__SAMD51__) || defined(__SAME51__) +#define WIRE3_IT_HANDLER_3 WIRE_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_WIRE3) +#elif defined(__SAME53__) || defined(__SAME54__) +#define WIRE3_IT_HANDLER_OTHER \ + WIRE_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_WIRE3) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !WIRE3_IT_HANDLER_0 + WIRE_DEFINE_SERCOM_HANDLERS(WIRE3, Wire3) +#endif // WIRE_INTERFACES_COUNT > 3 #if WIRE_INTERFACES_COUNT > 4 TwoWire Wire4(&PERIPH_WIRE4, PIN_WIRE4_SDA, PIN_WIRE4_SCL); - - void WIRE4_IT_HANDLER(void) { - Wire4.onService(); - } - - #if defined(__SAMD51__) - void WIRE4_IT_HANDLER_0(void) { Wire4.onService(); } - void WIRE4_IT_HANDLER_1(void) { Wire4.onService(); } - void WIRE4_IT_HANDLER_2(void) { Wire4.onService(); } - void WIRE4_IT_HANDLER_3(void) { Wire4.onService(); } - #endif // __SAMD51__ -#endif + #ifndef WIRE4_IT_HANDLER +#define WIRE4_IT_HANDLER WIRE_SERCOM_HANDLER_FROM_TOKEN(PERIPH_WIRE4) +#endif // !WIRE4_IT_HANDLER +#ifndef WIRE4_IT_HANDLER_0 +#define WIRE4_IT_HANDLER_0 WIRE_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_WIRE4) +#define WIRE4_IT_HANDLER_1 WIRE_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_WIRE4) +#define WIRE4_IT_HANDLER_2 WIRE_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_WIRE4) +#if defined(__SAMD51__) || defined(__SAME51__) +#define WIRE4_IT_HANDLER_3 WIRE_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_WIRE4) +#elif defined(__SAME53__) || defined(__SAME54__) +#define WIRE4_IT_HANDLER_OTHER \ + WIRE_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_WIRE4) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !WIRE4_IT_HANDLER_0 + WIRE_DEFINE_SERCOM_HANDLERS(WIRE4, Wire4) +#endif // WIRE_INTERFACES_COUNT > 4 #if WIRE_INTERFACES_COUNT > 5 TwoWire Wire5(&PERIPH_WIRE5, PIN_WIRE5_SDA, PIN_WIRE5_SCL); - - void WIRE5_IT_HANDLER(void) { - Wire5.onService(); - } - - #if defined(__SAMD51__) - void WIRE5_IT_HANDLER_0(void) { Wire5.onService(); } - void WIRE5_IT_HANDLER_1(void) { Wire5.onService(); } - void WIRE5_IT_HANDLER_2(void) { Wire5.onService(); } - void WIRE5_IT_HANDLER_3(void) { Wire5.onService(); } - #endif // __SAMD51__ -#endif - + #ifndef WIRE5_IT_HANDLER +#define WIRE5_IT_HANDLER WIRE_SERCOM_HANDLER_FROM_TOKEN(PERIPH_WIRE5) +#endif // !WIRE5_IT_HANDLER +#ifndef WIRE5_IT_HANDLER_0 +#define WIRE5_IT_HANDLER_0 WIRE_SERCOM_HANDLER0_FROM_TOKEN(PERIPH_WIRE5) +#define WIRE5_IT_HANDLER_1 WIRE_SERCOM_HANDLER1_FROM_TOKEN(PERIPH_WIRE5) +#define WIRE5_IT_HANDLER_2 WIRE_SERCOM_HANDLER2_FROM_TOKEN(PERIPH_WIRE5) +#if defined(__SAMD51__) || defined(__SAME51__) +#define WIRE5_IT_HANDLER_3 WIRE_SERCOM_HANDLER3_FROM_TOKEN(PERIPH_WIRE5) +#elif defined(__SAME53__) || defined(__SAME54__) +#define WIRE5_IT_HANDLER_OTHER \ + WIRE_SERCOM_HANDLER_OTHER_FROM_TOKEN(PERIPH_WIRE5) +#endif // __SAMD51__ / __SAME51__ / __SAME53__ / __SAME54__ +#endif // !WIRE5_IT_HANDLER_0 + WIRE_DEFINE_SERCOM_HANDLERS(WIRE5, Wire5) +#endif // WIRE_INTERFACES_COUNT > 5 diff --git a/libraries/Wire/Wire.h b/libraries/Wire/Wire.h index db2ae646e..aae01ed41 100644 --- a/libraries/Wire/Wire.h +++ b/libraries/Wire/Wire.h @@ -23,37 +23,78 @@ #include "Stream.h" #include "variant.h" -#include "SERCOM.h" #include "RingBuffer.h" +#include "SERCOM.h" +#include "SERCOM_WireBusErrorPolicy.h" +#include - // WIRE_HAS_END means Wire has end() +// WIRE_HAS_END means Wire has end() #define WIRE_HAS_END 1 +// NOTE: SAMD21/SAMD51 silicon errata: when I2C master uses SCLSM=1, CTRLB.CMD +// (STOP/RESTART) is ignored, so interrupt-driven byte mode cannot reliably end +// transfers or issue repeated starts. Hs-mode requires SCLSM=1, therefore Hs-mode +// is DMA-only and STOP-only (no repeated starts). The non-DMA Wire path should +// not enable Hs-mode. Also per errata, do not enable QCEN when SCLSM=1 (bus error). + class TwoWire : public Stream { - public: - TwoWire(SERCOM *s, uint8_t pinSDA, uint8_t pinSCL); - void begin(); - void begin(uint8_t, bool enableGeneralCall = false); - void end(); - void setClock(uint32_t); +public: + using RequestCompletion = void (*)(void *user, SercomWireError result); + TwoWire(SERCOM *s, uint8_t pinSDA, uint8_t pinSCL); + bool begin(); + bool begin(uint8_t, bool enableGeneralCall = false); + bool begin(uint16_t, bool enableGeneralCall, uint8_t speed = 0x0, + bool enable10Bit = false); + void end(); + void setClock(uint32_t); - void beginTransmission(uint8_t); - uint8_t endTransmission(bool stopBit); - uint8_t endTransmission(void); + void beginTransmission(uint8_t); + void setTransactionReplaySafe(bool replaySafe = true); + // If onComplete is nullptr, this blocks for legacy sync behavior. + // If onComplete is non-null, this enqueues and returns immediately (async). + uint8_t endTransmission(bool stopBit = true, + void (*onComplete)(void *user, int status) = nullptr, + void *user = nullptr); + bool abortTransmission( + int status = static_cast(SercomWireError::MASTER_TIMEOUT)); + inline const SercomWireCompletionReport &lastCompletionReport(void) const { + return sercom->lastCompletionReportWIRE(); + } - uint8_t requestFrom(uint8_t address, size_t quantity, bool stopBit); - uint8_t requestFrom(uint8_t address, size_t quantity); + // If onComplete is nullptr, this blocks for legacy sync behavior. + // If onComplete is non-null, this enqueues and returns immediately (async). + // If rxBuffer is nullptr, the internal buffer is used; otherwise rxBuffer is + // used. + uint8_t requestFrom(uint8_t address, size_t quantity, bool stopBit = true, + uint8_t *rxBuffer = nullptr, + void (*onComplete)(void *user, int status) = nullptr, + void *user = nullptr, bool replaySafe = false); - size_t write(uint8_t data); - size_t write(const uint8_t * data, size_t quantity); + size_t write(uint8_t data); + // 3-arg write: when setExternal=true, data is used directly (zero-copy) and + // quantity is treated as both length and capacity; subsequent write() calls + // return 0. For streaming > WIRE_BUFFER_LENGTH or async usage, call + // setTxBuffer() before write() on every transaction. + size_t write(const uint8_t *data, size_t quantity, bool setExternal = false); virtual int available(void); virtual int read(void); virtual int peek(void); virtual void flush(void); - void onReceive(void(*)(int)); - void onRequest(void(*)(void)); + void onReceive(void (*)(int)); + void onReceive(void (*)(SercomWireError, int)); + void onRequest(void (*)(void)); + void onRequest(void (*)(void), RequestCompletion completion, + void *user = nullptr); + void setRxBuffer(uint8_t *buffer, size_t length); + void setTxBuffer(uint8_t *buffer, size_t length); + void clearRxBuffer(void); + void resetRxBuffer(void); + uint8_t *getRxBuffer(void); + size_t getRxLength(void) const; + inline SERCOM *getSercom(void) { return sercom; } + inline const SERCOM *getSercom(void) const { return sercom; } inline size_t write(unsigned long n) { return write((uint8_t)n); } inline size_t write(long n) { return write((uint8_t)n); } @@ -61,47 +102,393 @@ class TwoWire : public Stream inline size_t write(int n) { return write((uint8_t)n); } using Print::write; - void onService(void); + inline void onService(void); - private: - SERCOM * sercom; +private: + SERCOM *sercom; uint8_t _uc_pinSDA; uint8_t _uc_pinSCL; bool transmissionBegun; - // RX Buffer - RingBufferN<256> rxBuffer; + // RX/TX buffers (sync compatibility, async staging) + static constexpr size_t WIRE_BUFFER_LENGTH = 255; + uint8_t rxBuffer[WIRE_BUFFER_LENGTH]; + uint8_t txBuffer[WIRE_BUFFER_LENGTH]; + uint8_t *rxBufferPtr; + size_t rxBufferCapacity; + size_t rxLength; + size_t rxIndex; + size_t txBufferCapacity; + size_t masterIndex; + bool awaitingAddressAck; + volatile bool txnDone; + volatile int txnStatus; + SercomTxn slaveTxn; + SercomTxn loader; // Staging area for building transactions + + // Transaction pool for async operations (matches SERCOM queue depth) + static constexpr size_t TXN_POOL_SIZE = 8; + SercomTxn txnPool[TXN_POOL_SIZE]; + uint8_t txnPoolHead; - //TX buffer - RingBufferN<256> txBuffer; - uint8_t txAddress; + SercomTxn *allocateTxn(); + void freeTxn(SercomTxn *txn); // Callback user functions void (*onRequestCallback)(void); void (*onReceiveCallback)(int); + void (*onReceiveResultCallback)(SercomWireError, int); + RequestCompletion requestCompletionCallback; + void *requestCompletionUser; + + static void onTxnComplete(void *user, int status); + void prepareSlaveReceive(); + static void onDeferredReceive(void *user); + static void onDeferredRequest(void *user); + static void onSlaveReceiveComplete(void *user, int status); + static void onSlaveRequestComplete(void *user, int status); // TWI clock frequency static const uint32_t TWI_CLOCK = 100000; }; #if WIRE_INTERFACES_COUNT > 0 - extern TwoWire Wire; +extern TwoWire Wire; #endif #if WIRE_INTERFACES_COUNT > 1 - extern TwoWire Wire1; +extern TwoWire Wire1; #endif #if WIRE_INTERFACES_COUNT > 2 - extern TwoWire Wire2; +extern TwoWire Wire2; #endif #if WIRE_INTERFACES_COUNT > 3 - extern TwoWire Wire3; +extern TwoWire Wire3; #endif #if WIRE_INTERFACES_COUNT > 4 - extern TwoWire Wire4; +extern TwoWire Wire4; #endif #if WIRE_INTERFACES_COUNT > 5 - extern TwoWire Wire5; +extern TwoWire Wire5; +#endif + +inline void TwoWire::onService(void) +{ + uint8_t flags = (uint8_t)sercom->getINTFLAG(); + uint16_t status = (uint16_t)sercom->getSTATUS(); + bool isMaster = sercom->isMasterWIRE(); + + if (!isMaster && !sercom->isSlaveWIRE()) { + sercom->clearINTFLAG(); + return; + } + + if (flags == 0) + return; + +#if defined(__SAME53__) || defined(__SAME54__) + const bool rxNack = status & SERCOM_I2CM_STATUS_RXNACK_Msk; + const bool wireError = flags & SERCOM_I2CM_INTFLAG_ERROR_Msk; + const bool slaveDrdy = + !isMaster && (flags & SERCOM_I2CS_INTFLAG_DRDY_Msk); + const bool slavePrec = + !isMaster && (flags & SERCOM_I2CS_INTFLAG_PREC_Msk); + const bool slaveAmatch = + !isMaster && (flags & SERCOM_I2CS_INTFLAG_AMATCH_Msk); +#else + const bool rxNack = status & SERCOM_I2CM_STATUS_RXNACK; + const bool wireError = flags & SERCOM_I2CM_INTFLAG_ERROR; + const bool slaveDrdy = !isMaster && (flags & SERCOM_I2CS_INTFLAG_DRDY); + const bool slavePrec = + !isMaster && (flags & SERCOM_I2CS_INTFLAG_PREC); + const bool slaveAmatch = + !isMaster && (flags & SERCOM_I2CS_INTFLAG_AMATCH); +#endif // __SAME53__ / __SAME54__ + + SercomTxn *activeTxn = sercom->getCurrentTxnWIRE(); + const bool rxSlaveNack = + rxNack && activeTxn && (activeTxn->config & I2C_CFG_READ) != 0; + const bool isRxNack = isMaster ? rxNack : rxSlaveNack; + +#if defined(__SAME53__) || defined(__SAME54__) + const bool busError = status & SERCOM_I2CM_STATUS_BUSERR_Msk; +#else + const bool busError = status & SERCOM_I2CM_STATUS_BUSERR; +#endif // __SAME53__ / __SAME54__ + const uint8_t busState = + (status & SERCOM_I2CM_STATUS_BUSSTATE_Msk) >> + SERCOM_I2CM_STATUS_BUSSTATE_Pos; + const bool slaveBusError = !isMaster && wireError && busError; + if (slaveBusError) { +#if defined(__SAME53__) || defined(__SAME54__) + sercom->clearStatusWIRE(SERCOM_I2CS_STATUS_BUSERR_Msk); + sercom->clearINTFLAG(SERCOM_I2CS_INTFLAG_ERROR_Msk); +#else + sercom->clearStatusWIRE(SERCOM_I2CS_STATUS_BUSERR); + sercom->clearINTFLAG(SERCOM_I2CS_INTFLAG_ERROR); +#endif // __SAME53__ / __SAME54__ + } + + if (slavePrec && !slaveAmatch) { + if (!sercom->isSlaveTransactionActiveWIRE()) { + sercom->clearINTFLAG(); + return; + } + const bool slaveTransmit = + activeTxn && (activeTxn->config & I2C_CFG_READ) != 0; +#ifdef USE_ZERODMA + if (slaveTransmit && sercom->dmaTxBusy()) + sercom->dmaAbortTx(); +#endif // USE_ZERODMA + if (slaveTransmit) + sercom->deferStopWIRE(SercomWireError::SUCCESS); + else if (activeTxn) + sercom->deferReceiveCompleteWIRE(); + else + sercom->clearINTFLAG(); + return; + } + + bool continueOwnedArbitration = false; + if (isRxNack || (wireError && !slaveBusError)) { + if (!isMaster && isRxNack) { +#ifdef USE_ZERODMA + if (sercom->dmaTxBusy()) + sercom->dmaAbortTx(); +#endif // USE_ZERODMA + sercom->deferStopWIRE(SercomWireError::NACK_ON_DATA); + return; + } +#if defined(__SAME53__) || defined(__SAME54__) + const bool arbitrationLost = status & SERCOM_I2CM_STATUS_ARBLOST_Msk; + const bool lowTimeout = status & SERCOM_I2CM_STATUS_LOWTOUT_Msk; + const bool slaveExtendTimeout = status & SERCOM_I2CM_STATUS_SEXTTOUT_Msk; + const bool masterExtendTimeout = + isMaster && (status & SERCOM_I2CM_STATUS_MEXTTOUT_Msk); + const bool lengthError = + isMaster && (status & SERCOM_I2CM_STATUS_LENERR_Msk); +#else + const bool arbitrationLost = status & SERCOM_I2CM_STATUS_ARBLOST; + const bool lowTimeout = status & SERCOM_I2CM_STATUS_LOWTOUT; + const bool slaveExtendTimeout = status & SERCOM_I2CM_STATUS_SEXTTOUT; + const bool masterExtendTimeout = + isMaster && (status & SERCOM_I2CM_STATUS_MEXTTOUT); + const bool lengthError = isMaster && (status & SERCOM_I2CM_STATUS_LENERR); +#endif // __SAME53__ / __SAME54__ + const bool masterTimeout = isMaster && (masterExtendTimeout || lowTimeout); + const bool slaveTimeout = slaveExtendTimeout || (!isMaster && lowTimeout); + const bool terminalCondition = + isRxNack || masterTimeout || slaveTimeout || lengthError; + const bool arbitrationOnly = !isRxNack && !busError && !masterTimeout && + !slaveTimeout && !lengthError; + + bool commandReady = false; +#if defined(__SAME53__) || defined(__SAME54__) + commandReady = + (flags & (SERCOM_I2CM_INTFLAG_MB_Msk | SERCOM_I2CM_INTFLAG_SB_Msk)) != + 0u; +#else + commandReady = + (flags & (SERCOM_I2CM_INTFLAG_MB | SERCOM_I2CM_INTFLAG_SB)) != 0u; +#endif // __SAME53__ / __SAME54__ + + if (isMaster && busError) { + const auto capturedBusState = + static_cast(busState); + const bool replayAllowed = + activeTxn && (activeTxn->config & I2C_CFG_REPLAY_SAFE); + const auto busErrorAction = simio::wire::decideBusErrorAction( + {true, capturedBusState, arbitrationLost, commandReady, + terminalCondition, + replayAllowed, activeTxn != nullptr}); + if (busErrorAction != simio::wire::BusErrorAction::RetireAmbiguous && + busErrorAction != simio::wire::BusErrorAction::RetireTerminal) { +#if defined(__SAME53__) || defined(__SAME54__) + sercom->clearStatusWIRE(SERCOM_I2CM_STATUS_BUSERR_Msk | + SERCOM_I2CM_STATUS_ARBLOST_Msk); + sercom->clearINTFLAG(SERCOM_I2CM_INTFLAG_ERROR_Msk); +#else + sercom->clearStatusWIRE(SERCOM_I2CM_STATUS_BUSERR | + SERCOM_I2CM_STATUS_ARBLOST); + sercom->clearINTFLAG(SERCOM_I2CM_INTFLAG_ERROR); +#endif // __SAME53__ / __SAME54__ + sercom->deferBusErrorRecoveryWIRE(arbitrationLost, commandReady); + return; + } + } + + if (isMaster && arbitrationLost && !busError) { + if (busState == WIRE_OWNER_STATE && arbitrationOnly) { + // ARBLOST normally transitions OWNER to BUSY. If OWNER remains set, + // rewriting ADDR would request a repeated START and restart a + // transaction that the hardware still owns. Clear only the error + // indications and preserve MB/SB so normal master service continues. +#if defined(__SAME53__) || defined(__SAME54__) + sercom->clearStatusWIRE(SERCOM_I2CM_STATUS_ARBLOST_Msk); + sercom->clearINTFLAG(SERCOM_I2CM_INTFLAG_ERROR_Msk); +#else + sercom->clearStatusWIRE(SERCOM_I2CM_STATUS_ARBLOST); + sercom->clearINTFLAG(SERCOM_I2CM_INTFLAG_ERROR); +#endif // __SAME53__ / __SAME54__ + continueOwnedArbitration = true; + } else { +#ifdef USE_ZERODMA + sercom->dmaAbortTx(); + sercom->dmaAbortRx(); + sercom->setDmaWIRE(false); #endif + // Arbitration loss releases SDA and SCL. Re-arm the same queue head by + // writing ADDR again. ADDR clears ARBLOST; when another master still + // owns the bus, SERCOM remains in BUSY and waits for IDLE before START. + sercom->clearINTFLAG(); + awaitingAddressAck = true; + sercom->startTransmissionWIRE(); + return; + } + } + + if (!continueOwnedArbitration) { + SercomWireError error = SercomWireError::UNKNOWN_ERROR; + + if (isRxNack) { + error = isMaster && awaitingAddressAck + ? SercomWireError::NACK_ON_ADDRESS + : SercomWireError::NACK_ON_DATA; + } else if (masterTimeout) { + error = SercomWireError::MASTER_TIMEOUT; + } else if (slaveTimeout) { + error = SercomWireError::SLAVE_TIMEOUT; + } else if (lengthError) { + error = SercomWireError::LENGTH_ERROR; + } else if (busError) { + error = SercomWireError::BUS_ERROR; + } else if (isMaster) { + if (busState == WIRE_UNKNOWN_STATE) + error = SercomWireError::BUS_STATE_UNKNOWN; + } + + if (isMaster && !arbitrationLost) + sercom->prepareCommandBitsWIRE(WIRE_MASTER_ACT_STOP); + if (wireError) + sercom->clearINTFLAG(); + sercom->deferStopWIRE(error); + return; + } + } + + if (isMaster) { + SercomTxn *txn = activeTxn; + if (!txn) { + sercom->clearINTFLAG(); + return; + } + + bool isRead = (txn->config & I2C_CFG_READ); + + if (sercom->getTxnIndexWIRE() < sercom->getTxnLengthWIRE()) { + bool more = isRead ? sercom->readDataWIRE() : sercom->sendDataWIRE(); + awaitingAddressAck = false; + if (!isRead || more) + return; + } + + if ((txn->config & I2C_CFG_STOP) && !isRead) + sercom->prepareCommandBitsWIRE(WIRE_MASTER_ACT_STOP); + else + sercom->clearINTFLAG(); + + awaitingAddressAck = true; + sercom->deferStopWIRE(SercomWireError::SUCCESS); + return; + } else { +#if defined(__SAME53__) || defined(__SAME54__) + bool isMasterRead = (status & SERCOM_I2CS_STATUS_DIR_Msk); + bool prec = slavePrec; + bool amatch = slaveAmatch; +#else + bool isMasterRead = + (status & SERCOM_I2CS_STATUS_DIR); // Master Read / Slave Transmit + bool prec = slavePrec; // Stop detected + bool amatch = slaveAmatch; // Address Match detected +#endif // __SAME53__ / __SAME54__ + + // A new address match terminates an active slave receive even when the + // master uses a repeated START instead of STOP. Queue receive completion + // before the follow-up setup so a combined write/read transaction publishes + // its request bytes before onRequest prepares the response. + if (amatch) { + // PREC can arrive with the next AMATCH when the preceding transaction's + // STOP is recognized just before a new address. It belongs to the + // completed transaction and must not retire the transaction started by + // this address match. + if (prec) { +#if defined(__SAME53__) || defined(__SAME54__) + sercom->clearINTFLAG(SERCOM_I2CS_INTFLAG_PREC_Msk); +#else + sercom->clearINTFLAG(SERCOM_I2CS_INTFLAG_PREC); +#endif // __SAME53__ / __SAME54__ + } + if (!sercom->isSlaveTransactionActiveWIRE()) { + sercom->discardIdleSlaveTransactionWIRE(); + activeTxn = sercom->getCurrentTxnWIRE(); + } + const bool activeReceive = + sercom->isSlaveTransactionActiveWIRE() && activeTxn && + (activeTxn->config & I2C_CFG_READ) == 0; + if (activeReceive) { +#if defined(__SAME53__) || defined(__SAME54__) + sercom->disableInterrupts(SERCOM_I2CS_INTENCLR_AMATCH_Msk); +#else + sercom->disableInterrupts(SERCOM_I2CS_INTENCLR_AMATCH); +#endif // __SAME53__ / __SAME54__ + if (isMasterRead) + sercom->deferRequestWIRE(); + else + sercom->deferReceiveWIRE(); + sercom->deferReceiveCompleteWIRE(); + return; + } + sercom->markSlaveTransactionActiveWIRE(); + if (isMasterRead) { +#if defined(__SAME53__) || defined(__SAME54__) + sercom->disableInterrupts(SERCOM_I2CS_INTENCLR_AMATCH_Msk); +#else + sercom->disableInterrupts(SERCOM_I2CS_INTENCLR_AMATCH); +#endif // __SAME53__ / __SAME54__ + sercom->deferRequestWIRE(); + } else { + prepareSlaveReceive(); + sercom->setTxnWIRE(&slaveTxn); + sercom->startTransmissionWIRE(); + } + return; + } + + // Preserve the interrupt-driven slave byte engine both when DMA is not + // compiled and when this transaction is not DMA-eligible. + if (slaveDrdy && !amatch && !sercom->isDmaWIRE()) { + SercomTxn *slaveTxn = activeTxn; + if (!slaveTxn) { + sercom->clearINTFLAG(); + return; + } + + if (slaveTxn->config & I2C_CFG_READ) { + if (sercom->getTxnIndexWIRE() < sercom->getTxnLengthWIRE()) + sercom->sendDataWIRE(); + else { + sercom->prepareSlaveCommandBitsWIRE(WIRE_SLAVE_ACT_COMPLETE); + sercom->deferStopWIRE(SercomWireError::SUCCESS); + } + } else if (sercom->getTxnIndexWIRE() < sercom->getTxnLengthWIRE()) { + sercom->readDataWIRE(); + } else { + sercom->prepareNackBitWIRE(); + } + return; + } + + } +} #endif diff --git a/libraries/Wire/examples/slave_receiver/slave_receiver.ino b/libraries/Wire/examples/slave_receiver/slave_receiver.ino index a3103f8b9..b1430051b 100644 --- a/libraries/Wire/examples/slave_receiver/slave_receiver.ino +++ b/libraries/Wire/examples/slave_receiver/slave_receiver.ino @@ -14,7 +14,7 @@ void setup() { - Wire.begin(4); // join i2c bus with address #4 + Wire.begin((uint8_t)4); // join i2c bus with address #4 Wire.onReceive(receiveEvent); // register event Serial.begin(9600); // start serial for output } @@ -29,7 +29,7 @@ void loop() void receiveEvent(int howMany) { (void)howMany; // avoid compiler warning about unused parameter - + while(1 < Wire.available()) // loop through all but the last { char c = Wire.read(); // receive byte as a character diff --git a/libraries/Wire/examples/slave_sender/slave_sender.ino b/libraries/Wire/examples/slave_sender/slave_sender.ino index d3b238af9..34f44be9d 100644 --- a/libraries/Wire/examples/slave_sender/slave_sender.ino +++ b/libraries/Wire/examples/slave_sender/slave_sender.ino @@ -14,7 +14,7 @@ void setup() { - Wire.begin(2); // join i2c bus with address #2 + Wire.begin((uint8_t)2); // join i2c bus with address #2 Wire.onRequest(requestEvent); // register event } diff --git a/package.json b/package.json new file mode 100644 index 000000000..b2a4a76b5 --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "framework-arduino-samd-adafruit", + "version": "1.7.16", + "description": "Arduino Wiring-based framework for Microchip SAM D and SAME microcontrollers.", + "keywords": [ + "framework", + "arduino", + "microchip", + "samd", + "same" + ], + "license": "LGPL-2.1-or-later", + "repository": { + "type": "git", + "url": "https://github.com/adafruit/ArduinoCore-samd" + } +} diff --git a/tools/generate_pinmux_inc.py b/tools/generate_pinmux_inc.py new file mode 100644 index 000000000..6a657d02b --- /dev/null +++ b/tools/generate_pinmux_inc.py @@ -0,0 +1,627 @@ +#!/usr/bin/env python3 +""" +Generate SercomPinMux.inc from SAMD21/DA1 and SAMD51/E5x device tables. + +Workflow: +1. Load device-to-package mappings from Tables 2-1, 2-2 (SAMD21/DA1) and 1-1, 1-2 (SAMD51/E5x) +2. Load I2C pin configurations from Tables 7-5 (SAMD21/DA1) and 6-8 (SAMD5x/E5x) +3. For each pin, parse columns C and D to extract primary/alternate SERCOM+PAD +4. Group devices by series and emit guard blocks with I2C_PIN macros + +Emits: + cores/arduino/SercomPinMux.inc + +Each pin entry: + SERCOM_I2C_PIN(PA08, 0, 0, 2, 1) +where arguments are (pin, primary_sercom, primary_pad, alt_sercom, alt_pad). +If an alternate SERCOM is missing, alt_sercom/pad are set to 255. +""" +from __future__ import annotations + +import csv +import re +from pathlib import Path +from typing import Dict, List, Set, Tuple + +ROOT = Path(__file__).resolve().parent.parent +DATA_DIR = ROOT / "extras" / "wirepinmux" +SERCOM_OUTPUT = ROOT / "cores" / "arduino" / "SercomPinMux.inc" + +# Device-to-package mapping CSVs +SAMD21_TABLE_2_1 = DATA_DIR / "SAMD21_Table_2-1.csv" +SAMD21_TABLE_2_2 = DATA_DIR / "SAMD21_Table_2-2.csv" +SAMD51_TABLE_1_1 = DATA_DIR / "SAMD51_Table_1-1.csv" +SAMD51_TABLE_1_2 = DATA_DIR / "SAMD51_Table_1-2.csv" + +# I2C pin configuration CSVs +SAMD21_TABLE_7_5 = DATA_DIR / "SAMD21_Table_7-5.csv" +SAMD51_TABLE_6_8 = DATA_DIR / "SAMD51_Table_6-8.csv" + +# Full pin mux tables (SERCOM column C/D) +SAMD21_TABLE_7_1 = DATA_DIR / "SAMD21_Table_7-1.csv" +SAMD51_TABLE_6_1 = DATA_DIR / "SAMD51_Table_6-1.csv" + +# Regex patterns +SERCOM_PAD_RE = re.compile(r"SERCOM(\d+)/PAD\[(\d+)\]") + +# Fallback when alt is missing +NO_ALT = (255, 255) + + +def load_csv(path: Path, skip_rows: int = 0) -> List[Dict[str, str]]: + """Load CSV file and return list of row dictionaries.""" + with path.open(newline="", encoding="utf-8-sig") as f: # utf-8-sig removes BOM + # Skip header rows if needed + for _ in range(skip_rows): + next(f) + return list(csv.DictReader(f)) + + +def parse_sercom_pad(text: str) -> Tuple[int, int] | None: + """Parse 'SERCOM0/PAD[0]' -> (0, 0), return None if not found.""" + if not text or text.strip() == "": + return None + m = SERCOM_PAD_RE.search(text) + if m: + return (int(m.group(1)), int(m.group(2))) + return None + + +def load_device_pin_map( + csv_paths: List[Tuple[Path, int]], +) -> Dict[str, Set[str]]: + """ + Load device-to-package tables and return device -> set of pins mapping. + + For SAMD21/DA1 (Tables 2-1, 2-2): 'Pins' column indicates package size (32, 48, 64). + For SAMD51/E5x (Tables 1-1, 1-2): 'Pins' column indicates package size (48, 64, 100, 120/128). + + Args: + csv_paths: List of (path, skip_rows) tuples + + We'll cross-reference with the I2C pin tables (7-5, 6-8) which list pins by package size. + """ + device_to_pins: Dict[str, Set[str]] = {} + + for csv_path, skip_rows in csv_paths: + rows = load_csv(csv_path, skip_rows=skip_rows) + for row in rows: + device = row.get("Device", "").strip() + pins_str = row.get("Pins", "").strip() + + if not device or not pins_str: + continue + + # Extract numeric pin count + try: + pin_count = int(pins_str) + except ValueError: + continue + + device_to_pins[device] = {str(pin_count)} + + return device_to_pins + + +def load_i2c_pins_samd21(csv_path: Path) -> Dict[str, List[str]]: + """Load I2C pin list by package from Table 7-5 (SAMD21/DA1).""" + package_to_pins: Dict[str, List[str]] = {} + + rows = load_csv(csv_path) + for row in rows: + package = row.get("Device", "").strip() + if not package: + continue + + pin_tokens: List[str] = [] + for key, val in row.items(): + if key == "Device": + continue + if val is None: + continue + values = val if isinstance(val, list) else [val] + for v in values: + token = v.strip() + if not token: + continue + pin_tokens.extend(t.strip() for t in token.split(",") if t.strip()) + + if not pin_tokens: + continue + + package_to_pins[package] = pin_tokens + + return package_to_pins + + +def load_i2c_pins_samd51(csv_path: Path) -> Dict[str, List[str]]: + """ + Load I2C pin list by package from Table 6-8 (SAMD5x/E5x). + + Each device can have multiple rows (different supplies). Merge pin lists per device: + - VDDIOB rows (if any) come first + - then other supplies (e.g., VDDIO) + Pins are de-duplicated preserving first-seen order. + Returns: package_size -> [pin_names] + """ + package_to_pins: Dict[str, List[str]] = {} + rows = load_csv(csv_path) + + # Collect per-device rows keyed by (device, supply_order) + per_device: Dict[str, List[Tuple[int, List[str]]]] = {} + for row in rows: + device = row.get("Device", "").strip() + supply = row.get("Supply", "").strip().upper() + # Gather pin tokens from all remaining columns (some rows spread pins across columns) + pin_tokens: List[str] = [] + for key, val in row.items(): + if key in {"Device", "Supply"}: + continue + if val is None: + continue + values = val if isinstance(val, list) else [val] + for v in values: + token = v.strip() + if not token: + continue + pin_tokens.extend(t.strip() for t in token.split(",") if t.strip()) + + if not device or not pin_tokens: + continue + pin_names = pin_tokens + + # Order supplies: VDDIOB first (0), others after (1) + supply_order = 0 if supply == "VDDIOB" else 1 + per_device.setdefault(device, []).append((supply_order, pin_names)) + + # Merge per device + for device, pin_lists in per_device.items(): + # Sort by supply order so VDDIOB pins precede + pin_lists.sort(key=lambda x: x[0]) + merged: List[str] = [] + seen: Set[str] = set() + for _, pins in pin_lists: + for pin in pins: + if pin not in seen: + seen.add(pin) + merged.append(pin) + package_to_pins[device] = merged + + return package_to_pins + + +def load_pin_mux_configs( + csv_path: Path, is_samd51: bool = False +) -> Dict[str, Tuple[int, int, int, int]]: + """ + Load pin multiplexing configuration from Table 7-1 (SAMD21) or 6-1 (SAMD51). + + Returns: pin_name -> (primary_sercom, primary_pad, alt_sercom, alt_pad) + + For SAMD21 Table 7-1: columns are organized with column C (primary) and D (alt) for SERCOM + For SAMD51 Table 6-1: columns C (primary) and D (alt) for SERCOM + + Special case: Some pins only have alternate SERCOM (column D only, no column C). + For these, we store them with 255,255 as primary and the SERCOM from D as alternate. + """ + pin_configs: Dict[str, Tuple[int, int, int, int]] = {} + + rows = load_csv(csv_path) + for row in rows: + # Pin name is in 'I/O Pin' column for SAMD21, 'Pad Name' for SAMD51 + pin_name = row.get("Pad Name" if is_samd51 else "I/O Pin", "").strip() + + if not pin_name or not pin_name.startswith("P"): + continue + + # Column C is primary SERCOM, column D is alternate SERCOM + col_c = row.get("C", "").strip() + col_d = row.get("D", "").strip() + + primary = parse_sercom_pad(col_c) + alt = parse_sercom_pad(col_d) + + if primary: + # Pin has primary SERCOM (column C) + primary_sercom, primary_pad = primary + alt_sercom, alt_pad = alt if alt else NO_ALT + pin_configs[pin_name] = (primary_sercom, primary_pad, alt_sercom, alt_pad) + elif alt: + # Pin only has alternate SERCOM (column D only, no column C) + # Store as: no primary (255,255), alternate from column D + alt_sercom, alt_pad = alt + pin_configs[pin_name] = (NO_ALT[0], NO_ALT[1], alt_sercom, alt_pad) + + return pin_configs + + +def pin_name_to_port_pin(pin_name: str) -> Tuple[str, int]: + """Convert pin label like PA08 -> ('A', 8).""" + pin_name = pin_name.strip().upper() + if len(pin_name) < 4 or pin_name[0] != "P": + raise ValueError(f"Unsupported pin format: {pin_name}") + return pin_name[1], int(pin_name[2:]) + + +def macro_candidates(dev: str) -> List[str]: + """ + Return CMSIS sam.h device macros for a device name. + + CMSIS sam.h accepts both stripped and AT-prefixed forms for the selected + device. SAMD51/E5x datasheet tables omit the revision suffix, while the + CMSIS device selectors include it. + + Examples: + ATSAMD21E18A → __SAMD21E18A__ + ATSAMDA1E14B → __SAMDA1E14B__ + SAMD51J19 → __SAMD51J19A__ or __ATSAMD51J19A__ + SAME53N20 → __SAME53N20A__ or __ATSAME53N20A__ + """ + dev_upper = dev.upper() + # Strip "AT" prefix if present (ATSAMD21E18A → SAMD21E18A) + if dev_upper.startswith("AT"): + dev_upper = dev_upper[2:] + + if re.match(r"SAM[DE]5[134][GJNP]\d\d$", dev_upper): + dev_upper = f"{dev_upper}A" + + return [f"__{dev_upper}__", f"__AT{dev_upper}__"] + + +def classify_device_series(device: str, pin_count: str) -> str: + """ + Classify device into series based on family and package. + + Returns series macro name like "SAMD21E_SERIES", "SAMD51_120_SERIES", etc. + """ + dev_upper = device.upper() + + # Remove "AT" prefix if present + if dev_upper.startswith("AT"): + dev_upper = dev_upper[2:] + + # SAMD21/DA1 classification by letter (E, G, J) + if dev_upper.startswith("SAMD21E"): + return "SAMD21E_SERIES" + elif dev_upper.startswith("SAMD21G"): + return "SAMD21G_SERIES" + elif dev_upper.startswith("SAMD21J"): + return "SAMD21J_SERIES" + elif dev_upper.startswith("SAMDA1"): + return "SAMDA1_SERIES" + + # SAMD51/E5x classification by pin count + # 120/128-pin packages have 5 SERCOMs (with PD08/PD09) + # Others have 4 SERCOMs + pin_num = int(pin_count) if pin_count.isdigit() else 0 + + if dev_upper.startswith("SAMD51"): + if pin_num >= 120: + return "SAMD51_120_SERIES" + else: + return "SAMD51_SERIES" + elif dev_upper.startswith("SAME51"): + return "SAME51_SERIES" + elif dev_upper.startswith("SAME53"): + return "SAME53_SERIES" + elif dev_upper.startswith("SAME54"): + if pin_num >= 120: + return "SAME54_120_SERIES" + else: + return "SAME54_SERIES" + + return "UNKNOWN_SERIES" + + +def build_series_map() -> ( + Dict[str, Tuple[List[str], List[Tuple[str, Tuple[int, int, int, int]]]]] +): + """ + Build series -> (devices, pins) mapping. + + Returns: { + "SAMD21E_SERIES": ([device_names], [(pin, (s0, p0, s1, p1))]) + } + """ + series_map: Dict[ + str, Tuple[List[str], List[Tuple[str, Tuple[int, int, int, int]]]] + ] = {} + + # Load device-to-package mappings (with skip_rows for header lines) + device_pins_samd21 = load_device_pin_map( + [ + (SAMD21_TABLE_2_1, 2), # Skip 2 header rows + (SAMD21_TABLE_2_2, 1), # Skip 1 header row + ] + ) + device_pins_samd51 = load_device_pin_map( + [ + (SAMD51_TABLE_1_1, 2), # Skip 2 header rows (table title + subheader) + (SAMD51_TABLE_1_2, 2), # Skip 2 header rows (table title + subheader) + ] + ) + + # Load I2C pin configurations by package + i2c_pins_samd21 = load_i2c_pins_samd21(SAMD21_TABLE_7_5) + i2c_pins_samd51 = load_i2c_pins_samd51(SAMD51_TABLE_6_8) + + # Load pin mux configurations (SERCOM mappings from columns C/D) + pin_mux_samd21 = load_pin_mux_configs(SAMD21_TABLE_7_1, is_samd51=False) + pin_mux_samd51 = load_pin_mux_configs(SAMD51_TABLE_6_1, is_samd51=True) + + # Process SAMD21/DA1 devices + for device, pin_counts in device_pins_samd21.items(): + pin_count = list(pin_counts)[0] # Get the pin count + series = classify_device_series(device, pin_count) + + if series not in series_map: + series_map[series] = ([], []) + + series_map[series][0].append(device) + + # Get I2C pins for this package size + if pin_count in i2c_pins_samd21: + pin_list = i2c_pins_samd21[pin_count] + # Resolve SERCOM configs from mux table + resolved_pins = [] + for pin_name in pin_list: + if pin_name in pin_mux_samd21: + resolved_pins.append((pin_name, pin_mux_samd21[pin_name])) + + # Only set pins for the first device in series (all same series share pins) + if not series_map[series][1]: + series_map[series] = (series_map[series][0], resolved_pins) + + # Process SAMD51/E5x devices + for device, pin_counts in device_pins_samd51.items(): + pin_count = list(pin_counts)[0] + series = classify_device_series(device, pin_count) + + if series not in series_map: + series_map[series] = ([], []) + + series_map[series][0].append(device) + + # Get I2C pins for this package size + if pin_count in i2c_pins_samd51: + pin_list = i2c_pins_samd51[pin_count] + # Resolve SERCOM configs from mux table + resolved_pins = [] + for pin_name in pin_list: + if pin_name in pin_mux_samd51: + resolved_pins.append((pin_name, pin_mux_samd51[pin_name])) + + # Only set pins for the first device in series + if not series_map[series][1]: + series_map[series] = (series_map[series][0], resolved_pins) + + return series_map + + +def format_series_macro(series_name: str, device_macros: List[str]) -> List[str]: + """ + Format a series macro with intelligent grouping. + + For SAMD21, group by numeric suffix (15, 16, 17, 18). + For SAMD51/E5x, group by letter prefix (G, J, N, P). + + Returns list of lines including #ifndef, #define, content lines, #endif. + """ + lines: List[str] = [] + lines.append(f"#ifndef {series_name}") + + if len(device_macros) == 1: + lines.append(f"#define {series_name} (defined({device_macros[0]}))") + else: + # Group devices by their variant (numeric for SAMD21, letter for SAMD51/E5x) + groups: Dict[str, List[str]] = {} + + for macro in sorted(device_macros): + # Extract the device name from __DEVICENAME__ + device_name = macro.strip("_") + + # For SAMD21/DA1: extract numeric suffix (15, 16, 17, 18, 14, etc.) + # Examples: SAMD21E15A -> "15", SAMDA1E14B -> "14", SAMD21J18A -> "18" + # Match: (SAMD21|SAMDA1)([DEGJ]?)(\d+) + if "SAMD21" in device_name or "SAMDA1" in device_name: + # Extract the number that appears after the family letter (E, G, J) + match = re.search(r"(SAMD21|SAMDA1)([DEGJ]?)(\d+)", device_name) + if match: + suffix = match.group(3) # "15", "16", "14", etc. + else: + suffix = "unknown" + # For SAMD51/E5x: extract letter prefix (G, J, N, P) + # Examples: SAMD51G18 -> "G", SAME51J19 -> "J" + else: + match = re.search(r"(SAM[DE]\d+)([A-Z])\d+", device_name) + if match: + suffix = match.group(2) # "G", "J", "N", etc. + else: + suffix = "unknown" + + if suffix not in groups: + groups[suffix] = [] + groups[suffix].append(macro) + + # Sort groups by their key (numeric or letter order) + sorted_groups = sorted(groups.items(), key=lambda x: x[0]) + + # Build macro output with proper line continuations + output_lines = [] + for group_idx, (suffix, macros) in enumerate(sorted_groups): + is_last = group_idx == len(sorted_groups) - 1 + group_line = " || ".join(f"defined({m})" for m in macros) + + if group_idx == 0: + # First group: start the macro + if is_last: + # Only one group + output_lines.append(f"#define {series_name} ({group_line})") + else: + # Multiple groups + output_lines.append(f"#define {series_name} ({group_line} || \\") + else: + # Continuation lines + if is_last: + # Last group + output_lines.append(f" {group_line})") + else: + # Middle group + output_lines.append(f" {group_line} || \\") + + lines.extend(output_lines) + + lines.append(f"#endif // {series_name}") + return lines + + +SERIES_ORDER = { + "SAMD21E_SERIES": 0, + "SAMD21G_SERIES": 1, + "SAMD21J_SERIES": 2, + "SAMDA1_SERIES": 3, + "SAMD51_120_SERIES": 4, + "SAMD51_SERIES": 5, + "SAME51_SERIES": 5, + "SAME53_SERIES": 5, + "SAME54_SERIES": 5, + "SAME54_120_SERIES": 6, +} + + +def emit_series_macros( + series_map: Dict[str, Tuple[List[str], List[Tuple[str, Tuple[int, int, int, int]]]]], +) -> List[str]: + lines: List[str] = [] + for series_name in sorted(series_map.keys(), key=lambda s: (SERIES_ORDER.get(s, 999), s)): + devices, _ = series_map[series_name] + device_checks: List[str] = [] + for dev in sorted(set(devices)): + device_checks.extend(macro_candidates(dev)) + + seen: Set[str] = set() + unique_checks: List[str] = [] + for check in device_checks: + if check not in seen: + seen.add(check) + unique_checks.append(check) + + lines.extend(format_series_macro(series_name, unique_checks)) + lines.append("") + + lines.append("#if !defined(__SAMD51__) && !defined(__SAME51__) && !defined(__SAME53__) && !defined(__SAME54__)") + lines.append("#if !(SAMD21E_SERIES || SAMD21G_SERIES || SAMD21J_SERIES || SAMDA1_SERIES)") + lines.append("#define SAMD21E_SERIES 1") + lines.append("#endif // !(SAMD21E_SERIES || SAMD21G_SERIES || SAMD21J_SERIES || SAMDA1_SERIES)") + lines.append("#endif // !__SAMD51__ / __SAME51__ && !__SAME53__ / __SAME54__") + lines.append("#if defined(__SAMD51__) || defined(__SAME51__)") + lines.append("#if !(SAMD51_SERIES || SAMD51_120_SERIES || SAME51_SERIES)") + lines.append("#define SAMD51_SERIES 1") + lines.append("#endif // !(SAMD51_SERIES || SAMD51_120_SERIES || SAME51_SERIES)") + lines.append("#endif // __SAMD51__ / __SAME51__") + lines.append("#if defined(__SAME53__) || defined(__SAME54__)") + lines.append("#if !(SAME53_SERIES || SAME54_SERIES || SAME54_120_SERIES)") + lines.append("#define SAME54_SERIES 1") + lines.append("#endif // !(SAME53_SERIES || SAME54_SERIES || SAME54_120_SERIES)") + lines.append("#endif // __SAME53__ / __SAME54__") + lines.append("") + return lines + + +def emit_i2c_entries( + series_map: Dict[str, Tuple[List[str], List[Tuple[str, Tuple[int, int, int, int]]]]], +) -> List[str]: + lines: List[str] = [] + pin_config_groups: Dict[Tuple, List[str]] = {} + for series_name, (_, pins) in series_map.items(): + pin_tuple = tuple((p, s0, p0, s1, p1) for p, (s0, p0, s1, p1) in pins) + pin_config_groups.setdefault(pin_tuple, []).append(series_name) + + sorted_groups = sorted( + pin_config_groups.items(), + key=lambda x: (SERIES_ORDER.get(sorted(x[1])[0], 999), sorted(x[1])[0]), + ) + + for pin_config, series_list in sorted_groups: + guard_expr = " || ".join(sorted(series_list)) + lines.append(f"#if {guard_expr}") + for pin_name, s0, p0, s1, p1 in pin_config: + port, pin = pin_name_to_port_pin(pin_name) + lines.append(f"SERCOM_I2C_PIN('{port}', {pin}, {s0}, {p0}, {s1}, {p1})") + lines.append(f"#endif // {guard_expr}\n") + return lines + + +def build_spi_series_map( + series_map: Dict[str, Tuple[List[str], List[Tuple[str, Tuple[int, int, int, int]]]]], +) -> Dict[str, List[Tuple[str, Tuple[int, int, int, int]]]]: + """Build SPI MOSI-capable pin configs per series.""" + pin_mux_samd21 = load_pin_mux_configs(SAMD21_TABLE_7_1, is_samd51=False) + pin_mux_samd51 = load_pin_mux_configs(SAMD51_TABLE_6_1, is_samd51=True) + + result: Dict[str, List[Tuple[str, Tuple[int, int, int, int]]]] = {} + for series_name in series_map.keys(): + family_mux = pin_mux_samd51 if ("SAMD51" in series_name or "SAME" in series_name) else pin_mux_samd21 + pins: List[Tuple[str, Tuple[int, int, int, int]]] = [] + for pin_name, cfg in sorted(family_mux.items()): + s0, p0, s1, p1 = cfg + # MOSI can be PAD 0, 2, or 3. Keep entries where at least one route is MOSI-capable. + if ((s0 != 255 and p0 in (0, 2, 3)) or (s1 != 255 and p1 in (0, 2, 3))): + pins.append((pin_name, cfg)) + result[series_name] = pins + return result + + +def emit_spi_entries( + series_map: Dict[str, Tuple[List[str], List[Tuple[str, Tuple[int, int, int, int]]]]], + spi_series_map: Dict[str, List[Tuple[str, Tuple[int, int, int, int]]]], +) -> List[str]: + lines: List[str] = [] + for series_name in sorted(spi_series_map.keys(), key=lambda s: (SERIES_ORDER.get(s, 999), s)): + lines.append(f"#if {series_name}") + for pin_name, (s0, p0, s1, p1) in spi_series_map[series_name]: + port, pin = pin_name_to_port_pin(pin_name) + lines.append(f"SERCOM_SPI_PIN('{port}', {pin}, {s0}, {p0}, {s1}, {p1})") + lines.append(f"#endif // {series_name}\n") + return lines + + +def emit_sercom_inc( + series_map: Dict[str, Tuple[List[str], List[Tuple[str, Tuple[int, int, int, int]]]]], + spi_series_map: Dict[str, List[Tuple[str, Tuple[int, int, int, int]]]], +) -> str: + lines: List[str] = [] + lines.append("// Auto-generated from SAMD21/SAMD51 device tables. Do not edit manually.") + lines.append("// Define SERCOM_PINMUX_EMIT_I2C and/or SERCOM_PINMUX_EMIT_SPI before including.") + lines.append("") + lines.extend(emit_series_macros(series_map)) + + lines.append("#if defined(SERCOM_PINMUX_EMIT_I2C)") + lines.extend(emit_i2c_entries(series_map)) + lines.append("#endif // SERCOM_PINMUX_EMIT_I2C") + lines.append("") + + lines.append("#if defined(SERCOM_PINMUX_EMIT_SPI)") + lines.extend(emit_spi_entries(series_map, spi_series_map)) + lines.append("#endif // SERCOM_PINMUX_EMIT_SPI") + lines.append("") + + return "\n".join(lines) + + +def main() -> None: + """Main entry point.""" + series_map = build_series_map() + spi_series_map = build_spi_series_map(series_map) + sercom_inc_text = emit_sercom_inc(series_map, spi_series_map) + + SERCOM_OUTPUT.write_text(sercom_inc_text) + + total_devices = sum(len(devices) for devices, _ in series_map.values()) + print( + f"Wrote SERCOM pinmux for {len(series_map)} series covering {total_devices} devices to {SERCOM_OUTPUT}" + ) + + +if __name__ == "__main__": + main() diff --git a/variants/arduino_mzero/variant.cpp b/variants/arduino_mzero/variant.cpp index 7c094b172..41b128474 100644 --- a/variants/arduino_mzero/variant.cpp +++ b/variants/arduino_mzero/variant.cpp @@ -203,15 +203,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom0, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; -Uart Serial( &sercom5, PIN_SERIAL_RX, PIN_SERIAL_TX, PAD_SERIAL_RX, PAD_SERIAL_TX ) ; -void SERCOM0_Handler() -{ - Serial1.IrqHandler(); -} - -void SERCOM5_Handler() -{ - Serial.IrqHandler(); -} diff --git a/variants/arduino_mzero/variant.h b/variants/arduino_mzero/variant.h index b48fde2ed..f24ad23c9 100755 --- a/variants/arduino_mzero/variant.h +++ b/variants/arduino_mzero/variant.h @@ -110,28 +110,30 @@ static const uint8_t DAC0 = PIN_DAC0; * Serial interfaces */ // Serial (EDBG) -#define PIN_SERIAL_RX (36ul) -#define PIN_SERIAL_TX (35ul) -#define PAD_SERIAL_TX (UART_TX_PAD_2) -#define PAD_SERIAL_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL_RX (36ul) +#define PIN_SERIAL_TX (35ul) +#define PAD_SERIAL_TX (UART_TX_PAD_2) +#define PAD_SERIAL_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL sercom5 // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_2) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL1 sercom0 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO (18u) -#define PIN_SPI_MOSI (21u) -#define PIN_SPI_SCK (20u) -#define PERIPH_SPI sercom4 -#define PAD_SPI_TX SPI_PAD_2_SCK_3 -#define PAD_SPI_RX SERCOM_RX_PAD_0 +#define PIN_SPI_MISO (18u) +#define PIN_SPI_MOSI (21u) +#define PIN_SPI_SCK (20u) +#define PERIPH_SPI sercom4 +#define PAD_SPI_TX SPI_PAD_2_SCK_3 +#define PAD_SPI_RX SERCOM_RX_PAD_0 static const uint8_t SS = 14; //GND static const uint8_t MOSI = PIN_SPI_MOSI; @@ -143,10 +145,9 @@ static const uint8_t SCK = PIN_SPI_SCK; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (16u) -#define PIN_WIRE_SCL (17u) -#define PERIPH_WIRE sercom3 -#define WIRE_IT_HANDLER SERCOM3_Handler +#define PIN_WIRE_SDA (16u) +#define PIN_WIRE_SCL (17u) +#define PERIPH_WIRE sercom3 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/arduino_zero/variant.cpp b/variants/arduino_zero/variant.cpp index dfbaf745a..de911f261 100644 --- a/variants/arduino_zero/variant.cpp +++ b/variants/arduino_zero/variant.cpp @@ -212,16 +212,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom0, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; -Uart Serial5( &sercom5, PIN_SERIAL_RX, PIN_SERIAL_TX, PAD_SERIAL_RX, PAD_SERIAL_TX ) ; -void SERCOM0_Handler() -{ - Serial1.IrqHandler(); -} - -void SERCOM5_Handler() -{ - Serial5.IrqHandler(); -} - diff --git a/variants/arduino_zero/variant.h b/variants/arduino_zero/variant.h index 196ef773b..307f39b14 100644 --- a/variants/arduino_zero/variant.h +++ b/variants/arduino_zero/variant.h @@ -117,28 +117,30 @@ static const uint8_t ATN = PIN_ATN; * Serial interfaces */ // Serial (EDBG) -#define PIN_SERIAL_RX (31ul) -#define PIN_SERIAL_TX (30ul) -#define PAD_SERIAL_TX (UART_TX_PAD_2) -#define PAD_SERIAL_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL_RX (31ul) +#define PIN_SERIAL_TX (30ul) +#define PAD_SERIAL_TX (UART_TX_PAD_2) +#define PAD_SERIAL_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL5 sercom5 // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_2) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL1 sercom0 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO (22u) -#define PIN_SPI_MOSI (23u) -#define PIN_SPI_SCK (24u) -#define PERIPH_SPI sercom4 -#define PAD_SPI_TX SPI_PAD_2_SCK_3 -#define PAD_SPI_RX SERCOM_RX_PAD_0 +#define PIN_SPI_MISO (22u) +#define PIN_SPI_MOSI (23u) +#define PIN_SPI_SCK (24u) +#define PERIPH_SPI sercom4 +#define PAD_SPI_TX SPI_PAD_2_SCK_3 +#define PAD_SPI_RX SERCOM_RX_PAD_0 static const uint8_t SS = PIN_A2 ; // SERCOM4 last PAD is present on A2 but HW SS isn't used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -150,10 +152,9 @@ static const uint8_t SCK = PIN_SPI_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (20u) -#define PIN_WIRE_SCL (21u) -#define PERIPH_WIRE sercom3 -#define WIRE_IT_HANDLER SERCOM3_Handler +#define PIN_WIRE_SDA (20u) +#define PIN_WIRE_SCL (21u) +#define PERIPH_WIRE sercom3 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/blm_badge/variant.cpp b/variants/blm_badge/variant.cpp index 805b6e262..1f1938468 100644 --- a/variants/blm_badge/variant.cpp +++ b/variants/blm_badge/variant.cpp @@ -85,11 +85,3 @@ SERCOM sercom0( SERCOM0 ) ; SERCOM sercom1( SERCOM1 ) ; SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; - -Uart Serial1( &sercom0, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM0_Handler() -{ - Serial1.IrqHandler(); -} - diff --git a/variants/blm_badge/variant.h b/variants/blm_badge/variant.h index dbee168d1..cceda8695 100644 --- a/variants/blm_badge/variant.h +++ b/variants/blm_badge/variant.h @@ -114,10 +114,11 @@ static const uint8_t DAC0 = PIN_DAC0; */ // Serial1 (sercom 0) -#define PIN_SERIAL1_RX (3ul) // captouch pad -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_2) -#define PIN_SERIAL1_TX (2ul) // captouch pad -#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PIN_SERIAL1_RX (3ul) // captouch pad +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_2) +#define PIN_SERIAL1_TX (2ul) // captouch pad +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL1 sercom0 /* * SPI Interfaces @@ -129,9 +130,9 @@ static const uint8_t DAC0 = PIN_DAC0; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (5u) -#define PIN_WIRE_SCL (6u) -#define PERIPH_WIRE sercom1 +#define PIN_WIRE_SDA (5u) +#define PIN_WIRE_SCL (6u) +#define PERIPH_WIRE sercom1 //#define WIRE_IT_HANDLER // hack! we call the i2c handler from within the serial handler! static const uint8_t SDA = PIN_WIRE_SDA; diff --git a/variants/circuitplay/variant.cpp b/variants/circuitplay/variant.cpp index 0e39cf35e..81aa3b247 100644 --- a/variants/circuitplay/variant.cpp +++ b/variants/circuitplay/variant.cpp @@ -61,7 +61,7 @@ const PinDescription g_APinDescription[]= { PORTA, 11, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG), ADC_Channel19, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_11 }, // A8 / Light Sensor { PORTA, 9, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER|PIN_ATTR_ANALOG), ADC_Channel17, PWM0_CH1, TCC0_CH1, EXTERNAL_INT_9 }, // A9 / Thermistor { PORTA, 4, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG), ADC_Channel4, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_4 }, // A10 Proximity - + // GPIO 25 / IR Transmit { PORTA, 23, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM4_CH1, TC4_CH1, EXTERNAL_INT_7 }, // GPIO D25 - IR Transmitter // GPIO 26 / IR Remote in @@ -89,7 +89,7 @@ const PinDescription g_APinDescription[]= // 36..38 - USB - // -------------------- + // -------------------- { PORTA, 22, PIO_SERCOM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // GPIO 29 - Host USB (not used) { PORTA, 24, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB/DM { PORTA, 25, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB/DP @@ -111,11 +111,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom4, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM4_Handler() -{ - Serial1.IrqHandler(); -} - diff --git a/variants/circuitplay/variant.h b/variants/circuitplay/variant.h index 7a0a5a55c..708ecc441 100644 --- a/variants/circuitplay/variant.h +++ b/variants/circuitplay/variant.h @@ -148,12 +148,12 @@ static const uint8_t DAC0 = PIN_DAC0; #define SPI_INTERFACES_COUNT 3 // SPI interface for QSPI flash -#define PIN_SPI_MISO (30u) -#define PIN_SPI_SCK (31u) -#define PIN_SPI_MOSI (32u) -#define PERIPH_SPI sercom3 -#define PAD_SPI_TX SPI_PAD_2_SCK_3 // MOSI / SCK -#define PAD_SPI_RX SERCOM_RX_PAD_0 // MISO +#define PIN_SPI_MISO (30u) +#define PIN_SPI_SCK (31u) +#define PIN_SPI_MOSI (32u) +#define PERIPH_SPI sercom3 +#define PAD_SPI_TX SPI_PAD_2_SCK_3 // MOSI / SCK +#define PAD_SPI_RX SERCOM_RX_PAD_0 // MISO static const uint8_t SS = 33 ; static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -162,12 +162,12 @@ static const uint8_t SCK = PIN_SPI_SCK ; // Extra hardware SPI for Gizmo -#define PIN_SPI1_SCK (40u) -#define PIN_SPI1_MOSI (39u) -#define PIN_SPI1_MISO (41u) -#define PERIPH_SPI1 sercom5 -#define PAD_SPI1_TX SPI_PAD_0_SCK_1 // MOSI / SCK -#define PAD_SPI1_RX SERCOM_RX_PAD_2 // MISO not avail +#define PIN_SPI1_SCK (40u) +#define PIN_SPI1_MOSI (39u) +#define PIN_SPI1_MISO (41u) +#define PERIPH_SPI1 sercom5 +#define PAD_SPI1_TX SPI_PAD_0_SCK_1 // MOSI / SCK +#define PAD_SPI1_RX SERCOM_RX_PAD_2 // MISO not avail static const uint8_t SS1 = 42 ; static const uint8_t MOSI1 = PIN_SPI_MOSI ; @@ -176,13 +176,13 @@ static const uint8_t SCK1 = PIN_SPI_SCK ; // Extra hardware for SD card -#define PIN_SPI2_SCK (10u) -#define PIN_SPI2_MOSI (9u) -#define PIN_SPI2_MISO (6u) -#define PIN_SPI2_SS (5u) -#define PERIPH_SPI2 sercom0 -#define PAD_SPI2_TX SPI_PAD_2_SCK_3 // MOSI / SCK -#define PAD_SPI2_RX SERCOM_RX_PAD_1 // MISO not avail +#define PIN_SPI2_SCK (10u) +#define PIN_SPI2_MOSI (9u) +#define PIN_SPI2_MISO (6u) +#define PIN_SPI2_SS (5u) +#define PERIPH_SPI2 sercom0 +#define PAD_SPI2_TX SPI_PAD_2_SCK_3 // MOSI / SCK +#define PAD_SPI2_RX SERCOM_RX_PAD_1 // MISO not avail static const uint8_t SS2 = 5 ; static const uint8_t MOSI2 = PIN_SPI2_MOSI ; @@ -203,18 +203,16 @@ static const uint8_t SCK2 = PIN_SPI2_SCK ; #define WIRE_INTERFACES_COUNT 2 // "external" public i2c interface -#define PIN_WIRE_SDA (2u) -#define PIN_WIRE_SCL (3u) -#define PERIPH_WIRE sercom5 -#define WIRE_IT_HANDLER SERCOM5_Handler +#define PIN_WIRE_SDA (2u) +#define PIN_WIRE_SCL (3u) +#define PERIPH_WIRE sercom5 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; // "internal" lis3dh i2c interface -#define PIN_WIRE1_SDA (28u) -#define PIN_WIRE1_SCL (29u) -#define PERIPH_WIRE1 sercom1 -#define WIRE1_IT_HANDLER SERCOM1_Handler +#define PIN_WIRE1_SDA (28u) +#define PIN_WIRE1_SCL (29u) +#define PERIPH_WIRE1 sercom1 static const uint8_t SDA1 = PIN_WIRE1_SDA; static const uint8_t SCL1 = PIN_WIRE1_SCL; @@ -244,10 +242,11 @@ extern SERCOM sercom5; // Serial1 extern Uart Serial1; -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PERIPH_SERIAL1 sercom4 #endif // __cplusplus diff --git a/variants/crickit_m0/variant.cpp b/variants/crickit_m0/variant.cpp index 944e731e4..6c299b973 100644 --- a/variants/crickit_m0/variant.cpp +++ b/variants/crickit_m0/variant.cpp @@ -45,13 +45,13 @@ const PinDescription g_APinDescription[]= { PORTA, 27, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15 }, // D11 External NeoPixel - { PORTA, 20, PIO_TIMER_ALT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER_ALT), No_ADC_Channel, PWM0_CH6, TCC0_CH6, EXTERNAL_INT_4 }, + { PORTA, 20, PIO_TIMER_ALT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER_ALT), No_ADC_Channel, PWM0_CH6, TCC0_CH6, EXTERNAL_INT_4 }, // D12 IRQ - { PORTA, 28, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_8 }, + { PORTA, 28, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_8 }, // 13 (LED) - { PORTB, 22, PIO_SERCOM_ALT, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // Yellow LED next to USB + { PORTB, 22, PIO_SERCOM_ALT, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // Yellow LED next to USB // A0-A8 - Analog signal pins // A0 is duplicated since we mark it starting at analog1, so might as well! @@ -102,11 +102,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM5_Handler() -{ - Serial1.IrqHandler(); -} - diff --git a/variants/crickit_m0/variant.h b/variants/crickit_m0/variant.h index 9b7646578..676551e29 100644 --- a/variants/crickit_m0/variant.h +++ b/variants/crickit_m0/variant.h @@ -157,10 +157,11 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_TX (35ul) -#define PIN_SERIAL1_RX (36ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_TX (35ul) +#define PIN_SERIAL1_RX (36ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL1 sercom5 /* * SPI Interfaces @@ -172,10 +173,9 @@ static const uint8_t ATN = PIN_ATN; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (0u) -#define PIN_WIRE_SCL (1u) -#define PERIPH_WIRE sercom1 -#define WIRE_IT_HANDLER SERCOM1_Handler +#define PIN_WIRE_SDA (0u) +#define PIN_WIRE_SCL (1u) +#define PERIPH_WIRE sercom1 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/feather_m0/variant.cpp b/variants/feather_m0/variant.cpp index f9e76061c..9806c68b5 100644 --- a/variants/feather_m0/variant.cpp +++ b/variants/feather_m0/variant.cpp @@ -124,16 +124,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom0, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; -Uart Serial5( &sercom5, PIN_SERIAL_RX, PIN_SERIAL_TX, PAD_SERIAL_RX, PAD_SERIAL_TX ) ; -void SERCOM0_Handler() -{ - Serial1.IrqHandler(); -} - -void SERCOM5_Handler() -{ - Serial5.IrqHandler(); -} - diff --git a/variants/feather_m0/variant.h b/variants/feather_m0/variant.h index 20ecbbbaf..d8cf33856 100644 --- a/variants/feather_m0/variant.h +++ b/variants/feather_m0/variant.h @@ -118,28 +118,30 @@ static const uint8_t ATN = PIN_ATN; * Serial interfaces */ // Serial (EDBG) -#define PIN_SERIAL_RX (31ul) -#define PIN_SERIAL_TX (30ul) -#define PAD_SERIAL_TX (UART_TX_PAD_2) -#define PAD_SERIAL_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL_RX (31ul) +#define PIN_SERIAL_TX (30ul) +#define PAD_SERIAL_TX (UART_TX_PAD_2) +#define PAD_SERIAL_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL5 sercom5 // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_2) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL1 sercom0 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO (22u) -#define PIN_SPI_MOSI (23u) -#define PIN_SPI_SCK (24u) -#define PERIPH_SPI sercom4 -#define PAD_SPI_TX SPI_PAD_2_SCK_3 -#define PAD_SPI_RX SERCOM_RX_PAD_0 +#define PIN_SPI_MISO (22u) +#define PIN_SPI_MOSI (23u) +#define PIN_SPI_SCK (24u) +#define PERIPH_SPI sercom4 +#define PAD_SPI_TX SPI_PAD_2_SCK_3 +#define PAD_SPI_RX SERCOM_RX_PAD_0 static const uint8_t SS = PIN_A2 ; // SERCOM4 last PAD is present on A2 but HW SS isn't used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -151,10 +153,9 @@ static const uint8_t SCK = PIN_SPI_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (20u) -#define PIN_WIRE_SCL (21u) -#define PERIPH_WIRE sercom3 -#define WIRE_IT_HANDLER SERCOM3_Handler +#define PIN_WIRE_SDA (20u) +#define PIN_WIRE_SCL (21u) +#define PERIPH_WIRE sercom3 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/feather_m0_express/variant.cpp b/variants/feather_m0_express/variant.cpp index a3e87b89e..ecedbb2d1 100644 --- a/variants/feather_m0_express/variant.cpp +++ b/variants/feather_m0_express/variant.cpp @@ -118,11 +118,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom0, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM0_Handler() -{ - Serial1.IrqHandler(); -} - diff --git a/variants/feather_m0_express/variant.h b/variants/feather_m0_express/variant.h index f4d3ae9bf..879788d78 100644 --- a/variants/feather_m0_express/variant.h +++ b/variants/feather_m0_express/variant.h @@ -138,22 +138,23 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_2) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL1 sercom0 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 2 -#define PIN_SPI_MISO (28u) -#define PIN_SPI_MOSI (29u) -#define PIN_SPI_SCK (30u) -#define PERIPH_SPI sercom4 -#define PAD_SPI_TX SPI_PAD_2_SCK_3 -#define PAD_SPI_RX SERCOM_RX_PAD_0 +#define PIN_SPI_MISO (28u) +#define PIN_SPI_MOSI (29u) +#define PIN_SPI_SCK (30u) +#define PERIPH_SPI sercom4 +#define PAD_SPI_TX SPI_PAD_2_SCK_3 +#define PAD_SPI_RX SERCOM_RX_PAD_0 static const uint8_t SS = PIN_A2 ; // SERCOM4 last PAD is present on A2 but HW SS isn't used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -161,12 +162,12 @@ static const uint8_t MISO = PIN_SPI_MISO ; static const uint8_t SCK = PIN_SPI_SCK ; -#define PIN_SPI1_MISO (36u) -#define PIN_SPI1_MOSI (37u) -#define PIN_SPI1_SCK (38u) -#define PERIPH_SPI1 sercom2 -#define PAD_SPI1_TX SPI_PAD_0_SCK_1 -#define PAD_SPI1_RX SERCOM_RX_PAD_2 +#define PIN_SPI1_MISO (36u) +#define PIN_SPI1_MOSI (37u) +#define PIN_SPI1_SCK (38u) +#define PERIPH_SPI1 sercom2 +#define PAD_SPI1_TX SPI_PAD_0_SCK_1 +#define PAD_SPI1_RX SERCOM_RX_PAD_2 static const uint8_t SS1 = 39 ; // HW SS isn't used. Set here only for reference. static const uint8_t MOSI1 = PIN_SPI1_MOSI ; @@ -179,10 +180,9 @@ static const uint8_t SCK1 = PIN_SPI1_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (26u) -#define PIN_WIRE_SCL (27u) -#define PERIPH_WIRE sercom3 -#define WIRE_IT_HANDLER SERCOM3_Handler +#define PIN_WIRE_SDA (26u) +#define PIN_WIRE_SCL (27u) +#define PERIPH_WIRE sercom3 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/feather_m4/variant.cpp b/variants/feather_m4/variant.cpp index 88ba1ff6c..a2e53d446 100644 --- a/variants/feather_m4/variant.cpp +++ b/variants/feather_m4/variant.cpp @@ -119,22 +119,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM5_0_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_1_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_2_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_3_Handler() -{ - Serial1.IrqHandler(); -} diff --git a/variants/feather_m4/variant.h b/variants/feather_m4/variant.h index 6be35dccb..d8ad9e232 100644 --- a/variants/feather_m4/variant.h +++ b/variants/feather_m4/variant.h @@ -126,22 +126,23 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL1 sercom5 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO (23u) -#define PIN_SPI_MOSI (24u) -#define PIN_SPI_SCK (25u) -#define PERIPH_SPI sercom1 -#define PAD_SPI_TX SPI_PAD_3_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_2 +#define PIN_SPI_MISO (23u) +#define PIN_SPI_MOSI (24u) +#define PIN_SPI_SCK (25u) +#define PERIPH_SPI sercom1 +#define PAD_SPI_TX SPI_PAD_3_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_2 static const uint8_t SS = 9 ; // SERCOM1 last PAD is present on d9 but HW SS isn't used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -153,14 +154,9 @@ static const uint8_t SCK = PIN_SPI_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (21u) -#define PIN_WIRE_SCL (22u) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler -#define WIRE_IT_HANDLER_0 SERCOM2_0_Handler -#define WIRE_IT_HANDLER_1 SERCOM2_1_Handler -#define WIRE_IT_HANDLER_2 SERCOM2_2_Handler -#define WIRE_IT_HANDLER_3 SERCOM2_3_Handler +#define PIN_WIRE_SDA (21u) +#define PIN_WIRE_SCL (22u) +#define PERIPH_WIRE sercom2 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/feather_m4_can/variant.cpp b/variants/feather_m4_can/variant.cpp index 64d982e5e..bfaa62d63 100644 --- a/variants/feather_m4_can/variant.cpp +++ b/variants/feather_m4_can/variant.cpp @@ -128,24 +128,6 @@ SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; -Uart Serial1( &sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM5_0_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_1_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_2_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_3_Handler() -{ - Serial1.IrqHandler(); -} void initVariant(void) { // special initialization code just for us diff --git a/variants/feather_m4_can/variant.h b/variants/feather_m4_can/variant.h index 853086c65..96fb478ad 100644 --- a/variants/feather_m4_can/variant.h +++ b/variants/feather_m4_can/variant.h @@ -127,22 +127,23 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL1 sercom5 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO (23u) -#define PIN_SPI_MOSI (24u) -#define PIN_SPI_SCK (25u) -#define PERIPH_SPI sercom1 -#define PAD_SPI_TX SPI_PAD_3_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_2 +#define PIN_SPI_MISO (23u) +#define PIN_SPI_MOSI (24u) +#define PIN_SPI_SCK (25u) +#define PERIPH_SPI sercom1 +#define PAD_SPI_TX SPI_PAD_3_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_2 static const uint8_t SS = 9 ; // SERCOM1 last PAD is present on d9 but HW SS isn't used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -154,14 +155,9 @@ static const uint8_t SCK = PIN_SPI_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (21u) -#define PIN_WIRE_SCL (22u) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler -#define WIRE_IT_HANDLER_0 SERCOM2_0_Handler -#define WIRE_IT_HANDLER_1 SERCOM2_1_Handler -#define WIRE_IT_HANDLER_2 SERCOM2_2_Handler -#define WIRE_IT_HANDLER_3 SERCOM2_3_Handler +#define PIN_WIRE_SDA (21u) +#define PIN_WIRE_SCL (22u) +#define PERIPH_WIRE sercom2 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/gemma_m0/variant.cpp b/variants/gemma_m0/variant.cpp index c0fa9700e..d04220ff4 100644 --- a/variants/gemma_m0/variant.cpp +++ b/variants/gemma_m0/variant.cpp @@ -83,15 +83,13 @@ SERCOM sercom1( SERCOM1 ) ; SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; -Uart Serial1( &sercom0, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - +Uart Serial1( &PERIPH_SERIAL1, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; // If wire.h isnt included, just do nothing void WIRE_IT_HANDLER(void) __attribute__ ((weak)); -void SERCOM0_Handler() +void SERIAL1_IT_HANDLER() { Serial1.IrqHandler(); WIRE_IT_HANDLER(); } - diff --git a/variants/gemma_m0/variant.h b/variants/gemma_m0/variant.h index ee1273b55..ed701b65d 100644 --- a/variants/gemma_m0/variant.h +++ b/variants/gemma_m0/variant.h @@ -112,22 +112,25 @@ static const uint8_t DAC0 = PIN_DAC0; */ // Serial1 (sercom 0) -#define PIN_SERIAL1_RX (2ul) // PA05 -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) -#define PIN_SERIAL1_TX (0ul) // PA04 -#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PIN_SERIAL1_RX (2ul) // PA05 +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PIN_SERIAL1_TX (0ul) // PA04 +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL1 sercom0 +#define SERIAL1_IT_HANDLER SERCOM0_Handler +#define UART_VARIANT_OWNS_SERIAL1 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 1 // we'll just have SPI CLK and MOSI on sercom 0, no MISO -#define PIN_SPI_MISO (6u) // PA06, not actually available -#define PIN_SPI_MOSI (0ul) // PA04 -#define PIN_SPI_SCK (2ul) // PA05 -#define PERIPH_SPI sercom0 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_2 +#define PIN_SPI_MISO (6u) // PA06, not actually available +#define PIN_SPI_MOSI (0ul) // PA04 +#define PIN_SPI_SCK (2ul) // PA05 +#define PERIPH_SPI sercom0 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_2 static const uint8_t SS = 1 ; // only pin remaining (shrug) static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -140,9 +143,9 @@ static const uint8_t SCK = PIN_SPI_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (0u) -#define PIN_WIRE_SCL (2u) -#define PERIPH_WIRE sercom0 +#define PIN_WIRE_SDA (0u) +#define PIN_WIRE_SCL (2u) +#define PERIPH_WIRE sercom0 //#define WIRE_IT_HANDLER // hack! we call the i2c handler from within the serial handler! static const uint8_t SDA = PIN_WIRE_SDA; @@ -200,4 +203,3 @@ extern Uart Serial1; #define SERIAL_PORT_HARDWARE_OPEN Serial1 #endif /* _VARIANT_ARDUINO_ZERO_ */ - diff --git a/variants/grand_central_m4/variant.cpp b/variants/grand_central_m4/variant.cpp index 78aa1495d..7163d11f3 100644 --- a/variants/grand_central_m4/variant.cpp +++ b/variants/grand_central_m4/variant.cpp @@ -198,22 +198,3 @@ SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; SERCOM sercom6( SERCOM6 ) ; SERCOM sercom7( SERCOM7 ) ; - -Uart Serial1( &sercom0, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM0_0_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM0_1_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM0_2_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM0_3_Handler() -{ - Serial1.IrqHandler(); -} diff --git a/variants/grand_central_m4/variant.h b/variants/grand_central_m4/variant.h index 3092191b1..7effa36e5 100644 --- a/variants/grand_central_m4/variant.h +++ b/variants/grand_central_m4/variant.h @@ -146,55 +146,56 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0) -#define PIN_SERIAL1_TX (1) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PIN_SERIAL1_RX (0) +#define PIN_SERIAL1_TX (1) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PERIPH_SERIAL1 sercom0 // Serial2 -#define PIN_SERIAL2_RX (19) -#define PIN_SERIAL2_TX (18) -#define PAD_SERIAL2_TX (UART_TX_PAD_0) -#define PAD_SERIAL2_RX (SERCOM_RX_PAD_1) +#define PIN_SERIAL2_RX (19) +#define PIN_SERIAL2_TX (18) +#define PAD_SERIAL2_TX (UART_TX_PAD_0) +#define PAD_SERIAL2_RX (SERCOM_RX_PAD_1) #define SERCOM_SERIAL2 sercom4 // Serial3 -#define PIN_SERIAL3_RX (17) -#define PIN_SERIAL3_TX (16) -#define PAD_SERIAL3_TX (UART_TX_PAD_0) -#define PAD_SERIAL3_RX (SERCOM_RX_PAD_1) +#define PIN_SERIAL3_RX (17) +#define PIN_SERIAL3_TX (16) +#define PAD_SERIAL3_TX (UART_TX_PAD_0) +#define PAD_SERIAL3_RX (SERCOM_RX_PAD_1) #define SERCOM_SERIAL3 sercom1 // Serial4 -#define PIN_SERIAL4_RX (15) -#define PIN_SERIAL4_TX (14) -#define PAD_SERIAL4_TX (UART_TX_PAD_0) -#define PAD_SERIAL4_RX (SERCOM_RX_PAD_1) +#define PIN_SERIAL4_RX (15) +#define PIN_SERIAL4_TX (14) +#define PAD_SERIAL4_TX (UART_TX_PAD_0) +#define PAD_SERIAL4_RX (SERCOM_RX_PAD_1) #define SERCOM_SERIAL4 sercom5 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 2 -#define PIN_SPI_MISO (64) -#define PIN_SPI_MOSI (66) -#define PIN_SPI_SCK (65) -#define PERIPH_SPI sercom7 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_3 +#define PIN_SPI_MISO (64) +#define PIN_SPI_MOSI (66) +#define PIN_SPI_SCK (65) +#define PERIPH_SPI sercom7 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_3 static const uint8_t SS = (53); static const uint8_t MOSI = PIN_SPI_MOSI; static const uint8_t MISO = PIN_SPI_MISO; static const uint8_t SCK = PIN_SPI_SCK; -#define PIN_SPI1_MISO (80) -#define PIN_SPI1_MOSI (82) -#define PIN_SPI1_SCK (81) -#define PIN_SPI1_SS (83) -#define PERIPH_SPI1 sercom2 -#define PAD_SPI1_TX SPI_PAD_0_SCK_1 -#define PAD_SPI1_RX SERCOM_RX_PAD_3 +#define PIN_SPI1_MISO (80) +#define PIN_SPI1_MOSI (82) +#define PIN_SPI1_SCK (81) +#define PIN_SPI1_SS (83) +#define PERIPH_SPI1 sercom2 +#define PAD_SPI1_TX SPI_PAD_0_SCK_1 +#define PAD_SPI1_RX SERCOM_RX_PAD_3 static const uint8_t SS1 = PIN_SPI1_SS; static const uint8_t MOSI1 = PIN_SPI1_MOSI; @@ -213,26 +214,16 @@ static const uint8_t SCK1 = PIN_SPI1_SCK; */ #define WIRE_INTERFACES_COUNT 2 -#define PIN_WIRE_SDA (62) -#define PIN_WIRE_SCL (63) -#define PERIPH_WIRE sercom3 -#define WIRE_IT_HANDLER SERCOM3_Handler -#define WIRE_IT_HANDLER_0 SERCOM3_0_Handler -#define WIRE_IT_HANDLER_1 SERCOM3_1_Handler -#define WIRE_IT_HANDLER_2 SERCOM3_2_Handler -#define WIRE_IT_HANDLER_3 SERCOM3_3_Handler +#define PIN_WIRE_SDA (62) +#define PIN_WIRE_SCL (63) +#define PERIPH_WIRE sercom3 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; -#define PIN_WIRE1_SDA (25) -#define PIN_WIRE1_SCL (24) -#define PERIPH_WIRE1 sercom6 -#define WIRE1_IT_HANDLER SERCOM6_Handler -#define WIRE1_IT_HANDLER_0 SERCOM6_0_Handler -#define WIRE1_IT_HANDLER_1 SERCOM6_1_Handler -#define WIRE1_IT_HANDLER_2 SERCOM6_2_Handler -#define WIRE1_IT_HANDLER_3 SERCOM6_3_Handler +#define PIN_WIRE1_SDA (25) +#define PIN_WIRE1_SCL (24) +#define PERIPH_WIRE1 sercom6 static const uint8_t SDA1 = PIN_WIRE1_SDA; static const uint8_t SCL1 = PIN_WIRE1_SCL; diff --git a/variants/hallowing_m0_express/variant.cpp b/variants/hallowing_m0_express/variant.cpp index 441e2faee..2dec78875 100644 --- a/variants/hallowing_m0_express/variant.cpp +++ b/variants/hallowing_m0_express/variant.cpp @@ -120,11 +120,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom2, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM2_Handler() -{ - Serial1.IrqHandler(); -} - diff --git a/variants/hallowing_m0_express/variant.h b/variants/hallowing_m0_express/variant.h index 8a84c6023..398368248 100644 --- a/variants/hallowing_m0_express/variant.h +++ b/variants/hallowing_m0_express/variant.h @@ -135,22 +135,23 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) -#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PERIPH_SERIAL1 sercom2 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 2 -#define PIN_SPI_MISO (28u) -#define PIN_SPI_MOSI (29u) -#define PIN_SPI_SCK (30u) -#define PERIPH_SPI sercom5 -#define PAD_SPI_TX SPI_PAD_2_SCK_3 -#define PAD_SPI_RX SERCOM_RX_PAD_1 +#define PIN_SPI_MISO (28u) +#define PIN_SPI_MOSI (29u) +#define PIN_SPI_SCK (30u) +#define PERIPH_SPI sercom5 +#define PAD_SPI_TX SPI_PAD_2_SCK_3 +#define PAD_SPI_RX SERCOM_RX_PAD_1 static const uint8_t SS = PIN_A2 ; // SERCOM4 last PAD is present on A2 but HW SS isn't used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -158,12 +159,12 @@ static const uint8_t MISO = PIN_SPI_MISO ; static const uint8_t SCK = PIN_SPI_SCK ; -#define PIN_SPI1_MISO (33u) -#define PIN_SPI1_MOSI (34u) -#define PIN_SPI1_SCK (35u) -#define PERIPH_SPI1 sercom4 -#define PAD_SPI1_TX SPI_PAD_2_SCK_3 -#define PAD_SPI1_RX SERCOM_RX_PAD_1 +#define PIN_SPI1_MISO (33u) +#define PIN_SPI1_MOSI (34u) +#define PIN_SPI1_SCK (35u) +#define PERIPH_SPI1 sercom4 +#define PAD_SPI1_TX SPI_PAD_2_SCK_3 +#define PAD_SPI1_RX SERCOM_RX_PAD_1 static const uint8_t SS1 = 36; static const uint8_t MOSI1 = PIN_SPI1_MOSI ; @@ -176,10 +177,9 @@ static const uint8_t SCK1 = PIN_SPI1_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (26u) -#define PIN_WIRE_SCL (27u) -#define PERIPH_WIRE sercom3 -#define WIRE_IT_HANDLER SERCOM3_Handler +#define PIN_WIRE_SDA (26u) +#define PIN_WIRE_SCL (27u) +#define PERIPH_WIRE sercom3 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/hallowing_m4/variant.cpp b/variants/hallowing_m4/variant.cpp index 8f9ab0838..0a3679c95 100644 --- a/variants/hallowing_m4/variant.cpp +++ b/variants/hallowing_m4/variant.cpp @@ -35,7 +35,7 @@ const PinDescription g_APinDescription[]= { PORTB, 2, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel14, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_2 }, // D3 { PORTA, 14, PIO_DIGITAL, PIN_ATTR_PWM_E, No_ADC_Channel, TC3_CH0, TC3_CH0, EXTERNAL_INT_14 }, // D4 { PORTA, 16, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_0 }, // D5 - { PORTA, 17, PIO_DIGITAL, (PIN_ATTR_DIGITAL), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_1 }, // D6 + { PORTA, 17, PIO_DIGITAL, (PIN_ATTR_DIGITAL), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_1 }, // D6 { PORTB, 15, PIO_DIGITAL, PIN_ATTR_PWM_F, No_ADC_Channel, TCC4_CH0, TC5_CH0, EXTERNAL_INT_15 }, // D7 (LISIRQ) // Digital High @@ -47,7 +47,7 @@ const PinDescription g_APinDescription[]= { PORTA, 21, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_5 }, // D12 // 13 (LED) - { PORTA, 23, PIO_SERCOM, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH3, TC4_CH1, EXTERNAL_INT_7 }, + { PORTA, 23, PIO_SERCOM, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH3, TC4_CH1, EXTERNAL_INT_7 }, // 14..23 - Analog pins @@ -127,22 +127,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom4, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM4_0_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM4_1_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM4_2_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM4_3_Handler() -{ - Serial1.IrqHandler(); -} diff --git a/variants/hallowing_m4/variant.h b/variants/hallowing_m4/variant.h index 221821d59..230a1056d 100644 --- a/variants/hallowing_m4/variant.h +++ b/variants/hallowing_m4/variant.h @@ -123,22 +123,23 @@ static const uint8_t DAC1 = PIN_DAC1; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL1 sercom4 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 2 -#define PIN_SPI_MISO (26u) -#define PIN_SPI_MOSI (27u) -#define PIN_SPI_SCK (28u) -#define PERIPH_SPI sercom5 -#define PAD_SPI_TX SPI_PAD_3_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_2 +#define PIN_SPI_MISO (26u) +#define PIN_SPI_MOSI (27u) +#define PIN_SPI_SCK (28u) +#define PERIPH_SPI sercom5 +#define PAD_SPI_TX SPI_PAD_3_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_2 static const uint8_t SS = 10 ; static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -146,12 +147,12 @@ static const uint8_t MISO = PIN_SPI_MISO ; static const uint8_t SCK = PIN_SPI_SCK ; // Internal SPI for TFT -#define PIN_SPI1_MOSI (41u) -#define PIN_SPI1_SCK (42u) -#define PIN_SPI1_MISO (43u) -#define PERIPH_SPI1 sercom1 -#define PAD_SPI1_TX SPI_PAD_0_SCK_1 -#define PAD_SPI1_RX SERCOM_RX_PAD_2 +#define PIN_SPI1_MOSI (41u) +#define PIN_SPI1_SCK (42u) +#define PIN_SPI1_MISO (43u) +#define PERIPH_SPI1 sercom1 +#define PAD_SPI1_TX SPI_PAD_0_SCK_1 +#define PAD_SPI1_RX SERCOM_RX_PAD_2 static const uint8_t SS1 = 44 ; static const uint8_t MOSI1 = PIN_SPI1_MOSI ; @@ -163,14 +164,9 @@ static const uint8_t SCK1 = PIN_SPI1_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (24u) -#define PIN_WIRE_SCL (25u) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler -#define WIRE_IT_HANDLER_0 SERCOM2_0_Handler -#define WIRE_IT_HANDLER_1 SERCOM2_1_Handler -#define WIRE_IT_HANDLER_2 SERCOM2_2_Handler -#define WIRE_IT_HANDLER_3 SERCOM2_3_Handler +#define PIN_WIRE_SDA (24u) +#define PIN_WIRE_SCL (25u) +#define PERIPH_WIRE sercom2 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/itsybitsy_m0/variant.cpp b/variants/itsybitsy_m0/variant.cpp index fa35301d7..623e26d59 100644 --- a/variants/itsybitsy_m0/variant.cpp +++ b/variants/itsybitsy_m0/variant.cpp @@ -116,11 +116,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom0, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM0_Handler() -{ - Serial1.IrqHandler(); -} - diff --git a/variants/itsybitsy_m0/variant.h b/variants/itsybitsy_m0/variant.h index e9b945fed..dd914cce3 100644 --- a/variants/itsybitsy_m0/variant.h +++ b/variants/itsybitsy_m0/variant.h @@ -133,22 +133,23 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_2) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL1 sercom0 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 2 -#define PIN_SPI_MISO (28u) -#define PIN_SPI_MOSI (29u) -#define PIN_SPI_SCK (30u) -#define PERIPH_SPI sercom4 -#define PAD_SPI_TX SPI_PAD_2_SCK_3 -#define PAD_SPI_RX SERCOM_RX_PAD_0 +#define PIN_SPI_MISO (28u) +#define PIN_SPI_MOSI (29u) +#define PIN_SPI_SCK (30u) +#define PERIPH_SPI sercom4 +#define PAD_SPI_TX SPI_PAD_2_SCK_3 +#define PAD_SPI_RX SERCOM_RX_PAD_0 static const uint8_t SS = PIN_A2 ; // SERCOM4 last PAD is present on A2 but HW SS isn't used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -156,12 +157,12 @@ static const uint8_t MISO = PIN_SPI_MISO ; static const uint8_t SCK = PIN_SPI_SCK ; -#define PIN_SPI1_MISO (36u) -#define PIN_SPI1_MOSI (37u) -#define PIN_SPI1_SCK (38u) -#define PERIPH_SPI1 sercom5 -#define PAD_SPI1_TX SPI_PAD_2_SCK_3 -#define PAD_SPI1_RX SERCOM_RX_PAD_1 +#define PIN_SPI1_MISO (36u) +#define PIN_SPI1_MOSI (37u) +#define PIN_SPI1_SCK (38u) +#define PERIPH_SPI1 sercom5 +#define PAD_SPI1_TX SPI_PAD_2_SCK_3 +#define PAD_SPI1_RX SERCOM_RX_PAD_1 static const uint8_t SS1 = 39 ; // HW SS isn't used. Set here only for reference. static const uint8_t MOSI1 = PIN_SPI_MOSI ; @@ -173,10 +174,9 @@ static const uint8_t SCK1 = PIN_SPI_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (26u) -#define PIN_WIRE_SCL (27u) -#define PERIPH_WIRE sercom3 -#define WIRE_IT_HANDLER SERCOM3_Handler +#define PIN_WIRE_SDA (26u) +#define PIN_WIRE_SCL (27u) +#define PERIPH_WIRE sercom3 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/itsybitsy_m4/variant.cpp b/variants/itsybitsy_m4/variant.cpp index 35323cfcd..dadba4510 100644 --- a/variants/itsybitsy_m4/variant.cpp +++ b/variants/itsybitsy_m4/variant.cpp @@ -110,22 +110,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom3, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM3_0_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM3_1_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM3_2_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM3_3_Handler() -{ - Serial1.IrqHandler(); -} diff --git a/variants/itsybitsy_m4/variant.h b/variants/itsybitsy_m4/variant.h index dd6da9ba7..9865e62c5 100644 --- a/variants/itsybitsy_m4/variant.h +++ b/variants/itsybitsy_m4/variant.h @@ -125,22 +125,23 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL1 sercom3 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO (23u) -#define PIN_SPI_SCK (24u) -#define PIN_SPI_MOSI (25u) -#define PERIPH_SPI sercom1 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_3 +#define PIN_SPI_MISO (23u) +#define PIN_SPI_SCK (24u) +#define PIN_SPI_MOSI (25u) +#define PERIPH_SPI sercom1 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_3 static const uint8_t SS = PIN_A2 ; static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -152,14 +153,9 @@ static const uint8_t SCK = PIN_SPI_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (21u) -#define PIN_WIRE_SCL (22u) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler -#define WIRE_IT_HANDLER_0 SERCOM2_0_Handler -#define WIRE_IT_HANDLER_1 SERCOM2_1_Handler -#define WIRE_IT_HANDLER_2 SERCOM2_2_Handler -#define WIRE_IT_HANDLER_3 SERCOM2_3_Handler +#define PIN_WIRE_SDA (21u) +#define PIN_WIRE_SCL (22u) +#define PERIPH_WIRE sercom2 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/matrixportal_m4/variant.cpp b/variants/matrixportal_m4/variant.cpp index df23508fe..be25f6652 100644 --- a/variants/matrixportal_m4/variant.cpp +++ b/variants/matrixportal_m4/variant.cpp @@ -132,42 +132,5 @@ SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; -Uart Serial1( &sercom1, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM1_0_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM1_1_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM1_2_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM1_3_Handler() -{ - Serial1.IrqHandler(); -} - // sercom for internal ESP32 UART connection -Uart Serial2( &sercom4, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX ) ; - -void SERCOM4_0_Handler() -{ - Serial2.IrqHandler(); -} -void SERCOM4_1_Handler() -{ - Serial2.IrqHandler(); -} -void SERCOM4_2_Handler() -{ - Serial2.IrqHandler(); -} -void SERCOM4_3_Handler() -{ - Serial2.IrqHandler(); -} diff --git a/variants/matrixportal_m4/variant.h b/variants/matrixportal_m4/variant.h index deedf8502..e11def585 100644 --- a/variants/matrixportal_m4/variant.h +++ b/variants/matrixportal_m4/variant.h @@ -136,16 +136,18 @@ static const uint8_t DAC1 = PIN_DAC1; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL1 sercom1 // Serial2 -#define PIN_SERIAL2_RX (27ul) -#define PIN_SERIAL2_TX (28ul) -#define PAD_SERIAL2_RX (SERCOM_RX_PAD_1) -#define PAD_SERIAL2_TX (UART_TX_PAD_0) +#define PIN_SERIAL2_RX (27ul) +#define PIN_SERIAL2_TX (28ul) +#define PAD_SERIAL2_RX (SERCOM_RX_PAD_1) +#define PAD_SERIAL2_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL2 sercom4 /* @@ -153,12 +155,12 @@ static const uint8_t DAC1 = PIN_DAC1; */ #define SPI_INTERFACES_COUNT 2 -#define PIN_SPI_SCK (34u) -#define PIN_SPI_MISO (35u) -#define PIN_SPI_MOSI (36u) -#define PERIPH_SPI sercom3 -#define PAD_SPI_TX SPI_PAD_3_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_0 +#define PIN_SPI_SCK (34u) +#define PIN_SPI_MISO (35u) +#define PIN_SPI_MOSI (36u) +#define PERIPH_SPI sercom3 +#define PAD_SPI_TX SPI_PAD_3_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_0 static const uint8_t SS = 33 ; static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -166,12 +168,12 @@ static const uint8_t MISO = PIN_SPI_MISO ; static const uint8_t SCK = PIN_SPI_SCK ; -#define PIN_SPI1_SCK (48u) -#define PIN_SPI1_MOSI (49u) -#define PIN_SPI1_MISO (50u) -#define PERIPH_SPI1 sercom0 -#define PAD_SPI1_TX SPI_PAD_0_SCK_1 -#define PAD_SPI1_RX SERCOM_RX_PAD_3 +#define PIN_SPI1_SCK (48u) +#define PIN_SPI1_MOSI (49u) +#define PIN_SPI1_MISO (50u) +#define PERIPH_SPI1 sercom0 +#define PAD_SPI1_TX SPI_PAD_0_SCK_1 +#define PAD_SPI1_RX SERCOM_RX_PAD_3 static const uint8_t SS1 = PIN_A3 ; static const uint8_t MOSI1 = PIN_SPI1_MOSI ; @@ -183,14 +185,9 @@ static const uint8_t SCK1 = PIN_SPI1_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (5u) -#define PIN_WIRE_SCL (6u) -#define PERIPH_WIRE sercom5 -#define WIRE_IT_HANDLER SERCOM5_Handler -#define WIRE_IT_HANDLER_0 SERCOM5_0_Handler -#define WIRE_IT_HANDLER_1 SERCOM5_1_Handler -#define WIRE_IT_HANDLER_2 SERCOM5_2_Handler -#define WIRE_IT_HANDLER_3 SERCOM5_3_Handler +#define PIN_WIRE_SDA (5u) +#define PIN_WIRE_SCL (6u) +#define PERIPH_WIRE sercom5 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/metro_m0/variant.cpp b/variants/metro_m0/variant.cpp index b4836efe8..de192fa60 100644 --- a/variants/metro_m0/variant.cpp +++ b/variants/metro_m0/variant.cpp @@ -117,11 +117,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom0, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM0_Handler() -{ - Serial1.IrqHandler(); -} - diff --git a/variants/metro_m0/variant.h b/variants/metro_m0/variant.h index 5aa2e8525..4c749423c 100644 --- a/variants/metro_m0/variant.h +++ b/variants/metro_m0/variant.h @@ -135,22 +135,23 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_2) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL1 sercom0 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 2 -#define PIN_SPI_MISO (28u) -#define PIN_SPI_MOSI (29u) -#define PIN_SPI_SCK (30u) -#define PERIPH_SPI sercom4 -#define PAD_SPI_TX SPI_PAD_2_SCK_3 -#define PAD_SPI_RX SERCOM_RX_PAD_0 +#define PIN_SPI_MISO (28u) +#define PIN_SPI_MOSI (29u) +#define PIN_SPI_SCK (30u) +#define PERIPH_SPI sercom4 +#define PAD_SPI_TX SPI_PAD_2_SCK_3 +#define PAD_SPI_RX SERCOM_RX_PAD_0 static const uint8_t SS = PIN_A2 ; // SERCOM4 last PAD is present on A2 but HW SS isn't used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -158,12 +159,12 @@ static const uint8_t MISO = PIN_SPI_MISO ; static const uint8_t SCK = PIN_SPI_SCK ; -#define PIN_SPI1_MISO (36u) -#define PIN_SPI1_MOSI (37u) -#define PIN_SPI1_SCK (38u) -#define PERIPH_SPI1 sercom5 -#define PAD_SPI1_TX SPI_PAD_2_SCK_3 -#define PAD_SPI1_RX SERCOM_RX_PAD_1 +#define PIN_SPI1_MISO (36u) +#define PIN_SPI1_MOSI (37u) +#define PIN_SPI1_SCK (38u) +#define PERIPH_SPI1 sercom5 +#define PAD_SPI1_TX SPI_PAD_2_SCK_3 +#define PAD_SPI1_RX SERCOM_RX_PAD_1 static const uint8_t SS1 = 39 ; // HW SS isn't used. Set here only for reference. static const uint8_t MOSI1 = PIN_SPI_MOSI ; @@ -176,10 +177,9 @@ static const uint8_t SCK1 = PIN_SPI_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (26u) -#define PIN_WIRE_SCL (27u) -#define PERIPH_WIRE sercom3 -#define WIRE_IT_HANDLER SERCOM3_Handler +#define PIN_WIRE_SDA (26u) +#define PIN_WIRE_SCL (27u) +#define PERIPH_WIRE sercom3 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/metro_m4/variant.cpp b/variants/metro_m4/variant.cpp index 528a25ce7..7a99558c9 100644 --- a/variants/metro_m4/variant.cpp +++ b/variants/metro_m4/variant.cpp @@ -127,22 +127,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom3, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM3_0_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM3_1_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM3_2_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM3_3_Handler() -{ - Serial1.IrqHandler(); -} diff --git a/variants/metro_m4/variant.h b/variants/metro_m4/variant.h index 2b510e744..06d979fa8 100644 --- a/variants/metro_m4/variant.h +++ b/variants/metro_m4/variant.h @@ -127,22 +127,23 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PERIPH_SERIAL1 sercom3 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO (24u) -#define PIN_SPI_MOSI (26u) -#define PIN_SPI_SCK (25u) -#define PERIPH_SPI sercom2 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_2 +#define PIN_SPI_MISO (24u) +#define PIN_SPI_MOSI (26u) +#define PIN_SPI_SCK (25u) +#define PERIPH_SPI sercom2 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_2 static const uint8_t SS = PIN_A2 ; static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -155,14 +156,9 @@ static const uint8_t SCK = PIN_SPI_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (22u) -#define PIN_WIRE_SCL (23u) -#define PERIPH_WIRE sercom5 -#define WIRE_IT_HANDLER SERCOM5_Handler -#define WIRE_IT_HANDLER_0 SERCOM5_0_Handler -#define WIRE_IT_HANDLER_1 SERCOM5_1_Handler -#define WIRE_IT_HANDLER_2 SERCOM5_2_Handler -#define WIRE_IT_HANDLER_3 SERCOM5_3_Handler +#define PIN_WIRE_SDA (22u) +#define PIN_WIRE_SCL (23u) +#define PERIPH_WIRE sercom5 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/metro_m4_airlift/variant.cpp b/variants/metro_m4_airlift/variant.cpp index a160346fd..cf038d8c8 100644 --- a/variants/metro_m4_airlift/variant.cpp +++ b/variants/metro_m4_airlift/variant.cpp @@ -94,7 +94,7 @@ const PinDescription g_APinDescription[]= { PORTB, 4, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_4 }, { PORTB, 5, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_5 }, - // 39 - SWO + // 39 - SWO { PORTB, 30, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_6 }, // used as output only // 40 - Internal NeoPixel @@ -132,41 +132,5 @@ SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; // sercom for pins 0 & 1 UART -Uart Serial1( &sercom3, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM3_0_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM3_1_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM3_2_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM3_3_Handler() -{ - Serial1.IrqHandler(); -} // sercom for internal ESP32 UART connection -Uart Serial2( &sercom0, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX ) ; - -void SERCOM0_0_Handler() -{ - Serial2.IrqHandler(); -} -void SERCOM0_1_Handler() -{ - Serial2.IrqHandler(); -} -void SERCOM0_2_Handler() -{ - Serial2.IrqHandler(); -} -void SERCOM0_3_Handler() -{ - Serial2.IrqHandler(); -} diff --git a/variants/metro_m4_airlift/variant.h b/variants/metro_m4_airlift/variant.h index d078f2099..75ec79a1f 100644 --- a/variants/metro_m4_airlift/variant.h +++ b/variants/metro_m4_airlift/variant.h @@ -139,28 +139,30 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL1 sercom3 // Serial2 -#define PIN_SERIAL2_RX (32ul) -#define PIN_SERIAL2_TX (33ul) -#define PAD_SERIAL2_RX (SERCOM_RX_PAD_3) -#define PAD_SERIAL2_TX (UART_TX_PAD_0) +#define PIN_SERIAL2_RX (32ul) +#define PIN_SERIAL2_TX (33ul) +#define PAD_SERIAL2_RX (SERCOM_RX_PAD_3) +#define PAD_SERIAL2_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL2 sercom0 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO (24u) -#define PIN_SPI_MOSI (26u) -#define PIN_SPI_SCK (25u) -#define PERIPH_SPI sercom2 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_2 +#define PIN_SPI_MISO (24u) +#define PIN_SPI_MOSI (26u) +#define PIN_SPI_SCK (25u) +#define PERIPH_SPI sercom2 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_2 static const uint8_t SS = SPIWIFI_SS ; static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -173,14 +175,9 @@ static const uint8_t SCK = PIN_SPI_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (22u) -#define PIN_WIRE_SCL (23u) -#define PERIPH_WIRE sercom5 -#define WIRE_IT_HANDLER SERCOM5_Handler -#define WIRE_IT_HANDLER_0 SERCOM5_0_Handler -#define WIRE_IT_HANDLER_1 SERCOM5_1_Handler -#define WIRE_IT_HANDLER_2 SERCOM5_2_Handler -#define WIRE_IT_HANDLER_3 SERCOM5_3_Handler +#define PIN_WIRE_SDA (22u) +#define PIN_WIRE_SCL (23u) +#define PERIPH_WIRE sercom5 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/mkr1000/variant.cpp b/variants/mkr1000/variant.cpp index 51d0b37eb..76af54188 100644 --- a/variants/mkr1000/variant.cpp +++ b/variants/mkr1000/variant.cpp @@ -171,10 +171,3 @@ SERCOM sercom4(SERCOM4); SERCOM sercom5(SERCOM5); // Serial1 -Uart Serial1(&sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX); - -void SERCOM5_Handler() -{ - Serial1.IrqHandler(); -} - diff --git a/variants/mkr1000/variant.h b/variants/mkr1000/variant.h index ce9f6c12c..c88f9ba89 100644 --- a/variants/mkr1000/variant.h +++ b/variants/mkr1000/variant.h @@ -92,26 +92,26 @@ static const uint8_t DAC0 = PIN_DAC0; #define SPI_INTERFACES_COUNT 2 // SPI -#define PIN_SPI_MISO (10u) -#define PIN_SPI_MOSI (8u) -#define PIN_SPI_SCK (9u) -#define PIN_SPI_SS (24u) -#define PERIPH_SPI sercom1 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_3 +#define PIN_SPI_MISO (10u) +#define PIN_SPI_MOSI (8u) +#define PIN_SPI_SCK (9u) +#define PIN_SPI_SS (24u) +#define PERIPH_SPI sercom1 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_3 static const uint8_t SS = PIN_SPI_SS; // SPI Slave SS not used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI; static const uint8_t MISO = PIN_SPI_MISO; static const uint8_t SCK = PIN_SPI_SCK; // SPI1: Connected to WINC1501B -#define PIN_SPI1_MISO (29u) -#define PIN_SPI1_MOSI (26u) -#define PIN_SPI1_SCK (27u) -#define PIN_SPI1_SS (28u) -#define PERIPH_SPI1 sercom4 -#define PAD_SPI1_TX SPI_PAD_0_SCK_1 -#define PAD_SPI1_RX SERCOM_RX_PAD_3 +#define PIN_SPI1_MISO (29u) +#define PIN_SPI1_MOSI (26u) +#define PIN_SPI1_SCK (27u) +#define PIN_SPI1_SS (28u) +#define PERIPH_SPI1 sercom4 +#define PAD_SPI1_TX SPI_PAD_0_SCK_1 +#define PAD_SPI1_RX SERCOM_RX_PAD_3 static const uint8_t SS1 = PIN_SPI1_SS; static const uint8_t MOSI1 = PIN_SPI1_MOSI; static const uint8_t MISO1 = PIN_SPI1_MISO; @@ -122,10 +122,9 @@ static const uint8_t SCK1 = PIN_SPI1_SCK; #define WIRE_INTERFACES_COUNT 1 // Wire -#define PIN_WIRE_SDA (11u) -#define PIN_WIRE_SCL (12u) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler +#define PIN_WIRE_SDA (11u) +#define PIN_WIRE_SCL (12u) +#define PERIPH_WIRE sercom2 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; @@ -170,10 +169,11 @@ extern SERCOM sercom5; // Serial1 extern Uart Serial1; -#define PIN_SERIAL1_RX (13ul) -#define PIN_SERIAL1_TX (14ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_2) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_RX (13ul) +#define PIN_SERIAL1_TX (14ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL1 sercom5 #endif // __cplusplus // These serial port names are intended to allow libraries and architecture-neutral diff --git a/variants/mkrfox1200/variant.cpp b/variants/mkrfox1200/variant.cpp index 9b46cafd9..a17081b82 100644 --- a/variants/mkrfox1200/variant.cpp +++ b/variants/mkrfox1200/variant.cpp @@ -149,7 +149,7 @@ const PinDescription g_APinDescription[] = { { PORTA, 14, PIO_DIGITAL, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // SS: as GPIO { PORTA, 15, PIO_SERCOM_ALT, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // MISO: SERCOM4/PAD[3] { PORTA, 27, PIO_DIGITAL, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, - + { PORTA, 28, PIO_DIGITAL, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, { PORTB, 8, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG ), ADC_Channel2, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, { PORTB, 9, PIO_ANALOG, (PIN_ATTR_PWM|PIN_ATTR_TIMER ), ADC_Channel3, PWM4_CH1, TC4_CH1, EXTERNAL_INT_9 }, @@ -169,10 +169,3 @@ SERCOM sercom4(SERCOM4); SERCOM sercom5(SERCOM5); // Serial1 -Uart Serial1(&sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX); - -void SERCOM5_Handler() -{ - Serial1.IrqHandler(); -} - diff --git a/variants/mkrfox1200/variant.h b/variants/mkrfox1200/variant.h index ade82e8ba..17b743bb3 100644 --- a/variants/mkrfox1200/variant.h +++ b/variants/mkrfox1200/variant.h @@ -91,13 +91,13 @@ static const uint8_t A6 = PIN_A6; #define SPI_INTERFACES_COUNT 2 // SPI -#define PIN_SPI_MISO (10u) -#define PIN_SPI_MOSI (8u) -#define PIN_SPI_SCK (9u) -#define PIN_SPI_SS (4u) -#define PERIPH_SPI sercom1 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_3 +#define PIN_SPI_MISO (10u) +#define PIN_SPI_MOSI (8u) +#define PIN_SPI_SCK (9u) +#define PIN_SPI_SS (4u) +#define PERIPH_SPI sercom1 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_3 static const uint8_t SS = PIN_SPI_SS; // SPI Slave SS not used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI; @@ -105,16 +105,16 @@ static const uint8_t MISO = PIN_SPI_MISO; static const uint8_t SCK = PIN_SPI_SCK; // SPI1: Connected to SIGFOX module -#define PIN_SPI1_MISO (29u) -#define PIN_SPI1_MOSI (26u) -#define PIN_SPI1_SCK (27u) -#define PIN_SPI1_SS (28u) +#define PIN_SPI1_MISO (29u) +#define PIN_SPI1_MOSI (26u) +#define PIN_SPI1_SCK (27u) +#define PIN_SPI1_SS (28u) #define PIN_SIGFOX_RES (30u) #define PIN_SIGFOX_PWRON (31u) #define PIN_SIGFOX_EVENT (33u) -#define PERIPH_SPI1 sercom4 -#define PAD_SPI1_TX SPI_PAD_0_SCK_1 -#define PAD_SPI1_RX SERCOM_RX_PAD_3 +#define PERIPH_SPI1 sercom4 +#define PAD_SPI1_TX SPI_PAD_0_SCK_1 +#define PAD_SPI1_RX SERCOM_RX_PAD_3 static const uint8_t SS1 = PIN_SPI1_SS; static const uint8_t MOSI1 = PIN_SPI1_MOSI; static const uint8_t MISO1 = PIN_SPI1_MISO; @@ -135,10 +135,9 @@ static const uint8_t SCK1 = PIN_SPI1_SCK; #define WIRE_INTERFACES_COUNT 1 // Wire -#define PIN_WIRE_SDA (11u) -#define PIN_WIRE_SCL (12u) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler +#define PIN_WIRE_SDA (11u) +#define PIN_WIRE_SCL (12u) +#define PERIPH_WIRE sercom2 // USB // --- @@ -172,10 +171,11 @@ extern SERCOM sercom5; // Serial1 extern Uart Serial1; -#define PIN_SERIAL1_RX (13ul) -#define PIN_SERIAL1_TX (14ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_2) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_RX (13ul) +#define PIN_SERIAL1_TX (14ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL1 sercom5 #endif // __cplusplus // These serial port names are intended to allow libraries and architecture-neutral diff --git a/variants/mkrgsm1400/variant.cpp b/variants/mkrgsm1400/variant.cpp index c534367c2..43d9136ce 100644 --- a/variants/mkrgsm1400/variant.cpp +++ b/variants/mkrgsm1400/variant.cpp @@ -151,7 +151,7 @@ const PinDescription g_APinDescription[] = { { PORTA, 14, PIO_SERCOM_ALT, (PIN_ATTR_DIGITAL ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // SS: as GPIO { PORTA, 15, PIO_SERCOM_ALT, (PIN_ATTR_DIGITAL ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // MISO: SERCOM4/PAD[3] { PORTA, 27, PIO_DIGITAL, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15 }, - + { PORTB, 8, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG ), ADC_Channel2, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, { PORTB, 9, PIO_ANALOG, (PIN_ATTR_PWM|PIN_ATTR_TIMER ), ADC_Channel3, PWM4_CH1, TC4_CH1, EXTERNAL_INT_9 }, @@ -174,6 +174,7 @@ SERCOM sercom5(SERCOM5); #if defined(USE_BQ24195L_PMIC) #include "wiring_private.h" +#include "SERCOM_Txn.h" #define PMIC_ADDRESS 0x6B #define PMIC_REG01 0x01 @@ -185,12 +186,17 @@ static inline void enable_battery_charging() { pinPeripheral(PIN_WIRE_SDA, g_APinDescription[PIN_WIRE_SDA].ulPinType); pinPeripheral(PIN_WIRE_SCL, g_APinDescription[PIN_WIRE_SCL].ulPinType); - PERIPH_WIRE.startTransmissionWIRE( PMIC_ADDRESS, WIRE_WRITE_FLAG ); - PERIPH_WIRE.sendDataMasterWIRE(PMIC_REG01); - PERIPH_WIRE.sendDataMasterWIRE(0x1B); // Charge Battery + Minimum System Voltage 3.5V - PERIPH_WIRE.prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); + static SercomTxn txn; + static uint8_t txData[2] = {PMIC_REG01, 0x1B}; // Charge Battery + Minimum System Voltage 3.5V + + txn = SercomTxn{}; + txn.config = I2C_CFG_STOP; + txn.address = PMIC_ADDRESS; + txn.length = 2; + txn.txPtr = txData; - PERIPH_WIRE.disableWIRE(); + PERIPH_WIRE.enqueueWIRE(&txn); + PERIPH_WIRE.startTransmissionWIRE(); } static inline void disable_battery_fet(bool disabled) { @@ -199,14 +205,21 @@ static inline void disable_battery_fet(bool disabled) { pinPeripheral(PIN_WIRE_SDA, g_APinDescription[PIN_WIRE_SDA].ulPinType); pinPeripheral(PIN_WIRE_SCL, g_APinDescription[PIN_WIRE_SCL].ulPinType); - PERIPH_WIRE.startTransmissionWIRE( PMIC_ADDRESS, WIRE_WRITE_FLAG ); - PERIPH_WIRE.sendDataMasterWIRE(PMIC_REG07); + static SercomTxn txn; + static uint8_t txData[2]; + txData[0] = PMIC_REG07; // No D+/D– detection + Safety timer not slowed by 2X during input DPM or thermal regulation + // BAT fet disabled/enabled + charge and bat fault INT - PERIPH_WIRE.sendDataMasterWIRE(0x0B | (disabled ? 0x20 : 0x00)); - PERIPH_WIRE.prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); + txData[1] = 0x0B | (disabled ? 0x20 : 0x00); + + txn = SercomTxn{}; + txn.config = I2C_CFG_STOP; + txn.address = PMIC_ADDRESS; + txn.length = 2; + txn.txPtr = txData; - PERIPH_WIRE.disableWIRE(); + PERIPH_WIRE.enqueueWIRE(&txn); + PERIPH_WIRE.startTransmissionWIRE(); } #endif @@ -234,19 +247,3 @@ void initVariant() { pinMode(PIN_SERIAL2_DTR, OUTPUT); digitalWrite(PIN_SERIAL2_DTR, LOW); } - -// Serial1 -Uart Serial1(&sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX); - -void SERCOM5_Handler() -{ - Serial1.IrqHandler(); -} - -// SerialGSM -Uart Serial2(&sercom4, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX, PIN_SERIAL2_RTS, PIN_SERIAL2_CTS); - -void SERCOM4_Handler() -{ - Serial2.IrqHandler(); -} diff --git a/variants/mkrgsm1400/variant.h b/variants/mkrgsm1400/variant.h index f3c2832aa..4d7206b58 100644 --- a/variants/mkrgsm1400/variant.h +++ b/variants/mkrgsm1400/variant.h @@ -97,13 +97,13 @@ static const uint8_t A6 = PIN_A6; #define SPI_INTERFACES_COUNT 1 // SPI -#define PIN_SPI_MISO (10u) -#define PIN_SPI_MOSI (8u) -#define PIN_SPI_SCK (9u) -#define PIN_SPI_SS (4u) -#define PERIPH_SPI sercom1 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_3 +#define PIN_SPI_MISO (10u) +#define PIN_SPI_MOSI (8u) +#define PIN_SPI_SCK (9u) +#define PIN_SPI_SS (4u) +#define PERIPH_SPI sercom1 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_3 static const uint8_t SS = PIN_SPI_SS; // SPI Slave SS not used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI; @@ -115,10 +115,9 @@ static const uint8_t SCK = PIN_SPI_SCK; #define WIRE_INTERFACES_COUNT 1 // Wire -#define PIN_WIRE_SDA (11u) -#define PIN_WIRE_SCL (12u) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler +#define PIN_WIRE_SDA (11u) +#define PIN_WIRE_SCL (12u) +#define PERIPH_WIRE sercom2 // USB // --- @@ -152,20 +151,22 @@ extern SERCOM sercom5; // Serial1 extern Uart Serial1; -#define PIN_SERIAL1_RX (13ul) -#define PIN_SERIAL1_TX (14ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_2) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_RX (13ul) +#define PIN_SERIAL1_TX (14ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL1 sercom5 // Serial2 - GSM extern Uart Serial2; -#define PIN_SERIAL2_RX (27ul) -#define PIN_SERIAL2_TX (26ul) -#define PAD_SERIAL2_TX (UART_TX_RTS_CTS_PAD_0_2_3) -#define PAD_SERIAL2_RX (SERCOM_RX_PAD_1) -#define PIN_SERIAL2_RTS (28u) -#define PIN_SERIAL2_CTS (29u) -#define PIN_SERIAL2_DTR (35u) +#define PIN_SERIAL2_RX (27ul) +#define PIN_SERIAL2_TX (26ul) +#define PAD_SERIAL2_TX (UART_TX_RTS_CTS_PAD_0_2_3) +#define PAD_SERIAL2_RX (SERCOM_RX_PAD_1) +#define PERIPH_SERIAL2 sercom4 +#define PIN_SERIAL2_RTS (28u) +#define PIN_SERIAL2_CTS (29u) +#define PIN_SERIAL2_DTR (35u) #endif // __cplusplus diff --git a/variants/mkrnb1500/variant.cpp b/variants/mkrnb1500/variant.cpp index 3cc0a5921..aab3a6496 100644 --- a/variants/mkrnb1500/variant.cpp +++ b/variants/mkrnb1500/variant.cpp @@ -151,7 +151,7 @@ const PinDescription g_APinDescription[] = { { PORTA, 14, PIO_SERCOM_ALT, (PIN_ATTR_DIGITAL ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // SS: as GPIO { PORTA, 15, PIO_SERCOM_ALT, (PIN_ATTR_DIGITAL ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // MISO: SERCOM4/PAD[3] { PORTA, 27, PIO_DIGITAL, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15 }, - + { PORTB, 8, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG ), ADC_Channel2, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, { PORTB, 9, PIO_ANALOG, (PIN_ATTR_PWM|PIN_ATTR_TIMER ), ADC_Channel3, PWM4_CH1, TC4_CH1, EXTERNAL_INT_9 }, @@ -174,6 +174,7 @@ SERCOM sercom5(SERCOM5); #if defined(USE_BQ24195L_PMIC) #include "wiring_private.h" +#include "SERCOM_Txn.h" #define PMIC_ADDRESS 0x6B #define PMIC_REG01 0x01 @@ -185,12 +186,17 @@ static inline void enable_battery_charging() { pinPeripheral(PIN_WIRE_SDA, g_APinDescription[PIN_WIRE_SDA].ulPinType); pinPeripheral(PIN_WIRE_SCL, g_APinDescription[PIN_WIRE_SCL].ulPinType); - PERIPH_WIRE.startTransmissionWIRE( PMIC_ADDRESS, WIRE_WRITE_FLAG ); - PERIPH_WIRE.sendDataMasterWIRE(PMIC_REG01); - PERIPH_WIRE.sendDataMasterWIRE(0x1B); // Charge Battery + Minimum System Voltage 3.5V - PERIPH_WIRE.prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); + static SercomTxn txn; + static uint8_t txData[2] = {PMIC_REG01, 0x1B}; // Charge Battery + Minimum System Voltage 3.5V + + txn = SercomTxn{}; + txn.config = I2C_CFG_STOP; + txn.address = PMIC_ADDRESS; + txn.length = 2; + txn.txPtr = txData; - PERIPH_WIRE.disableWIRE(); + PERIPH_WIRE.enqueueWIRE(&txn); + PERIPH_WIRE.startTransmissionWIRE(); } static inline void disable_battery_fet(bool disabled) { @@ -199,14 +205,21 @@ static inline void disable_battery_fet(bool disabled) { pinPeripheral(PIN_WIRE_SDA, g_APinDescription[PIN_WIRE_SDA].ulPinType); pinPeripheral(PIN_WIRE_SCL, g_APinDescription[PIN_WIRE_SCL].ulPinType); - PERIPH_WIRE.startTransmissionWIRE( PMIC_ADDRESS, WIRE_WRITE_FLAG ); - PERIPH_WIRE.sendDataMasterWIRE(PMIC_REG07); + static SercomTxn txn; + static uint8_t txData[2]; + txData[0] = PMIC_REG07; // No D+/D– detection + Safety timer not slowed by 2X during input DPM or thermal regulation + // BAT fet disabled/enabled + charge and bat fault INT - PERIPH_WIRE.sendDataMasterWIRE(0x0B | (disabled ? 0x20 : 0x00)); - PERIPH_WIRE.prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); + txData[1] = 0x0B | (disabled ? 0x20 : 0x00); + + txn = SercomTxn{}; + txn.config = I2C_CFG_STOP; + txn.address = PMIC_ADDRESS; + txn.length = 2; + txn.txPtr = txData; - PERIPH_WIRE.disableWIRE(); + PERIPH_WIRE.enqueueWIRE(&txn); + PERIPH_WIRE.startTransmissionWIRE(); } #endif @@ -238,19 +251,3 @@ void initVariant() { pinMode(SARA_RTS, OUTPUT); digitalWrite(SARA_RTS, LOW); } - -// Serial1 -Uart Serial1(&sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX); - -void SERCOM5_Handler() -{ - Serial1.IrqHandler(); -} - -// SerialSARA -Uart Serial2(&sercom4, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX); - -void SERCOM4_Handler() -{ - Serial2.IrqHandler(); -} diff --git a/variants/mkrnb1500/variant.h b/variants/mkrnb1500/variant.h index 3482528ce..24e5034d8 100644 --- a/variants/mkrnb1500/variant.h +++ b/variants/mkrnb1500/variant.h @@ -98,13 +98,13 @@ static const uint8_t A6 = PIN_A6; #define SPI_INTERFACES_COUNT 1 // SPI -#define PIN_SPI_MISO (10u) -#define PIN_SPI_MOSI (8u) -#define PIN_SPI_SCK (9u) -#define PIN_SPI_SS (4u) -#define PERIPH_SPI sercom1 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_3 +#define PIN_SPI_MISO (10u) +#define PIN_SPI_MOSI (8u) +#define PIN_SPI_SCK (9u) +#define PIN_SPI_SS (4u) +#define PERIPH_SPI sercom1 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_3 static const uint8_t SS = PIN_SPI_SS; // SPI Slave SS not used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI; @@ -116,10 +116,9 @@ static const uint8_t SCK = PIN_SPI_SCK; #define WIRE_INTERFACES_COUNT 1 // Wire -#define PIN_WIRE_SDA (11u) -#define PIN_WIRE_SCL (12u) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler +#define PIN_WIRE_SDA (11u) +#define PIN_WIRE_SCL (12u) +#define PERIPH_WIRE sercom2 // USB // --- @@ -153,19 +152,21 @@ extern SERCOM sercom5; // Serial1 extern Uart Serial1; -#define PIN_SERIAL1_RX (13ul) -#define PIN_SERIAL1_TX (14ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_2) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_RX (13ul) +#define PIN_SERIAL1_TX (14ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL1 sercom5 // Serial2 - GSM extern Uart Serial2; -#define PIN_SERIAL2_RX (27ul) -#define PIN_SERIAL2_TX (26ul) -#define PAD_SERIAL2_TX (UART_TX_PAD_0) -#define PAD_SERIAL2_RX (SERCOM_RX_PAD_1) -#define PIN_SERIAL2_RTS (28u) -#define PIN_SERIAL2_CTS (29u) +#define PIN_SERIAL2_RX (27ul) +#define PIN_SERIAL2_TX (26ul) +#define PAD_SERIAL2_TX (UART_TX_PAD_0) +#define PAD_SERIAL2_RX (SERCOM_RX_PAD_1) +#define PERIPH_SERIAL2 sercom4 +#define PIN_SERIAL2_RTS (28u) +#define PIN_SERIAL2_CTS (29u) #endif // __cplusplus diff --git a/variants/mkrwan1300/variant.cpp b/variants/mkrwan1300/variant.cpp index c9a19c5be..7be6e72eb 100644 --- a/variants/mkrwan1300/variant.cpp +++ b/variants/mkrwan1300/variant.cpp @@ -148,7 +148,7 @@ const PinDescription g_APinDescription[] = { { PORTA, 14, PIO_DIGITAL, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // SS: as GPIO { PORTA, 15, PIO_SERCOM_ALT, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // MISO: SERCOM4/PAD[3] { PORTA, 27, PIO_DIGITAL, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, - + { PORTA, 28, PIO_DIGITAL, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, { PORTB, 8, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG ), ADC_Channel2, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, { PORTB, 9, PIO_DIGITAL, (PIN_ATTR_PWM|PIN_ATTR_TIMER ), ADC_Channel3, PWM4_CH1, TC4_CH1, EXTERNAL_INT_9 }, @@ -172,17 +172,5 @@ SERCOM sercom4(SERCOM4); SERCOM sercom5(SERCOM5); // Serial1 -Uart Serial1(&sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX); - -void SERCOM5_Handler() -{ - Serial1.IrqHandler(); -} // SerialLoRa -Uart Serial2(&sercom4, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX); - -void SERCOM4_Handler() -{ - Serial2.IrqHandler(); -} \ No newline at end of file diff --git a/variants/mkrwan1300/variant.h b/variants/mkrwan1300/variant.h index 7368e02f5..883ab02b2 100644 --- a/variants/mkrwan1300/variant.h +++ b/variants/mkrwan1300/variant.h @@ -95,13 +95,13 @@ static const uint8_t A6 = PIN_A6; #define SPI_INTERFACES_COUNT 2 // SPI -#define PIN_SPI_MISO (10u) -#define PIN_SPI_MOSI (8u) -#define PIN_SPI_SCK (9u) -#define PIN_SPI_SS (4u) -#define PERIPH_SPI sercom1 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_3 +#define PIN_SPI_MISO (10u) +#define PIN_SPI_MOSI (8u) +#define PIN_SPI_SCK (9u) +#define PIN_SPI_SS (4u) +#define PERIPH_SPI sercom1 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_3 static const uint8_t SS = PIN_SPI_SS; // SPI Slave SS not used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI; @@ -109,13 +109,13 @@ static const uint8_t MISO = PIN_SPI_MISO; static const uint8_t SCK = PIN_SPI_SCK; // SPI1 -#define PIN_SPI1_MISO (38u) -#define PIN_SPI1_MOSI (36u) -#define PIN_SPI1_SCK (37u) +#define PIN_SPI1_MISO (38u) +#define PIN_SPI1_MOSI (36u) +#define PIN_SPI1_SCK (37u) #define LORA_IRQ_DUMB (28u) -#define PERIPH_SPI1 sercom4 -#define PAD_SPI1_TX SPI_PAD_0_SCK_1 -#define PAD_SPI1_RX SERCOM_RX_PAD_3 +#define PERIPH_SPI1 sercom4 +#define PAD_SPI1_TX SPI_PAD_0_SCK_1 +#define PAD_SPI1_RX SERCOM_RX_PAD_3 static const uint8_t MOSI1 = PIN_SPI1_MOSI; static const uint8_t MISO1 = PIN_SPI1_MISO; static const uint8_t SCK1 = PIN_SPI1_SCK; @@ -125,10 +125,9 @@ static const uint8_t SCK1 = PIN_SPI1_SCK; #define WIRE_INTERFACES_COUNT 1 // Wire -#define PIN_WIRE_SDA (11u) -#define PIN_WIRE_SCL (12u) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler +#define PIN_WIRE_SDA (11u) +#define PIN_WIRE_SCL (12u) +#define PERIPH_WIRE sercom2 // USB // --- @@ -162,17 +161,19 @@ extern SERCOM sercom5; // Serial1 extern Uart Serial1; -#define PIN_SERIAL1_RX (13ul) -#define PIN_SERIAL1_TX (14ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_2) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_RX (13ul) +#define PIN_SERIAL1_TX (14ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL1 sercom5 // Serial2 extern Uart Serial2; -#define PIN_SERIAL2_RX (29ul) -#define PIN_SERIAL2_TX (26ul) -#define PAD_SERIAL2_TX (UART_TX_PAD_0) -#define PAD_SERIAL2_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL2_RX (29ul) +#define PIN_SERIAL2_TX (26ul) +#define PAD_SERIAL2_TX (UART_TX_PAD_0) +#define PAD_SERIAL2_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL2 sercom4 #endif // __cplusplus diff --git a/variants/mkrwifi1010/variant.cpp b/variants/mkrwifi1010/variant.cpp index f1938506b..7739e3d05 100644 --- a/variants/mkrwifi1010/variant.cpp +++ b/variants/mkrwifi1010/variant.cpp @@ -151,7 +151,7 @@ const PinDescription g_APinDescription[] = { { PORTA, 14, PIO_DIGITAL, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // SS: as GPIO { PORTA, 15, PIO_SERCOM_ALT, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // MISO: SERCOM4/PAD[3] { PORTA, 27, PIO_DIGITAL, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15 }, - + { PORTB, 8, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG ), ADC_Channel2, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, { PORTB, 9, PIO_ANALOG, (PIN_ATTR_PWM|PIN_ATTR_TIMER ), ADC_Channel3, PWM4_CH1, TC4_CH1, EXTERNAL_INT_9 }, @@ -174,6 +174,7 @@ SERCOM sercom5(SERCOM5); #if defined(USE_BQ24195L_PMIC) #include "wiring_private.h" +#include "SERCOM_Txn.h" #define PMIC_ADDRESS 0x6B #define PMIC_REG01 0x01 @@ -185,12 +186,17 @@ static inline void enable_battery_charging() { pinPeripheral(PIN_WIRE_SDA, g_APinDescription[PIN_WIRE_SDA].ulPinType); pinPeripheral(PIN_WIRE_SCL, g_APinDescription[PIN_WIRE_SCL].ulPinType); - PERIPH_WIRE.startTransmissionWIRE( PMIC_ADDRESS, WIRE_WRITE_FLAG ); - PERIPH_WIRE.sendDataMasterWIRE(PMIC_REG01); - PERIPH_WIRE.sendDataMasterWIRE(0x1B); // Charge Battery + Minimum System Voltage 3.5V - PERIPH_WIRE.prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); + static SercomTxn txn; + static uint8_t txData[2] = {PMIC_REG01, 0x1B}; // Charge Battery + Minimum System Voltage 3.5V + + txn = SercomTxn{}; + txn.config = I2C_CFG_STOP; + txn.address = PMIC_ADDRESS; + txn.length = 2; + txn.txPtr = txData; - PERIPH_WIRE.disableWIRE(); + PERIPH_WIRE.enqueueWIRE(&txn); + PERIPH_WIRE.startTransmissionWIRE(); } static inline void disable_battery_fet(bool disabled) { @@ -199,14 +205,21 @@ static inline void disable_battery_fet(bool disabled) { pinPeripheral(PIN_WIRE_SDA, g_APinDescription[PIN_WIRE_SDA].ulPinType); pinPeripheral(PIN_WIRE_SCL, g_APinDescription[PIN_WIRE_SCL].ulPinType); - PERIPH_WIRE.startTransmissionWIRE( PMIC_ADDRESS, WIRE_WRITE_FLAG ); - PERIPH_WIRE.sendDataMasterWIRE(PMIC_REG07); + static SercomTxn txn; + static uint8_t txData[2]; + txData[0] = PMIC_REG07; // No D+/D– detection + Safety timer not slowed by 2X during input DPM or thermal regulation + // BAT fet disabled/enabled + charge and bat fault INT - PERIPH_WIRE.sendDataMasterWIRE(0x0B | (disabled ? 0x20 : 0x00)); - PERIPH_WIRE.prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); + txData[1] = 0x0B | (disabled ? 0x20 : 0x00); + + txn = SercomTxn{}; + txn.config = I2C_CFG_STOP; + txn.address = PMIC_ADDRESS; + txn.length = 2; + txn.txPtr = txData; - PERIPH_WIRE.disableWIRE(); + PERIPH_WIRE.enqueueWIRE(&txn); + PERIPH_WIRE.startTransmissionWIRE(); } #endif @@ -234,19 +247,3 @@ void initVariant() { pinMode(NINA_RESETN, OUTPUT); digitalWrite(NINA_RESETN, HIGH); } - -// Serial1 -Uart Serial1(&sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX); - -void SERCOM5_Handler() -{ - Serial1.IrqHandler(); -} - -// Serial2 -Uart Serial2(&sercom4, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX, PIN_SERIAL2_RTS, PIN_SERIAL2_CTS); - -void SERCOM4_Handler() -{ - Serial2.IrqHandler(); -} diff --git a/variants/mkrwifi1010/variant.h b/variants/mkrwifi1010/variant.h index dcd7f7775..9dbd832b8 100644 --- a/variants/mkrwifi1010/variant.h +++ b/variants/mkrwifi1010/variant.h @@ -96,13 +96,13 @@ static const uint8_t A6 = PIN_A6; #define SPI_INTERFACES_COUNT 2 // SPI -#define PIN_SPI_MISO (10u) -#define PIN_SPI_MOSI (8u) -#define PIN_SPI_SCK (9u) -#define PIN_SPI_SS (4u) -#define PERIPH_SPI sercom1 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_3 +#define PIN_SPI_MISO (10u) +#define PIN_SPI_MOSI (8u) +#define PIN_SPI_SCK (9u) +#define PIN_SPI_SS (4u) +#define PERIPH_SPI sercom1 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_3 static const uint8_t SS = PIN_SPI_SS; // SPI Slave SS not used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI; @@ -110,13 +110,13 @@ static const uint8_t MISO = PIN_SPI_MISO; static const uint8_t SCK = PIN_SPI_SCK; // SPI1 -#define PIN_SPI1_MISO (27u) -#define PIN_SPI1_MOSI (26u) -#define PIN_SPI1_SCK (29u) -#define PIN_SPI1_SS (28u) -#define PERIPH_SPI1 sercom4 -#define PAD_SPI1_TX SPI_PAD_0_SCK_3 -#define PAD_SPI1_RX SERCOM_RX_PAD_1 +#define PIN_SPI1_MISO (27u) +#define PIN_SPI1_MOSI (26u) +#define PIN_SPI1_SCK (29u) +#define PIN_SPI1_SS (28u) +#define PERIPH_SPI1 sercom4 +#define PAD_SPI1_TX SPI_PAD_0_SCK_3 +#define PAD_SPI1_RX SERCOM_RX_PAD_1 static const uint8_t SS1 = PIN_SPI1_SS; static const uint8_t MOSI1 = PIN_SPI1_MOSI; static const uint8_t MISO1 = PIN_SPI1_MISO; @@ -132,10 +132,9 @@ static const uint8_t SCK1 = PIN_SPI1_SCK; #define WIRE_INTERFACES_COUNT 1 // Wire -#define PIN_WIRE_SDA (11u) -#define PIN_WIRE_SCL (12u) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler +#define PIN_WIRE_SDA (11u) +#define PIN_WIRE_SCL (12u) +#define PERIPH_WIRE sercom2 // USB // --- @@ -169,19 +168,21 @@ extern SERCOM sercom5; // Serial1 extern Uart Serial1; -#define PIN_SERIAL1_RX (13ul) -#define PIN_SERIAL1_TX (14ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_2) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_RX (13ul) +#define PIN_SERIAL1_TX (14ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL1 sercom5 // Serial2 extern Uart Serial2; -#define PIN_SERIAL2_RX (27ul) -#define PIN_SERIAL2_TX (26ul) -#define PAD_SERIAL2_TX (UART_TX_RTS_CTS_PAD_0_2_3) -#define PAD_SERIAL2_RX (SERCOM_RX_PAD_1) -#define PIN_SERIAL2_RTS (28u) -#define PIN_SERIAL2_CTS (29u) +#define PIN_SERIAL2_RX (27ul) +#define PIN_SERIAL2_TX (26ul) +#define PAD_SERIAL2_TX (UART_TX_RTS_CTS_PAD_0_2_3) +#define PAD_SERIAL2_RX (SERCOM_RX_PAD_1) +#define PERIPH_SERIAL2 sercom4 +#define PIN_SERIAL2_RTS (28u) +#define PIN_SERIAL2_CTS (29u) #endif // __cplusplus diff --git a/variants/mkrzero/variant.cpp b/variants/mkrzero/variant.cpp index 30b359150..96feae51e 100644 --- a/variants/mkrzero/variant.cpp +++ b/variants/mkrzero/variant.cpp @@ -150,7 +150,7 @@ const PinDescription g_APinDescription[] = { { PORTA, 14, PIO_DIGITAL, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // SS: as GPIO { PORTA, 15, PIO_SERCOM_ALT, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // MISO: SERCOM4/PAD[3] { PORTA, 27, PIO_DIGITAL, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, - + { PORTA, 28, PIO_DIGITAL, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, { PORTB, 8, PIO_DIGITAL, (PIN_ATTR_NONE ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, { PORTB, 9, PIO_ANALOG, (PIN_ATTR_PWM|PIN_ATTR_TIMER ), ADC_Channel3, PWM4_CH1, TC4_CH1, EXTERNAL_INT_9 }, @@ -170,10 +170,3 @@ SERCOM sercom4(SERCOM4); SERCOM sercom5(SERCOM5); // Serial1 -Uart Serial1(&sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX); - -void SERCOM5_Handler() -{ - Serial1.IrqHandler(); -} - diff --git a/variants/mkrzero/variant.h b/variants/mkrzero/variant.h index ca59b5ab2..a11ebbb1a 100644 --- a/variants/mkrzero/variant.h +++ b/variants/mkrzero/variant.h @@ -91,13 +91,13 @@ static const uint8_t A6 = PIN_A6; #define SPI_INTERFACES_COUNT 2 // SPI -#define PIN_SPI_MISO (10u) -#define PIN_SPI_MOSI (8u) -#define PIN_SPI_SCK (9u) -#define PIN_SPI_SS (4u) -#define PERIPH_SPI sercom1 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_3 +#define PIN_SPI_MISO (10u) +#define PIN_SPI_MOSI (8u) +#define PIN_SPI_SCK (9u) +#define PIN_SPI_SS (4u) +#define PERIPH_SPI sercom1 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_3 static const uint8_t SS = PIN_SPI_SS; // SPI Slave SS not used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI; @@ -105,13 +105,13 @@ static const uint8_t MISO = PIN_SPI_MISO; static const uint8_t SCK = PIN_SPI_SCK; // SPI1: Connected to SD -#define PIN_SPI1_MISO (29u) -#define PIN_SPI1_MOSI (26u) -#define PIN_SPI1_SCK (27u) -#define PIN_SPI1_SS (28u) -#define PERIPH_SPI1 sercom4 -#define PAD_SPI1_TX SPI_PAD_0_SCK_1 -#define PAD_SPI1_RX SERCOM_RX_PAD_3 +#define PIN_SPI1_MISO (29u) +#define PIN_SPI1_MOSI (26u) +#define PIN_SPI1_SCK (27u) +#define PIN_SPI1_SS (28u) +#define PERIPH_SPI1 sercom4 +#define PAD_SPI1_TX SPI_PAD_0_SCK_1 +#define PAD_SPI1_RX SERCOM_RX_PAD_3 static const uint8_t SS1 = PIN_SPI1_SS; static const uint8_t MOSI1 = PIN_SPI1_MOSI; static const uint8_t MISO1 = PIN_SPI1_MISO; @@ -129,10 +129,9 @@ static const uint8_t SCK1 = PIN_SPI1_SCK; #define WIRE_INTERFACES_COUNT 1 // Wire -#define PIN_WIRE_SDA (11u) -#define PIN_WIRE_SCL (12u) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler +#define PIN_WIRE_SDA (11u) +#define PIN_WIRE_SCL (12u) +#define PERIPH_WIRE sercom2 // USB // --- @@ -166,10 +165,11 @@ extern SERCOM sercom5; // Serial1 extern Uart Serial1; -#define PIN_SERIAL1_RX (13ul) -#define PIN_SERIAL1_TX (14ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_2) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_RX (13ul) +#define PIN_SERIAL1_TX (14ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL1 sercom5 #endif // __cplusplus // These serial port names are intended to allow libraries and architecture-neutral diff --git a/variants/monster_m4sk/variant.h b/variants/monster_m4sk/variant.h index eb3a283fe..d33cd24cf 100644 --- a/variants/monster_m4sk/variant.h +++ b/variants/monster_m4sk/variant.h @@ -114,10 +114,10 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) // sercom3 -#define PIN_SERIAL1_TX (1ul) // sercom3 -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PIN_SERIAL1_RX (0ul) // sercom3 +#define PIN_SERIAL1_TX (1ul) // sercom3 +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) /* * SPI Interfaces @@ -125,12 +125,12 @@ static const uint8_t ATN = PIN_ATN; #define SPI_INTERFACES_COUNT 3 // Right TFT -#define PIN_SPI_MISO (6u) // actually DC pin, ignored -#define PIN_SPI_SCK (8u) -#define PIN_SPI_MOSI (7u) -#define PERIPH_SPI sercom2 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_3 +#define PIN_SPI_MISO (6u) // actually DC pin, ignored +#define PIN_SPI_SCK (8u) +#define PIN_SPI_MOSI (7u) +#define PERIPH_SPI sercom2 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_3 static const uint8_t SS = 5 ; static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -138,12 +138,12 @@ static const uint8_t MISO = PIN_SPI_MISO ; static const uint8_t SCK = PIN_SPI_SCK ; // Left TFT -#define PIN_SPI1_MISO (10u) // actually DC pin, ignored -#define PIN_SPI1_SCK (12u) -#define PIN_SPI1_MOSI (11u) -#define PERIPH_SPI1 sercom5 -#define PAD_SPI1_TX SPI_PAD_0_SCK_1 -#define PAD_SPI1_RX SERCOM_RX_PAD_3 +#define PIN_SPI1_MISO (10u) // actually DC pin, ignored +#define PIN_SPI1_SCK (12u) +#define PIN_SPI1_MOSI (11u) +#define PERIPH_SPI1 sercom5 +#define PAD_SPI1_TX SPI_PAD_0_SCK_1 +#define PAD_SPI1_RX SERCOM_RX_PAD_3 static const uint8_t SS1 = 9 ; static const uint8_t MOSI1 = PIN_SPI_MOSI ; @@ -151,12 +151,12 @@ static const uint8_t MISO1 = PIN_SPI_MISO ; static const uint8_t SCK1 = PIN_SPI_SCK ; // SPI for PDM -#define PIN_SPI2_MISO (23u) -#define PIN_SPI2_SCK (24u) -#define PIN_SPI2_MOSI (13u) // actually LED, ignored -#define PERIPH_SPI2 sercom3 -#define PAD_SPI2_TX SPI_PAD_3_SCK_1 -#define PAD_SPI2_RX SERCOM_RX_PAD_0 +#define PIN_SPI2_MISO (23u) +#define PIN_SPI2_SCK (24u) +#define PIN_SPI2_MOSI (13u) // actually LED, ignored +#define PERIPH_SPI2 sercom3 +#define PAD_SPI2_TX SPI_PAD_3_SCK_1 +#define PAD_SPI2_RX SERCOM_RX_PAD_0 static const uint8_t SS2 = 13 ; // also ignored static const uint8_t MOSI2 = PIN_SPI_MOSI ; @@ -169,14 +169,9 @@ static const uint8_t SCK2 = PIN_SPI_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (18u) -#define PIN_WIRE_SCL (19u) -#define PERIPH_WIRE sercom1 -#define WIRE_IT_HANDLER SERCOM1_Handler -#define WIRE_IT_HANDLER_0 SERCOM1_0_Handler -#define WIRE_IT_HANDLER_1 SERCOM1_1_Handler -#define WIRE_IT_HANDLER_2 SERCOM1_2_Handler -#define WIRE_IT_HANDLER_3 SERCOM1_3_Handler +#define PIN_WIRE_SDA (18u) +#define PIN_WIRE_SCL (19u) +#define PERIPH_WIRE sercom1 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/neokeytrinkey_m0/variant.cpp b/variants/neokeytrinkey_m0/variant.cpp index e64ad7b21..4e58e9f3c 100644 --- a/variants/neokeytrinkey_m0/variant.cpp +++ b/variants/neokeytrinkey_m0/variant.cpp @@ -27,19 +27,19 @@ const PinDescription g_APinDescription[]= { PORTA, 15, PIO_DIGITAL, (PIN_ATTR_DIGITAL), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15 }, // Mechanical switch - { PORTA, 28, PIO_DIGITAL, (PIN_ATTR_DIGITAL), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_8 }, + { PORTA, 28, PIO_DIGITAL, (PIN_ATTR_DIGITAL), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_8 }, // Touch pad - { PORTA, 7, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel7, PWM1_CH1, TCC1_CH1, EXTERNAL_INT_7 }, + { PORTA, 7, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel7, PWM1_CH1, TCC1_CH1, EXTERNAL_INT_7 }, + - // USB pins { PORTA, 28, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB Host enable { PORTA, 24, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB/DM { PORTA, 25, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB/DP // Fake DAC pin just so we can compile stuff - { PORTA, 2, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel0, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_2 }, // A0 / D0 / DAC + { PORTA, 2, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel0, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_2 }, // A0 / D0 / DAC } ; const void* g_apTCInstances[TCC_INST_NUM+TC_INST_NUM]={ TCC0, TCC1, TCC2, TC3, TC4, TC5 } ; diff --git a/variants/neokeytrinkey_m0/variant.h b/variants/neokeytrinkey_m0/variant.h index 27e532bf4..3298f854b 100644 --- a/variants/neokeytrinkey_m0/variant.h +++ b/variants/neokeytrinkey_m0/variant.h @@ -102,12 +102,12 @@ static const uint8_t A1 = PIN_A1; */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO PIN_A0 -#define PIN_SPI_MOSI PIN_A0 -#define PIN_SPI_SCK PIN_A0 -#define PERIPH_SPI sercom0 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_0 +#define PIN_SPI_MISO PIN_A0 +#define PIN_SPI_MOSI PIN_A0 +#define PIN_SPI_SCK PIN_A0 +#define PERIPH_SPI sercom0 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_0 static const uint8_t SS = PIN_A0; static const uint8_t MOSI = PIN_SPI_MOSI; diff --git a/variants/neotrinkey_m0/variant.cpp b/variants/neotrinkey_m0/variant.cpp index 150034974..e4e9adbb3 100644 --- a/variants/neotrinkey_m0/variant.cpp +++ b/variants/neotrinkey_m0/variant.cpp @@ -30,7 +30,7 @@ const PinDescription g_APinDescription[]= { PORTA, 3, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG), ADC_Channel1, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_3 }, // Touch Pin 2 - { PORTA, 7, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel7, PWM1_CH1, TCC1_CH1, EXTERNAL_INT_7 }, + { PORTA, 7, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel7, PWM1_CH1, TCC1_CH1, EXTERNAL_INT_7 }, // USB pins { PORTA, 28, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB Host enable @@ -38,7 +38,7 @@ const PinDescription g_APinDescription[]= { PORTA, 25, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB/DP // Fake DAC pin just so we can compile stuff - { PORTA, 2, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel0, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_2 }, // A0 / D0 / DAC + { PORTA, 2, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel0, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_2 }, // A0 / D0 / DAC } ; const void* g_apTCInstances[TCC_INST_NUM+TC_INST_NUM]={ TCC0, TCC1, TCC2, TC3, TC4, TC5 } ; diff --git a/variants/neotrinkey_m0/variant.h b/variants/neotrinkey_m0/variant.h index 3cf172c23..82dde49e2 100644 --- a/variants/neotrinkey_m0/variant.h +++ b/variants/neotrinkey_m0/variant.h @@ -101,12 +101,12 @@ static const uint8_t A2 = PIN_A2; */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO PIN_A0 -#define PIN_SPI_MOSI PIN_A0 -#define PIN_SPI_SCK PIN_A0 -#define PERIPH_SPI sercom0 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_0 +#define PIN_SPI_MISO PIN_A0 +#define PIN_SPI_MOSI PIN_A0 +#define PIN_SPI_SCK PIN_A0 +#define PERIPH_SPI sercom0 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_0 static const uint8_t SS = PIN_A0; static const uint8_t MOSI = PIN_SPI_MOSI; diff --git a/variants/pirkey/variant.cpp b/variants/pirkey/variant.cpp index 61734c020..f0cdbe448 100644 --- a/variants/pirkey/variant.cpp +++ b/variants/pirkey/variant.cpp @@ -86,11 +86,3 @@ SERCOM sercom0( SERCOM0 ) ; SERCOM sercom1( SERCOM1 ) ; SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; - -Uart Serial1( &sercom1, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM1_Handler() -{ - Serial1.IrqHandler(); -} - diff --git a/variants/pirkey/variant.h b/variants/pirkey/variant.h index e6d0ce74a..9dd0a5d56 100644 --- a/variants/pirkey/variant.h +++ b/variants/pirkey/variant.h @@ -113,10 +113,11 @@ static const uint8_t DAC0 = PIN_DAC0; */ // Serial1 (sercom 1) -#define PIN_SERIAL1_RX (4ul) // SWDIO PA31 -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) -#define PIN_SERIAL1_TX (3ul) // SWCLK PA30 -#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PIN_SERIAL1_RX (4ul) // SWDIO PA31 +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_TX (3ul) // SWCLK PA30 +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PERIPH_SERIAL1 sercom1 /* * SPI Interfaces diff --git a/variants/pixeltrinkey_m0/variant.cpp b/variants/pixeltrinkey_m0/variant.cpp index 15c9cce9c..2ce95e009 100644 --- a/variants/pixeltrinkey_m0/variant.cpp +++ b/variants/pixeltrinkey_m0/variant.cpp @@ -24,7 +24,7 @@ const PinDescription g_APinDescription[]= { // DAC / A0 for monitoring 5V - { PORTA, 2, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel0, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_2 }, // A0 / D0 / DAC + { PORTA, 2, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel0, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_2 }, // A0 / D0 / DAC // Internal NeoPixel / D1 { PORTA, 1, PIO_ANALOG, PIN_ATTR_ANALOG, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, diff --git a/variants/pixeltrinkey_m0/variant.h b/variants/pixeltrinkey_m0/variant.h index 9a2b8222f..a9ee352bc 100644 --- a/variants/pixeltrinkey_m0/variant.h +++ b/variants/pixeltrinkey_m0/variant.h @@ -103,12 +103,12 @@ static const uint8_t A6 = PIN_A6; */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO (4ul) // off 3-pin JST, broken out -#define PIN_SPI_MOSI (2ul) -#define PIN_SPI_SCK (3ul) -#define PERIPH_SPI sercom0 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_2 +#define PIN_SPI_MISO (4ul) // off 3-pin JST, broken out +#define PIN_SPI_MOSI (2ul) +#define PIN_SPI_SCK (3ul) +#define PERIPH_SPI sercom0 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_2 static const uint8_t SS = (5ul); // not actually broken out static const uint8_t MOSI = PIN_SPI_MOSI; @@ -120,10 +120,9 @@ static const uint8_t SCK = PIN_SPI_SCK; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (2u) -#define PIN_WIRE_SCL (3u) -#define PERIPH_WIRE sercom0 -#define WIRE_IT_HANDLER SERCOM0_Handler +#define PIN_WIRE_SDA (2u) +#define PIN_WIRE_SCL (3u) +#define PERIPH_WIRE sercom0 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/proxlighttrinkey_m0/variant.cpp b/variants/proxlighttrinkey_m0/variant.cpp index d9688d084..8efea6e18 100644 --- a/variants/proxlighttrinkey_m0/variant.cpp +++ b/variants/proxlighttrinkey_m0/variant.cpp @@ -24,7 +24,7 @@ const PinDescription g_APinDescription[]= { // Fake DAC A0 pin just so we can compile stuff - { PORTA, 2, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel0, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_2 }, // A0 / D0 / DAC + { PORTA, 2, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel0, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_2 }, // A0 / D0 / DAC // touch 1 / A1 { PORTA, 7, PIO_ANALOG, (PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel7, PWM1_CH1, TCC1_CH1, EXTERNAL_INT_7 }, // TCC1/WO[1] @@ -40,7 +40,7 @@ const PinDescription g_APinDescription[]= // Interrupt D6 { PORTA, 0, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_0 }, - + // USB pins D7, D8, D9 { PORTA, 28, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB Host enable { PORTA, 24, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB/DM diff --git a/variants/proxlighttrinkey_m0/variant.h b/variants/proxlighttrinkey_m0/variant.h index 93554eafc..6dccd31c0 100644 --- a/variants/proxlighttrinkey_m0/variant.h +++ b/variants/proxlighttrinkey_m0/variant.h @@ -107,12 +107,12 @@ static const uint8_t A2 = PIN_A2; */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO PIN_A0 -#define PIN_SPI_MOSI PIN_A0 -#define PIN_SPI_SCK PIN_A0 -#define PERIPH_SPI sercom0 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_0 +#define PIN_SPI_MISO PIN_A0 +#define PIN_SPI_MOSI PIN_A0 +#define PIN_SPI_SCK PIN_A0 +#define PERIPH_SPI sercom0 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_0 static const uint8_t SS = PIN_A0; static const uint8_t MOSI = PIN_SPI_MOSI; @@ -124,10 +124,9 @@ static const uint8_t SCK = PIN_SPI_SCK; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (4u) -#define PIN_WIRE_SCL (5u) -#define PERIPH_WIRE sercom1 -#define WIRE_IT_HANDLER SERCOM1_Handler +#define PIN_WIRE_SDA (4u) +#define PIN_WIRE_SCL (5u) +#define PERIPH_WIRE sercom1 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/pybadge_airlift_m4/variant.cpp b/variants/pybadge_airlift_m4/variant.cpp index ce2304ba1..fbc8dd93a 100644 --- a/variants/pybadge_airlift_m4/variant.cpp +++ b/variants/pybadge_airlift_m4/variant.cpp @@ -119,7 +119,7 @@ const PinDescription g_APinDescription[] = // ESP GPIO0, BUSY, RESET (52-54) {PORTA, 31, PIO_DIGITAL, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE}, // D52 ESP32_GPIO0 {PORTA, 0, PIO_DIGITAL, PIN_ATTR_PWM_E, No_ADC_Channel, TC2_CH0, TC2_CH0, EXTERNAL_INT_0}, // D53 ESP32_BUSY - {PORTB, 12, PIO_DIGITAL, PIN_ATTR_PWM_F, No_ADC_Channel, TCC3_CH0, TC4_CH0, EXTERNAL_INT_12}, // D54 ESP32_RESET + {PORTB, 12, PIO_DIGITAL, PIN_ATTR_PWM_F, No_ADC_Channel, TCC3_CH0, TC4_CH0, EXTERNAL_INT_12}, // D54 ESP32_RESET }; @@ -133,22 +133,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM5_0_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_1_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_2_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_3_Handler() -{ - Serial1.IrqHandler(); -} diff --git a/variants/pybadge_airlift_m4/variant.h b/variants/pybadge_airlift_m4/variant.h index 0887238d5..351fd9619 100644 --- a/variants/pybadge_airlift_m4/variant.h +++ b/variants/pybadge_airlift_m4/variant.h @@ -140,22 +140,23 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL1 sercom5 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 2 -#define PIN_SPI_MISO (26u) -#define PIN_SPI_MOSI (27u) -#define PIN_SPI_SCK (28u) -#define PERIPH_SPI sercom1 -#define PAD_SPI_TX SPI_PAD_3_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_2 +#define PIN_SPI_MISO (26u) +#define PIN_SPI_MOSI (27u) +#define PIN_SPI_SCK (28u) +#define PERIPH_SPI sercom1 +#define PAD_SPI_TX SPI_PAD_3_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_2 static const uint8_t SS = 9 ; // SERCOM1 last PAD is present on d9 but HW SS isn't used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -163,12 +164,12 @@ static const uint8_t MISO = PIN_SPI_MISO ; static const uint8_t SCK = PIN_SPI_SCK ; // Internal SPI for TFT -#define PIN_SPI1_MOSI (41u) -#define PIN_SPI1_SCK (42u) -#define PIN_SPI1_MISO (43u) -#define PERIPH_SPI1 sercom4 -#define PAD_SPI1_TX SPI_PAD_3_SCK_1 -#define PAD_SPI1_RX SERCOM_RX_PAD_0 +#define PIN_SPI1_MOSI (41u) +#define PIN_SPI1_SCK (42u) +#define PIN_SPI1_MISO (43u) +#define PERIPH_SPI1 sercom4 +#define PAD_SPI1_TX SPI_PAD_3_SCK_1 +#define PAD_SPI1_RX SERCOM_RX_PAD_0 static const uint8_t SS1 = 44 ; static const uint8_t MOSI1 = PIN_SPI1_MOSI ; @@ -180,14 +181,9 @@ static const uint8_t SCK1 = PIN_SPI1_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (24u) -#define PIN_WIRE_SCL (25u) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler -#define WIRE_IT_HANDLER_0 SERCOM2_0_Handler -#define WIRE_IT_HANDLER_1 SERCOM2_1_Handler -#define WIRE_IT_HANDLER_2 SERCOM2_2_Handler -#define WIRE_IT_HANDLER_3 SERCOM2_3_Handler +#define PIN_WIRE_SDA (24u) +#define PIN_WIRE_SCL (25u) +#define PERIPH_WIRE sercom2 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/pybadge_m4/variant.cpp b/variants/pybadge_m4/variant.cpp index ebc2c7f48..61aaee045 100644 --- a/variants/pybadge_m4/variant.cpp +++ b/variants/pybadge_m4/variant.cpp @@ -46,7 +46,7 @@ const PinDescription g_APinDescription[]= { PORTA, 22, PIO_SERCOM, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH2, TC4_CH0, EXTERNAL_INT_6 }, // 13 (LED) - { PORTA, 23, PIO_SERCOM, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH3, TC4_CH1, EXTERNAL_INT_7 }, + { PORTA, 23, PIO_SERCOM, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH3, TC4_CH1, EXTERNAL_INT_7 }, // 14..23 - Analog pins // -------------------- @@ -113,7 +113,7 @@ const PinDescription g_APinDescription[]= { PORTB, 31, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15 }, // D48 button clock { PORTB, 30, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_14 }, // D49 button data { PORTB, 0, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_0 }, // D50 button latch - + // D51 Speaker enable { PORTA, 27, PIO_DIGITAL, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, @@ -131,22 +131,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM5_0_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_1_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_2_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_3_Handler() -{ - Serial1.IrqHandler(); -} diff --git a/variants/pybadge_m4/variant.h b/variants/pybadge_m4/variant.h index fbfb6824a..256313cd1 100644 --- a/variants/pybadge_m4/variant.h +++ b/variants/pybadge_m4/variant.h @@ -128,22 +128,23 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL1 sercom5 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 3 -#define PIN_SPI_MISO (26u) -#define PIN_SPI_MOSI (27u) -#define PIN_SPI_SCK (28u) -#define PERIPH_SPI sercom1 -#define PAD_SPI_TX SPI_PAD_3_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_2 +#define PIN_SPI_MISO (26u) +#define PIN_SPI_MOSI (27u) +#define PIN_SPI_SCK (28u) +#define PERIPH_SPI sercom1 +#define PAD_SPI_TX SPI_PAD_3_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_2 static const uint8_t SS = 9 ; // SERCOM1 last PAD is present on d9 but HW SS isn't used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -151,12 +152,12 @@ static const uint8_t MISO = PIN_SPI_MISO ; static const uint8_t SCK = PIN_SPI_SCK ; // Internal SPI for TFT -#define PIN_SPI1_MOSI (41u) -#define PIN_SPI1_SCK (42u) -#define PIN_SPI1_MISO (43u) -#define PERIPH_SPI1 sercom4 -#define PAD_SPI1_TX SPI_PAD_3_SCK_1 -#define PAD_SPI1_RX SERCOM_RX_PAD_0 +#define PIN_SPI1_MOSI (41u) +#define PIN_SPI1_SCK (42u) +#define PIN_SPI1_MISO (43u) +#define PERIPH_SPI1 sercom4 +#define PAD_SPI1_TX SPI_PAD_3_SCK_1 +#define PAD_SPI1_RX SERCOM_RX_PAD_0 static const uint8_t SS1 = 44 ; static const uint8_t MOSI1 = PIN_SPI1_MOSI ; @@ -164,12 +165,12 @@ static const uint8_t MISO1 = PIN_SPI1_MISO ; static const uint8_t SCK1 = PIN_SPI1_SCK ; // SPI for PDM mic -#define PIN_SPI2_MOSI (9u) -#define PIN_SPI2_SCK (5u) -#define PIN_SPI2_MISO (6u) -#define PERIPH_SPI2 sercom3 -#define PAD_SPI2_TX SPI_PAD_3_SCK_1 -#define PAD_SPI2_RX SERCOM_RX_PAD_2 +#define PIN_SPI2_MOSI (9u) +#define PIN_SPI2_SCK (5u) +#define PIN_SPI2_MISO (6u) +#define PERIPH_SPI2 sercom3 +#define PAD_SPI2_TX SPI_PAD_3_SCK_1 +#define PAD_SPI2_RX SERCOM_RX_PAD_2 static const uint8_t SS2 = 10 ; static const uint8_t MOSI2 = PIN_SPI2_MOSI ; @@ -181,14 +182,9 @@ static const uint8_t SCK2 = PIN_SPI2_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (24u) -#define PIN_WIRE_SCL (25u) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler -#define WIRE_IT_HANDLER_0 SERCOM2_0_Handler -#define WIRE_IT_HANDLER_1 SERCOM2_1_Handler -#define WIRE_IT_HANDLER_2 SERCOM2_2_Handler -#define WIRE_IT_HANDLER_3 SERCOM2_3_Handler +#define PIN_WIRE_SDA (24u) +#define PIN_WIRE_SCL (25u) +#define PERIPH_WIRE sercom2 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/pygamer_advance_m4/variant.cpp b/variants/pygamer_advance_m4/variant.cpp index 34f7e9831..70eb5449d 100644 --- a/variants/pygamer_advance_m4/variant.cpp +++ b/variants/pygamer_advance_m4/variant.cpp @@ -46,7 +46,7 @@ const PinDescription g_APinDescription[]= { PORTA, 22, PIO_SERCOM, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH2, TC4_CH0, EXTERNAL_INT_6 }, // 13 (LED) - { PORTA, 23, PIO_SERCOM, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH3, TC4_CH1, EXTERNAL_INT_7 }, + { PORTA, 23, PIO_SERCOM, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH3, TC4_CH1, EXTERNAL_INT_7 }, // 14..25 - Analog pins // -------------------- @@ -95,7 +95,7 @@ const PinDescription g_APinDescription[]= // 41..46 - TFT SPI port + control pins // -------------------- - { PORTB, 12, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_12 }, // SERCOM 4.0 MOSI + { PORTB, 12, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_12 }, // SERCOM 4.0 MOSI { PORTB, 13, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_13 }, // SERCOM 4.1 SCK { PORTB, 15, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15 }, // SERCOM 4.3 'miso' (NC) { PORTB, 15, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15 }, // D44 TFT CS @@ -109,7 +109,7 @@ const PinDescription g_APinDescription[]= { PORTB, 31, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15 }, // D48 button clock { PORTB, 30, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_14 }, // D49 button data { PORTB, 0, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_0 }, // D50 button latch - + // D51 Speaker enable { PORTA, 27, PIO_DIGITAL, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, @@ -130,22 +130,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM5_0_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_1_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_2_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_3_Handler() -{ - Serial1.IrqHandler(); -} diff --git a/variants/pygamer_advance_m4/variant.h b/variants/pygamer_advance_m4/variant.h index cd5e271dd..915f5625a 100644 --- a/variants/pygamer_advance_m4/variant.h +++ b/variants/pygamer_advance_m4/variant.h @@ -132,22 +132,23 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL1 sercom5 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 2 -#define PIN_SPI_MISO (28u) -#define PIN_SPI_MOSI (29u) -#define PIN_SPI_SCK (30u) -#define PERIPH_SPI sercom1 -#define PAD_SPI_TX SPI_PAD_3_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_2 +#define PIN_SPI_MISO (28u) +#define PIN_SPI_MOSI (29u) +#define PIN_SPI_SCK (30u) +#define PERIPH_SPI sercom1 +#define PAD_SPI_TX SPI_PAD_3_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_2 static const uint8_t SS = 4 ; // SD card CS static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -155,12 +156,12 @@ static const uint8_t MISO = PIN_SPI_MISO ; static const uint8_t SCK = PIN_SPI_SCK ; // Internal SPI for TFT -#define PIN_SPI1_MOSI (41u) -#define PIN_SPI1_SCK (42u) -#define PIN_SPI1_MISO (0u) -#define PERIPH_SPI1 sercom4 -#define PAD_SPI1_TX SPI_PAD_0_SCK_1 -#define PAD_SPI1_RX SERCOM_RX_PAD_3 +#define PIN_SPI1_MOSI (41u) +#define PIN_SPI1_SCK (42u) +#define PIN_SPI1_MISO (0u) +#define PERIPH_SPI1 sercom4 +#define PAD_SPI1_TX SPI_PAD_0_SCK_1 +#define PAD_SPI1_RX SERCOM_RX_PAD_3 static const uint8_t SS1 = 44 ; static const uint8_t MOSI1 = PIN_SPI1_MOSI ; @@ -172,14 +173,9 @@ static const uint8_t SCK1 = PIN_SPI1_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (26u) -#define PIN_WIRE_SCL (27u) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler -#define WIRE_IT_HANDLER_0 SERCOM2_0_Handler -#define WIRE_IT_HANDLER_1 SERCOM2_1_Handler -#define WIRE_IT_HANDLER_2 SERCOM2_2_Handler -#define WIRE_IT_HANDLER_3 SERCOM2_3_Handler +#define PIN_WIRE_SDA (26u) +#define PIN_WIRE_SCL (27u) +#define PERIPH_WIRE sercom2 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/pygamer_m4/variant.cpp b/variants/pygamer_m4/variant.cpp index ffbccefe8..813acecf8 100644 --- a/variants/pygamer_m4/variant.cpp +++ b/variants/pygamer_m4/variant.cpp @@ -46,7 +46,7 @@ const PinDescription g_APinDescription[]= { PORTA, 22, PIO_SERCOM, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH2, TC4_CH0, EXTERNAL_INT_6 }, // 13 (LED) - { PORTA, 23, PIO_SERCOM, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH3, TC4_CH1, EXTERNAL_INT_7 }, + { PORTA, 23, PIO_SERCOM, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH3, TC4_CH1, EXTERNAL_INT_7 }, // 14..25 - Analog pins // -------------------- @@ -109,7 +109,7 @@ const PinDescription g_APinDescription[]= { PORTB, 31, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15 }, // D48 button clock { PORTB, 30, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_14 }, // D49 button data { PORTB, 0, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_0 }, // D50 button latch - + // D51 Speaker enable { PORTA, 27, PIO_DIGITAL, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, @@ -130,22 +130,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM5_0_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_1_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_2_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM5_3_Handler() -{ - Serial1.IrqHandler(); -} diff --git a/variants/pygamer_m4/variant.h b/variants/pygamer_m4/variant.h index 12c5b4ffb..15feb2584 100644 --- a/variants/pygamer_m4/variant.h +++ b/variants/pygamer_m4/variant.h @@ -132,22 +132,23 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL1 sercom5 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 2 -#define PIN_SPI_MISO (28u) -#define PIN_SPI_MOSI (29u) -#define PIN_SPI_SCK (30u) -#define PERIPH_SPI sercom1 -#define PAD_SPI_TX SPI_PAD_3_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_2 +#define PIN_SPI_MISO (28u) +#define PIN_SPI_MOSI (29u) +#define PIN_SPI_SCK (30u) +#define PERIPH_SPI sercom1 +#define PAD_SPI_TX SPI_PAD_3_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_2 static const uint8_t SS = 4 ; // SD card CS static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -155,12 +156,12 @@ static const uint8_t MISO = PIN_SPI_MISO ; static const uint8_t SCK = PIN_SPI_SCK ; // Internal SPI for TFT -#define PIN_SPI1_MOSI (41u) -#define PIN_SPI1_SCK (42u) -#define PIN_SPI1_MISO (0u) -#define PERIPH_SPI1 sercom4 -#define PAD_SPI1_TX SPI_PAD_3_SCK_1 -#define PAD_SPI1_RX SERCOM_RX_PAD_0 +#define PIN_SPI1_MOSI (41u) +#define PIN_SPI1_SCK (42u) +#define PIN_SPI1_MISO (0u) +#define PERIPH_SPI1 sercom4 +#define PAD_SPI1_TX SPI_PAD_3_SCK_1 +#define PAD_SPI1_RX SERCOM_RX_PAD_0 static const uint8_t SS1 = 44 ; static const uint8_t MOSI1 = PIN_SPI1_MOSI ; @@ -172,14 +173,9 @@ static const uint8_t SCK1 = PIN_SPI1_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (26u) -#define PIN_WIRE_SCL (27u) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler -#define WIRE_IT_HANDLER_0 SERCOM2_0_Handler -#define WIRE_IT_HANDLER_1 SERCOM2_1_Handler -#define WIRE_IT_HANDLER_2 SERCOM2_2_Handler -#define WIRE_IT_HANDLER_3 SERCOM2_3_Handler +#define PIN_WIRE_SDA (26u) +#define PIN_WIRE_SCL (27u) +#define PERIPH_WIRE sercom2 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/pyportal_m4/variant.cpp b/variants/pyportal_m4/variant.cpp index a74da78f6..de93d0e3f 100644 --- a/variants/pyportal_m4/variant.cpp +++ b/variants/pyportal_m4/variant.cpp @@ -130,22 +130,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom4, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM4_0_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM4_1_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM4_2_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM4_3_Handler() -{ - Serial1.IrqHandler(); -} diff --git a/variants/pyportal_m4/variant.h b/variants/pyportal_m4/variant.h index 75fcb354c..5ab4c3f2b 100644 --- a/variants/pyportal_m4/variant.h +++ b/variants/pyportal_m4/variant.h @@ -142,10 +142,11 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL1 sercom4 /* @@ -153,12 +154,12 @@ static const uint8_t ATN = PIN_ATN; */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO (31u) -#define PIN_SPI_MOSI (29u) -#define PIN_SPI_SCK (30u) -#define PERIPH_SPI sercom2 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_2 +#define PIN_SPI_MISO (31u) +#define PIN_SPI_MOSI (29u) +#define PIN_SPI_SCK (30u) +#define PERIPH_SPI sercom2 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_2 static const uint8_t SS = 32; static const uint8_t MOSI = PIN_SPI_MOSI; @@ -171,14 +172,9 @@ static const uint8_t SCK = PIN_SPI_SCK; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (27u) -#define PIN_WIRE_SCL (28u) -#define PERIPH_WIRE sercom5 -#define WIRE_IT_HANDLER SERCOM5_Handler -#define WIRE_IT_HANDLER_0 SERCOM5_0_Handler -#define WIRE_IT_HANDLER_1 SERCOM5_1_Handler -#define WIRE_IT_HANDLER_2 SERCOM5_2_Handler -#define WIRE_IT_HANDLER_3 SERCOM5_3_Handler +#define PIN_WIRE_SDA (27u) +#define PIN_WIRE_SCL (28u) +#define PERIPH_WIRE sercom5 static const uint8_t SDA = PIN_WIRE_SDA; diff --git a/variants/pyportal_m4_titano/variant.cpp b/variants/pyportal_m4_titano/variant.cpp index 53cfdaca5..b0b03adad 100644 --- a/variants/pyportal_m4_titano/variant.cpp +++ b/variants/pyportal_m4_titano/variant.cpp @@ -130,22 +130,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom4, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM4_0_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM4_1_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM4_2_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM4_3_Handler() -{ - Serial1.IrqHandler(); -} diff --git a/variants/pyportal_m4_titano/variant.h b/variants/pyportal_m4_titano/variant.h index 0da7c158a..ec9b7386e 100644 --- a/variants/pyportal_m4_titano/variant.h +++ b/variants/pyportal_m4_titano/variant.h @@ -142,10 +142,11 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 -#define PIN_SERIAL1_RX (0ul) -#define PIN_SERIAL1_TX (1ul) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PIN_SERIAL1_RX (0ul) +#define PIN_SERIAL1_TX (1ul) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL1 sercom4 /* @@ -153,12 +154,12 @@ static const uint8_t ATN = PIN_ATN; */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO (31u) -#define PIN_SPI_MOSI (29u) -#define PIN_SPI_SCK (30u) -#define PERIPH_SPI sercom2 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_2 +#define PIN_SPI_MISO (31u) +#define PIN_SPI_MOSI (29u) +#define PIN_SPI_SCK (30u) +#define PERIPH_SPI sercom2 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_2 static const uint8_t SS = 32; static const uint8_t MOSI = PIN_SPI_MOSI; @@ -171,14 +172,9 @@ static const uint8_t SCK = PIN_SPI_SCK; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (27u) -#define PIN_WIRE_SCL (28u) -#define PERIPH_WIRE sercom5 -#define WIRE_IT_HANDLER SERCOM5_Handler -#define WIRE_IT_HANDLER_0 SERCOM5_0_Handler -#define WIRE_IT_HANDLER_1 SERCOM5_1_Handler -#define WIRE_IT_HANDLER_2 SERCOM5_2_Handler -#define WIRE_IT_HANDLER_3 SERCOM5_3_Handler +#define PIN_WIRE_SDA (27u) +#define PIN_WIRE_SCL (28u) +#define PERIPH_WIRE sercom5 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/qtpy_m0/variant.cpp b/variants/qtpy_m0/variant.cpp index 4d5135036..0f0fcd02a 100644 --- a/variants/qtpy_m0/variant.cpp +++ b/variants/qtpy_m0/variant.cpp @@ -38,11 +38,11 @@ const PinDescription g_APinDescription[]= // SPI SCK, MISO, MOSI { PORTA, 11, PIO_SERCOM_ALT, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER_ALT), ADC_Channel19, PWM0_CH3, TCC0_CH3, EXTERNAL_INT_11 }, // A8 / D8 / SCK / PWM - { PORTA, 9, PIO_SERCOM_ALT, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER_ALT), ADC_Channel17, PWM1_CH3, TCC1_CH3, EXTERNAL_INT_9 }, // A9 / D9 / MISO / PWM + { PORTA, 9, PIO_SERCOM_ALT, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER_ALT), ADC_Channel17, PWM1_CH3, TCC1_CH3, EXTERNAL_INT_9 }, // A9 / D9 / MISO / PWM { PORTA, 10, PIO_SERCOM_ALT, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER_ALT), ADC_Channel18, PWM0_CH2, TCC0_CH2, EXTERNAL_INT_10 }, // A10 / D10 / MOSI / PWM { PORTA, 18, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_2 }, // D11 Neopix - { PORTA, 15, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15 }, // D12 Neopix power + { PORTA, 15, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15 }, // D12 Neopix power // D13 fake pin { PORTA, 27, PIO_OUTPUT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // used as fake output only @@ -70,12 +70,6 @@ SERCOM sercom1( SERCOM1 ) ; SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; -Uart Serial1( &sercom0, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM0_Handler() -{ - Serial1.IrqHandler(); -} void initVariant(void) { // special initialization code just for us diff --git a/variants/qtpy_m0/variant.h b/variants/qtpy_m0/variant.h index 1e4c4e0e1..3735f4bb4 100644 --- a/variants/qtpy_m0/variant.h +++ b/variants/qtpy_m0/variant.h @@ -119,22 +119,23 @@ static const uint8_t DAC0 = PIN_DAC0; */ // Serial1 -#define PIN_SERIAL1_TX (6ul) -#define PIN_SERIAL1_RX (7ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_2) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_TX (6ul) +#define PIN_SERIAL1_RX (7ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL1 sercom0 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 2 -#define PIN_SPI_SCK (8u) -#define PIN_SPI_MISO (9u) -#define PIN_SPI_MOSI (10u) -#define PERIPH_SPI sercom2 -#define PAD_SPI_TX SPI_PAD_2_SCK_3 -#define PAD_SPI_RX SERCOM_RX_PAD_1 +#define PIN_SPI_SCK (8u) +#define PIN_SPI_MISO (9u) +#define PIN_SPI_MOSI (10u) +#define PERIPH_SPI sercom2 +#define PAD_SPI_TX SPI_PAD_2_SCK_3 +#define PAD_SPI_RX SERCOM_RX_PAD_1 static const uint8_t SS = PIN_A0 ; // unused, just for reference static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -142,12 +143,12 @@ static const uint8_t MISO = PIN_SPI_MISO ; static const uint8_t SCK = PIN_SPI_SCK ; -#define PIN_SPI1_SCK (14u) -#define PIN_SPI1_MISO (15u) -#define PIN_SPI1_MOSI (16u) -#define PERIPH_SPI1 sercom3 -#define PAD_SPI1_TX SPI_PAD_0_SCK_1 -#define PAD_SPI1_RX SERCOM_RX_PAD_3 +#define PIN_SPI1_SCK (14u) +#define PIN_SPI1_MISO (15u) +#define PIN_SPI1_MOSI (16u) +#define PERIPH_SPI1 sercom3 +#define PAD_SPI1_TX SPI_PAD_0_SCK_1 +#define PAD_SPI1_RX SERCOM_RX_PAD_3 static const uint8_t SS1 = 17; static const uint8_t MOSI1 = PIN_SPI1_MOSI ; @@ -159,10 +160,9 @@ static const uint8_t SCK1 = PIN_SPI1_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (4u) -#define PIN_WIRE_SCL (5u) -#define PERIPH_WIRE sercom1 -#define WIRE_IT_HANDLER SERCOM1_Handler +#define PIN_WIRE_SDA (4u) +#define PIN_WIRE_SCL (5u) +#define PERIPH_WIRE sercom1 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/rotarytrinkey_m0/variant.cpp b/variants/rotarytrinkey_m0/variant.cpp index e3c824ff5..0b5aa7f4b 100644 --- a/variants/rotarytrinkey_m0/variant.cpp +++ b/variants/rotarytrinkey_m0/variant.cpp @@ -30,22 +30,22 @@ const PinDescription g_APinDescription[]= { PORTA, 0, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_0 }, // Encoder pin 2 - { PORTA, 4, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel4, PWM0_CH0, TCC0_CH0, EXTERNAL_INT_4 }, + { PORTA, 4, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel4, PWM0_CH0, TCC0_CH0, EXTERNAL_INT_4 }, // Encoder switch - { PORTA, 27, PIO_DIGITAL, (PIN_ATTR_DIGITAL), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15 }, + { PORTA, 27, PIO_DIGITAL, (PIN_ATTR_DIGITAL), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15 }, // Touch pad - { PORTA, 6, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel6, PWM1_CH0, TCC1_CH0, EXTERNAL_INT_6 }, + { PORTA, 6, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel6, PWM1_CH0, TCC1_CH0, EXTERNAL_INT_6 }, + - // USB pins { PORTA, 28, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB Host enable { PORTA, 24, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB/DM { PORTA, 25, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB/DP // Fake DAC pin just so we can compile stuff - { PORTA, 2, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel0, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_2 }, // A0 / D0 / DAC + { PORTA, 2, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel0, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_2 }, // A0 / D0 / DAC } ; const void* g_apTCInstances[TCC_INST_NUM+TC_INST_NUM]={ TCC0, TCC1, TCC2, TC3, TC4, TC5 } ; diff --git a/variants/rotarytrinkey_m0/variant.h b/variants/rotarytrinkey_m0/variant.h index a6442918e..3dc3eece7 100644 --- a/variants/rotarytrinkey_m0/variant.h +++ b/variants/rotarytrinkey_m0/variant.h @@ -108,12 +108,12 @@ static const uint8_t A2 = PIN_A2; */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO PIN_A0 -#define PIN_SPI_MOSI PIN_A0 -#define PIN_SPI_SCK PIN_A0 -#define PERIPH_SPI sercom0 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_0 +#define PIN_SPI_MISO PIN_A0 +#define PIN_SPI_MOSI PIN_A0 +#define PIN_SPI_SCK PIN_A0 +#define PERIPH_SPI sercom0 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_0 static const uint8_t SS = PIN_A0; static const uint8_t MOSI = PIN_SPI_MOSI; @@ -142,10 +142,10 @@ static const uint8_t SCK = PIN_SPI_SCK; */ // Serial1 -#define PIN_SERIAL1_TX (2ul) // D2 / PA04 / SERCOM 0.0 -#define PIN_SERIAL1_RX (4ul) // D2 / PA06 / SERCOM 0.2 -#define PAD_SERIAL1_TX (UART_TX_PAD_0) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_2) +#define PIN_SERIAL1_TX (2ul) // D2 / PA04 / SERCOM 0.0 +#define PIN_SERIAL1_RX (4ul) // D2 / PA06 / SERCOM 0.2 +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_2) #ifdef __cplusplus diff --git a/variants/sht4xtrinkey_m0/variant.cpp b/variants/sht4xtrinkey_m0/variant.cpp index 7d25cd281..7f69b38dd 100644 --- a/variants/sht4xtrinkey_m0/variant.cpp +++ b/variants/sht4xtrinkey_m0/variant.cpp @@ -24,7 +24,7 @@ const PinDescription g_APinDescription[]= { // Fake DAC A0 pin just so we can compile stuff - { PORTA, 2, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel0, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_2 }, // A0 / D0 / DAC + { PORTA, 2, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel0, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_2 }, // A0 / D0 / DAC // touch / A1 { PORTA, 7, PIO_ANALOG, (PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel7, PWM1_CH1, TCC1_CH1, EXTERNAL_INT_7 }, // TCC1/WO[1] diff --git a/variants/sht4xtrinkey_m0/variant.h b/variants/sht4xtrinkey_m0/variant.h index 2a3a0ee9b..bc58549b5 100644 --- a/variants/sht4xtrinkey_m0/variant.h +++ b/variants/sht4xtrinkey_m0/variant.h @@ -102,12 +102,12 @@ static const uint8_t A1 = PIN_A1; */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO PIN_A0 -#define PIN_SPI_MOSI PIN_A0 -#define PIN_SPI_SCK PIN_A0 -#define PERIPH_SPI sercom0 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_0 +#define PIN_SPI_MISO PIN_A0 +#define PIN_SPI_MOSI PIN_A0 +#define PIN_SPI_SCK PIN_A0 +#define PERIPH_SPI sercom0 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_0 static const uint8_t SS = PIN_A0; static const uint8_t MOSI = PIN_SPI_MOSI; @@ -119,10 +119,9 @@ static const uint8_t SCK = PIN_SPI_SCK; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (3u) -#define PIN_WIRE_SCL (4u) -#define PERIPH_WIRE sercom0 -#define WIRE_IT_HANDLER SERCOM0_Handler +#define PIN_WIRE_SDA (3u) +#define PIN_WIRE_SCL (4u) +#define PERIPH_WIRE sercom0 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/slidetrinkey_m0/variant.cpp b/variants/slidetrinkey_m0/variant.cpp index 88a348db7..bbbb14862 100644 --- a/variants/slidetrinkey_m0/variant.cpp +++ b/variants/slidetrinkey_m0/variant.cpp @@ -30,7 +30,7 @@ const PinDescription g_APinDescription[]= { PORTA, 7, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel7, PWM1_CH1, TCC1_CH1, EXTERNAL_INT_7 }, // NeoPixel - { PORTA, 4, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel4, PWM0_CH0, TCC0_CH0, EXTERNAL_INT_4 }, + { PORTA, 4, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel4, PWM0_CH0, TCC0_CH0, EXTERNAL_INT_4 }, // USB pins { PORTA, 28, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB Host enable diff --git a/variants/slidetrinkey_m0/variant.h b/variants/slidetrinkey_m0/variant.h index 65d2e75e8..5ad08de90 100644 --- a/variants/slidetrinkey_m0/variant.h +++ b/variants/slidetrinkey_m0/variant.h @@ -105,12 +105,12 @@ static const uint8_t A2 = PIN_A2; */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO PIN_A0 -#define PIN_SPI_MOSI PIN_A0 -#define PIN_SPI_SCK PIN_A0 -#define PERIPH_SPI sercom0 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_0 +#define PIN_SPI_MISO PIN_A0 +#define PIN_SPI_MOSI PIN_A0 +#define PIN_SPI_SCK PIN_A0 +#define PERIPH_SPI sercom0 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_0 static const uint8_t SS = PIN_A0; static const uint8_t MOSI = PIN_SPI_MOSI; diff --git a/variants/trellis_m4/variant.cpp b/variants/trellis_m4/variant.cpp index cbe7be633..8285c4096 100644 --- a/variants/trellis_m4/variant.cpp +++ b/variants/trellis_m4/variant.cpp @@ -93,7 +93,7 @@ const PinDescription g_APinDescription[]= // Unused { PORTB, 2, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel14, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_2 }, - { PORTB, 3, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel15, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_3 }, + { PORTB, 3, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel15, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_3 }, // AREF tied to 3.3V { PORTA, 3, PIO_ANALOG, PIN_ATTR_ANALOG, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_3 }, // DAC/VREFP @@ -109,22 +109,3 @@ SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; - -Uart Serial1( &sercom4, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM4_0_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM4_1_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM4_2_Handler() -{ - Serial1.IrqHandler(); -} -void SERCOM4_3_Handler() -{ - Serial1.IrqHandler(); -} diff --git a/variants/trellis_m4/variant.h b/variants/trellis_m4/variant.h index 46e66b754..403089718 100644 --- a/variants/trellis_m4/variant.h +++ b/variants/trellis_m4/variant.h @@ -124,24 +124,25 @@ static const uint8_t LINE_RIGHT = PIN_LINE_RIGHT; */ // Serial1 -#define PIN_SERIAL1_RX (22ul) -#define PIN_SERIAL1_TX (21ul) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) -#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PIN_SERIAL1_RX (22ul) +#define PIN_SERIAL1_TX (21ul) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_1) +#define PAD_SERIAL1_TX (UART_TX_PAD_0) +#define PERIPH_SERIAL1 sercom4 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_SCK (9u) // COL7 -#define PIN_SPI_MOSI (8u) // COL6 -#define PIN_SPI_MISO (7u) // COL5 -#define PERIPH_SPI sercom3 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_3 +#define PIN_SPI_SCK (9u) // COL7 +#define PIN_SPI_MOSI (8u) // COL6 +#define PIN_SPI_MISO (7u) // COL5 +#define PERIPH_SPI sercom3 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_3 -static const uint8_t SS = PIN_A2 ; +static const uint8_t SS = PIN_A2 ; static const uint8_t MOSI = PIN_SPI_MOSI ; static const uint8_t MISO = PIN_SPI_MISO ; static const uint8_t SCK = PIN_SPI_SCK ; @@ -152,10 +153,9 @@ static const uint8_t SCK = PIN_SPI_SCK ; */ #define WIRE_INTERFACES_COUNT 2 -#define PIN_WIRE_SDA (21u) -#define PIN_WIRE_SCL (22u) -#define PERIPH_WIRE sercom4 -#define WIRE_IT_HANDLER SERCOM4_Handler +#define PIN_WIRE_SDA (21u) +#define PIN_WIRE_SCL (22u) +#define PERIPH_WIRE sercom4 // Sercom interrupt handlers for I2C slave not set; they are used by Serial1 // #define WIRE_IT_HANDLER_0 SERCOM4_0_Handler @@ -167,14 +167,9 @@ static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; -#define PIN_WIRE1_SDA (0u) -#define PIN_WIRE1_SCL (1u) -#define PERIPH_WIRE1 sercom2 -#define WIRE1_IT_HANDLER SERCOM2_Handler -#define WIRE1_IT_HANDLER_0 SERCOM2_0_Handler -#define WIRE1_IT_HANDLER_1 SERCOM2_1_Handler -#define WIRE1_IT_HANDLER_2 SERCOM2_2_Handler -#define WIRE1_IT_HANDLER_3 SERCOM2_3_Handler +#define PIN_WIRE1_SDA (0u) +#define PIN_WIRE1_SCL (1u) +#define PERIPH_WIRE1 sercom2 static const uint8_t SDA1 = PIN_WIRE_SDA; static const uint8_t SCL1 = PIN_WIRE_SCL; diff --git a/variants/trinket_m0/variant.cpp b/variants/trinket_m0/variant.cpp index 5363f8daf..ebff53f2e 100644 --- a/variants/trinket_m0/variant.cpp +++ b/variants/trinket_m0/variant.cpp @@ -93,11 +93,3 @@ SERCOM sercom0( SERCOM0 ) ; SERCOM sercom1( SERCOM1 ) ; SERCOM sercom2( SERCOM2 ) ; SERCOM sercom3( SERCOM3 ) ; - -Uart Serial1( &sercom0, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; - -void SERCOM0_Handler() -{ - Serial1.IrqHandler(); -} - diff --git a/variants/trinket_m0/variant.h b/variants/trinket_m0/variant.h index 12e99e9dc..57abe590d 100644 --- a/variants/trinket_m0/variant.h +++ b/variants/trinket_m0/variant.h @@ -116,22 +116,23 @@ static const uint8_t DAC0 = PIN_DAC0; */ // Serial1 (sercom 0) -#define PIN_SERIAL1_RX (3ul) // PA07 -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) -#define PIN_SERIAL1_TX (4ul) // PA06 -#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PIN_SERIAL1_RX (3ul) // PA07 +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_TX (4ul) // PA06 +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PERIPH_SERIAL1 sercom0 /* * SPI Interfaces */ #define SPI_INTERFACES_COUNT 1 // shared with I2C/UART (can't do both) -#define PIN_SPI_MISO (6u) // PA09 same as D2 -#define PIN_SPI_MOSI (4u) -#define PIN_SPI_SCK (3u) -#define PERIPH_SPI sercom0 -#define PAD_SPI_TX SPI_PAD_2_SCK_3 -#define PAD_SPI_RX SERCOM_RX_PAD_1 +#define PIN_SPI_MISO (6u) // PA09 same as D2 +#define PIN_SPI_MOSI (4u) +#define PIN_SPI_SCK (3u) +#define PERIPH_SPI sercom0 +#define PAD_SPI_TX SPI_PAD_2_SCK_3 +#define PAD_SPI_RX SERCOM_RX_PAD_1 static const uint8_t SS = 5 ; // SERCOM0 last PAD is present on 5 but HW SS isn't used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -143,10 +144,9 @@ static const uint8_t SCK = PIN_SPI_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (0u) -#define PIN_WIRE_SCL (2u) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler +#define PIN_WIRE_SDA (0u) +#define PIN_WIRE_SCL (2u) +#define PERIPH_WIRE sercom2 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/trrstrinkey_m0/variant.h b/variants/trrstrinkey_m0/variant.h index 998d00ddb..58c16d757 100644 --- a/variants/trrstrinkey_m0/variant.h +++ b/variants/trrstrinkey_m0/variant.h @@ -114,12 +114,12 @@ static const uint8_t A5 = PIN_A5; */ #define SPI_INTERFACES_COUNT 1 -#define PIN_SPI_MISO PIN_RING1 -#define PIN_SPI_MOSI PIN_RING2 -#define PIN_SPI_SCK PIN_SLEEVE -#define PERIPH_SPI sercom0 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_2 +#define PIN_SPI_MISO PIN_RING1 +#define PIN_SPI_MOSI PIN_RING2 +#define PIN_SPI_SCK PIN_SLEEVE +#define PERIPH_SPI sercom0 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_2 static const uint8_t SS = PIN_TIP; static const uint8_t MOSI = PIN_SPI_MOSI; @@ -132,16 +132,14 @@ static const uint8_t SCK = PIN_SPI_SCK; #define WIRE_INTERFACES_COUNT 2 // QT Port -#define PIN_WIRE_SDA (7ul) -#define PIN_WIRE_SCL (8ul) -#define PERIPH_WIRE sercom2 -#define WIRE_IT_HANDLER SERCOM2_Handler +#define PIN_WIRE_SDA (7ul) +#define PIN_WIRE_SCL (8ul) +#define PERIPH_WIRE sercom2 // second, sekret I2C on the headphone jack -#define PIN_WIRE1_SDA PIN_RING2 -#define PIN_WIRE1_SCL PIN_SLEEVE -#define PERIPH_WIRE1 sercom0 -#define WIRE1_IT_HANDLER SERCOM0_Handler +#define PIN_WIRE1_SDA PIN_RING2 +#define PIN_WIRE1_SCL PIN_SLEEVE +#define PERIPH_WIRE1 sercom0 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; diff --git a/variants/xplained_m4/debug_scripts/variant.gdb b/variants/xplained_m4/debug_scripts/variant.gdb new file mode 100644 index 000000000..78a89f013 --- /dev/null +++ b/variants/xplained_m4/debug_scripts/variant.gdb @@ -0,0 +1,31 @@ +# +# SAME54 Xplained Pro OpenOCD/GDB script. +# +# Copyright (c) 2014-2015 Arduino LLC. 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 +# + +# Define 'reset' command +define reset + +info reg + +break main + +# End of 'reset' command +end + +target remote | openocd -c "interface jlink" -c "transport select swd" -c "set CHIPNAME same54" -c "set _FLASHDRIVER atsame5" -f target/atsame5x.cfg -c "gdb_port pipe; log_output openocd.log" diff --git a/variants/xplained_m4/linker_scripts/gcc/flash_with_bootloader.ld b/variants/xplained_m4/linker_scripts/gcc/flash_with_bootloader.ld new file mode 100644 index 000000000..34e0c24d9 --- /dev/null +++ b/variants/xplained_m4/linker_scripts/gcc/flash_with_bootloader.ld @@ -0,0 +1,216 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. 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 +*/ + +/* Linker script to configure memory regions. + * Need modifying for a specific board. + * FLASH.ORIGIN: starting address of flash + * FLASH.LENGTH: length of flash + * RAM.ORIGIN: starting address of RAM bank 0 + * RAM.LENGTH: length of RAM bank 0 + */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000+0x4000, LENGTH = 0x00080000-0x4000 /* First 16KB used by bootloader */ + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00030000 +} + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __copy_table_start__ + * __copy_table_end__ + * __zero_table_start__ + * __zero_table_end__ + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + */ +ENTRY(Reset_Handler) + +SECTIONS +{ + .text : + { + __text_start__ = .; + + KEEP(*(.sketch_boot)) + + . = ALIGN(0x4000); + KEEP(*(.isr_vector)) + *(.text*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + + KEEP(*(.eh_frame*)) + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* To copy multiple ROM to RAM sections, + * uncomment .copy.table section and, + * define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */ + /* + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + LONG (__etext) + LONG (__data_start__) + LONG (__data_end__ - __data_start__) + LONG (__etext2) + LONG (__data2_start__) + LONG (__data2_end__ - __data2_start__) + __copy_table_end__ = .; + } > FLASH + */ + + /* To clear multiple BSS sections, + * uncomment .zero.table section and, + * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */ + /* + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + LONG (__bss_start__) + LONG (__bss_end__ - __bss_start__) + LONG (__bss2_start__) + LONG (__bss2_end__ - __bss2_start__) + __zero_table_end__ = .; + } > FLASH + */ + + __etext = .; + + .data : AT (__etext) + { + __data_start__ = .; + *(vtable) + *(.data*) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP(*(.jcr*)) + . = ALIGN(16); + /* All data end */ + __data_end__ = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (COPY): + { + __end__ = .; + PROVIDE(end = .); + *(.heap*) + __HeapLimit = .; + } > RAM + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > RAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(RAM) + LENGTH(RAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + __ram_end__ = ORIGIN(RAM) + LENGTH(RAM) -1 ; + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") +} diff --git a/variants/xplained_m4/linker_scripts/gcc/flash_without_bootloader.ld b/variants/xplained_m4/linker_scripts/gcc/flash_without_bootloader.ld new file mode 100644 index 000000000..46e8d8846 --- /dev/null +++ b/variants/xplained_m4/linker_scripts/gcc/flash_without_bootloader.ld @@ -0,0 +1,214 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. 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 +*/ + +/* Linker script to configure memory regions. + * Need modifying for a specific board. + * FLASH.ORIGIN: starting address of flash + * FLASH.LENGTH: length of flash + * RAM.ORIGIN: starting address of RAM bank 0 + * RAM.LENGTH: length of RAM bank 0 + */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00080000 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00030000 +} + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __copy_table_start__ + * __copy_table_end__ + * __zero_table_start__ + * __zero_table_end__ + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + * __ram_end__ + */ +ENTRY(Reset_Handler) + +SECTIONS +{ + .text : + { + __text_start__ = .; + + KEEP(*(.isr_vector)) + *(.text*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + + KEEP(*(.eh_frame*)) + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* To copy multiple ROM to RAM sections, + * uncomment .copy.table section and, + * define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */ + /* + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + LONG (__etext) + LONG (__data_start__) + LONG (__data_end__ - __data_start__) + LONG (__etext2) + LONG (__data2_start__) + LONG (__data2_end__ - __data2_start__) + __copy_table_end__ = .; + } > FLASH + */ + + /* To clear multiple BSS sections, + * uncomment .zero.table section and, + * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */ + /* + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + LONG (__bss_start__) + LONG (__bss_end__ - __bss_start__) + LONG (__bss2_start__) + LONG (__bss2_end__ - __bss2_start__) + __zero_table_end__ = .; + } > FLASH + */ + + __etext = .; + + .data : AT (__etext) + { + __data_start__ = .; + *(vtable) + *(.data*) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP(*(.jcr*)) + . = ALIGN(16); + /* All data end */ + __data_end__ = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (COPY): + { + __end__ = .; + PROVIDE(end = .); + *(.heap*) + __HeapLimit = .; + } > RAM + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > RAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(RAM) + LENGTH(RAM) ; + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + __ram_end__ = ORIGIN(RAM) + LENGTH(RAM) -1 ; + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") +} diff --git a/variants/xplained_m4/openocd_scripts/jlink_same54.cfg b/variants/xplained_m4/openocd_scripts/jlink_same54.cfg new file mode 100644 index 000000000..67e059621 --- /dev/null +++ b/variants/xplained_m4/openocd_scripts/jlink_same54.cfg @@ -0,0 +1,32 @@ +# +# Arduino Zero OpenOCD script. +# +# Copyright (c) 2014-2015 Arduino LLC. 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 +# + +source [find interface/jlink.cfg] +transport select swd + +# chip name +set CHIPNAME same54 +set _FLASHDRIVER atsame5 +set ENDIAN little + +# choose a port here +set telnet_port 0 + +source [find target/atsame5x.cfg] diff --git a/variants/xplained_m4/pins_arduino.h b/variants/xplained_m4/pins_arduino.h new file mode 100644 index 000000000..dbc5a93c4 --- /dev/null +++ b/variants/xplained_m4/pins_arduino.h @@ -0,0 +1,20 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. 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 +*/ + +// API compatibility +#include "variant.h" diff --git a/variants/xplained_m4/variant.cpp b/variants/xplained_m4/variant.cpp new file mode 100644 index 000000000..d80e1c9e0 --- /dev/null +++ b/variants/xplained_m4/variant.cpp @@ -0,0 +1,139 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. 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 +*/ + +#include "variant.h" + +/* + * Pins descriptions + */ + +const PinDescription g_APinDescription[] = + { + // 0..15: EXT1. UART first, then GPIO/PWM/IRQ/SPI/ADC/I2C. + {PORTA, 5, PIO_SERCOM, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG, ADC_Channel5, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_5}, + {PORTA, 4, PIO_SERCOM, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG, ADC_Channel4, NOT_ON_PWM, TC0_CH0, EXTERNAL_INT_4}, + {PORTA, 6, PIO_DIGITAL, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG | PIN_ATTR_PWM_E, ADC_Channel6, TC1_CH0, TC1_CH0, EXTERNAL_INT_6}, + {PORTA, 7, PIO_DIGITAL, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG | PIN_ATTR_PWM_E, ADC_Channel7, TC1_CH1, TC1_CH1, EXTERNAL_INT_7}, + {PORTB, 8, PIO_TIMER, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG | PIN_ATTR_PWM_E, ADC_Channel2, TC4_CH0, TC4_CH0, EXTERNAL_INT_8}, + {PORTB, 9, PIO_TIMER, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG | PIN_ATTR_PWM_E, ADC_Channel3, TC4_CH1, TC4_CH1, EXTERNAL_INT_9}, + {PORTB, 7, PIO_DIGITAL, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG_ALT, ADC_Channel9, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_7}, + {PORTA, 27, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_11}, + {PORTB, 28, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_14}, + {PORTB, 27, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_13}, + {PORTB, 29, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15}, + {PORTB, 26, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_12}, + {PORTB, 4, PIO_ANALOG, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG_ALT, ADC_Channel6, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_4}, + {PORTB, 5, PIO_ANALOG, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG_ALT, ADC_Channel7, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_5}, + {PORTA, 22, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, TC4_CH0, EXTERNAL_INT_6}, + {PORTA, 23, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, TC4_CH1, EXTERNAL_INT_7}, + + // 16..31: EXT2, including the I2C/SPI lines shared with EXT3. + {PORTB, 17, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, TC6_CH1, EXTERNAL_INT_1}, + {PORTB, 16, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, TC6_CH0, EXTERNAL_INT_0}, + {PORTB, 1, PIO_DIGITAL, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG, ADC_Channel13, NOT_ON_PWM, TC7_CH1, EXTERNAL_INT_1}, + {PORTB, 6, PIO_DIGITAL, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG_ALT, ADC_Channel8, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_6}, + {PORTB, 14, PIO_TIMER_ALT, PIN_ATTR_DIGITAL | PIN_ATTR_PWM_F, No_ADC_Channel, TCC4_CH0, TC5_CH0, EXTERNAL_INT_14}, + {PORTB, 15, PIO_TIMER_ALT, PIN_ATTR_DIGITAL | PIN_ATTR_PWM_F, No_ADC_Channel, TCC4_CH1, TC5_CH1, EXTERNAL_INT_15}, + {PORTD, 0, PIO_DIGITAL, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG_ALT, ADC_Channel14, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_0}, + {PORTB, 2, PIO_DIGITAL, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG | PIN_ATTR_PWM_E, ADC_Channel14, TC6_CH0, TC6_CH0, EXTERNAL_INT_2}, + {PORTC, 6, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_6}, + {PORTC, 4, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_4}, + {PORTC, 7, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_9}, + {PORTC, 5, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_5}, + {PORTB, 0, PIO_ANALOG, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG, ADC_Channel12, NOT_ON_PWM, TC7_CH0, EXTERNAL_INT_0}, + {PORTA, 3, PIO_ANALOG, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG, ADC_Channel1, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_3}, + {PORTD, 8, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_3}, + {PORTD, 9, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_4}, + + // 32..42: EXT3 pins that are not duplicates of EXT2 shared buses. + {PORTC, 23, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_7}, + {PORTC, 22, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_6}, + {PORTC, 1, PIO_DIGITAL, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG_ALT, ADC_Channel11, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_1}, + {PORTC, 10, PIO_DIGITAL, PIN_ATTR_DIGITAL | PIN_ATTR_PWM_F, No_ADC_Channel, TCC0_CH0, NOT_ON_TIMER, EXTERNAL_INT_10}, + {PORTD, 10, PIO_TIMER_ALT, PIN_ATTR_DIGITAL | PIN_ATTR_PWM_F, No_ADC_Channel, TCC0_CH3, NOT_ON_TIMER, EXTERNAL_INT_5}, + {PORTD, 11, PIO_TIMER_ALT, PIN_ATTR_DIGITAL | PIN_ATTR_PWM_F, No_ADC_Channel, TCC0_CH4, NOT_ON_TIMER, EXTERNAL_INT_6}, + {PORTC, 30, PIO_DIGITAL, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG_ALT, ADC_Channel12, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_14}, + {PORTC, 31, PIO_DIGITAL, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG_ALT, ADC_Channel13, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15}, + {PORTC, 14, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_14}, + {PORTC, 2, PIO_ANALOG, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG_ALT, ADC_Channel4, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_2}, + {PORTC, 3, PIO_ANALOG, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG_ALT, ADC_Channel5, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_3}, + + // 43..46: dedicated ADC/DAC header and PDEC header. + {PORTA, 2, PIO_ANALOG, PIN_ATTR_DIGITAL | PIN_ATTR_ANALOG, ADC_Channel0, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_2}, + {PORTC, 16, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_0}, + {PORTC, 17, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_1}, + {PORTC, 18, PIO_DIGITAL, PIN_ATTR_DIGITAL | PIN_ATTR_PWM_F, No_ADC_Channel, TCC0_CH2, NOT_ON_TIMER, EXTERNAL_INT_2}, + + // 47..58: internal EDBG UART, target USB, and onboard QSPI flash. + {PORTB, 24, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_8}, + {PORTB, 25, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_9}, + {PORTC, 0, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_0}, + {PORTC, 19, PIO_COM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_3}, + {PORTA, 24, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_8}, + {PORTA, 25, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_9}, + {PORTB, 10, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_10}, + {PORTB, 11, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_11}, + {PORTA, 8, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NMI}, + {PORTA, 9, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_9}, + {PORTA, 10, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_10}, + {PORTA, 11, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_11}, + {PORTB, 31, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_15}, +}; + +static_assert(sizeof(g_APinDescription) / sizeof(g_APinDescription[0]) == PINS_COUNT, + "xplained_m4 pin count does not match g_APinDescription"); + +const uint8_t g_AAnalogPinMap[NUM_ANALOG_INPUTS] = { + PIN_A0, PIN_A1, PIN_A2, PIN_A3, PIN_A4, PIN_A5, PIN_A6, PIN_A7, + PIN_A8, PIN_A9, PIN_A10, PIN_A11, PIN_A12, PIN_A13, PIN_A14, PIN_A15, +}; + +const void *g_apTCInstances[ARDUINO_TCC_INSTANCE_COUNT + ARDUINO_TC_INSTANCE_COUNT] = { + TCC0_REGS, TCC1_REGS, TCC2_REGS, TCC3_REGS, TCC4_REGS, + TC0_REGS, TC1_REGS, TC2_REGS, TC3_REGS, TC4_REGS, TC5_REGS, + TC6_REGS, TC7_REGS}; +const uint32_t GCLK_CLKCTRL_IDs[ARDUINO_TCC_INSTANCE_COUNT + ARDUINO_TC_INSTANCE_COUNT] = { + TCC0_GCLK_ID, TCC1_GCLK_ID, TCC2_GCLK_ID, TCC3_GCLK_ID, TCC4_GCLK_ID, + TC0_GCLK_ID, TC1_GCLK_ID, TC2_GCLK_ID, TC3_GCLK_ID, TC4_GCLK_ID, + TC5_GCLK_ID, TC6_GCLK_ID, TC7_GCLK_ID}; + +// Multi-serial objects instantiation +SERCOM sercom0(SERCOM0_REGS); +SERCOM sercom1(SERCOM1_REGS); +SERCOM sercom2(SERCOM2_REGS); +SERCOM sercom3(SERCOM3_REGS); +SERCOM sercom4(SERCOM4_REGS); +SERCOM sercom5(SERCOM5_REGS); +SERCOM sercom6(SERCOM6_REGS); +SERCOM sercom7(SERCOM7_REGS); + +Uart Serial1(&PERIPH_SERIAL1, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX); +Uart Serial2(&PERIPH_SERIAL2, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX); +Uart Serial3(&PERIPH_SERIAL3, PIN_SERIAL3_RX, PIN_SERIAL3_TX, PAD_SERIAL3_RX, PAD_SERIAL3_TX); +Uart Serial4(&PERIPH_SERIAL4, PIN_SERIAL4_RX, PIN_SERIAL4_TX, PAD_SERIAL4_RX, PAD_SERIAL4_TX); + +#define UART_HANDLERS(prefix, serial) \ + void prefix##_IT_HANDLER_0(void) { serial.IrqHandler(); } \ + void prefix##_IT_HANDLER_1(void) { serial.IrqHandler(); } \ + void prefix##_IT_HANDLER_2(void) { serial.IrqHandler(); } \ + void prefix##_IT_HANDLER_OTHER(void) { serial.IrqHandler(); } + +UART_HANDLERS(SERIAL1, Serial1) +UART_HANDLERS(SERIAL2, Serial2) +UART_HANDLERS(SERIAL3, Serial3) +UART_HANDLERS(SERIAL4, Serial4) diff --git a/variants/xplained_m4/variant.h b/variants/xplained_m4/variant.h new file mode 100644 index 000000000..1126eafb1 --- /dev/null +++ b/variants/xplained_m4/variant.h @@ -0,0 +1,320 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. 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 _VARIANT_XPLAINED_M4_ +#define _VARIANT_XPLAINED_M4_ + +// The definitions here needs a SAMD core >=1.6.10 +#define ARDUINO_SAMD_VARIANT_COMPLIANCE 10610 + +/*---------------------------------------------------------------------------- + * Definitions + *----------------------------------------------------------------------------*/ + +/** Frequency of the board main oscillator */ +#define VARIANT_MAINOSC (32768ul) + +/** Master clock frequency */ +#define VARIANT_MCK (120000000ul) + +#define VARIANT_GCLK0_FREQ (120000000UL) +#define VARIANT_GCLK1_FREQ (48000000UL) +#define VARIANT_GCLK2_FREQ (100000000UL) + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +#include "SERCOM.h" +#include "Uart.h" +#endif // __cplusplus + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +/*---------------------------------------------------------------------------- + * Pins + *----------------------------------------------------------------------------*/ + +// Number of pins defined in PinDescription array +#define PINS_COUNT (60u) +#define NUM_DIGITAL_PINS (47u) +#define NUM_ANALOG_INPUTS (16u) +#define NUM_ANALOG_OUTPUTS (1u) +#define analogInputToDigitalPin(p) ((p < NUM_ANALOG_INPUTS) ? g_AAnalogPinMap[(p)] : -1) + +extern const uint8_t g_AAnalogPinMap[NUM_ANALOG_INPUTS]; + +#define digitalPinToPort(P) (&(PORT->Group[g_APinDescription[P].ulPort])) +#define digitalPinToBitMask(P) (1 << g_APinDescription[P].ulPin) +// #define analogInPinToBit(P) ( ) +#define portOutputRegister(port) (&(port->OUT.reg)) +#define portInputRegister(port) (&(port->IN.reg)) +#define portModeRegister(port) (&(port->DIR.reg)) +#define digitalPinHasPWM(P) (g_APinDescription[P].ulPWMChannel != NOT_ON_PWM || g_APinDescription[P].ulTCChannel != NOT_ON_TIMER) + +/* + * digitalPinToTimer(..) is AVR-specific and is not defined for SAMD + * architecture. If you need to check if a pin supports PWM you must + * use digitalPinHasPWM(..). + * + * https://github.com/arduino/Arduino/issues/1833 + */ +// #define digitalPinToTimer(P) + +// LEDs +#define PIN_LED (46u) +#define LED_BUILTIN PIN_LED +#define PIN_BUTTON (59u) + +/* + * Analog pins + */ +#define PIN_A0 (43u) +#define PIN_A1 (12u) +#define PIN_A2 (13u) +#define PIN_A3 (28u) +#define PIN_A4 (29u) +#define PIN_A5 (41u) +#define PIN_A6 (42u) +#define PIN_A7 (2u) +#define PIN_A8 (3u) +#define PIN_A9 (4u) +#define PIN_A10 (5u) +#define PIN_A11 (6u) +#define PIN_A12 (18u) +#define PIN_A13 (19u) +#define PIN_A14 (22u) +#define PIN_A15 (34u) + +#define PIN_DAC0 PIN_A0 + + static const uint8_t A0 = PIN_A0; + static const uint8_t A1 = PIN_A1; + static const uint8_t A2 = PIN_A2; + static const uint8_t A3 = PIN_A3; + static const uint8_t A4 = PIN_A4; + static const uint8_t A5 = PIN_A5; + static const uint8_t A6 = PIN_A6; + static const uint8_t A7 = PIN_A7; + static const uint8_t A8 = PIN_A8; + static const uint8_t A9 = PIN_A9; + static const uint8_t A10 = PIN_A10; + static const uint8_t A11 = PIN_A11; + static const uint8_t A12 = PIN_A12; + static const uint8_t A13 = PIN_A13; + static const uint8_t A14 = PIN_A14; + static const uint8_t A15 = PIN_A15; + + static const uint8_t DAC0 = PIN_DAC0; + +#define ADC_RESOLUTION 12 + +// Other pins +#define PIN_EXT1_SDA (14u) +#define PIN_EXT1_SCL (15u) +#define PIN_EXT2_SDA (30u) +#define PIN_EXT2_SCL (31u) +#define PIN_EXT3_SDA PIN_EXT2_SDA +#define PIN_EXT3_SCL PIN_EXT2_SCL + +/* + * Serial interfaces + */ + +// Numbered Arduino UARTs: EXT1, EXT2, EXT3, then the EDBG virtual COM port. +#define PIN_SERIAL1_RX (0u) +#define PIN_SERIAL1_TX (1u) +#define PAD_SERIAL1_RX SERCOM_RX_PAD_1 +#define PAD_SERIAL1_TX UART_TX_PAD_0 +#define PERIPH_SERIAL1 sercom0 +#define SERIAL1_IT_HANDLER_0 SERCOM0_0_Handler +#define SERIAL1_IT_HANDLER_1 SERCOM0_1_Handler +#define SERIAL1_IT_HANDLER_2 SERCOM0_2_Handler +#define SERIAL1_IT_HANDLER_OTHER SERCOM0_OTHER_Handler +#define UART_VARIANT_OWNS_SERIAL1 + +#define PIN_SERIAL2_RX (16u) +#define PIN_SERIAL2_TX (17u) +#define PAD_SERIAL2_RX SERCOM_RX_PAD_1 +#define PAD_SERIAL2_TX UART_TX_PAD_0 +#define PERIPH_SERIAL2 sercom5 +#define SERIAL2_IT_HANDLER_0 SERCOM5_0_Handler +#define SERIAL2_IT_HANDLER_1 SERCOM5_1_Handler +#define SERIAL2_IT_HANDLER_2 SERCOM5_2_Handler +#define SERIAL2_IT_HANDLER_OTHER SERCOM5_OTHER_Handler +#define UART_VARIANT_OWNS_SERIAL2 + +#define PIN_SERIAL3_RX (32u) +#define PIN_SERIAL3_TX (33u) +#define PAD_SERIAL3_RX SERCOM_RX_PAD_1 +#define PAD_SERIAL3_TX UART_TX_PAD_0 +#define PERIPH_SERIAL3 sercom1 +#define SERIAL3_IT_HANDLER_0 SERCOM1_0_Handler +#define SERIAL3_IT_HANDLER_1 SERCOM1_1_Handler +#define SERIAL3_IT_HANDLER_2 SERCOM1_2_Handler +#define SERIAL3_IT_HANDLER_OTHER SERCOM1_OTHER_Handler +#define UART_VARIANT_OWNS_SERIAL3 + +#define PIN_SERIAL4_RX (47u) +#define PIN_SERIAL4_TX (48u) +#define PAD_SERIAL4_RX SERCOM_RX_PAD_1 +#define PAD_SERIAL4_TX UART_TX_PAD_0 +#define PERIPH_SERIAL4 sercom2 +#define SERIAL4_IT_HANDLER_0 SERCOM2_0_Handler +#define SERIAL4_IT_HANDLER_1 SERCOM2_1_Handler +#define SERIAL4_IT_HANDLER_2 SERCOM2_2_Handler +#define SERIAL4_IT_HANDLER_OTHER SERCOM2_OTHER_Handler +#define UART_VARIANT_OWNS_SERIAL4 + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 2 + +#define PIN_SPI_MISO (10u) +#define PIN_SPI_MOSI (9u) +#define PIN_SPI_SCK (11u) +#define PIN_SPI_SS (8u) +#define PERIPH_SPI sercom4 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_3 + + static const uint8_t SS = PIN_SPI_SS; + static const uint8_t MOSI = PIN_SPI_MOSI; + static const uint8_t MISO = PIN_SPI_MISO; + static const uint8_t SCK = PIN_SPI_SCK; + +#define PIN_SPI1_MISO (26u) +#define PIN_SPI1_MOSI (25u) +#define PIN_SPI1_SCK (27u) +#define PIN_SPI1_SS (24u) +#define PERIPH_SPI1 sercom6 +#define PAD_SPI1_TX SPI_PAD_0_SCK_1 +#define PAD_SPI1_RX SERCOM_RX_PAD_3 + + static const uint8_t SS1 = PIN_SPI1_SS; + +/* + * Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 2 + +#define PIN_WIRE_SDA PIN_EXT1_SDA +#define PIN_WIRE_SCL PIN_EXT1_SCL +#define PERIPH_WIRE sercom3 + + static const uint8_t SDA = PIN_WIRE_SDA; + static const uint8_t SCL = PIN_WIRE_SCL; + +#define PIN_WIRE1_SDA PIN_EXT2_SDA +#define PIN_WIRE1_SCL PIN_EXT2_SCL +#define PERIPH_WIRE1 sercom7 + + static const uint8_t SDA1 = PIN_WIRE1_SDA; + static const uint8_t SCL1 = PIN_WIRE1_SCL; + +/* + * USB + */ +#define PIN_USB_VBUS (49u) +#define PIN_USB_HOST_ENABLE (50u) +#define PIN_USB_DM (51u) +#define PIN_USB_DP (52u) + +/* + * I2S Interfaces + */ +#define I2S_INTERFACES_COUNT 1 + +#define I2S_DEVICE 0 +#define I2S_CLOCK_GENERATOR 3 + +#define PIN_I2S_SDO (14u) +#define PIN_I2S_SDI (15u) +#define PIN_I2S_SCK PIN_SERIAL2_TX +#define PIN_I2S_FS (33u) +#define PIN_I2S_MCK PIN_SERIAL2_RX +// Onboard Micron N25Q256A QSPI flash routes. +#define PIN_QSPI_SCK (53u) +#define PIN_QSPI_CS (54u) +#define PIN_QSPI_IO0 (55u) +#define PIN_QSPI_IO1 (56u) +#define PIN_QSPI_IO2 (57u) +#define PIN_QSPI_IO3 (58u) + + // TODO: meaningful value for this + // #define VARIANT_QSPI_BAUD_DEFAULT 5000000 + +#ifdef __cplusplus +} +#endif // __cplusplus + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#ifdef __cplusplus + +/* ========================= + * ===== SERCOM DEFINITION + * ========================= + */ +extern SERCOM sercom0; +extern SERCOM sercom1; +extern SERCOM sercom2; +extern SERCOM sercom3; +extern SERCOM sercom4; +extern SERCOM sercom5; +extern SERCOM sercom6; +extern SERCOM sercom7; + +extern Uart Serial1; +extern Uart Serial2; +extern Uart Serial3; +extern Uart Serial4; + +#endif // __cplusplus + +// These serial port names are intended to allow libraries and architecture-neutral +// sketches to automatically default to the correct port name for a particular type +// of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN, +// the first hardware serial port whose RX/TX pins are not dedicated to another use. +// +// SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor +// +// SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial +// +// SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library +// +// SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins. +// +// SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX +// pins are NOT connected to anything by default. +#define SERIAL_PORT_USBVIRTUAL Serial +#define SERIAL_PORT_MONITOR Serial +// Serial has no physical pins broken out, so it's not listed as HARDWARE port +#define SERIAL_PORT_HARDWARE Serial1 +#define SERIAL_PORT_HARDWARE_OPEN Serial1 + +#endif /* _VARIANT_XPLAINED_M4_ */ diff --git a/variants/zero_radio/variant.cpp b/variants/zero_radio/variant.cpp index 8e3150122..ac1d42d04 100644 --- a/variants/zero_radio/variant.cpp +++ b/variants/zero_radio/variant.cpp @@ -218,8 +218,3 @@ SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; // We'll use sercom5 for Serial1 hardware serial since pins 0 and 1 are not external -Uart Serial1( &sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; -void SERCOM5_Handler() -{ - Serial1.IrqHandler(); -} diff --git a/variants/zero_radio/variant.h b/variants/zero_radio/variant.h index dfc5b93d7..18030276f 100644 --- a/variants/zero_radio/variant.h +++ b/variants/zero_radio/variant.h @@ -135,10 +135,11 @@ static const uint8_t ATN = PIN_ATN; */ // Serial1 on SERCOM5 -#define PIN_SERIAL1_RX (31ul) -#define PIN_SERIAL1_TX (30ul) -#define PAD_SERIAL1_TX (UART_TX_PAD_2) -#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PIN_SERIAL1_RX (31ul) +#define PIN_SERIAL1_TX (30ul) +#define PAD_SERIAL1_TX (UART_TX_PAD_2) +#define PAD_SERIAL1_RX (SERCOM_RX_PAD_3) +#define PERIPH_SERIAL1 sercom5 /* * SPI Interfaces @@ -146,12 +147,12 @@ static const uint8_t ATN = PIN_ATN; #define SPI_INTERFACES_COUNT 2 // "external" SPI, used for sensors, displays, available to user -#define PIN_SPI_MISO (2u) -#define PIN_SPI_MOSI (22u) -#define PIN_SPI_SCK (38u) -#define PERIPH_SPI sercom2 -#define PAD_SPI_TX SPI_PAD_0_SCK_1 -#define PAD_SPI_RX SERCOM_RX_PAD_2 +#define PIN_SPI_MISO (2u) +#define PIN_SPI_MOSI (22u) +#define PIN_SPI_SCK (38u) +#define PERIPH_SPI sercom2 +#define PAD_SPI_TX SPI_PAD_0_SCK_1 +#define PAD_SPI_RX SERCOM_RX_PAD_2 static const uint8_t SS = PIN_A2 ; // SERCOM4 last PAD is present on A2 but HW SS isn't used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -159,13 +160,13 @@ static const uint8_t MISO = PIN_SPI_MISO ; static const uint8_t SCK = PIN_SPI_SCK ; // "internal" SPI, used for AT86RF233 only! -#define PIN_SPI1_MISO (47u) -#define PIN_SPI1_MOSI (48u) -#define PIN_SPI1_SCK (46u) +#define PIN_SPI1_MISO (47u) +#define PIN_SPI1_MOSI (48u) +#define PIN_SPI1_SCK (46u) #define PIN_SPI1_SEL (49u) -#define PERIPH_SPI1 sercom4 -#define PAD_SPI1_TX SPI_PAD_2_SCK_3 -#define PAD_SPI1_RX SERCOM_RX_PAD_0 +#define PERIPH_SPI1 sercom4 +#define PAD_SPI1_TX SPI_PAD_2_SCK_3 +#define PAD_SPI1_RX SERCOM_RX_PAD_0 static const uint8_t SS1 = PIN_SPI1_SEL ; static const uint8_t MOSI1 = PIN_SPI_MOSI ; @@ -177,10 +178,9 @@ static const uint8_t SCK1 = PIN_SPI_SCK ; */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (20u) -#define PIN_WIRE_SCL (21u) -#define PERIPH_WIRE sercom3 -#define WIRE_IT_HANDLER SERCOM3_Handler +#define PIN_WIRE_SDA (20u) +#define PIN_WIRE_SCL (21u) +#define PERIPH_WIRE sercom3 static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL;