Port manipulation PINx commands with Arduino Due ?

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));
}

your code is working pretty well man, thank you a lot... i gained about almost 40% speed in my parallel flash memory writer :wink:

westfw:

Now I'm stuck in the control pins of the TFT.

Can't you just use digitalWrite() for the control pins, as a first effort?

Yes, I'll try that also.

Regards,

Joao

Hello!

tested reading ports A, B and C syncronously and port reading works OK,

but then tried syncronous writing with REG_PIOx_ODSR command did not succeed ,
although bitwise setting with REG_PIOx_SODR and clearing with REG_PIOx_CODR works OK,

I might have something wrong although tried also setting first REG_PIOx_OWER mask bit for those bits I wanted to write
syncronously ,

another test result still: enabled output to several bits with pinmode (xx, OUTPUT) commands but still the REG_PIOx_ODSR does not write
to the PIO port ,

so as a summary so far: input port reading (bytes , words , double words) reading works OK but
output does not work (yet :slight_smile:

testing continues ....

can someone write down the clear way how to manipulate different pins at the same time? i'm quite confused! :S

the reading is easy:

eg.

unsigned long int input_data = REG_PIOC_PDSR;

reads the C -port (32 bit wide) and all the bits simultaneously to input_data variable and fast ,
and I've tested A, B, C and D ports by changing bit states ((work ok with Arduino Due),

but then encountered problems when tried writing in the same way with command eg.

REG_PIOC_ODSR = 0xFF;

which should change all bits 0-15 simultanously to 1, look at my post earlier today, where test results are reported,

BR,
Seppo

seppo:
REG_PIOC_ODSR = 0xFF;

which should change all bits 0-15 simultanously to 1, look at my post earlier today, where test results are reported,

BR,
Seppo

No, that will only set bits 0-7 to 1 (0xFF is 11111111 in binary).

yes , of course 8 bits ,

and it is possible to write simultaneously words and double words (32 bits) but
not all the pins of PIO - ports are connected to Due I/O ,

Seppo

stimmer:

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);
}

Hi.

Ok, I've managed to put library working with your functions, Thank you!

But it's still very slow running DEMO compared to Chipkit. I know that in chipkit, the entire byte is written to port at once and in due I'm writing bit by bit, but I'm not sure that this is enough for a huge difference in run time for demo. In chipkit it takes around 24s, I'm getting with due 44s.

Is there a way to use ODSR in this functions? Can I write to ODSR bit by bit?

From datasheet, ODSR should be used for synchronous transfer. I'm thinking, maybe using ODSR i might get bet speed.

I was trying to do this without success:

		//DB00 on PIN37 -> PIO_PC5
		REG_PIOC_ODSR=((VL&0x01)<<5) & 0x20;
		//DB01 on PIN36 -> PIO_PC4
		REG_PIOC_ODSR=(VL<<3) & 0x10;
		//DB02 on PIN35 -> PIO_PC3
		REG_PIOC_ODSR=(VL<<1) & 0x08;
		//DB03 on PIN34 -> PIO_PC2
		REG_PIOC_ODSR=(VL>>1) & 0x04;
		//DB04 on PIN33 -> PIO_PC1
		REG_PIOC_ODSR=(VL>>3) & 0x02;
		//DB05 on PIN32 -> PIO_PD10
		REG_PIOD_ODSR=(VL<<5) & 0x400;
		//DB06 on PIN31 -> PIO_PA7
		REG_PIOA_ODSR=(VL<<1) & 0x80;
		//DB07 on PIN30 -> PIO_PD9
		REG_PIOD_ODSR=(VL<<2) & 0x200;
		//DB08 on PIN22 -> PIO_PB26
		REG_PIOB_ODSR=(VH<<26) & 0x4000000;
		//DB09 on PIN23 -> PIO_PA14
		REG_PIOA_ODSR=(VH<<13) & 0x4000;
		//DB10 on PIN24 -> PIO_PA15
		REG_PIOA_ODSR=(VH<<13) & 0x8000;
		//DB11 on PIN25 -> PIO_PD0
		REG_PIOD_ODSR=(VH>>3) & 0x01;
		//DB12 on PIN26 -> PIO_PD1
		REG_PIOD_ODSR=(VH>>3) & 0x02;
		//DB13 on PIN27 -> PIO_PD2
		REG_PIOD_ODSR=(VH>>3) & 0x04;
		//DB14 on PIN28 -> PIO_PD3
		REG_PIOD_ODSR=(VH>>3) & 0x08;
		//DB15 on PIN29 -> PIO_PD6
		REG_PIOD_ODSR=(VH>>1) & 0x40;

