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

  1. 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.

  1. Compiler

The implementation was written in C++ with templates. By now, most embedded GCC compilers should work well.

  1. MCU Architecture

The implementation is designed to work on a 32-bit MCU. It works on 16-bit MCU too.

  1. 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.

  1. Understanding The Fixed Point

I assume you already knew the Fixed Point algorithm. If don't, please teach yourself. It's very simple.

  1. 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.

/*
 * 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

你可能感兴趣的:(stm,c++)