Arduino DUE How to Direrct Port Access?

Hi All,

Just a quick question,

I am relatively new with the Arduino but have some experience with the direct port access on the UNO etc,

I have now moved to the DUE and IDE 1.5.7 I think , DDRD and PORTD commands no longer work, I get a" DDRD was not declared"

Is this an IDE thing or a processor command thing?

Can anyone help with what the direct port access commands are now?

Many thanks all

Rich

1 Like

The architecture's completely different in the SAM3X series.

There are 5 ports, A/B/C/D/E, each 32 bit, mapped to the pins as documented in variant.cpp.

There are several registers for each port that read and write it, and each pin can
be updated atomically so no special interrupt handling is needed:

PIO_PER - write 1's here to override other peripherals and allow GPIO use for pins
PIO_OER - write 1's here to set pins as OUTPUT
PIO_ODR - write 1's here to set pins as INPUT

  • PIO_SODR - write 1's here to set output pins HIGH
  • PIO_CODR - write 1's here to set output pins LOW
  • PIO_PDSR - read's actual state of the pins on the port.
    PIO_PUDR - write 1's here to switch off internal pull-up for pins
    PIO_PUER - write 1's here to switch on internal pull-up for pins

There are other registers to do with input filtering, interrupts, etc etc,
but I think these are the main ones. If you call pinMode() to setup the
pin you only need the one's marked '*' to do I/O

For instance

#define pinnum 2
#define pinport PIOB
#define pinmask (1<<25)   // Arduino pin 2 is port B pin 25.

... 
  pinMode (pinnum, OUTPUT) ;
  pinport -> PIO_SODR = pinmask ;   // set pin
  delay (1) ;
  pinport -> PIO_CODR = pinmask ;  // clear pin

(UNTESTED, note)

In fact to ensure the port(s) is enabled its simplest to call pinMode() for each
pin you want to directly manipulate, otherwise you have to configure the PIO
controller in more detail which isn't needed once pinMode() has done its thing.

HI Mark,

many thanks for the reply I will have a go at a simple example of this and see what results I get, I am assuming that I will need to send a 32bit mask to the ports ?

eg

pinMode (32, OUTPUT) ;
D -> PIO_SODR = B11111111111111111111111111111111 ; // set pin
delay (1) ;
D -> PIO_CODR = B1111111111111111111111111111111 ; // clear pin

These may help, pulled from other examples on the due section of the forum.

This sets D.9 high.
REG_PIOD_SODR = 0x1 << 9;

This sets D.9 low.
REG_PIOD_CODR = 0x1 << 9;

OK, great,

So I have a row of 4 pins that I want to send a WORD to, how would I go about setting the data for that to be sent to the 4 pins,

they would be PORT C slot 2,3,4,5 so easy to send the word to but how would I set the data to send?

eg, b1001 to PORT C 2,3,4 and 5

Cheers

Rich

As I understand it you can't simultaneously set some pins high and some low, you have
to set some high and then others low, or vice versa, using two instructions.

many thanks for the reply I will have a go at a simple example of this and see what results I get, I am assuming that I will need to send a 32bit mask to the ports ?

eg

  pinMode (32, OUTPUT) ;

D -> PIO_SODR = B11111111111111111111111111111111 ;  // set pin
  delay (1) ;
  D -> PIO_CODR = B1111111111111111111111111111111 ;  // clear pin

That sets 32 pins simultaneously (if they are outputs). You need to find
the relevant bit(s) for the pin(s) you're interested in as my example shows.

The syntax is 0b1111111111111111111111111111111 BTW.

Rich_P:
So I have a row of 4 pins that I want to send a WORD to, how would I go about setting the data for that to be sent to the 4 pins,

they would be PORT C slot 2,3,4,5 so easy to send the word to but how would I set the data to send?

eg, b1001 to PORT C 2,3,4 and 5

Something like :

uint8t data;

data = 0b1001;

REG_PIOC_CODR = 0x0F << 2;
REG_PIOC_SODR = data << 2;

Hii!!
Sorry for asking an out of context question but i was browsing through this topic to find something and i got a lot of help reading these conversations, let me ask a question-

There are 5 ports A,B,C,D,E in Due but what are the pin numbers in those ports?

sorry again for asking such a dumb question but i am kinda starter in this field.

1 Like

@Pranesh...
You can find the pin numbers associated with the DUE in a document on this site called SAM3X-Arduino Pin Mapping at http://arduino.cc/en/Hacking/PinMappingSAM3X

In that document you will find DUE pin numbers, the SAM3X pin name and the Mapped Pin Name...
The first column shows the pin number as you are used to... such as the famous LED pin 13. Across in the table you will find the pin name PB27, which implies you can find that pin on PORTB, pin 27.

Therefore you can access that pin at REG_PIOx_SODR, where x would be for PORTB, as in REG_PIOB_SODR and REG_PIOB_CODR, for setting and clearing that particular register...
To set or clear the particular bit, try this...

// This will create a mask with a one in a 32 bit number to set this bit 27 of PORTB
REG_PIOB_SODR |= (0x01 << 27); // Turn on the LED

REG_PIOB_CODR |= (0x01 << 27); // Turn off the LED using the CODR register

Enjoy...
Tim

"As I understand it you can't simultaneously set some pins high and some low, you have
to set some high and then others low, or vice versa, using two instructions."

Yes, you can. The magic trick is to write directly on the register status rather than on
the SET and CLEAR registers. Here is how:

PIOC->PIO_PER = 0x01FF; // Configure PORTC to PIO controller, pins 33-40
PIOC->PIO_OER = 0x01FF; // Enable PORTC to output
....
PIOC->PIO_ODSR = something; // Write something on pins 33-40.

The Output Data Status Register (ODSR) is available for reading and writing (under
weird circunstances). However, this does not happen for all the registers; that's why
there are so many SET and CLEAR status registers. Of course you can add also bit
masks in order to avoid writing on protected pins.

Ah, yes you can do that, but its not interrupt-safe so you have to be careful
if driving several pins from the same port (especially via libraries).

Or is there an atomic read-modify-write for this? Been a while since I played
with the Due, my impression was the set and clear registers are there specifically
to allow single-instruction update without having to worry about interrupts using the
same port. Effectively the read-modify-write is done implicitly at the lowest level
in hardware.

How can i define OUTPUT and INPUT ? For example DDRB |=B00000100 is for sets D10 output in nano. How can i write it for due? I think i use PIO_OER but i couldnt write it completely.

asddsa11:
I think i use PIO_OER but i couldnt write it completely.

Nobody can guess what you did wrong and help you fix the code you wrote, unless you actually show your code.