The working code is:

		//DB00 on PIN37 -> PIO_PC5
		digitalWriteDirect(37,(VL & 0x01));
		//DB01 on PIN36 -> PIO_PC4
		digitalWriteDirect(36,(VL & 0x02));
		//DB02 on PIN35 -> PIO_PC3
		digitalWriteDirect(35,(VL & 0x04));
		//DB03 on PIN34 -> PIO_PC2
		digitalWriteDirect(34,(VL & 0x08));
		//DB04 on PIN33 -> PIO_PC1
		digitalWriteDirect(33,(VL & 0x10));
		//DB05 on PIN32 -> PIO_PD10
		digitalWriteDirect(32,(VL & 0x20));
		//DB06 on PIN31 -> PIO_PA7
		digitalWriteDirect(31,(VL & 0x40));
		//DB07 on PIN30 -> PIO_PD9
		digitalWriteDirect(30,(VL & 0x80));
		//DB08 on PIN22 -> PIO_PB26
		digitalWriteDirect(22,(VH & 0x01));
		//DB09 on PIN23 -> PIO_PA14
		digitalWriteDirect(23,(VH & 0x02));
		//DB10 on PIN24 -> PIO_PA15
		digitalWriteDirect(24,(VH & 0x04));
		//DB11 on PIN25 -> PIO_PD0
		digitalWriteDirect(25,(VH & 0x08));
		//DB12 on PIN26 -> PIO_PD1
		digitalWriteDirect(26,(VH & 0x10));
		//DB13 on PIN27 -> PIO_PD2
		digitalWriteDirect(27,(VH & 0x20));
		//DB14 on PIN28 -> PIO_PD3
		digitalWriteDirect(28,(VH & 0x40));
		//DB15 on PIN29 -> PIO_PD6
		digitalWriteDirect(29,(VH & 0x80));

stimmer:
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 :slight_smile:

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);
}

They seem to work fine. I just used it for my first sketch for my Due, a comparison of port switching and square wave generation using DigitalWrite vs. direct writing using your inline function. Big difference, this is what it looks like on my scope (it overshoots the square because I have a long lead which I corrected for the second measurement):

The waves are a whole lot squarer when running at 1% of the maximum speed. :slight_smile:

Sorry for the bad smartphone pics, I haven't figured out how to properly screen capture on the scope yet and I can't open the manual right now because Adobe Acrobat is having a weird fit.

To use REG_PIOD_ODSR use must first enable the bits with REG_PIOD_OWER (the output write enable).
For instance:

void setup() {
pinMode(12, OUTPUT);
pinMode(14, OUTPUT);
pinMode(15, OUTPUT);
REG_PIOD_OWER = 0xFFFF;
}

void loop() {
REG_PIOD_ODSR = 0x0130;
REG_PIOD_ODSR = 0x0000;
REG_PIOD_ODSR = 0x0130;
}

Will produce a ~23ns low going pulse on pin 12, 14 and 15. For some reason you need to set the pinModes to make this work.

I don't know if any one has posted on this yet, fastest update rate for a DAC(?). Here is some code:

int j = 0, topcount = 5;

void setup() {
// this is a cheat - enable the DAC
analogWrite(DAC0,0);
}

