Loading files
438de4276This file is pinned to the selected release. Download the original to open it in your design tool.
// * This file is part of the Tinymovr-Firmware distribution
// * (https://github.com/yconst/tinymovr-firmware).
// *
// * *except* for the function "SVM()", which is Copyright (c) 2016-2018 Oskar Weigl
// *
// * Copyright (c) 2020-2023 Ioannis Chatzikonstantinou.
// *
// * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation, version 3.
// *
// * This program is distributed in the hope that it will be useful, but
// * WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// * General Public License for more details.
// *
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include "src/common.h"
#define DIVIDE_AND_ROUND_UP(numerator, divisor) (((numerator) + (divisor) - 1) / (divisor))
extern void wait_for_control_loop_interrupt(void);
#if __ARM_FEATURE_FMA && __ARM_FP&4 && !__SOFTFP__ && !BROKEN_VFP_ASM
static inline float fast_sqrt(float x)
{
__asm__ ("vsqrt.f32 %0, %1" : "=t"(x) : "t"(x));
return x;
}
static inline float our_fabsf(float x)
{
__asm__ ("vabs.f32 %0, %1" : "=t"(x) : "t"(x));
return x;
}
#else
#error No math implemented without Arm FPU!
#endif
static inline void wait_pwm_cycles(uint32_t cycles)
{
for (uint32_t i = 0; i < cycles; i++)
{
wait_for_control_loop_interrupt();
}
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#pragma GCC diagnostic ignored "-Wuninitialized"
static inline float fast_inv_sqrt(float n)
{
long i;
float y;
const float x = n * 0.5f;
y = n;
i = *(long *)&y;
i = 0x5f3759df - (i >> 1);
y = *(float *)&i;
y = y * (1.5f - (x * y * y));
return y;
}
#pragma GCC diagnostic pop
static inline float our_fminf(float a, float b)
{
return a > b ? b : a;
}
static inline float our_fmaxf(float a, float b)
{
return a > b ? a : b;
}
static inline float sgnf(float v)
{
return (v > 0.0f) - (v < 0.0f);
}
static inline void delay_us(uint32_t us)
{
pac_delay_asm(us * 16u);
}
static inline bool our_clampc(float *d, const float min, const float max)
{
const float t = *d < min ? min : *d;
*d = t > max ? max : t;
return (*d == min) || (*d == max);
}
static inline float our_clamp(float d, float min, float max)
{
const float t = d < min ? min : d;
return t > max ? max : t;
}
static inline float our_floorf(float x)
{
if (x >= 0.0f)
{
return (float)((int)x);
}
return (float)((int)x - 1);
}
// based on https://github.com/divideconcept/FastTrigo/blob/master/fasttrigo.cpp
static inline float cos_32s(float x)
{
const float c1= 0.99940307f;
const float c2=-0.49558072f;
const float c3= 0.03679168f;
float x2; // The input argument squared
x2=x * x;
return (c1 + x2*(c2 + c3 * x2));
}
static inline float fast_cos(float angle)
{
//clamp to the range 0..2pi
angle=angle-our_floorf(angle * INVTWOPI) * TWOPI;
angle=angle>0.f?angle:-angle;
if(angle<halfpi) return cos_32s(angle);
if(angle<pi) return -cos_32s(pi-angle);
if(angle<threehalfpi) return -cos_32s(angle-pi);
return cos_32s(TWOPI - angle);
}
static inline float fast_sin(float angle)
{
return fast_cos(halfpi-angle);
}
typedef struct {
float sum_current;
float sum_current_squared;
uint32_t size;
} Statistics;
static inline void update_statistics(Statistics *s, float new_current)
{
s->sum_current += new_current;
s->sum_current_squared += new_current * new_current;
s->size++;
}
static inline float calculate_standard_deviation(Statistics *s)
{
float mean = s->sum_current / s->size;
float mean_squares = s->sum_current_squared / s->size;
return fast_sqrt(mean_squares - mean * mean);
}
// https://github.com/madcowswe/ODrive/blob/3113aedf081cf40e942d25d3b0b36c8806f11f23/Firmware/MotorControl/utils.c
// Released under teh following license:
// The MIT License (MIT)
// Copyright (c) 2016-2018 Oskar Weigl
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
static inline int SVM(float alpha, float beta, float* tA, float* tB, float* tC)
{
int Sextant;
if (beta >= 0.0f)
{
if (alpha >= 0.0f)
{
//quadrant I
if (one_by_sqrt3 * beta > alpha)
Sextant = 2; //sextant v2-v3
else
Sextant = 1; //sextant v1-v2
}
else
{
//quadrant II
if (-one_by_sqrt3 * beta > alpha)
Sextant = 3; //sextant v3-v4
else
Sextant = 2; //sextant v2-v3
}
}
else
{
if (alpha >= 0.0f)
{
//quadrant IV
if (-one_by_sqrt3 * beta > alpha)
Sextant = 5; //sextant v5-v6
else
Sextant = 6; //sextant v6-v1
}
else
{
//quadrant III
if (one_by_sqrt3 * beta > alpha)
Sextant = 4; //sextant v4-v5
else
Sextant = 5; //sextant v5-v6
}
}
switch (Sextant)
{
// sextant v1-v2
case 1:
{
// Vector on-times
float t1 = alpha - one_by_sqrt3 * beta;
float t2 = two_by_sqrt3 * beta;
// PWM timings
*tA = (1.0f - t1 - t2) * 0.5f;
*tB = *tA + t1;
*tC = *tB + t2;
} break;
// sextant v2-v3
case 2:
{
// Vector on-times
float t2 = alpha + one_by_sqrt3 * beta;
float t3 = -alpha + one_by_sqrt3 * beta;
// PWM timings
*tB = (1.0f - t2 - t3) * 0.5f;
*tA = *tB + t3;
*tC = *tA + t2;
} break;
// sextant v3-v4
case 3:
{
// Vector on-times
float t3 = two_by_sqrt3 * beta;
float t4 = -alpha - one_by_sqrt3 * beta;
// PWM timings
*tB = (1.0f - t3 - t4) * 0.5f;
*tC = *tB + t3;
*tA = *tC + t4;
} break;
// sextant v4-v5
case 4:
{
// Vector on-times
float t4 = -alpha + one_by_sqrt3 * beta;
float t5 = -two_by_sqrt3 * beta;
// PWM timings
*tC = (1.0f - t4 - t5) * 0.5f;
*tB = *tC + t5;
*tA = *tB + t4;
} break;
// sextant v5-v6
case 5:
{
// Vector on-times
float t5 = -alpha - one_by_sqrt3 * beta;
float t6 = alpha - one_by_sqrt3 * beta;
// PWM timings
*tC = (1.0f - t5 - t6) * 0.5f;
*tA = *tC + t5;
*tB = *tA + t6;
} break;
// sextant v6-v1
case 6:
{
// Vector on-times
float t6 = -two_by_sqrt3 * beta;
float t1 = alpha + one_by_sqrt3 * beta;
// PWM timings
*tA = (1.0f - t6 - t1) * 0.5f;
*tC = *tA + t1;
*tB = *tC + t6;
} break;
}
// if any of the results becomes NaN, result_valid will evaluate to false
int result_valid =
*tA >= 0.0f && *tA <= 1.0f
&& *tB >= 0.0f && *tB <= 1.0f
&& *tC >= 0.0f && *tC <= 1.0f;
return result_valid ? 0 : -1;
}