Issue with higher number digital pins

I have a custom board but based on the M0 boards with a SAMD21 18G (will need to wait till 2023 for mass production as new IC's are expected only then :cry:). But it leaves more time to focus on the software. I want to use PA12 and PA13 for i2c. The step before that is that I test the pins by connecting an LED. That is where I stumbled upon this strange phenomenon:

// global:
#define sclLED 38 // PA13
#define sdaLED 22 // PA12

// in setup:
pinMode(sclLED, OUTPUT);
pinMode(sdaLED, OUTPUT);

// in loop:
digitalWrite(sdaLED, LOW);   
digitalWrite(sclLED, HIGH);   
delay(500);
digitalWrite(sdaLED, HIGH);    
digitalWrite(sclLED, LOW);
delay(500);

Actually nothing happens to my LEDs...

Of course this can be due to a lot of different causes, but interestingly enough this works like a charm:

// in setup:
REG_PORT_DIR0 |= (1 << PIN_PA12) | (1 << PIN_PA13); // pinmode, setting pins in direction register to output 
REG_PORT_OUT0 &= ~((1 << PIN_PA12) | (1 << PIN_PA13)); // setting pins low

// in loop:
REG_PORT_OUT0 |= (1 << PIN_PA12);
REG_PORT_OUT0 &= ~(1 << PIN_PA13);
delay(500);
REG_PORT_OUT0 |= (1 << PIN_PA13);
REG_PORT_OUT0 &= ~(1 << PIN_PA12);
delay(500);

(Of course I could simplify the code above using a bitwise XOR, but that is not the point right now).

Therefor it must be some software issue...

In variant.cpp PA12 is supposed to be D22 and PA13 should be D38.

The 'normal' Arduino code does work for:
#define sclLED 13 // PA16
#define sdaLED 11 // PA17

However also for PA22 and PA23 only the lower level direction register code works (D33, D32).

Interesting isn't it? Of course for testing I don't see any problems with my second solution, but it might confuse other people (in my case students that will work with my software), so I would prefer the normal Arduino solution.

For the AVR core, there is a check at digitalWrite() for the maximum pin number. It seems to work a little different for the SAMD core.
You should have given a link to the Github for your variant.

Others might also be interested in a schematic.

I think the Arduino M0 was designed in Italy and the Arduino Zero and MKR boards by the international team. I have forgotten how it was, but I remember vaguely that one or two pins are different and the Arduino M0 might have a different bootloader as well.
Can you select one of the current boards to be compatible with ? Such as the Arduino Zero or the MKR Zero ?

Thanks Koepel for thinking along. The entire project will be open sourced in the end, but for now I don't think that is really relevant as it mainly deals with how Arduino 'backend' works.

I have looked into a number of files:

  • wiring.c
  • Arduino.h
  • wiring_digital.c
  • wiring_digital.h

I assumed there would be a file that had all the digital inputs mapped to a port/pin, but after checking pinMode I realized that that is not the case. I modified pinMode and put that modified version in my test sketch:

void pinModeTest( uint32_t ulPin, uint32_t ulMode )
{
  // Reports Port/Pin for digital pin
  Serial.print("D");
  Serial.print(ulPin);

  if ( g_APinDescription[ulPin].ulPinType == PIO_NOT_A_PIN )
  {
    Serial.print(" is not usable as PIO");
    Serial.println();
    return ;
  }

  EPortType port = g_APinDescription[ulPin].ulPort;
  uint32_t pin = g_APinDescription[ulPin].ulPin;
  uint32_t pinMask = (1ul << pin);
 
  Serial.print(", P");
  char portLetter = 'A';
  portLetter += port;
  Serial.print(portLetter);
  Serial.print(pin);
  /*
  // Maybe useful, but not for my intended purpose.
  Serial.print(" Mask: ");
  Serial.print(pinMask, BIN);
  */
  Serial.println();
}

I call it in a normal for-loop between 0 and 50 and it reports pins like this:

D0, PA11
D1, PA10
D2, PA14
D3, PA9
D4, PA8
D5, PA15
D6, PA20
D7, PA21
D8, PA6
D9, PA7
etc.

D43 and higher give me weird values, so apparently they D42 is the highest possible digital PIN number for an M0.

So now I know which digital pins I can use for in my case PA12, PA13, PA16, PA17, PA22 and PA23. When I use the following defines everything works like a charm when using pinMode and digitalWrite.

#define sclLED0 27 // PA23
#define sdaLED0 26 // PA22
#define sclLED1 13 // PA16
#define sdaLED1 11 // PA17
#define sclLED2 39 // PA13
#define sdaLED2 28 // PA12

Next step will be to adjust my SERCOM Wire setups based on these finds, but I expect that to work well also.

Can you give a link to Github to show in which branch you are looking and which variant you choose ?

Of course:

But there are many other possibilities, so it just depends on personal preference. But as I also use a custom development kit based on a number of coupled Adafruit M0 (Express) and M4 boards + Raspberry Pi Zero W2, I heavily base the custom boards also on that (M0 Express in this case).

Note: the M0 Express does not have the exact same configuration, but comparable. I use the CS FRAM pin (PA13) from the original as SCL pin. My solution use three SERCOM TWI buses. Apart from that my design is essentially the same as the Feather M0 express.

So all this time you were talking about the Adafruit M0 ? That is not a Arduino M0. I didn't even had to bring up Italy.

If you want the Adafruit fork, then you can ask on the forum of Adafruit.
For the development environment, you are depending on Adafruit for support in the coming years.

I would select the Arduino MKR Zero for the hardware to be compatible with and the official Arduino ArduinoCore-samd branch.
My personal preference is to have the best support for the longest time. So I stick with Arduino :nerd_face:

However, it is not so bad. Some buy the Seeeduino XIAO and learn that its development environment is a fork of a older Arduino version.

I totally disagree as it does not matter, the issue was that I needed to better understand the Arduino SAMD structure. I could have used the M0 and M0 Pro from Arduino, or even the Arduino Nano 33 (IoT) that I often use in some other project. That would not have changed anything. The matter was at software level, not at hardware variety level, Adafruit / Limor Fried did not create the Arduino software did she (apart from her great contributions to the Arduino community).

Hope my little my little code snippet might benefit other Arduino users regardless whether they use Official Arduino/Sparkfun/Adafruit/Seeedstudio/Microchip Xplained boards. Apart from that I would agree that we should buy / use boards that contribute, both Sparkfun and Adafruit contribute to the Arduino community in more than one way, maybe Seeedstudio a little less and I always discourage e.g. students to go with copy-cat leeches.

Are you sure you’re looking at the correct variant?
Feather m0 and feather m0 express seem to have different pinouts. The express has pa12 where you’re seeing it, and the other has it where you expected to see it…

That is also tricky even about GitHub, when you fork one variant, and try to fork another it says that you already forked it. It works perfectly at the moment b.t.w., steps that I took:

  • soldering the board
  • flashing custom boot loader into the uC
  • change variants.cpp for my board
  • report digital pins for my variant based on the source I showed
  • create SERCOM wire variants with the settings I like.
// i2c system bus
#define W0_SCL 27 // PA22 
#define W0_SDA 26 // PA23 

#define W1_SCL 39 // PA13  
#define W1_SDA 28 // PA12  

#define W2_SCL 13 // PA17 
#define W2_SDA 11 // PA16

TwoWire Wire0(&sercom3, W0_SDA, W0_SCL); 
TwoWire Wire1(&sercom1, W1_SDA, W1_SCL); 
TwoWire Wire2(&sercom4, W2_SDA, W2_SCL); 

void setup()
{
  Serial.begin(115200);
  delay(1500);
  Wire0.begin();
  Wire1.begin();
  Wire2.begin();

  // set pinPeripheral(pin, PIO_SERCOM/PIO_SERCOM_ALT);
  pinPeripheral(W0_SCL, PIO_SERCOM);
  pinPeripheral(W0_SDA, PIO_SERCOM);
  pinPeripheral(W1_SCL, PIO_SERCOM);
  pinPeripheral(W1_SDA, PIO_SERCOM);
  pinPeripheral(W2_SCL, PIO_SERCOM_ALT);
  pinPeripheral(W2_SDA, PIO_SERCOM_ALT);
  
}

// in loop I perform Wire Scanner operations to report devices it sees.

Works really well, I still want to refactor the above so that I have a wrapper around the three i2c buses / SERCOM Wire items that I can delegate all the intricacies to.

Maybe something like here: Duino-hacks/test_sercomlib at master · WestfW/Duino-hacks · GitHub
This was mostly implemented for UART, and mostly for SAMD51 (where each sercom has multiple interrupts), but the idea was to allow user programs to contain code lines like:

sercom_UseSerial(  5,      4)   // Serial4 - pins 14 and 15
sercom_UseI2CPins( 7,   Wire7, 82, 81)  // Wire7 on SPI pins.

instead of having to define all the pins and isr functions.

I'll have a look at it. Abstracting away UART/SPI/TWI is quite a good idea that we already had in mind.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.