Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ARM-based arduino-type system much slower than AVR-based for same math

Tags:

c

arm

arduino

I'm working on some robotics kinematics code, and I first wrote the naive, intentionally non-optimized function for calculating joint angles, so that I could measure the timings with a logic analyzer and have a tangible way of measuring the gains in optimizations such as fixed-point math.

I have two microcontroller boards that I'm playing with: a Teensy 2.0 and a Teensy 3.0. I'm using the Arduino environment to build code for them. The 2.0 is an 8-bit 16MHz AVR, like most Arduinos. The 3.0 is a 32-bit 48MHz ARM cortex M4.

The code pulls a pin low, does one leg's IK calculations, and then pulls the pin back high. I'm using an ancient logic analyzer to measure the time that the line is low.

The bizarre thing is that the ARM board has SIGNIFICANTLY longer time between edges! The AVR does it in around 960us, but the ARM takes more like 18.5ms!

This doesn't add up in my mind. Does anyone have any insight into why this could be?

logic analyzer timing of AVR board, 960.0us

logic analyzer timing of ARM board, 18.5ms

Here's the code I'm using. Don't mind the fact that it's intentionally non-optimized, and probably I'm bad at math, but that's not the question here :)

#include <math.h>

#define lc 21.0
#define lf 40.0
#define lt 62.0

#define lfsqrd 1600.0
#define ltsqrd 3844.0

struct Vector {
  double x;
  double y;
  double z;
};

struct Joints {
  double c;
  double f;
  double t;
};

void calc_joints(struct Vector *foot, struct Joints *joints) {
   double l1 = sqrt(pow(foot->y,2) + pow(foot->x, 2));
   double l2 = l1 - lc;
   double l3 = sqrt(pow(foot->z,2) + pow(l2, 2));

   double tx = atan2(l2, foot->z);
   double ty = acos( (pow(l3,2) + lfsqrd - ltsqrd) / (2 * l3 * lf) );

  // todo: convert these from radians to degrees
   joints->c = atan2(foot->y, foot->x);
   joints->f = tx + ty;
   joints->t = acos( (lfsqrd + ltsqrd - pow(l3,2)) / (2 * lf * lt) );
}

void setup() {
   Serial.begin(9600);
   pinMode(0, OUTPUT);
   digitalWrite(0, HIGH);
}

void loop() {
    digitalWrite(0, LOW);
    struct Vector v = { 10, 20, 30 };
    struct Joints j;

    calc_joints(&v, &j);
    digitalWrite(0, HIGH);


    Serial.print(j.c);    
    Serial.print(", ");
    Serial.print(j.f);    
    Serial.print(", ");
    Serial.println(j.t); 
}
like image 756
Ian McMahon Avatar asked Dec 10 '25 00:12

Ian McMahon


1 Answers

ARM cortex M4

The FPU in the Cortex M4 only supports single precisition, but you use a lot of double in your code. This means software calculations instead of hardware. Have you tried to change the double variables - and function calls - to float?

like image 185
Turbo J Avatar answered Dec 11 '25 14:12

Turbo J



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!