1

Some variant.cpp files have more than one entry that points to the same physical pin. For example (from Arduino Zero's file):

// 14..19 - Analog pins
// --------------------
{ PORTA,  2, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel0, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_2 }, // ADC/AIN[0]

...

// 43..45 - Alternate use of A0 (DAC output), 44 SWCLK, 45, SWDIO
{ PORTA,  2, PIO_ANALOG, PIN_ATTR_ANALOG, DAC_Channel0, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_2 }, // DAC/VOUT

The first entry sets up the pin as a regular analog input pin on A0. The second entry sets it up as a DAC on pin IDE pin 43.

The corresponding variant.h file defines the DAC pin and A0 as entry 14, rather than 43. I also have seen plenty of examples online that use the DAC via A0 when working with an Arduino Zero.

/*
 * Analog pins
 */
#define PIN_A0               (14ul)
#define PIN_A1               (15ul)
#define PIN_A2               (16ul)
#define PIN_A3               (17ul)
#define PIN_A4               (18ul)
#define PIN_A5               (19ul)
#define PIN_DAC0             (14ul)

Finally, I see other variants, like this one that don't even bother to create a DAC-specific entry. So presumably it doesn't actually matter? If not, then why is it in the Arduino Zero variant.cpp file at all?

A related question: How does using a pin for multiple purposes work? For instance, if I had a pin I've configured for SPI MOSI (in variant.cpp), and I wanted to also use it for PWM (given the datasheet says the pin is on a SERCOM and a timer), do I actually need two entries in variant.cpp and thus two different IDE pins to use in my sketches (one that has a pin type of PIO_SERCOM and another with PIO_PWM)? I can think of plenty of times working with an Arduino UNO, for instance, where I've just used the same IDE pin number for general IO as well as SPI (MOSI).

Andrew M.
  • 145
  • 6

1 Answers1

1

The analogWrite function checks the PIN_ATTR_ANALOG attribute from pin description in variant.cpp to determine if the pin has DAC capability. Then it checks if the pin is ADC_Channel0 or DAC_Channel0. This is unnecessary and redundant. There is no other use for DAC_Channel0.

In Arduino SAMD core and derived cores the pin 'map' in variant.cpp defines pin capabilities used by Arduino core. It is not a complete copy of the mux table from the datasheet. In some variant.cpp files comments contain the additional mux options of the pin.

For PWM the analogWrite function configures the pin and for SPI, the SPI library configures the pin.

If you want to use the pin for other SERCOM function, the function pinPeripheral is used to set up the pin. Here is a tutorial.

Arduino core doesn't support a configuration of a different wave output then analogWrite. To configure a different wave output or capture, a third party library or direct registers configuration is necessary.

The Arduino pinPeripheral(pin, peripheral) function uses the variant.cpp mapping and the possible parameters are:

PIO_EXTINT=0,     /* The pin is controlled by the associated signal of peripheral A. */
PIO_ANALOG,       /* The pin is controlled by the associated signal of peripheral B. */
PIO_SERCOM,       /* The pin is controlled by the associated signal of peripheral C. */
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. */
PIO_COM,          /* The pin is controlled by the associated signal of peripheral G. */
PIO_AC_CLK,       /* The pin is controlled by the associated signal of peripheral H. */
PIO_DIGITAL,      /* The pin is controlled by PORT. */

If you are good with the Arduino variant.cpp configuration, then for direct registers access configuration the pin 'map' from variant.cpp and the pinPeripheral function can be at help if the pin should not be hardcoded. Example from peripherals setup for 'phase cutting' with a Triac in my project:

const PinDescription& pinDesc = g_APinDescription[triacPin]; // Arduino pin description
TCC = (Tcc*) GetTC(pinDesc.ulPWMChannel);
uint8_t tcChannel = GetTCChannelNumber(pinDesc.ulPWMChannel);
bool periF = (pinDesc.ulPinAttribute & PIN_ATTR_TIMER_ALT);

// setup the pin as TCC wave out pin
pinPeripheral(triacPin, periF ? PIO_TIMER_ALT : PIO_TIMER);

TCC->CC[tcChannel].reg = PULSE_PERIOD;
Juraj
  • 18,264
  • 4
  • 31
  • 49