PlatformIO Community

How to access pins on SAMD21 E18A with Arduino Framework on custom board?

Hi,
I’ve got a custom board with a SAMD21 E18A on it. I want to program it using Platform IO (VS Code) and want to be able to use Arduino libraries.
Since I couldn’t find a custom board board, I went with adafruit_trinket_m0.
Now I wan’t to toggle IOs PA05 to PA07 but I can’t find their names. How do I refer to an IO like PA05?!

This is my platformio.ini:

[env:adafruit_trinket_m0]
platform = atmelsam
board = adafruit_trinket_m0
framework = arduino
board_build.mcu = samd21e18a

This is my code:

#include <Arduino.h>

#define LED_R PIN_PA06 // actually toggles PA09 by measurement
#define LED_G PIN_PA05 // actually toggles PA08 by measurement
#define LED_B PIN_PA07 // actually toggles PA00 by measurement

void setup() {
  pinMode(LED_R, OUTPUT);
  pinMode(LED_G, OUTPUT);
  pinMode(LED_B, OUTPUT);
}

uint8_t cnt = 0;
void loop() {
  cnt++;
  digitalWrite(LED_R,cnt&0x01);
  digitalWrite(LED_G,cnt&0x02);
  digitalWrite(LED_B,cnt&0x04);
  delay(10);
}

Actually PA08 is toggled instead of PA05.
The pin definitions from samd21e18a.h are not very helpful:

...
#define PIN_PA05                           5  /**< \brief Pin Number for PA05 */
#define PORT_PA05                 (1ul <<  5) /**< \brief PORT Mask  for PA05 */
#define PIN_PA06                           6  /**< \brief Pin Number for PA06 */
#define PORT_PA06                 (1ul <<  6) /**< \brief PORT Mask  for PA06 */
#define PIN_PA07                           7  /**< \brief Pin Number for PA07 */
#define PORT_PA07                 (1ul <<  7) /**< \brief PORT Mask  for PA07 */

Guess these are just the bit positions in the actual port register and are not meant to be used as pin names in the Arduino world.
When I use this:

#define LED_R 4 // actually PA06 by measurement
#define LED_G PIN_PA05 // actually PA08 by measurement
#define LED_B 3 // actually PA07 by measurement

It actually works. 3/4 are the pin labels used by the adafruit trinket M0. But the problem is, the trinket only has 5 IOs and PA05 isn’t one of them.

All the SAMD21 E18A boards available only have a hand full of IOs broken out.
Isn’t there a way to use the SAMD21 without writing my own board definition?

Hi,

I am having the same problem for the SAMD21G18. From what I understand there is no other way then creating your own variant.

But I just found out that there is another way creating a variant without having to create you own framework and platform.

  1. Add script.py to the project root

    Import("env")
    env.Append(OVERRIDE_VARIANT=True)
    
  2. Add your custom variant in a “variants” folder in the project root. E.g. variants/samd21g18/

  3. platformio.ini

    [env:samd21g18]
    framework = arduino
    platform = atmelsam
    board_build.variant = samd21g18
    board_build.variants_dir = variants
    board = samd21g18a
    debug_tool = jlink
    upload_protocol = jlink
    

Source

It’s not perfect solution, because this way you have to manually update your variants file in all the projects where you use it. But for me it’s still a bit cleaner and easier than maintaining a fork of the platform and framework.

I started with a generic version for the SAMD21G18, where I have now definitions for all pins with the original names and all the SERCOMs are undefined and can now be configured the way I need them in project. This is still work in progress and the variant.cpp will for sure still contain bugs :slight_smile:

Generic SAMD21G18 Example - WIP !!!

variant.h

#pragma once

// The definitions here needs a SAMD core >=1.6.10
#define ARDUINO_SAMD_VARIANT_COMPLIANCE 10610

#include <WVariant.h>

// General definitions
// -------------------

// Frequency of the board main oscillator
#define VARIANT_MAINOSC (32768ul)

// Master clock frequency
#define VARIANT_MCK     (48000000ul)

// Pins
// ----

