Embedded World 2023 - STM32 CORDIC CO-PROCESSOR

I think I have a solution… make _sin and _cos accept angles outside 0-2pi range, and inside the function convert to fixed-point before doing the table lookup. It has to do a float-to-int conversion anyway, and by doing it before the normalization step we can use bit shifting/masking instead of fmod and checking for negative.

It will require some care and testing to ensure that there are no off-by-one problems in each quadrant. And the sine array will need to be re-generated with 256 entries instead of 200. I can do the work if you’d like.

EDIT: I went ahead and did it. Here is our new super speedy and slightly higher resolution sine lookup :slight_smile: Also cosine can be moved to foc_utils.h as inline float _cos(float a) { return _sin(a + _PI_2); }
I also discovered a minor problem with the old one, the sine_array was type int, which is 16 bits on AVR but 32 bits on ARM, so was wasting 400 bytes of flash.
All the code that calls _sin and _cos will need to be evaluated for whether associated _normalizeAngle calls can be removed.

// int array instead of float array
// 4x256 points per 360 deg
// 2x storage save (int 2Byte float 4 Byte )
// Generation code:
//	FILE *file = fopen("SineFile.txt", "wt");
//	for(int i = 0; i <= 256; i++) fprintf(file, "%i,", (int)(sin(i * M_PI / 512) * 10000 + 0.5));
//	fclose(file);
uint16_t sine_array[257] = {0,61,123,184,245,307,368,429,491,552,613,674,736,797,858,919,980,1041,1102,1163,1224,1285,1346,1407,1467,1528,1589,1649,1710,1770,1830,1891,1951,2011,2071,2131,2191,2251,2311,2370,2430,2489,2549,2608,2667,2726,2785,2844,2903,2962,3020,3078,3137,3195,3253,3311,3369,3427,3484,3542,3599,3656,3713,3770,3827,3883,3940,3996,4052,4108,4164,4220,4276,4331,4386,4441,4496,4551,4605,4660,4714,4768,4822,4876,4929,4982,5035,5088,5141,5194,5246,5298,5350,5402,5453,5505,5556,5607,5657,5708,5758,5808,5858,5908,5957,6006,6055,6104,6152,6201,6249,6296,6344,6391,6438,6485,6532,6578,6624,6670,6716,6761,6806,6851,6895,6940,6984,7028,7071,7114,7157,7200,7242,7285,7327,7368,7410,7451,7491,7532,7572,7612,7652,7691,7730,7769,7807,7846,7883,7921,7958,7995,8032,8068,8105,8140,8176,8211,8246,8280,8315,8349,8382,8416,8449,8481,8514,8546,8577,8609,8640,8670,8701,8731,8761,8790,8819,8848,8876,8904,8932,8960,8987,9013,9040,9066,9092,9117,9142,9167,9191,9215,9239,9262,9285,9308,9330,9352,9373,9395,9415,9436,9456,9476,9495,9514,9533,9551,9569,9587,9604,9621,9638,9654,9670,9685,9700,9715,9729,9743,9757,9770,9783,9796,9808,9820,9831,9842,9853,9863,9873,9883,9892,9901,9909,9917,9925,9932,9939,9946,9952,9958,9963,9968,9973,9977,9981,9985,9988,9991,9993,9995,9997,9998,9999,10000,10000};

// function approximating the sine calculation by using fixed size array
// precision +-0.003108
// a is in radians. No restriction on range.
float _sin(float a) {
  unsigned int i = ((unsigned int)(a * (2048 / _2PI) + 1) >> 1) & 0x3ff;
  if (i < 256)
    return 0.0001f*sine_array[i];
  else if(i < 512)
    return 0.0001f*sine_array[512 - i];
  else if(i < 768)
    return -0.0001f*sine_array[-512 + i];
  else
    return -0.0001f*sine_array[1024 - i];
}

EDIT2: Better yet, we can do sine and cosine with a single float-to-int conversion and series of if statements :slight_smile:

void _sincos(float a, float *s, float *c) {
  unsigned int i = ((unsigned int)(a * (2048 / _2PI) + 1) >> 1) & 0x3ff;
  if (i < 256) {
    *s = 0.0001f*sine_array[i];
    *c = 0.0001f*sine_array[256 - i];
  }
  else if(i < 512) {
    *s = 0.0001f*sine_array[512 - i];
    *c = -0.0001f*sine_array[-256 + i];
  }
  else if(i < 768) {
    *s = -0.0001f*sine_array[-512 + i];
    *c = -0.0001f*sine_array[768 - i];
  }
  else {
    *s = -0.0001f*sine_array[1024 - i];
    *c = 0.0001f*sine_array[-768 + i];
  }
}

From my evaluation, the biggest issue is that the velocity/angle PID loops operate on angle values, so pid.cpp/h would have to be converted to fixed-point math or else would be very slow with all the float/int conversions. But the current sense PID would still need to operate on float values, so then it would be slow with conversions…

User code doing arithmetic on angle values would need to be aware of the caveats of fixed-point math, which might intimidate new users who are inexperienced with programming in general. But as long as we have functions or macros for doing multiplication/division, it would probably be ok. And a lot of things would be easier rather than more difficult, as I said back in post #16.

Another factor is that fixed-point division can be even slower than float division, so all the internal code will need to be evaluated for whether divisions can be eliminated or carefully done without overflowing 32 bits or losing too much precision.