Arduino Zero Read In Registers & Speed Question

I'm currently porting an Arduino Uno program i wrote using port manipulation over to my Arduino Zero. I am just curious if anyone knows the Arduino Zero equivalent of PINC, or PIND. I realize on the Zero there are only two ports, 0 and 1, however i assume PIN0/PIN1 wont work.

I originally wrote the Uno's program using port manipulation for speed(It is used in-between an rX and a flight controller), however taking into consideration the Zero's clock speed is port manipulation still largely faster or could i get away with just using digitalRead/Write and Interrupts on six of the pins?

Any info is greatly appreciated!

The SAMD21 has two 32-bit ports, A and B. The SAMD21G variant used on the Arduino Zero uses most pins of port A, but only a few of port B. In the following examples a 0 suffix after the register's name defines the register for port A, while a 1 defines the register for port B.

The SAMD21 equivalent of AVR's PINx is the IN register. To check if a given pin, say digital pin 12 is high:

if (REG_PORT_IN0 & PORT_PA19)  // if (digitalRead(12) == HIGH)

Alternatively to check if it's low:

if (!(REG_PORT_IN0 | ~PORT_PA19)) // if (digitalRead(12) == LOW)

For digital output it's possible to use the SAMD21's OUT register. This requires the register to be masked, just like the AVR's PORTx. Here's an example of the blink sketch using the OUT register:

void setup() {
  // put your setup code here, to run once:
  REG_PORT_DIRSET0 = PORT_PA17;   // Set the direction of the port pin PA17 to an output
}

void loop() {
  // put your main code here, to run repeatedly:
  REG_PORT_OUT0 |= PORT_PA17;     // Switch the output to 1 or HIGH
  delay(1000);
  REG_PORT_OUT0 &= ~PORT_PA17;     // Switch the output to 0 or LOW
  delay(1000);
}

However, the SAMD21 can save you overhead of having to read-modify-write to the register, by instead masking it in hardware using OUTSET and OUTCLR. Here's an example of the blink sketch using these registers:

void setup() {
  // put your setup code here, to run once:
  REG_PORT_DIRSET0 = PORT_PA17;   // Set the direction of the port pin PA17 to an output
}

void loop() {
  // put your main code here, to run repeatedly:
  REG_PORT_OUTSET0 = PORT_PA17;     // Switch the output to 1 or HIGH
  delay(1000);
  REG_PORT_OUTCLR0 = PORT_PA17;     // Switch the output to 0 or LOW
  delay(1000);
}

Alternatively, there's the toggle register. Here's an example of the blink sketch using the OUTTGL register:

void setup() {
  // put your setup code here, to run once:
  REG_PORT_DIRSET0 = PORT_PA17;   // Set the direction of the port pin PA17 to an output
}

void loop() {
  // put your main code here, to run repeatedly:
  REG_PORT_OUTTGL0 = PORT_PA17;     // Toggle the output HIGH and LOW
  delay(1000);
}

The register definitions are a number of Atmel files (on my Windows machine) currently located at: C:\User\AppData\Local\Arduino15\packages\arduino\tools\CMSIS\4.0.0-atmel\Device\ATMEL\SAMD21\include...

If you're using port register manipulation there are two directories named "component" and "instance". The "port.h" file in the "component" directory defines the structure of each register. Using this file you can use the format:

PORT->Group[PORTA].DIRSET.reg = PORT_PA17;

The "port.h" file in the "instance" directory gives the definitions that define the registers' absolute locations, this gives an alternative, but equivalent format used in the examples above:

REG_PORT_DIRSET0 = PORT_PA17;

Thank you so much! I have one more question. On the Uno you could write to the output registers using binary. I realize that above 8 bits isnt defined for arduino so my thought was using the binary equivalent hex value to get the same function. Would this work, or will it cause issues with the mixed up pin to register mapping of the zero?

Would this work, or will it cause issues with the mixed up pin to register mapping of the zero?

Yes, you can write to the Zero's port registers using hex or binary. It's just that being a 32-bit processor the SAMD21's port registers are 32-bits long, so in hex for example it's 0x00000000, rather than the AVR's 8-bit 0x00.