// Number of pins defined in PinDescription array
#ifdef __cplusplus
extern "C" unsigned int PINCOUNT_fn();
#endif
#define PINS_COUNT           (PINCOUNT_fn())
#define NUM_DIGITAL_PINS     (15u)
#define NUM_ANALOG_INPUTS    (7u)
#define NUM_ANALOG_OUTPUTS   (1u)

// Low-level pin register query macros
// -----------------------------------
#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)

#define NATIVE_PIN_PA00 1
#define NATIVE_PIN_PA01 2
#define NATIVE_PIN_PA02 3
#define NATIVE_PIN_PA03 4
#define NATIVE_PIN_PB08 7
#define NATIVE_PIN_PB09 8
#define NATIVE_PIN_PA04 9
#define NATIVE_PIN_PA05 10
#define NATIVE_PIN_PA06 11
#define NATIVE_PIN_PA07 12
#define NATIVE_PIN_PA08 13
#define NATIVE_PIN_PA09 14
#define NATIVE_PIN_PA10 15
#define NATIVE_PIN_PA11 16
#define NATIVE_PIN_PB10 19
#define NATIVE_PIN_PB11 20
#define NATIVE_PIN_PA12 21
#define NATIVE_PIN_PA13 22
#define NATIVE_PIN_PA14 23
#define NATIVE_PIN_PA15 24
#define NATIVE_PIN_PA16 25
#define NATIVE_PIN_PA17 26
#define NATIVE_PIN_PA18 27
#define NATIVE_PIN_PA19 28
#define NATIVE_PIN_PA20 29
#define NATIVE_PIN_PA21 30
#define NATIVE_PIN_PA22 31
#define NATIVE_PIN_PA23 32
#define NATIVE_PIN_PA24 33
#define NATIVE_PIN_PA25 34
#define NATIVE_PIN_PB22 37
#define NATIVE_PIN_PB23 38
#define NATIVE_PIN_PA27 39
#define NATIVE_PIN_PA28 41
#define NATIVE_PIN_PB02 47
#define NATIVE_PIN_PB03 48


// Analog pins
// -----------
#ifndef A0
#define A0 NATIVE_PIN_PA10
#endif

// USB
// ---
#ifndef PIN_USB_DM
#define PIN_USB_DM          NATIVE_PIN_PA24
#endif
#ifndef PIN_USB_DP
#define PIN_USB_DP          NATIVE_PIN_PA25
#endif
#ifndef PIN_USB_HOST_ENABLE
#define PIN_USB_HOST_ENABLE NATIVE_PIN_PA18
#endif

// SERCOM ports
// ------------
#ifdef __cplusplus
#include "SERCOM.h"
#include "Uart.h"

// Instances of SERCOM
extern SERCOM sercom0;
extern SERCOM sercom1;
extern SERCOM sercom2;
extern SERCOM sercom3;
extern SERCOM sercom4;
extern SERCOM sercom5;

#endif // __cplusplus

#ifdef __cplusplus
extern "C" {
#endif
unsigned int PINCOUNT_fn();
#ifdef __cplusplus
}
#endif

variant.cpp

#include "variant.h"

