Go Down

Topic: weird micros() behavior  (Read 203 times) previous topic - next topic

gunky

I am trying to use micros() in a loop for precise frequency measurement and I am getting some really weird results, I don't know what's going on.

1. What is the default arduino due clock? I assume it's 84MHZ but I want to make sure.

2. What is the minimal interval for micros()?  

3. I have a couple of readdigitalpin calls within the loop, it's possible that is causing some delay, if that's the case - how can I speed up the read? I assume the peripheral clock is set to maximum? 

I ended up using the milis() function but I really need to use micros() and to decrease loop time as I need to track 500hz signals. 

Code: [Select]
const int left_sensor_1 = 31;
const int left_sensor_2 = 32;
const int right_sensor_1 = 33;
const int right_sensor_2 = 34;

const int left_output_1 = 2;
const int left_output_2 = 3;
const int right_output_1 = 4;
const int right_output_2 = 5;

unsigned const long sensor_polling_interval = 1;
unsigned const long error_update_interval = 100;

unsigned long current_time = 0;
unsigned long last_sensor_update_time = 0;
unsigned long last_error_update_time = 0;

int left_count = 0;
int right_count = 0;

int prior_left_sensor_1_bit = 0;
int prior_left_sensor_2_bit = 0;
int prior_right_sensor_1_bit = 0;
int prior_right_sensor_2_bit = 0;

int left_sensor_1_bit = 0;
int left_sensor_2_bit = 0;
int right_sensor_1_bit = 0;
int right_sensor_2_bit = 0;

float left_velocity = 0;
float right_velocity = 0;

float left_integral = 0;
float right_integral = 0;

void setup() {
  // put your setup code here, to run once:

  pinMode(left_sensor_1, INPUT);
  pinMode(left_sensor_2, INPUT);
  pinMode(right_sensor_1, INPUT);
  pinMode(right_sensor_2, INPUT);
 
  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:

  float left_error = 0;
  float right_error = 0;
 
  float left_target_velocity = 10;
  float right_target_velocity = 10;



  float k_p = 1;
  float k_i = 1;

  int left_output = 0;
  int right_output = 0;

  current_time = millis();

  //read sensors and update velocity
 
  if (current_time - last_sensor_update_time >= sensor_polling_interval)
  {
    left_sensor_1_bit = digitalRead(left_sensor_1);
    //left_sensor_2_bit = digitalRead(left_sensor_2);
    right_sensor_1_bit = digitalRead(right_sensor_1);
    //right_sensor_2_bit = digitalRead(right_sensor_2);

    if (left_sensor_1_bit == 1 and prior_left_sensor_1_bit == 0)
    {
      left_velocity = 1/((left_count+1) * sensor_polling_interval/1000.0);
      left_count = 0;
   
    }
    else
    {
      left_count += 1;
    }

    if (left_count == 100)
    {
      left_velocity = 0;
      left_count = 0;
    }

    prior_left_sensor_1_bit = left_sensor_1_bit;
   
    if (right_sensor_1_bit == 1 and prior_right_sensor_1_bit == 0)
    {
      right_velocity = 1/((right_count+1) * sensor_polling_interval/1000.0);
      right_count = 0;
    }
    else
    {
      right_count += 1;
    }

    if (right_count == 100)
    {
      right_velocity = 0;
      right_count = 0;
    }

    prior_right_sensor_1_bit = right_sensor_1_bit;
    last_sensor_update_time = current_time;
  }
 
  if (current_time - last_error_update_time >= error_update_interval)
  {
   
    left_error = left_target_velocity - left_velocity;
    left_integral = left_integral + left_error*error_update_interval;
    left_integral = constrain(left_integral, -100,100);
    left_output = (int)(k_p*left_error + k_i*left_integral);

    Serial.println("left target velocity: " + String(left_target_velocity) + " left velocity: " + String(left_velocity, 10) +   " left error: " + String(left_error, 10) + " left integral: " + String(left_integral, 10) + " left output: " + String(left_output, 10));

    if (left_output >= 0)
    {
      left_output = min(left_output, 255);
      analogWrite(left_output_2, 0);
      analogWrite(left_output_1,left_output);
    }
    else
    {
      left_output = -1*max(left_output, -1*255);
      analogWrite(left_output_1, 0);
      analogWrite(left_output_2, left_output);
    }

    right_error = right_target_velocity - right_velocity;
    right_integral = right_integral + right_error*error_update_interval;
    right_integral = constrain(right_integral, -100, 100);
    right_output = (int)(k_p*right_error + k_i*right_integral);

    //Serial.println("right target velocity: " + String(right_target_velocity) + " right velocity: " + String(right_velocity, 10) +   " right error: " + String(right_error, 10) + " right integral: " + String(right_integral, 10) + " right output: " + String(right_output, 10));

    if (right_output >= 0)
    {
      right_output = min(right_output, 255);
      analogWrite(left_output_2, 0);
      analogWrite(left_output_1,left_output);
    }
    else
    {
      right_output = -1*max(right_output, -1*255);
      analogWrite(right_output_1, 0);
      analogWrite(right_output_2, right_output);
    }

    last_error_update_time = current_time;
   
  }
}



ard_newbie

84 MHz is the DUE default clock. AFAIK micros() works nicely. Of course, if you are looking for an interval within 1 us, micros() is not the right tool.

For short intervals (<< 1 ms) and a good accuracy, SysTick timer counter and PIO_PDSR can be used.

An example sketch to read PIO_PDSR register 8 times consecutively:

Code: [Select]
void setup() {

  Serial.begin(250000);

  PMC->PMC_PCER0 |= PMC_PCER0_PID12;  // PIOB power ON

  PIOB->PIO_PUDR = ~(0UL);   //Disable light pull-ups for all PIOB GPIOs

}
void loop() {

  uint32_t t0, t1, t3;
  uint32_t A[8];
  uint8_t Index;

  Index = 0;
  noInterrupts();
  t0 = SysTick->VAL;

  A[Index++] = PIOB->PIO_PDSR;
  A[Index++] = PIOB->PIO_PDSR;
  A[Index++] = PIOB->PIO_PDSR;
  A[Index++] = PIOB->PIO_PDSR;
  A[Index++] = PIOB->PIO_PDSR;
  A[Index++] = PIOB->PIO_PDSR;
  A[Index++] = PIOB->PIO_PDSR;
  A[Index++] = PIOB->PIO_PDSR;

  t1 = SysTick->VAL;
  t3 = ((t0 < t1) ? 84000 + t0 : t0) - t1 - 2 ;
  interrupts();
  printf("number of ticks: %d\n", t3);

  for (int i = 0; i < 8; i++) {
    Serial.println(A[i], BIN);
  }

  delay(1000);

}


As you will see on Serial monitor, when GPIOs are floating in the air, PIO_PDSR catches all EMIs.

Go Up