Port manipulation PINx commands with Arduino Due ?

Sorry, haven't been here for some time.
I dunno understand what exactly you want, so here just a short example of running Timer counter TC0
at 42 MHz. Maybe this is something that can fit your needs.
Sketch starts and reads (CV = counter value) counter.

void setup(){  Serial.begin(9600); }

void loop() 
{
unsigned long v[10];
int i;
  PMC->PMC_PCER0 = 1<<27;  // PMC: Enable Timer TC0
  TC0->TC_CHANNEL[0].TC_CMR = 0;  // Control mode reg.: set Clock to MCK/2 = 42 MHz  
  TC0->TC_CHANNEL[0].TC_CCR = 4 + 1;  // activate Timer:  // Start + Enable 
  Serial.println("---------------------------------------------------------");
  Serial.println("-------       delay is not exackt, TC0 is!      ---------");
  Serial.println("---------------------------------------------------------");
  Serial.println("Delayed Readout (24 us -> ~1000 Ticks)");
  TC0->TC_BCR = 1;  // restart(sync) 
  for(i=0; i<10; i++) { v[i]= TC0->TC_CHANNEL[0].TC_CV;  delayMicroseconds(24); }
  for(i=0; i<10; i++) { Serial.print(i); Serial.print(": "); Serial.println(v[i]); }
  delay(5000);  
  Serial.println("---------------------------------------------------------");
  Serial.println("Endless Readout (1s -> +42 000 000)");
  TC0->TC_BCR = 1;  // restart(sync) 
  while(1==1)  { Serial.println(TC0->TC_CHANNEL[0].TC_CV); delay(1000); }
}

stimmer:
The squarewave is uneven because of function call overhead. You can lessen this by making your own loop:

void loop() {

for(;;){
    digitalWriteDirect(9, HIGH);           
    digitalWriteDirect(9, LOW);         
  }
}

To make HIGH and LOW phases simmetric, just add a cuple of NOP (No Operation) after the digitalWriteDirect(9, HIGH) :

#define NOP __asm__ __volatile__ ("nop\n\t");

...

void loop() {
  for(;;){
    digitalWriteDirect(9, HIGH);
    NOP
    ...
    NOP   
    digitalWriteDirect(9, LOW);         
  }
}

Each NOP extends the HIGH phase by 1 clock cycle, i.e. 12 ns on DUE (1/84 MHz).

I know that this is an old thread but I found the answer and thought I'd share.

You can find the register info for each pin on the Arduino website at:

The registers are listed in the file instance_piob.h. These registers are 32 bit since the Due uses 32 bit architecture. Instead of setting a register to 1 and 0 for High and Low, there is a set register (SODR) and a clear register (CODR).

// Enable
REG_PIO[port]_SODR = [Pin mask];
// Disable
REG_PIO[port]_CODR = [Pin mask];

For example to blink pin 13 you could use the following code. From the link provided, the SAM3X pin name of 13 is PB27 so the port is B and the bit is 27

REG_PIOB_SODR = 0x1 << 27;
delay(1000);
REG_PIOB_CODR = 0x1 << 27;
delay(1000);

Using this method you could set multiple pin simultaneously, etc. There is a simpler way to do this if you do not know the port information because it is stored in the array g_APinDescription for each pin so you could save the reg address in a local variable or just access the array.

g_APinDescription[13].pPort->PIO_SODR = g_APinDescription[13].ulPin; // ulPin is the mask for that one pin so 1 << 27

Speedwise, I did a comparison and the results were 166us vs 5148us which is just over 31 times faster.

time = millis();
  for (int i = 0; i < 1000000; i++) {
    REG_PIOB_SODR = mask;
    REG_PIOB_CODR = mask;
  }
  Serial.println(millis() - time);
  
  time = millis();
  for (int i = 0; i < 1000000; i++) {
    digitalWrite(13, 1);
    digitalWrite(13, 0);
  }
  Serial.println(millis() - time);
1 Like
REG_PIOB_SODR = 0x1 << 27;
delay(1000);
REG_PIOB_CODR = 0x1 << 27;
delay(1000);

Although not having deep knowledges I could follow this.

But I don't know how to use this to
a) convert data on 8 input pins to a one byte value and
b) set other 8 output pins to the value of another byte value
both as quick as possible.
There are no limitations which pins to use as long as I can use Serial Input.

Can you help me?

Thanks!

Measureino:

REG_PIOB_SODR = 0x1 << 27;

delay(1000);
REG_PIOB_CODR = 0x1 << 27;
delay(1000);



Although not having deep knowledges I could follow this. 

