Pages: 1 2 [3]   Go Down
Author Topic: Port manipulation PINx commands with Arduino Due ?  (Read 20477 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi guys,
I would like to ask if is possible to generate square waves with digitalWriteDirect?
this code
Code:
void loop() {
  digitalWriteDirect(9, HIGH);          
  digitalWriteDirect(9, LOW);        
}
produces these waves (sry for bad quality)
http://imageshack.us/f/838/19052013i.jpg/
thanks
« Last Edit: May 19, 2013, 02:29:34 pm by blazek » Logged

Offline Offline
God Member
*****
Karma: 32
Posts: 507
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Code:
void loop() {
  for(;;){
    digitalWriteDirect(9, HIGH);           
    digitalWriteDirect(9, LOW);         
  }
}
Logged


Show Your Work
Offline Offline
Edison Member
*
Karma: 14
Posts: 1098
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
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.
Logged

I have only come here seeking knowledge. Things they would not teach me of in college.

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Mainz
Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Quote
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?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Mainz
Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Code:
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); }
}
Logged

Innsbruck
Offline Offline
Newbie
*
Karma: 0
Posts: 3
"Demand of yourself, even when no one else demands of you"
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Code:
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) :

Code:
#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).
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
http://arduino.cc/en/Hacking/PinMappingSAM3X

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

Code:
// 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
Code:
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.

Code:
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.

Code:
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);
« Last Edit: June 10, 2014, 06:05:44 pm by Professor_Oak » Logged

Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 29
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
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!
Logged

Pages: 1 2 [3]   Go Up
Jump to: