PORTD comand will work on Zero?

Hi!

after being disapointed by Arduino Due because it does not suport the transfer of the content of ports D, C etc directly to the pins, in one comand like PORTD = B00000001; ,
I decided to look for 32 bit CPU Arduino that does suport that comand (PORTD = … ).

For example, in Arduino Uno, we can easily transfer the content of port D in one comand, to all the pins that port D is connected to, 8 pins, with this simple comand:

PORTD = B00000001;

But in Arduino Due that is impossible.

Can somebody answer if this code and comands are supported by Arduino Zero:

void loop() {
  
  for (float i=0; i<5000000; i++)
  {
    PORTD = B00000001;
    PORTD = B00000010;
    PORTD = B00000100;
   }
}

Thank you!

God gave you "numbered" pins like Digital#9 or Analog#3 to make shields work with different Arduino boards.

Yes, you can mix direct register statements with the Arduino code. But it obviously makes your sketch non-portable.

Writing to PORTD on an AVR will affect the whole 8-bit port. With a Due or Zero, you can set or clear multiple bits with a single statement VERY efficiently. Doing the same on a Mega is slower and non-atomic. The Xmega can write to its ports efficiently like the ARM.

You can probably create some macros to access 8-bit portions of a 32-bit port. However, the Zero shield pins are not in convenient 8-bit order.

David.

in Arduino Due that is impossible.

It turns out that that's wrong. http://forum.arduino.cc/index.php?topic=354434.msg2447212#msg2447212

The zero has a simpler (and I think faster, in terms of clocks) GPIO mechanism, so this is probably somewhat easier on the zero. The chip pins are still inconveniently combined with other functions (the way D0/D1 are Serial on AVR Arduinos), and the "board pins" are scattered annoyinly out-of-order, but it looks like PA8...PA23 are more or less available if you're not using TWI, SPI, etc. (16 bits worth of parallel IO, even on byte boundries so you could write it a byte at a time.)

On the Zero there are only ports A and B, but they're 32-bits wide and not all the pins on each port are available. The Zero's SAMD21G does have direct access both the data direction and the output registers, as well as the option of the set and clear registers like the Due.

The registers you're probably interested in are:

REG_PORT_DIR0: Data direction register for port A
REG_PORT_DIR1: Data direction register for port B
REG_PORT_OUT0: Data output register for port A
REG_PORT_OUT1: Data output register for port B

You can set a bit in the register by calling on the port pin definition, for example:

REG_PORT_DIR0 |= PORT_PA17;     // Set digital pin 13 to an output

The problem with setting the whole port on the Zero is that there's a limited number of pins and some are used for other peripherals like its native USB, I2C and EDBG communication. Setting the port on these pins will have no effect, unless you reconnect the port to pin using the port multiplexer.

By the way, it's also possible access the port in the same way on the Due by writing to the PIO_ODSR (Output Data Status Register), but the corresponding bits in the PIO_OWSR (Output Write Status Register) must be set first.

Here's a quote from the SAM3X datasheet:

Figure 32-4 shows how the outputs are driven either by writing PIO_SODR or PIO_CODR, or by
directly writing PIO_ODSR. This last case is valid only if the corresponding bit in PIO_OWSR is
set.

david_prentice:
God gave you “numbered” pins like Digital#9 or Analog#3 to make shields work with different Arduino boards.

Yes, you can mix direct register statements with the Arduino code. But it obviously makes your sketch non-portable.

David, my goal is not to make the sketch portable.

david_prentice:
Writing to PORTD on an AVR will affect the whole 8-bit port. With a Due or Zero, you can set or clear multiple bits with a single statement VERY efficiently. Doing the same on a Mega is slower and non-atomic. The Xmega can write to its ports efficiently like the ARM.

Yes, that is exactly what I’m trying to achive - to affect the whole 8-bit port on Arduino Uno, and at least 8-bit portion on port on Arduion Due.

For now, my understanding is that there is no way to affect the whole port on Arduion Due, but rather is has to be done is small steps, one at a time - by setting bit by bit of the whole port?

Am I right on this part?

Here is the code I wrote to set up 8-bit portion of PORT D on Arduino Due:

void setup() {
  pinMode(25, OUTPUT);
  pinMode(26, OUTPUT);
  pinMode(27, OUTPUT);
  pinMode(28, OUTPUT);
  pinMode(14, OUTPUT);
  pinMode(15, OUTPUT);
  pinMode(29, OUTPUT);
  pinMode(11, OUTPUT);
}

void loop() {
 
  for (float i=0; i<5000001; i++)
  {
  REG_PIOD_SODR = 0x1 << 0;
  REG_PIOD_SODR = 0x1 << 1;
  REG_PIOD_SODR = 0x1 << 2;
  REG_PIOD_SODR = 0x1 << 3;
  REG_PIOD_SODR = 0x1 << 4;
  REG_PIOD_SODR = 0x1 << 5;
  REG_PIOD_SODR = 0x1 << 6;
  REG_PIOD_SODR = 0x1 << 7;
  }
}

Do you agree that this is the only way to set up pins at port D on Arduino Due as a whole 8-bit?

david_prentice:
You can probably create some macros to access 8-bit portions of a 32-bit port. However, the Zero shield pins are not in convenient 8-bit order.

David.

I hope the Zero has comand to affect the whole port with one (1) single comand?

westfw:
It turns out that that's wrong. http://forum.arduino.cc/index.php?topic=354434.msg2447212#msg2447212

That link should lead to a topic that I started on Arduino Due part of a forum.

The link you posted is broken, here is the correct link:
http://forum.arduino.cc/index.php?topic=354434.msg2447212