But I don't know how to use this to 
a) convert data on 8 input pins to a one byte value and
b) set other 8 output pins to the value of another byte value
both as quick as possible.
There are no limitations which pins to use as long as I can use Serial Input.

Can you help me?

Thanks!

Hi, i know this is an old thread, but i still haven't found an easy way to put this together. i'm using an Arduino Mega 1280, with portA and PORTC and it's working ok.

Now i need to take this to Arduino Due, and i couldnt find a way to do it the same way.

coul you explain it again like for very dummies?

Thank you very much Professor_Oak!

iana - in order for this code to work you have to set the pin as output, just like in the Blink example.
_

Ok, the problem is that due layout dose not have the same ports as Arduino UNO or Mega, so there is no way to manipulate them like PORTC or PORTA, there is a way to do the same, but it's a really bad headache to find out how.

Hello iana,

To manipulate individual pins in Arduino Due you have to use Graynomad pinout diagram...

http://forum.arduino.cc/index.php?topic=132130.0

...with the following code lines:

// Pin HIGH
REG_PIO[port]_SODR = 0x1 << [port Pin];

// Pin LOW
REG_PIO[port]_CODR = 0x1 << [port Pin];

For example, if you want to set HIGH pin 13, look at its port pin (clear yellow background) which is B.27. This indicates pin 27 of port B. Thus,

REG_PIOB_SODR = 0x1 << 27;

if you want to set LOW pin 36, its port pin is C.4. Thus,

REG_PIOC_CODR = 0x1 << 4;

if you want to set LOW pin A7, its port pin is A.2. Thus,

REG_PIOA_CODR = 0x1 << 2;

and so on....

p

stimmer:
The other way of doing direct port manipulation looks like this:

PIOx->register=value;   

long r = PIOx->register;



where x is A,B,C or D and register is as in the data sheet

For example: 


PIOB->PIO_SODR=1<<27; //lights the LED
PIOB->PIO_CODR=1<<27; //clears it
boolean p12=!!(PIOD->PIO_PDSR & (1<<8)); //read pin 12




I had a go at writing some digitalReadDirect/digitalWriteDirect functions but you might want to give them some more thorough testing as I only checked if it worked with the LED :)



