STM32 - Fixed Point On MCU
Why this article has a stm tag?
Segmentfault doesn't support STM32 tag, and I have no enough points for creating new one.
Abstract
An implementation of Fixed Point algorithm for STM32 or any other MCUs which have no FPU support.
For You Information Motive
When using STM32F10x MCU, the lack of FPU makes the float computation too slow for a time sensitive processing--for example, an interrupt handle which should get job done in milliseconds. Assembly language is a good way but not best, because it involves the learning of another language and less generic. Not sure if others had built the wheels, but I like to reinvent it--for nothing else, just because I can. Compiler
The implementation was written in C++ with templates. By now, most embedded GCC compilers should work well. MCU Architecture
The implementation is designed to work on a 32-bit MCU. It works on 16-bit MCU too. Limitation of Precision and Range
To represent a float number, the implementation uses partial bits of 32-bit/64-bit integer to represent the integer part and fraction part. It also means the precision and the range the fixed point can represent are limited. For 32-bit representation, the integer part uses 21 bits and the fraction uses 11 bits. For 64-bit, the bits are 42 and 22, just doubled. Further more, the situation of overflow is not considered. It's your responsibility to handle it.Keep this in mind when using the code. Understanding The Fixed Point
I assume you already knew the Fixed Point algorithm. If don't, please teach yourself. It's very simple. Liability
The code is free for using for anyone. In no event shall I be liable for any situation arising in any way out of the use of the code. Take your own risk to use the code.
Code
Enough talk, let's show the code.
Good Luck
Segmentfault doesn't support STM32 tag, and I have no enough points for creating new one.
Abstract
An implementation of Fixed Point algorithm for STM32 or any other MCUs which have no FPU support.
For You Information
When using STM32F10x MCU, the lack of FPU makes the float computation too slow for a time sensitive processing--for example, an interrupt handle which should get job done in milliseconds. Assembly language is a good way but not best, because it involves the learning of another language and less generic. Not sure if others had built the wheels, but I like to reinvent it--for nothing else, just because I can.
The implementation was written in C++ with templates. By now, most embedded GCC compilers should work well.
The implementation is designed to work on a 32-bit MCU. It works on 16-bit MCU too.
To represent a float number, the implementation uses partial bits of 32-bit/64-bit integer to represent the integer part and fraction part. It also means the precision and the range the fixed point can represent are limited. For 32-bit representation, the integer part uses 21 bits and the fraction uses 11 bits. For 64-bit, the bits are 42 and 22, just doubled. Further more, the situation of overflow is not considered. It's your responsibility to handle it.Keep this in mind when using the code.
I assume you already knew the Fixed Point algorithm. If don't, please teach yourself. It's very simple.
The code is free for using for anyone. In no event shall I be liable for any situation arising in any way out of the use of the code. Take your own risk to use the code.
Code
Enough talk, let's show the code.
/*
* fxfloat.hpp
*
* Created on: Mar 4, 2019
* Author: igame
*/
#ifndef FXFLOAT_HPP_
#define FXFLOAT_HPP_
namespace igame {
template
class FxFloat {
public:
const uint32_t fixed_point_32bits = 11;
const uint32_t fixed_point_64bits = 22;
const uint32_t fixed_point_bits = sizeof(T) == 8 ? fixed_point_64bits : fixed_point_32bits;
const int64_t fixed_point_scale = (int64_t)1 << fixed_point_bits;
const uint64_t fixed_point_fraction_mask = ((uint64_t)0xFFFFFFFFFFFFFFFF >> (32 - fixed_point_bits));
const int64_t fixed_point_max = (int64_t)0x3F3F3F3F3F3F3F3F;
const int64_t fixed_point_min = -fixed_point_max;
public:
typedef T value_type;
typedef const T const_value_type;
public:
value_type value{ 0 };
public:
FxFloat() { }
FxFloat(const float x) {
int64_t integer = ((int64_t)x) << fixed_point_bits;
int64_t fract = (int64_t)((x - (int64_t)x) * fixed_point_scale);
this->value = integer + fract;
}
/// convert back to float
INLINE operator float() {
return to_float();
}
/// Assignment
INLINE FxFloat& operator = (const int64_t& right) {
this->value = right;
return *this;
}
INLINE FxFloat& operator = (const float& right) {
this->value = from_float(right);
return *this;
}
INLINE FxFloat& operator = (const FxFloat& right) {
return this->operator = (right.value);
}
/// Add
INLINE FxFloat& operator += (int64_t right) {
this->value += right;
return *this;
}
INLINE FxFloat& operator += (const float& right) {
return this->operator += (from_float(right));
}
INLINE FxFloat& operator += (const FxFloat& right) {
return this->operator += (right.value);
}
/// Sub
INLINE FxFloat& operator -= (const int64_t& right) {
this->value -= right;
return *this;
}
INLINE FxFloat& operator -= (const float& right) {
return this->operator -= (from_float(right));
}
INLINE FxFloat& operator -= (const FxFloat& right) {
return this->operator -= (right.value);
}
/// Mul
INLINE FxFloat& operator *= (const int64_t& right) {
this->value *= right;
this->value >>= fixed_point_bits;
return *this;
}
INLINE FxFloat& operator *= (const float& right) {
return this->operator *= (from_float(right));
}
INLINE FxFloat& operator *= (const FxFloat& right) {
return this->operator *= (right.value);
}
/// Div
INLINE FxFloat& operator /= (const int64_t& right) {
if (right == 0) {
this->value = fixed_point_max;
}
else {
this->value <<= fixed_point_bits;
this->value /= right;
}
return *this;
}
INLINE FxFloat& operator /= (const float& right) {
return this->operator /= (from_float(right));
}
INLINE FxFloat& operator /= (const FxFloat& right) {
return this->operator /= (right->value);
}
private:
INLINE int64_t from_float(const float& x) {
int64_t integer = ((int64_t)x) << fixed_point_bits;
int64_t fract = (int64_t)((x - (int64_t)x) * fixed_point_scale);
return integer + fract;
}
INLINE float to_float() {
(float)this->value / fixed_point_scale;
}
};
/// Global Operator Overloading
template
INLINE FxFloat operator + (FxFloat& left, FxFloat& right) {
FxFloat res{ left };
res += right;
return res;
}
template
INLINE FxFloat operator + (const FxFloat& left, const float& right) {
FxFloat res{ left };
res += right;
return res;
}
template
INLINE FxFloat operator + (const float& left, const FxFloat& right) {
FxFloat res{ left };
res.value += right;
return res;
}
template
INLINE FxFloat operator - (FxFloat& left, FxFloat& right) {
FxFloat res{ left };
res -= right;
return res;
}
template
INLINE FxFloat operator - (const FxFloat& left, const float& right) {
FxFloat res{ left };
res -= right;
return res;
}
template
INLINE FxFloat operator - (const float& left, const FxFloat& right) {
FxFloat res{ left };
res.value -= right;
return res;
}
template
INLINE FxFloat operator * (FxFloat& left, FxFloat& right) {
FxFloat res{ left };
res *= right;
return res;
}
template
INLINE FxFloat operator * (const FxFloat& left, const float& right) {
FxFloat res{ left };
res *= right;
return res;
}
template
INLINE FxFloat operator * (const float& left, const FxFloat& right) {
FxFloat res{ left };
res.value *= right;
return res;
}
template
INLINE FxFloat operator / (FxFloat& left, FxFloat& right) {
FxFloat res{ left };
res /= right;
return res;
}
template
INLINE FxFloat operator / (const FxFloat& left, const float& right) {
FxFloat res{ left };
res /= right;
return res;
}
template
INLINE FxFloat operator / (const float& left, const FxFloat& right) {
FxFloat res{ left };
res /= right;
return res;
}
} // ns igame
#endif /* FXFLOAT_HPP_ */
Good Luck