void loop() {
// write directly
dacc_write_conversion_data(DACC_INTERFACE, 0x0000);
for (j = 0;j < topcount;j++);
// delayMicroseconds(1);
dacc_write_conversion_data(DACC_INTERFACE, 0x0400);
for (j = 0;j < topcount;j++);
// delayMicroseconds(1);
dacc_write_conversion_data(DACC_INTERFACE, 0x0800);
for (j = 0;j < topcount;j++);
// delayMicroseconds(1);
dacc_write_conversion_data(DACC_INTERFACE, 0x0C00);
for (j = 0;j < topcount;j++);
// delayMicroseconds(1);
dacc_write_conversion_data(DACC_INTERFACE, 0x0FFF);
for (j = 0;j < topcount;j++);
// delayMicroseconds(1);
dacc_write_conversion_data(DACC_INTERFACE, 0x0C00);
for (j = 0;j < topcount;j++);
// delayMicroseconds(1);
dacc_write_conversion_data(DACC_INTERFACE, 0x0800);
for (j = 0;j < topcount;j++);
// delayMicroseconds(1);
dacc_write_conversion_data(DACC_INTERFACE, 0x0400);
for (j = 0;j < topcount;j++);
// delayMicroseconds(1);
dacc_write_conversion_data(DACC_INTERFACE, 0x0000);
for (j = 0;j < topcount;j++);

}

This code produces a triangular four steps up, four steps down ramp that goes from about 480mV to 2.32V. Each step is about 680ns wide.
The waveform becomes unstable below topcount = 5. Is this the fastest DAC step rate?

seppo:
the reading is easy:

eg.

unsigned long int input_data = REG_PIOC_PDSR;

reads the C -port (32 bit wide) and all the bits simultaneously to input_data variable and fast ,
and I've tested A, B, C and D ports by changing bit states ((work ok with Arduino Due),

but then encountered problems when tried writing in the same way with command eg.

REG_PIOC_ODSR = 0xFF;

which should change all bits 0-15 simultanously to 1, look at my post earlier today, where test results are reported,

BR,
Seppo

How did you read port C? I tried this but it does not work:

    REG_PIOC_ODR = 0x3fc;
    REG_PIOC_PER = 0x3fc;
    int pixelData = REG_PIOC_PDSR >> 2;

Hi guys,
I would like to ask if is possible to generate square waves with digitalWriteDirect?
this code

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

produces these waves (sry for bad quality)

thanks

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);         
  }
}
void loop() {
  for(;;){
    digitalWriteDirect(9, HIGH);           
    digitalWriteDirect(9, LOW);   
    digitalWriteDirect(9, HIGH);           
    digitalWriteDirect(9, LOW);   
    digitalWriteDirect(9, HIGH);           
    digitalWriteDirect(9, LOW);   
... repeat many times      
  }
}

Even with the tighter loop the square wave will be uneven because of the looping overhead of 3 or 4 machine cycles. You can cheat by repeating that block of code a bunch of times (feel free to hold ctrl-v down and paste it in a few hundred times). The more there is before the eventual hiccup, the better chance your scope will have at stabilizing the wave.

thanks a lot =) now I have nice sinus wave about 20MHz =)
and one more question:
I want to make frequency generator with this utility so is there any documentation about counting ticks? because with msDelay I can do freq. about several thousand KHz (not enough for me =/)..
thanks

I want to make frequency generator with this utility so is there any documentation about counting ticks?

=> Timer Counter (TC)!
You can count the clocks of MCK/2 (=42MHz)

ATMELSAM(datasheet) 37.1 Description
The Timer Counter (TC) includes three identical 32-bit Timer Counter channels.

Start the counter, read the counter (Counter Value register) or generate an interrupt (Interrupt Enable Register) and react
to your choosen number of counts.

Sound easy, but its a it lot of register manipulation. Maybe you can find a lib for he TC?

Could you be a bit more concrete please? I with code above I have got 32Mhz max... At the moment I think there is no working counter for Due, or am I wrong?
thanks

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).