在arduino中计算sin的错误
error with calculating sin in assembly in arduino
#include <avr/pgmspace.h>
//max errror ~0.017452 [91*4=364 bytes]
static const float PROGMEM SineTable[91] = {
0.0, 0.017452, 0.034899, 0.052336, 0.069756, 0.087156,
0.104528, 0.121869, 0.139173, 0.156434, 0.173648, 0.190809,
0.207912, 0.224951, 0.241922, 0.258819, 0.275637, 0.292372,
0.309017, 0.325568, 0.34202, 0.358368, 0.374607, 0.390731,
0.406737, 0.422618, 0.438371, 0.45399, 0.469472, 0.48481,
0.5, 0.515038, 0.529919, 0.544639, 0.559193, 0.573576,
0.587785, 0.601815, 0.615661, 0.62932, 0.642788, 0.656059,
0.669131, 0.681998, 0.694658, 0.707107, 0.71934, 0.731354,
0.743145, 0.75471, 0.766044, 0.777146, 0.788011, 0.798636,
0.809017, 0.819152, 0.829038, 0.838671, 0.848048, 0.857167,
0.866025, 0.87462, 0.882948, 0.891007, 0.898794, 0.906308,
0.913545, 0.920505, 0.927184, 0.93358, 0.939693, 0.945519,
0.951057, 0.956305, 0.961262, 0.965926, 0.970296, 0.97437,
0.978148, 0.981627, 0.984808, 0.987688, 0.990268, 0.992546,
0.994522, 0.996195, 0.997564, 0.99863, 0.999391, 0.999848, 1.0
};
float _Sine(uint16_t angle) {
float tmp;
asm (
//validate angle >= 0 && angle <= 90
"cpi %A1, 90+1 \n"
"cpc %B1, __zero_reg__ \n"
"brcc _NaN \n" //out of range
//calculate table index
"lsl %A1 \n" //float is 4 bytes wide
"rol %B1 \n" //index = angle * 4
"lsl %A1 \n"
"rol %B1 \n"
//add index to start of SineTable
"add r30, %A1 \n"
"adc r31, %B1 \n"
//get sine value (4-bytes)
"lpm %A0, Z+ \n"
"lpm %B0, Z+ \n"
"lpm %C0, Z+ \n"
"lpm %D0, Z \n"
"ret \n" //exit
//return NAN
"_NaN: \n"
"ldi %A0, lo8(%3) \n" //NAN = 0x7fc00000
"ldi %B0, hi8(%3) \n"
"ldi %C0, hlo8(%3) \n"
"ldi %D0, hhi8(%3) \n"
: "=r" (tmp) : "r" (angle), "z" (SineTable), "F" (NAN) :
);
return tmp;
}
int main() {
uint16_t a = 40;
float temp = _Sine(a);
Serial.begin(9600);
Serial.println(temp);
}
这是我在 avr 程序集中计算天使罪恶的代码。但我在 arduino 中编码并在 arduino IDE 中编写汇编。我得到的错误是:需要 15 以上的注册号
但我没有使用任何低于 15 的寄存器,我不知道这段代码有什么问题。
错误是 ldi
需要 15 以上的寄存器,但是您使用了通用寄存器约束 r
,因此允许编译器为这些操作数选择低位寄存器。您可以为 tmp
.
切换到 d
约束
另外,你在没有告诉编译器的情况下销毁了 Z
。
综上所述,我看不出使用汇编来做这件事有任何意义。编译器完全可以索引一个数组,你基本上只需要:
return angle <= 90 ? SineTable[angle] : NAN;
事实上,根据我的测试,生成的汇编代码几乎完全相同。
#include <avr/pgmspace.h>
//max errror ~0.017452 [91*4=364 bytes]
static const float PROGMEM SineTable[91] = {
0.0, 0.017452, 0.034899, 0.052336, 0.069756, 0.087156,
0.104528, 0.121869, 0.139173, 0.156434, 0.173648, 0.190809,
0.207912, 0.224951, 0.241922, 0.258819, 0.275637, 0.292372,
0.309017, 0.325568, 0.34202, 0.358368, 0.374607, 0.390731,
0.406737, 0.422618, 0.438371, 0.45399, 0.469472, 0.48481,
0.5, 0.515038, 0.529919, 0.544639, 0.559193, 0.573576,
0.587785, 0.601815, 0.615661, 0.62932, 0.642788, 0.656059,
0.669131, 0.681998, 0.694658, 0.707107, 0.71934, 0.731354,
0.743145, 0.75471, 0.766044, 0.777146, 0.788011, 0.798636,
0.809017, 0.819152, 0.829038, 0.838671, 0.848048, 0.857167,
0.866025, 0.87462, 0.882948, 0.891007, 0.898794, 0.906308,
0.913545, 0.920505, 0.927184, 0.93358, 0.939693, 0.945519,
0.951057, 0.956305, 0.961262, 0.965926, 0.970296, 0.97437,
0.978148, 0.981627, 0.984808, 0.987688, 0.990268, 0.992546,
0.994522, 0.996195, 0.997564, 0.99863, 0.999391, 0.999848, 1.0
};
float _Sine(uint16_t angle) {
float tmp;
asm (
//validate angle >= 0 && angle <= 90
"cpi %A1, 90+1 \n"
"cpc %B1, __zero_reg__ \n"
"brcc _NaN \n" //out of range
//calculate table index
"lsl %A1 \n" //float is 4 bytes wide
"rol %B1 \n" //index = angle * 4
"lsl %A1 \n"
"rol %B1 \n"
//add index to start of SineTable
"add r30, %A1 \n"
"adc r31, %B1 \n"
//get sine value (4-bytes)
"lpm %A0, Z+ \n"
"lpm %B0, Z+ \n"
"lpm %C0, Z+ \n"
"lpm %D0, Z \n"
"ret \n" //exit
//return NAN
"_NaN: \n"
"ldi %A0, lo8(%3) \n" //NAN = 0x7fc00000
"ldi %B0, hi8(%3) \n"
"ldi %C0, hlo8(%3) \n"
"ldi %D0, hhi8(%3) \n"
: "=r" (tmp) : "r" (angle), "z" (SineTable), "F" (NAN) :
);
return tmp;
}
int main() {
uint16_t a = 40;
float temp = _Sine(a);
Serial.begin(9600);
Serial.println(temp);
}
这是我在 avr 程序集中计算天使罪恶的代码。但我在 arduino 中编码并在 arduino IDE 中编写汇编。我得到的错误是:需要 15 以上的注册号 但我没有使用任何低于 15 的寄存器,我不知道这段代码有什么问题。
错误是 ldi
需要 15 以上的寄存器,但是您使用了通用寄存器约束 r
,因此允许编译器为这些操作数选择低位寄存器。您可以为 tmp
.
d
约束
另外,你在没有告诉编译器的情况下销毁了 Z
。
综上所述,我看不出使用汇编来做这件事有任何意义。编译器完全可以索引一个数组,你基本上只需要:
return angle <= 90 ? SineTable[angle] : NAN;
事实上,根据我的测试,生成的汇编代码几乎完全相同。