tools for profiling and more

Status
Not open for further replies.

gony

Well-known member
hello
i'm working with T3.5
i need my code to be faster and i was wondering if there are tools in the arduino\teensy that are ment for inspecting code for that manner . right now i'm using micros() and than i print the result in order to see how fast is a certain loop but i figured there must be something more accurate since printing and micros() takes time and all , not to mention i care about nanosecs so micros() is not good enough . in addition ,is there something like breakpoint ? i couldn't find info on google .

in another subject , i saw this link it has a lot of clear info about port manipulation

http://little-scale.blogspot.co.il/2013/05/teensy-basics-5-port-manipulation.html

but it didn't work out , perhaps because its not the same teensy ?
i tried to adjust pins with
Code:
DDRD = 0xFF;
but i got an error :
'DDRD' does not name a type

another question i had - someone told me to discard the digitalread/writefast and use port manipulation even when i need to set one pin only . is it actually faster ? how should i do it , say i want to turn pin 34 HIGH , which is pin 25 in port E . so i declare port E as
Code:
DDRE = 0x1000000;
?


the full code :
Code:
// PTA (12 13) = [3 4] // ready signal and XS2
// PTB (0 1 2 3) = [16 17 19 18] // For address bits
// PTC (0 1 2 3 4 5 6 7 8 9 10 11) = [15 22 23 9 10 13 11 12 35 36 37 38] // For digital inputs from NI cards
// PTD (0 1 2 3 4 5 6 7 ) = [2 14 7 8 6 20 21 5] // For digital output to marker
// PTE (25) = [34] // for digital output to reward

byte inputPins[] = {3, 4, 16, 17, 19, 18, 15, 22, 23, 9, 10, 13, 11, 12, 35, 36, 37, 38};
byte outputPIns[] = {2, 14, 7, 8, 6, 20, 21, 5, 34};
int k;// set to 1 when marker activated , and to 0 when deactivated
unsigned long rewardON;
unsigned long T1;
elapsedMillis rewardTime;
elapsedMicros markerTime;
IntervalTimer myTimerOne;
IntervalTimer myTimerTwo;


void reward(void) {
  if (!digitalReadFast(3)  && ((GPIOB_PDIR & 0xF) == 4)){// reward command received
     rewardON = GPIOC_PDIR;
     //Serial.println("rewardIFtest - GPIOC_PDIR-");
     //Serial.println(GPIOC_PDIR);
     //Serial.println(rewardON);
     //GPIOE_PDOR = 0x1;//reward
     rewardTime = 0;//start counting until stop
  }
}

void marker(void) {
  if (!digitalReadFast(3) && ((GPIOB_PDIR & 0xF) == 1)){//marker command received
    //Serial.println("markerIFtest - GPIOC_PDIR-");
    //Serial.println(GPIOC_PDIR,BIN);
    GPIOD_PDOR= (GPIOC_PDIR >>1) & 0x7FF;
    k=1;
    //Serial.println("GPIOD_PDOR-");
    //Serial.println(GPIOD_PDOR,BIN);
    markerTime = 0;//start counting until stop
    
  }
}

void setup() {
  //Serial.begin(9600); while(!Serial);
  //pinMode(34,OUTPUT);same as DDR
  //DDRE = 0x1000000;
  //for (int pinnum = 0; pinnum < 18; pinnum++) {
   //     pinMode(inputPins[pinnum], INPUT_PULLDOWN);
    //pinMode(inputPins[pinnum], INPUT);
  DDRC = 0x0;
  }
  //for (int pinnum = 0; pinnum < 9; pinnum++) {
   // pinMode(outputPIns[pinnum], OUTPUT);
  DDRD = 0xFF;
  }
  myTimerOne.priority(0);
  myTimerOne.begin(reward,100);
  myTimerTwo.priority(1);
  myTimerTwo.begin(marker,100);
}