const PinDescription g_APinDescription[] = {
  { NOT_A_PORT, 99, PIO_NOT_A_PIN,    (PIN_ATTR_NONE                         ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 00
  { PORTA,  0, PIO_DIGITAL,    (PIN_ATTR_NONE                                ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 01
  { PORTA,  1, PIO_DIGITAL,    (PIN_ATTR_NONE                                ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 02
  { PORTA,  2, PIO_DIGITAL,  (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG /*DAC*/       ), ADC_Channel0,   NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_2    }, // 03
  { PORTA,  3, PIO_DIGITAL, (PIN_ATTR_DIGITAL                                ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_3    }, // 04 // DAC/VREFP
  { NOT_A_PORT, 99, PIO_NOT_A_PIN,    (PIN_ATTR_NONE                         ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 05
  { NOT_A_PORT, 99, PIO_NOT_A_PIN,    (PIN_ATTR_NONE                         ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 06
  { PORTB,  8, PIO_DIGITAL,    (PIN_ATTR_NONE                                ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 07
  { PORTB,  9, PIO_ANALOG,     (PIN_ATTR_PWM|PIN_ATTR_TIMER                  ), ADC_Channel3,   PWM4_CH1,   TC4_CH1,      EXTERNAL_INT_9    }, // 08
  { PORTA,  4, PIO_ANALOG,  (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER    ), ADC_Channel4,   PWM0_CH0,   TCC0_CH0,     EXTERNAL_INT_NONE }, // 09
  { PORTA,  5, PIO_ANALOG,  (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER    ), ADC_Channel5,   PWM0_CH1,   TCC0_CH1,     EXTERNAL_INT_NONE }, // 10
  { PORTA,  6, PIO_ANALOG,  (PIN_ATTR_DIGITAL                                ), ADC_Channel6,   NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 11
  { PORTA,  7, PIO_ANALOG,  (PIN_ATTR_DIGITAL                                ), ADC_Channel7,   NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 12
  { PORTA,  8, PIO_SERCOM_ALT, (PIN_ATTR_DIGITAL                             ), ADC_Channel16,  NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NMI  }, // 13 // SDA:  SERCOM2/PAD[0]
  { PORTA,  9, PIO_SERCOM_ALT, (PIN_ATTR_DIGITAL                             ), ADC_Channel17,  NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 14 // SCL:  SERCOM2/PAD[1]
  { PORTA, 10, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER    ), ADC_Channel18,  PWM1_CH0,   TCC1_CH0,     EXTERNAL_INT_NONE }, // 15
  { PORTA, 11, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER    ), ADC_Channel19,  PWM1_CH1,   TCC1_CH1,     EXTERNAL_INT_NONE }, // 16
  { NOT_A_PORT, 99, PIO_NOT_A_PIN,    (PIN_ATTR_NONE                         ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 17
  { NOT_A_PORT, 99, PIO_NOT_A_PIN,    (PIN_ATTR_NONE                         ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 18
  { PORTB, 10, PIO_SERCOM_ALT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER ), No_ADC_Channel, PWM5_CH0,   TC5_CH0,      EXTERNAL_INT_10   }, // 19
  { PORTB, 11, PIO_SERCOM_ALT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER ), No_ADC_Channel, PWM5_CH1,   TC5_CH1,      EXTERNAL_INT_11   }, // 20
  { PORTA, 12, PIO_SERCOM_ALT, (PIN_ATTR_NONE                                ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 21 // MOSI: SERCOM4/PAD[0]
  { PORTA, 13, PIO_SERCOM_ALT, (PIN_ATTR_NONE                                ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 22 // SCK:  SERCOM4/PAD[1]
  { PORTA, 14, PIO_DIGITAL,    (PIN_ATTR_NONE                                ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 23 // SS:   as GPIO
  { PORTA, 15, PIO_SERCOM_ALT, (PIN_ATTR_NONE                                ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 24 // MISO: SERCOM4/PAD[3]
  { PORTA, 16, PIO_SERCOM,  (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER    ), No_ADC_Channel, PWM2_CH0,   TCC2_CH0,     EXTERNAL_INT_0    }, // 25 // MOSI: SERCOM1/PAD[0]
  { PORTA, 17, PIO_SERCOM,  (PIN_ATTR_DIGITAL                                ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_1    }, // 26 // SCK:  SERCOM1/PAD[1]
  { PORTA, 18, PIO_DIGITAL, (PIN_ATTR_DIGITAL                                ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 27 // SS:   SERCOM1/PAD[2]
  { PORTA, 19, PIO_SERCOM,  (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER    ), No_ADC_Channel, PWM3_CH1,   TC3_CH1,      EXTERNAL_INT_NONE }, // 28 // MISO: SERCOM1/PAD[3]
  { PORTA, 20, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER_ALT), No_ADC_Channel, PWM0_CH6,   TCC0_CH6,     EXTERNAL_INT_4    }, // 29
  { PORTA, 21, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER_ALT), No_ADC_Channel, PWM0_CH7,   TCC0_CH7,     EXTERNAL_INT_5    }, // 30
  { PORTA, 22, PIO_SERCOM,  (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER    ), No_ADC_Channel, PWM4_CH0,   TC4_CH0,      EXTERNAL_INT_6    }, // 31
  { PORTA, 23, PIO_SERCOM,  (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER    ), No_ADC_Channel, PWM4_CH1,   TC4_CH1,      EXTERNAL_INT_7    }, // 32
  { PORTA, 24, PIO_COM,     (PIN_ATTR_NONE                                   ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 33 // USB/DM
  { PORTA, 25, PIO_COM,     (PIN_ATTR_NONE                                   ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 34 // USB/DP
  { NOT_A_PORT, 99, PIO_NOT_A_PIN,    (PIN_ATTR_NONE                         ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 35
  { NOT_A_PORT, 99, PIO_NOT_A_PIN,    (PIN_ATTR_NONE                         ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 36
  { PORTB, 22, PIO_SERCOM_ALT, (PIN_ATTR_DIGITAL                             ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 37 // TX:   SERCOM5/PAD[2]
  { PORTB, 23, PIO_SERCOM_ALT, (PIN_ATTR_DIGITAL                             ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 38 // RX:   SERCOM5/PAD[3]
  { PORTA, 27, PIO_DIGITAL,    (PIN_ATTR_NONE                                ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 39
  { NOT_A_PORT, 99, PIO_NOT_A_PIN,    (PIN_ATTR_NONE                         ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 40
  { PORTA, 28, PIO_DIGITAL,    (PIN_ATTR_NONE                                ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 41
  { NOT_A_PORT, 99, PIO_NOT_A_PIN,    (PIN_ATTR_NONE                         ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 42
  { NOT_A_PORT, 99, PIO_NOT_A_PIN,    (PIN_ATTR_NONE                         ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 43
  { NOT_A_PORT, 99, PIO_NOT_A_PIN,    (PIN_ATTR_NONE                         ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 44
  { PORTA, 30, PIO_DIGITAL,    (PIN_ATTR_NONE                                ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 45
  { PORTA, 31, PIO_DIGITAL,    (PIN_ATTR_NONE                                ), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // 46
  { PORTB,  2, PIO_ANALOG,  (PIN_ATTR_DIGITAL                                ), ADC_Channel10,  NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_2    }, // 47
  { PORTB,  3, PIO_ANALOG,  (PIN_ATTR_DIGITAL                                ), ADC_Channel11,  NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_3    }, // 48
};

extern "C" {
    unsigned int PINCOUNT_fn() {
        return (sizeof(g_APinDescription) / sizeof(g_APinDescription[0]));
    }
}

const void* g_apTCInstances[TCC_INST_NUM + TC_INST_NUM]={ TCC0, TCC1, TCC2, TC3, TC4, TC5 };

// Multi-serial objects instantiation
SERCOM sercom0(SERCOM0);
SERCOM sercom1(SERCOM1);
SERCOM sercom2(SERCOM2);
SERCOM sercom3(SERCOM3);
SERCOM sercom4(SERCOM4);
SERCOM sercom5(SERCOM5);


2 Likes

Thanks for posting this, looks interesting, especially with all the pin information and attributes :slight_smile:

A similiar question also popped up in Programm SAMD21 directly and created an example repo https://github.com/maxgerhardt/pio-custom-samd21e17a-board for creating a custom Arduino variant for the Adafruit SAMD core.

This also works without

doing this, just using the variant and variants_dir option. Are you sure this is needed?

1 Like

Thank you, that was really helpful! I’ve now got basic access to all my pins I need. However, I don’t quite understand the PinDescription struct… Is there a reason why the order is mixed up and some pins are described multiple times?
I’d arrange my pins such that PORTA IO 0 is actually arduino pin 0 etc.
But why are pins defined multiple times, like PORTA IO 2 and 3? They are defined as arduino pins 3+4 and 47+48, even with different attributes. Also, why are arduino pins 5 and 6 not assigend to any IO?
Where do I get the correct attributes from? Even the original trinket m0 has some pins defined multiple times with different attributes…

Edit: Oops sorry, it’s actually PORTB on your file, I missed that. But the original trinket had multiple definitions that confused me: https://github.com/adafruit/ArduinoCore-samd/blob/master/variants/trinket_m0/variant.cpp

You are right, the script is not needed (anymore). I just copied it without testing any further :slight_smile:

I would say that these multiple defintions are used as placeholders, because they are actually not used on the Trinket M0, but they had to fill the array for the GPIO19-22. (see also the comment “GPIO 12 is a placeholder, same as D13”). I think Adafruit just used another SAMD21 board with more pins as a template and used the same “arduino pin layout”.

I found one downside on my current variant file. If you use libraries that uses somewhere hard coded “Wire” interface, then you also need to define the Wire interface in the variant.h. Most probably there are similar issues with SPI and Serial :confused:

hmm, good point. There are also macros in variant.h like #define analogInputToDigitalPin(p) ((p < 5u) ? (p) + PIN_A0 : -1) that require all analog pins to be defined in a row. Guess there are a lot of things to keep in mind that I don’t know yet…

Thank you very much, this was really helpful in the end. I also found additional reasons why some IOs are listed multiple times. This is required if you want to use them with different modes. If you look at the Datasheets IO Matrix (Table 7-1. PORT Function Multiplexing [Page 31]) some ports have alternative functions like SERCOM and SERCOM_ALT.
The pin definition however allows only for selecting one of these functions. If you want to able to use both, you have to declare the pin twice.
Lets say PA08 and PA09 … These are connected to SERCOM0 when SERCOM is selected, and are connected to SERCOM2 when SERCOM_ALT is selected.
2021-01-12-15_38_43-atmel-4

The Trinket M0 uses SERCOM0 for SPI, SERCOM1 for UART and SERCOM2 for I2C/Wire, which is mapped in variant.h.

Let’s say, for some reason, I want to use SERCOM0 for UART and SERCOM2 for I2C both on the IOs PA08 and PA09 that I’ll name D1 and D2 on my board. I will have to declare these IO twice to have access to both special functions:

const PinDescription g_APinDescription[]=
{
  // LABEL           PIN    SERCOM            SERCOM_ALT
  // D1,SDA,TX       PA08   SERCOM0 PAD 0     SERCOM2 PAD 0
  // D2,SCL,RX       PA09   SERCOM0 PAD 1     SERCOM2 PAD 1
  // 0, NC
  { NOT_A_PORT, 99, PIO_NOT_A_PIN, (PIN_ATTR_NONE), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE },
  // 1-2, D1/D2 as UART on SERCOM0
  { PORTA,  8, PIO_SERCOM, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel16, PWM0_CH0, TCC0_CH0, EXTERNAL_INT_NMI },
  { PORTA,  9, PIO_SERCOM, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel17, PWM0_CH1, TCC0_CH1, EXTERNAL_INT_9 },
  // 3-4, D1/D2 as I2C on SERCOM2
  { PORTA,  8, PIO_SERCOM_ALT, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel16, PWM0_CH0, TCC0_CH0, EXTERNAL_INT_NMI },
  { PORTA,  9, PIO_SERCOM_ALT, (PIN_ATTR_DIGITAL|PIN_ATTR_ANALOG|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel17, PWM0_CH1, TCC0_CH1, EXTERNAL_INT_9 },
}

Now the Arduino-Pins (Index of the array above) 1 and 2 will be the UART pins, and 3 and 4 will be the I2C/Wire pins.
But I also have to declare this in variant.h:

/*
 * Serial interfaces
 */
#define PIN_SERIAL1_RX       (2u)
#define PAD_SERIAL1_RX       SERCOM_RX_PAD_1
#define PIN_SERIAL1_TX       (1u)
#define PAD_SERIAL1_TX       UART_TX_PAD_0

/*
 * Wire Interfaces
 */
#define PIN_WIRE_SDA         (3u) // same pin as 1, but different SERCOM
#define PIN_WIRE_SCL         (4u) // same pin as 2, but different SERCOM
#define PERIPH_WIRE          sercom2
#define WIRE_IT_HANDLER      SERCOM2_Handler

and variant.cpp again:

Uart Serial1( &sercom0, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ;

void SERCOM0_Handler()
{
  Serial1.IrqHandler();
}

I hope I didn’t make any errors here, I simplified a lot… Hope this helps someone. It worked fine for the custom board I’m using.

Btw: In this case you obviously cannot use UART and I2C the same time, because they share the same physical pins. And therefore you could just use SERCOM0 for both and configure it accordingly. However, since the arduino framework declares the Handler-Functions for the different peripherals at this stage, you cannot attach two different handlers to the same SERCOM0 (if I got that right).

1 Like