Go Down

Topic: DueTimer blocking serial communication in Arduino DUE - SOLVED (Read 1 time) previous topic - next topic

Lorenzo2691

Hi everybody,
 
I am using serial communication inside a Timer (DueTimer library) on Arduino DUE.
Why does the serial communication block the timer?

Thank you for any suggestion!


ard_newbie

How about posting your code (between code tags) ?

AdderD

Yes, posting code would help. But, in general, don't do stuff in interrupt handlers. The more you do in an interrupt the more trouble you are asking for. Instead it's best to set a flag in the interrupt handler then loop looking for the flag to update and do your work in the loop() function instead.

Lorenzo2691

I need to use the timer because I have to write a command to a motor and read data from an encoder at a determined frequency. I am actually using the RoboClaw library of the driver.
Here is my code. The lines inside the myHandler() function are those who block the code.

Code: [Select]
#include <DueTimer.h>
#include "RoboClaw.h"

#define address 0x80

int zero_speed = 0;
int speed_m2 = 20;
uint8_t status2;
bool valid2;
int32_t actual_encoder_position;


RoboClaw roboclaw(&Serial1, 10000);



void setup()
{
  Serial.begin(115200);
  roboclaw.begin(460800);

  roboclaw.ForwardM2(address,zero_speed);  
  roboclaw.ResetEncoders(address);
  delay(1000);
  Timer6.attachInterrupt(myHandler).setPeriod(500000);  
  Serial.print("Start!");
  Serial.println();
}

void loop()
{
    Timer6.start();
    Serial.print("Encoder: ");
    Serial.print(actual_encoder_position, DEC);
    Serial.println();
    // in this loop I have to put the dynamic model and the closed-loop control
}

void myHandler()
{
  // this lines block the programm
  roboclaw.ForwardM2(address, speed_m2);                                        
  actual_encoder_position = roboclaw.ReadEncM2(address, &status2, &valid2);
}

ard_newbie

#4
Jan 22, 2018, 08:31 pm Last Edit: Jan 22, 2018, 08:33 pm by ard_newbie
I guess you start once and only once your timer, therefore Timer6.start(); should be in setup() ?
And if you set a Flag Inside the Handler and you test if this Flag has been set in loop(), you would not print twice the same value for nothing ?

Lorenzo2691

Yes, I agree with you, I should move the "Timer6.start();" in the setup loop. I have triesd it but it doesn't work in any case.
What do you mean with "set a Flag Inside the Handler"?

I need to run the timer af a higher frequency than the one of the main void loop cycle.

ard_newbie


Set and reset a Flag to Serial.print whenever it's necessary, e.g:

Code: [Select]

#include <DueTimer.h>
#include "RoboClaw.h"

#define address 0x80

volatile boolean FlagSomethingToPrint; //*******

int zero_speed = 0;
int speed_m2 = 20;
uint8_t status2;
bool valid2;
int32_t actual_encoder_position;


RoboClaw roboclaw(&Serial1, 10000);



void setup()
{
  Serial.begin(115200);
  roboclaw.begin(460800);

  roboclaw.ForwardM2(address, zero_speed);
  roboclaw.ResetEncoders(address);
  delay(1000);
  Timer6.attachInterrupt(myHandler).setPeriod(500000);
  Serial.println("Start!");

  Timer6.start(); //*****
}

void loop()
{
  if (FlagSomethingToPrint) {
    FlagSomethingToPrint = false; //*****
    Serial.print("Encoder: ");
    Serial.println(actual_encoder_position, DEC);
  }
  // in this loop I have to put the dynamic model and the closed-loop control
}

void myHandler()
{
  // this lines block the programm
  FlagSomethingToPrint = true;  //******
  roboclaw.ForwardM2(address, speed_m2);
  actual_encoder_position = roboclaw.ReadEncM2(address, &status2, &valid2);
}



Remember that Serial uses interrupts ( void UART_Handler()) with a high priority unlike void myHandler()...

Lorenzo2691

Thank you ard_newbie but the code doesn't work yet.

Could the block be due to the roboclaw library?


ard_newbie

#8
Jan 23, 2018, 05:23 am Last Edit: Jan 23, 2018, 05:33 am by ard_newbie
I am actually using the RoboClaw library of the driver

Post a link to the driver you are using.

Usually libraries come with basic example sketches, did you try to make them work ?

tito-t

better  use DueTimer just for short actions like pin r/w or flag setting, and for more time consuming tasks better use a proprietary thread loop via Due Scheduler.

Lorenzo2691

@ard_newbie:

The driver I am trying to use is RoboClaw 2x7A Motor Controller, you can find it in the following url:

http://www.ionmc.com/downloads


@tito-t 

Could you explain me some more about proprietary thread loop via Due Scheduler, please?

ard_newbie


In Roboclaw User Manual page 62, you can see how it's wired (Packet Serial wiring) via a Serial connection.  As you are using Serial  to communicate with the Serial Monitor, you will be using Serial1 (RX1/TX1).

The example sketches given in "Arduino Library and Examples" of ionmc.com are for an UNO. They are all using SoftwareSerial and declare, before setup(),SoftwareSerial serial(10,11); to open a softwareSerial connection.

If you have an UNO, you shoud practice with all the example sketches provided to understand how it works, then replace SoftwareSerial by an Hardware Serial on your DUE board.

Since you have HardwareSerial on the DUE, you want to replace this by an Hardware Serial connection.
Serial1 as to be initialized in setup() (Serial1.begin(460800) ; // The same baud rate you selected for Roboclaw  with roboclaw.begin(460800);)



tito-t

@tito-t 

Could you explain me some more about proprietary thread loop via Due Scheduler, please?
hi,
maybe you'll wish to look at this basic example:
https://github.com/arduino-libraries/Scheduler/blob/master/examples/MultipleBlinks/MultipleBlinks.ino

Lorenzo2691

#13
Jan 25, 2018, 04:26 pm Last Edit: Jan 25, 2018, 04:32 pm by Lorenzo2691
@ard_newbie

Thank you ard_newbie. I am using the Serial connections as reported at pag. 62 of the datasheet.
Serial.begin(115200); is used for the communication between Arduino DUE and the PC, whereas roboclaw.begin(460800); for the communication between Arduino DUE and the RoboClaw driver.
I can use different baud rates for different Serial communications, right?


@tito-t

Thank you very much for your suggestion.
This solves my problem!
With Due Scheduler library I am now able to control the motor and read the encoder at a different rate with respect to the main (slower) loop.   :D

I have just one little question about Due Scheduler: could the "yield();" command be used only once in the programm (at the end of the slower loop) or could I use it in more than one loop? Thank you again.


tito-t

@tito-t

I have just one little question about Due Scheduler: could the "yield();" command be used only once in the programm (at the end of the slower loop) or could I use it in more than one loop? Thank you again.
Glad to see that the Scheduler works fine for you and solved your problem! 8-)

I am using yield() arbitrarily also several times in either loop, e.g., when there are very long for- or while-loops to be performed, additionally to the one at the terminating "}" . A yield() inside such a nested loop then enables the scheduler to switch to a different time slice intermediately and so the other threads don't get stuck (IIUC, CMIIW).

Go Up