void loop() {
  //T1=micros();
  if ( GPIOE_PDOR == 0x1 && rewardTime > rewardON) {//if the reward output is being sent for the input time
    GPIOE_PDOR = 0x0;//stop reward
    //Serial.println("looprewardtest TIME");
    //Serial.println(rewardTime);
    //Serial.println(rewardON);
      }
  if (k == 1 && markerTime > 25){//if the marker message is being sent for 25us (maybe the interval is too long\short for some devices)
    GPIOD_PDOR = 0x00;//stop marker 
    k=0;
    //Serial.println("loopmarkertest - markerTIME ");
    //Serial.println(markerTime);
    //Serial.print(micros()-T1);
  //delay(1000);
  }
  
}
 
before writing to the ports its a good idea to print their values first so you know what your working with, or what other gpios are set at before just blindly writing to it. you can shift the value in after reading the port to set the value when needed, for additional gpio defined references, you can goto your arduino teensy3 cores folder and take a look at core_pins.h

i always make sure the pin is on the port and matches by setting it as INPUT_PULLUP and grounding that pin to see if it changes when constantly printing the port register, once i confirm ive got the right port, thats when you decide exactly where to bitshift and change that single bit only wothout touching the rest of the other port pins.

note that just setting the port blindly (unless you want all those pins affected) will affect your ability to use those pins later on, you'll wonder why they wont work, its because your other part of the code it plainly wiping out & setting its own values
 
add a line
void yield(void) {}
to your sketch. This overrides the inbuildt-yield that slows down your loop. You may want to cheat the systick either.
Then, of course things like DDRD do not work- they are for an oher processor family. I guess you don't try to use your as car as as truck. You may want to read the reference manual (2000+ pages) and a good book or tutorial about bit manipulation and optimizations, before trying to optimize at nanosecond-level.

btw, DigitalWriteFast alreay uses fast techniques (if used with consts).
 
thank you for the advice !
could you explain a bit further , there is no appropriate explanation of yield(void) {} and i don't want to use it without understanding what it does . and what do you mean by cheat the systick ? i understand the systick is the system which makes my intervalTimer work , so what do you mean by cheating it ?
 
Doing void yield() takes out the weak yield() supplied for Arduino compatibility - it runs the serialEvent's code for Arduino. it adds some amount of overhead. You can find it in the installed sources to see what it does. Depending on your installed TeensyDuino version (1.38 & 1.39) doing this may make a non running sketch unless you make a mod indicated as tested in this thread: Minimal-Blink-fails-with-void-yield()

There are posts on using the processor cycle counter. Using an external search engine can give good results for proper keywords where the forum search is lacking.
 
What I will typically do, is to use one or more IO pins to help debug and then trace them with a logic analyzer. In cases like yours I would also probably be tracking some of the IO pins.

Another way to minimize some of the effects of using yield would be to never have loop exit. Something like:
Code:
#define TRACE_PIN_1 0

void setup() {
...
   pinMode(TRACE_PIN_1, OUTPUT);
...
}

void loop() {
  for(;;) { 
   digitalWriteFast(TRACE_PIN_1, HIGH);
   //T1=micros();
    if ( GPIOE_PDOR == 0x1 && rewardTime > rewardON) {//if the reward output is being sent for the input time
      GPIOE_PDOR = 0x0;//stop reward
      //Serial.println("looprewardtest TIME");
      //Serial.println(rewardTime);
      //Serial.println(rewardON);
      }
    if (k == 1 && markerTime > 25){//if the marker message is being sent for 25us (maybe the interval is too long\short for some devices)
      GPIOD_PDOR = 0x00;//stop marker 
      k=0;
      //Serial.println("loopmarkertest - markerTIME ");
      //Serial.println(markerTime);
      //Serial.print(micros()-T1);
      //delay(1000);
    }
   digitalWriteFast(TRACE_PIN_1, LOW);
  }
  
}

In the above I used pin 0 as a debug pin. I put it in as a #define... You can then watch how long the loop code is taking... Actually in cases like this, where measuring whole loop and nothing else, I would replace the
two digitalWriteFast calls, with one line at the start: digitalWriteFast(TRACE_PIN_1, !digitalReadFast(TRACE_PIN_1));
Then the IO pin will toggle with each pass through... You can then add similar things to reward and ... on different IO pins and get a pretty good measurement of where your time is spent.
 
thats a good idea ,i'll use it !
and also i used the other tip about reducing the amount of timerIntervals to 1

thank you!
 
Status
Not open for further replies.
Back
Top