inline void digitalWriteDirect(int pin, boolean val){
 if(val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
 else    g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;
}

inline int digitalReadDirect(int pin){
 return !!(g_APinDescription[pin].pPort -> PIO_PDSR & g_APinDescription[pin].ulPin);
}

void setup() {                
 pinMode(13, OUTPUT);    
 pinMode(12, INPUT);    
 Serial.begin(9600);
}

void loop() {
 digitalWriteDirect(13, HIGH);  
 delay(1000);          
 digitalWriteDirect(13, LOW);    
 delay(1000);          
 Serial.println(digitalReadDirect(12));
}

I am currently trying to run the command digitalReadDirect() in my program.

Each iteration in the loop, the command is run to see if there is a LOW or HIGH state, and a variable is set to that state. In other words, I'm trying to synchronize a certain operation with an input square wave, changing from 0V to 3V. After the program changes the state of a variable 'volatile int state' to HIGH or LOW, I have an if(state == LOW) statement to determine whether an operation should run at that time.

The if(LOW) statement seems to operate correctly asynchronously to the square wave, so I had high hopes. The operation ran when the square wave was LOW, and stopped when the square wave was HIGH.

When I attempted the if(HIGH) statement, the operation was never triggered, and the signal remained LOW regardless of the square wave input.

Can anyone explain why the if(HIGH) statement might not correctly trigger the operation ?

I was using digital pin 12 as a square wave input, and I am trying to trigger an operation output on DAC0. I am using this command because I need my output to trigger quickly, and it did work asynchronously.

I think that was clear enough, but ask questions if needed, I will check up on this.

Hello, again.
Did any of you know how to start the clock that makes input mode posible in arduino DUE.

I'm doing direct port manipulation, but to be able to read direct from a pin, i'm currently using

pinMode(pin,input), where pin, is a non used pin of the port.

acording to the SAMx documentation, you do need to start this clock for each port. but i couldn't find how to do this, any other way

Why do you not use pinMode(pin, INPUT) for the pins you are actually using? That will set up the port in the correct way.

Hi everyone,
I've been reading lots of forum posts on Due port manipulation and am just looking for some clarification now. Can somebody confirm that we don't need to worry about overwriting another pin when we set or clear with SODR and CODR? So there is no need to use bitwise operators to make sure the other pins in the register are preserved?

Also, since these are registers, I would think it's the value in the register that matters. But, for example, in this code:

PIOB->PIO_SODR=1<<27; //lights the LED
PIOB->PIO_CODR=1<<27; //clears it

Now the bit at 1<<27 is set for both SODR and CODR. So is it the actual setting of the register that sets or clears the pin output, not the value in there itself? And then if I want to pull the value of an output pin from looking at its register (the way you could, say, by looking at PORTD with other Arduinos), I would look at PDSR?

Thanks!

In case anyone is interested, I wrote a quick sketch to test this out. SODR and CODR seem to always be 0, even after they're "set" to 1 to set or clear a pin. But the pin value does change as read from PDSR.

Another thing I noticed though is that I can only get pin values from PDSR (for output pins- I didn't try input pins)- from PORTC. PORTA, PORTB and PORTD always return 0. I can just use PORTC pins, but if anyone knows what's going on...

stimmer:
The other way of doing direct port manipulation looks like this:

PIOx->register=value;   

long r = PIOx->register;



where x is A,B,C or D and register is as in the data sheet

For example: 


PIOB->PIO_SODR=1<<27; //lights the LED
PIOB->PIO_CODR=1<<27; //clears it
boolean p12=!!(PIOD->PIO_PDSR & (1<<8)); //read pin 12




I had a go at writing some digitalReadDirect/digitalWriteDirect functions but you might want to give them some more thorough testing as I only checked if it worked with the LED :)



inline void digitalWriteDirect(int pin, boolean val){
 if(val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
 else    g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;
}

inline int digitalReadDirect(int pin){
 return !!(g_APinDescription[pin].pPort -> PIO_PDSR & g_APinDescription[pin].ulPin);
}

void setup() {                
 pinMode(13, OUTPUT);    
 pinMode(12, INPUT);    
 Serial.begin(9600);
}

void loop() {
 digitalWriteDirect(13, HIGH);  
 delay(1000);          
 digitalWriteDirect(13, LOW);    
 delay(1000);          
 Serial.println(digitalReadDirect(12));
}

Hi,im new in this forum, but i'd like to know where do you get this function (g_APinDescription[pin].pPort) from. Because i was looking for in datasheet ATMEL-SAM3X and i haven't found anything. Thanks

//Try this out. It works.

void setup()
{
REG_PIOB_OWER = 0xFFFFFFFF; // Enable PORT B
REG_PIOB_OER = 0xFFFFFFFF; // Set PORT B as output port
}

void loop()
{
REG_PIOB_ODSR = 0xFFFFFFFF; //set all pins of PORT B
delay(100);
REG_PIOB_ODSR = 0x00000000; //clear all pins of port B
delay(100);
}

To "cache" the port info and bitmask for a "fast SPI" function (as was implied in some of the early messages in the thread), you could use code like:

  Pio *p = digitalPinToPort(13);
  uint32_t b = digitalPinToBitMask(13);
  while (1) {
    p->PIO_SODR = b;
    p->PIO_CODR = b;
  }

That yields a crappy-looking waveform of about 16MHz on my scope, and produces code like:

   80152:       4a04            ldr     r2, [pc, #16]   ;get pin desc array
   80154:       f8d2 316c       ldr.w   r3, [r2, #364]  ; get pio ptr
   80158:       f8d2 2170       ldr.w   r2, [r2, #368]  ; get bitmask
   8015c:       631a            str     r2, [r3, #48]   ; set
   8015e:       635a            str     r2, [r3, #52]   ; clear
   80160:       e7fc            b.n     8015c <setup+0x14> ; loop

This looks like the section I'm looking for, if I wanted to use the PC20 pin which is not in the variant.h or variant.cpp files, how does it get called out in the sketch? It seems as if the h and .cpp files won't need rewriting if PIOC-PC20 can somehow be declared by using pinMode() or digitalWrite() in the setup and loop. The examples I've seen of PC20 being utilized by Digistump and Taijiuno both write different versions of the variant.h and variant.cpp files but this should not be required for just one pin correct?

The only way to have a pin available for digitalWrite() and similar arduino functions is to have it defined in the variant files, even if it is "just one pin." You CAN write to/from it with the direct IO calls being discussed here, regardless of whether it's available to the arduino functions:

PIOC->PIO_SODR=1<<20; //Set C20
PIOC->PIO_CODR=1<<20; //clears it

(you'd probably need something similar to do pinMode())

Thank you very much for these function. So if I want the pin set I probably don't need the line that clears it, is this correct? I am currently not using pin 33 or PC1, so I changed PC1 to PC20 in the variant.cpp file so now it should have a definition. Because I don't think I can give it a pin number unless I tack it on the end and call it pin 92. But replacing it with PC1 hopefully will work easier. Does it matter where I put these? Such as before the void setup or in the void loop, everything verifies no matter where it is so it seems they work the same everywhere/