Topic deals with impossibility or possibility of Arduino Due to affect the whole port with just one single command.

So far, I see that Arduino Due is not capible of setting all the pins on one port at the same time, as a whole, but rather is has to be done by setting bit by bit, which must give slower results for the same task if it is being compared with Arduino Uno.

Rubbish. All the Zero pins are on the same 32-bit port. So you can write to every pin with a single statement.

The Due has pins from two separate 32-bit ports. So you need two statements for a Due.

Note that any direct manipulation is going to be non-portable. The beauty of the Arduino pin abstraction is that you can compile the same sketch for a Uno, Due, Zero, ...

What do you really want to do with a port-write?

David.

david_prentice:
Rubbish. All the Zero pins are on the same 32-bit port. So you can write to every pin with a single statement.

The Due has pins from two separate 32-bit ports. So you need two statements for a Due.

David, that is great news for me, that we can write to every pin with a single statement on Zero.

But, how do we do it on Due?

I would appreciate some code example, instead of just simple comment "rubbish".

I give an example of code that I have for Due, and I'm not sure if that is the correct way to set 8-bit portion of port D on Due, I asked you a question, and if you can then please write something more meaningfull then just word "rubbish".

david_prentice:
Note that any direct manipulation is going to be non-portable. The beauty of the Arduino pin abstraction is that you can compile the same sketch for a Uno, Due, Zero, ...

What do you really want to do with a port-write?

David.

Trying to make simple function generator:
http://www.auctoris.co.uk/2011/05/25/arduino-function-generator-part-2/
and
http://www.auctoris.co.uk/2012/04/13/arduino-function-generator-part-3/

Actually, the link was supposed to point to the NEW message I had added there, quoting the same section of the manual that Martin also quote above. I’ll just paste it here as well:

From the SAM3X datasheet:

Synchronous Data Output
Clearing one (or more) PIO line(s) and setting another one (or more) PIO line(s) synchronously cannot be done by using PIO_SODR and PIO_CODR registers. It requires two successive write operations into two different registers. To overcome this, the PIO Controller offers a direct con- trol of PIO outputs by single write access to PIO_ODSR (Output Data Status Register).Only bits unmasked by PIO_OWSR (Output Write Status Register) are written. The mask bits in PIO_OWSR are set by writing to PIO_OWER (Output Write Enable Register) and cleared by writing to PIO_OWDR (Output Write Disable Register).
After reset, the synchronous data output is disabled on all the I/O lines as PIO_OWSR resets at 0x0.

So, you should be able to write up to 32bits at a time via the PIO_ODSR register. IIRC, the original Due core files did NOT initialize the OWSR mask register, causing the obvious use of ODSR to not work as expected. But if you need that last bit of speed, making sure the PIO is configured shouldn’t be that much trouble. (also, you can use the mask to your advantage.) Of course, the actual pins are still in inconvenient order with “holes” and such, but that was true of the AVR-based Arduinos as well.

I see that Arduino Due […] has to be done by setting bit by bit

Nonsense. Even in the prior discussion about PIO_SODR and PIO_CODR, it should have been clear that you could output up to 32bits in TWO writes (one to clear all the bits, the second to set the bits that should be ones. It was just missing the single-write register PIO_ODSR… SODR/CODR can set/clear MULTIPLE bits at one time.

While the GPIO ports on both Due and Zero are 32bits wide, you should all so be able to write individual bytes or halfwords when that is more convenient. I think.

Of course, there’s also the issue that “PORTD = 123;” on an AVR will usually be two instructions, while the equivalent “PIOA->PIO_ODSR = 123;” is usually 4 instructions. So writing data to the pins on Due or Zero isn’t going to be as much faster than the simple ratio of clock rates might suggest…

Well, both Due and Zero have got a hardware DAC. Your project seems to be creating a pretend-DAC with resistors.

Do you want to use a Due? This is a Zero forum.

David.

westfw:
Actually, the link was supposed to point to the NEW message I had added there, quoting the same section of the manual that Martin also quote above. I'll just paste it here as well:

the link is broken anyway, I'll post it again:

Thank you for your advice!

david_prentice:
Well, both Due and Zero have got a hardware DAC. Your project seems to be creating a pretend-DAC with resistors.

Do you want to use a Due? This is a Zero forum.

David.

I haven't seen any reply to my question from you yet?

Sorry, I was not at my PC. For a Due:

PIOA->PIO_ODSR = value;

For a Zero:

PORT->Group[0].OUT.reg = value;

Note that these are writing to all 32 bits at once. You normally want to write to a random selection of the bits. And ignore the other bits. Effectively, you mask the bits that you don't want to affect.

With a Due, it is easy to change a pin from output to input.
The Zero is quite fiddly.

Yes, you can mix in some native statements with your Arduino C++ methods. As I said, it makes everything non-portable but you can achieve the best of both worlds.

There have been questions (on other sites) about addressing an 8-bit chunk of the 32-bit PORT register. e.g. bits 16-23

David.

david_prentice:
Sorry, I was not at my PC. For a Due:

PIOA->PIO_ODSR = value;

David, thank you, I tried that code on Due but it does not work:

void setup() {
  pinMode(13, OUTPUT);
}

void loop() {
  PIOB->PIO_ODSR = 0x2000;
  delay(5000);
  PIOB->PIO_ODSR = 0x0;
  delay(500);
}

I have pin 13 connected to LED and to ground (GND) on Due.

But since this is forum about Zero, I won’t contunue writing here about code on Due,
if you want to join the discusion, please do it here:

Does Zero have ARM's bit manipulation engine? It's an optional Cortex-M0+ feature, which adds bitwise read-modify-write onto peripheral registers using atomic reads or writes in a large "decorated" address space.