📄 avrfix.c
字号:
/****************************************************************
* *
* __ ____ _________ *
* /_ \\\ \/ /| \______ *
* // \\\ /|| D /_ /. *
* // \\\_ /.|| \ ___/. *
* /___/\___\\__/. |__|\__\__.___ ___ *
* .... ....... ...|| _/_\ \////. *
* || |.| |\ ///. *
* |__|.|_|/// \ *
* .... ./__/\__\ *
* ........ *
* Fixed Point Library *
* according to *
* ISO/IEC DTR 18037 *
* *
* Version 1.0.1 *
* Maximilan Rosenblattl, Andreas Wolf 2007-02-07 *
****************************************************************/
#ifndef TEST_ON_PC
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/pgmspace.h>
#include "avrfix.h"
#include "avrfix_config.h"
#endif
#if BYTE_ORDER == BIG_ENDIAN
typedef struct {
unsigned short ll;
uint8_t lh;
int8_t h;
} lAccum_container;
#else
typedef struct {
int8_t h;
uint8_t lh;
unsigned short ll;
} lAccum_container;
#endif
#define us(x) ((unsigned short)(x))
#define ss(x) ((signed short)(x))
#define ul(x) ((unsigned long)(x))
#define sl(x) ((signed long)(x))
extern void cordicck(_Accum* x, _Accum* y, _Accum* z, uint8_t iterations, uint8_t mode);
extern void cordichk(_Accum* x, _Accum* y, _Accum* z, uint8_t iterations, uint8_t mode);
extern void cordiccsk(_sAccum* x, _sAccum* y, _sAccum* z, uint8_t mode);
extern void cordichsk(_sAccum* x, _sAccum* y, _sAccum* z, uint8_t mode);
#ifdef SMULSKD
_sAccum smulskD(_sAccum x, _sAccum y)
{
return ss(RSHIFT_static(sl(x)*sl(y), SACCUM_FBIT));
}
#endif
#ifdef SMULSKS
_sAccum smulskS(_sAccum x, _sAccum y)
{
long mul = RSHIFT_static(sl(x)*sl(y), SACCUM_FBIT);
if(mul >= 0) {
if((mul & 0xFFFF8000) != 0)
return SACCUM_MAX;
} else {
if((mul & 0xFFFF8000) != 0xFFFF8000)
return SACCUM_MIN;
}
return sl(mul);
}
#endif
#ifdef MULKD
_Accum mulkD(_Accum x, _Accum y)
{
#if BYTE_ORDER == BIG_ENDIAN
# define LO 0
# define HI 1
#else
# define LO 1
# define HI 0
#endif
unsigned short xs[2];
unsigned short ys[2];
int8_t positive = ((x < 0 && y < 0) || (y > 0 && x > 0)) ? 1 : 0;
y = absk(y);
*((_Accum*)xs) = absk(x);
*((_Accum*)ys) = y;
x = sl(xs[HI])*y + sl(xs[LO])*ys[HI];
*((_Accum*)xs) = ul(xs[LO])*ul(ys[LO]);
if(positive)
return x + us(xs[HI]);
else
return -(x + us(xs[HI]));
#undef HI
#undef LO
}
#endif
#ifdef MULKS
_Accum mulkS(_Accum x, _Accum y)
{
#if BYTE_ORDER == BIG_ENDIAN
# define LO 0
# define HI 1
#else
# define LO 1
# define HI 0
#endif
unsigned short xs[2];
unsigned short ys[2];
unsigned long mul;
int8_t positive = ((x < 0 && y < 0) || (y > 0 && x > 0)) ? 1 : 0;
*((_Accum*)xs) = absk(x);
*((_Accum*)ys) = absk(y);
mul = ul(xs[HI]) * ul(ys[HI]);
if(mul > 32767)
return (positive ? ACCUM_MAX : ACCUM_MIN);
mul = LSHIFT_static(mul, ACCUM_FBIT)
+ ul(xs[HI])*ul(ys[LO])
+ ul(xs[LO])*ul(ys[HI])
+ RSHIFT_static(ul(xs[LO]*ys[LO]), ACCUM_FBIT);
if(mul & 0x80000000)
return (positive ? ACCUM_MAX : ACCUM_MIN);
return (positive ? (long)mul : -(long)mul);
#undef HI
#undef LO
}
#endif
#ifdef LMULLKD
_lAccum lmullkD(_lAccum x, _lAccum y)
{
lAccum_container *xc, *yc;
xc = (lAccum_container*)&x;
yc = (lAccum_container*)&y;
return sl(xc->h)*y + sl(yc->h)*(x&0x00FFFFFF)
+ ((ul(xc->lh)*ul(yc->lh))*256)
+ RSHIFT_static((ul(xc->lh)*ul(yc->ll) + ul(xc->ll)*ul(yc->lh)), 8)
+ (RSHIFT_static((ul(xc->lh)*ul(yc->ll) + ul(xc->ll)*ul(yc->lh)), 7)&1)
+ RSHIFT_static((ul(xc->ll)*ul(yc->ll)), 24);
}
#endif
#ifdef LMULLKS
_lAccum lmullkS(_lAccum x, _lAccum y)
{
lAccum_container xc, yc;
unsigned long mul;
int8_t positive = ((x < 0 && y < 0) || (y > 0 && x > 0)) ? 1 : 0;
x = labslk(x);
y = labslk(y);
*((_lAccum*)&xc) = x;
*((_lAccum*)&yc) = y;
mul = xc.h * yc.h;
x &= 0x00FFFFFF;
y &= 0x00FFFFFF;
if(mul > 127)
return (positive ? LACCUM_MAX : LACCUM_MIN);
mul = LSHIFT_static(mul, LACCUM_FBIT) + ul(xc.h)*y + ul(yc.h)*x +
+ (ul(xc.lh)*ul(yc.lh)*256)
+ RSHIFT_static((ul(xc.lh)*ul(yc.ll) + ul(xc.ll)*ul(yc.lh)), 8)
+ (RSHIFT_static((ul(xc.lh)*ul(yc.ll) + ul(xc.ll)*ul(yc.lh)), 7)&1)
+ RSHIFT_static((ul(xc.ll)*ul(yc.ll)), 24);
if(mul & 0x80000000)
return (positive ? ACCUM_MAX : ACCUM_MIN);
return (positive ? (long)mul : -(long)mul);
}
#endif
#ifdef SDIVSKD
_sAccum sdivskD(_sAccum x, _sAccum y)
{
return ss((sl(x) << SACCUM_FBIT) / y);
}
#endif
#ifdef SDIVSKS
_sAccum sdivskS(_sAccum x, _sAccum y)
{
long div;
if(y == 0)
return (x < 0 ? SACCUM_MIN : SACCUM_MAX);
div = (sl(x) << SACCUM_FBIT) / y;
if(div >= 0) {
if((div & 0xFFFF8000) != 0)
return SACCUM_MAX;
} else {
if((div & 0xFFFF8000) != 0xFFFF8000)
return SACCUM_MIN;
}
return ss(div);
}
#endif
#ifdef DIVKD
/* if y = 0, divkD will enter an endless loop */
_Accum divkD(_Accum x, _Accum y) {
_Accum result;
int i,j=0;
int8_t sign = ((x < 0 && y < 0) || (x > 0 && y > 0)) ? 1 : 0;
x = absk(x);
y = absk(y);
/* Align x leftmost to get maximum precision */
for (i=0 ; i<ACCUM_FBIT ; i++)
{
if (x >= ACCUM_MAX / 2) break;
x = LSHIFT_static(x, 1);
}
while((y & 1) == 0) {
y = RSHIFT_static(y, 1);
j++;
}
result = x/y;
/* Correct value by shift left */
/* Check amount and direction of shifts */
i = (ACCUM_FBIT - i) - j;
if(i > 0)
result = LSHIFT_dynamic(result, i);
else if(i < 0) {
/* shift right except for 1 bit, wich will be used for rounding */
result = RSHIFT_dynamic(result, (-i) - 1);
/* determine if round is necessary */
result = RSHIFT_static(result, 1) + (result & 1);
}
return (sign ? result : -result);
}
#endif
#ifdef DIVKS
_Accum divkS(_Accum x, _Accum y) {
_Accum result;
int i,j=0;
int8_t sign = ((x < 0 && y < 0) || (y > 0 && x > 0)) ? 1 : 0;
if(y == 0)
return (x < 0 ? ACCUM_MIN : ACCUM_MAX);
x = absk(x);
y = absk(y);
for (i=0 ; i<ACCUM_FBIT ; i++)
{
if (x >= ACCUM_MAX / 2) break;
x = LSHIFT_static(x, 1);
}
while((y & 1) == 0) {
y = RSHIFT_static(y, 1);
j++;
}
result = x/y;
/* Correct value by shift left */
/* Check amount and direction of shifts */
i = (ACCUM_FBIT - i) - j;
if(i > 0)
for(;i>0;i--) {
if((result & 0x40000000) != 0) {
return sign ? ACCUM_MAX : ACCUM_MIN;
}
result = LSHIFT_static(result, 1);
}
else if(i < 0) {
/* shift right except for 1 bit, wich will be used for rounding */
result = RSHIFT_dynamic(result, (-i) - 1);
/* round */
result = RSHIFT_static(result, 1) + (result & 1);
}
return (sign ? result : -result);
}
#endif
#ifdef LDIVLKD
/* if y = 0, ldivlkD will enter an endless loop */
_lAccum ldivlkD(_lAccum x, _lAccum y) {
_lAccum result;
int i,j=0;
int8_t sign = ((x < 0 && y < 0) || (x > 0 && y > 0)) ? 1 : 0;
x = labslk(x);
y = labslk(y);
/* Align x leftmost to get maximum precision */
for (i=0 ; i<LACCUM_FBIT ; i++)
{
if (x >= LACCUM_MAX / 2) break;
x = LSHIFT_static(x, 1);
}
while((y & 1) == 0) {
y = RSHIFT_static(y, 1);
j++;
}
result = x/y;
/* Correct value by shift left */
/* Check amount and direction of shifts */
i = (LACCUM_FBIT - i) - j;
if(i > 0)
result = LSHIFT_dynamic(result, i);
else if(i < 0) {
/* shift right except for 1 bit, wich will be used for rounding */
result = RSHIFT_dynamic(result, (-i) - 1);
/* determine if round is necessary */
result = RSHIFT_static(result, 1) + (result & 1);
}
return (sign ? result : -result);
}
#endif
#ifdef LDIVLKS
_lAccum ldivlkS(_lAccum x, _lAccum y) {
_lAccum result;
int i,j=0;
int8_t sign = ((x < 0 && y < 0) || (y > 0 && x > 0)) ? 1 : 0;
if(y == 0)
return (x < 0 ? LACCUM_MIN : LACCUM_MAX);
x = labslk(x);
y = labslk(y);
for (i=0 ; i<LACCUM_FBIT ; i++)
{
if (x >= LACCUM_MAX / 2) break;
x = LSHIFT_static(x, 1);
}
while((y & 1) == 0) {
y = RSHIFT_static(y, 1);
j++;
}
result = x/y;
/* Correct value by shift left */
/* Check amount and direction of shifts */
i = (LACCUM_FBIT - i) - j;
if(i > 0)
for(;i>0;i--) {
if((result & 0x40000000) != 0) {
return sign ? LACCUM_MAX : LACCUM_MIN;
}
result = LSHIFT_static(result, 1);
}
else if(i < 0) {
/* shift right except for 1 bit, wich will be used for rounding */
result = RSHIFT_dynamic(result, (-i) - 1);
/* round */
result = RSHIFT_static(result, 1) + (result & 1);
}
return (sign ? result : -result);
}
#endif
#ifdef SINCOSK
_Accum sincosk(_Accum angle, _Accum* cosp)
{
_Accum x;
_Accum y = 0;
uint8_t correctionCount = 0;
uint8_t quadrant = 1;
if(cosp == NULL)
cosp = &x;
/* move large values into [0,2 PI] */
#define MAX_CORRECTION_COUNT 1
while(angle >= PIlk) { /* PIlk = PIk * 2^8 */
angle -= PIlk;
if(correctionCount == MAX_CORRECTION_COUNT) {
correctionCount = 0;
angle++;
} else {
correctionCount++;
}
}
correctionCount = 0;
while(angle < 0) {
angle += PIlk;
if(correctionCount == MAX_CORRECTION_COUNT) {
correctionCount = 0;
angle--;
} else {
correctionCount++;
}
}
#undef MAX_CORRECTION_COUNT
/* move small values into [0,2 PI] */
#define MAX_CORRECTION_COUNT 5
while(angle >= 2*PIk + 1) {
angle -= 2*PIk + 1;
if(correctionCount == MAX_CORRECTION_COUNT) {
correctionCount = 0;
angle++;
} else {
correctionCount++;
}
}
if(correctionCount > 0) {
angle++;
}
correctionCount = 0;
while(angle < 0) {
angle += 2*PIk + 1;
if(correctionCount == MAX_CORRECTION_COUNT) {
correctionCount = 0;
angle--;
} else {
correctionCount++;
}
}
if(correctionCount > 0) {
angle--;
}
#undef MAX_CORRECTION_COUNT
if(angle > PIk) {
angle = angle - PIk;
quadrant += 2;
}
if(angle > (PIk/2 + 1)) {
angle = PIk - angle + 1;
quadrant += 1;
}
if(angle == 0) {
*cosp = (quadrant == 2 || quadrant == 3 ? -itok(1) : itok(1));
return 0;
}
*cosp = CORDICC_GAIN;
angle = LSHIFT_static(angle, 8);
cordicck(cosp, &y, &angle, 17, 0);
(*cosp) = RSHIFT_static(*cosp, 8);
y = RSHIFT_static(y, 8);
switch(quadrant) {
case 2: {
(*cosp) = -(*cosp);
} break;
case 3: {
y = -y;
(*cosp) = -(*cosp);
} break;
case 4: {
y = -y;
} break;
default:;
}
return y;
}
#endif
#ifdef LSINCOSLK
_lAccum lsincoslk(_lAccum angle, _lAccum* cosp)
{
_lAccum x;
_lAccum y = 0;
uint8_t correctionCount;
uint8_t quadrant = 1;
if(cosp == NULL)
cosp = &x;
/* move values into [0, 2 PI] */
#define MAX_CORRECTION_COUNT 1
correctionCount = 0;
while(angle >= 2*PIlk) {
angle -= 2*PIlk;
if(correctionCount == MAX_CORRECTION_COUNT) {
correctionCount = 0;
angle++;
} else {
correctionCount++;
}
}
correctionCount = 0;
while(angle < 0) {
angle += 2*PIlk;
if(correctionCount == MAX_CORRECTION_COUNT) {
correctionCount = 0;
angle--;
} else {
correctionCount++;
}
}
#undef MAX_CORRECTION_COUNT
if(angle > PIlk) {
angle = angle - PIlk;
quadrant += 2;
}
if(angle > (PIlk/2)) {
angle = PIlk - angle;
quadrant += 1;
}
if(angle == 0) {
*cosp = (quadrant == 2 || quadrant == 3 ? -itolk(1) : itolk(1));
return 0;
}
*cosp = CORDICC_GAIN;
cordicck(cosp, &y, &angle, 24, 0);
switch(quadrant) {
case 2: {
(*cosp) = -(*cosp);
} break;
case 3: {
y = -y;
(*cosp) = -(*cosp);
} break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -