Created
June 30, 2022 18:20
-
-
Save Klafyvel/c933a8609427c81e98c5f3498dc439df to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Timing 16bits fixed-point multiplications. The technique used is described | |
here : https://forum.arduino.cc/t/timing-the-little-things/47247 | |
this should print on an arduino Uno: | |
loops: 39 clocks: 156 | |
*/ | |
#include <FixedPoints.h> | |
#include <FixedPointsCommon.h> | |
SFixed<0, 15> a,b; | |
void setup() { | |
Serial.begin(9600); | |
a = SFixed<0,15>(0.25); | |
b = SFixed<0,15>(-0.5); | |
// This call is here so that the compiler does not inline the fixed_mul function | |
a = a*b; | |
} | |
void loop() | |
{ | |
unsigned long loops = 0; | |
// TCNT0 is the timer used to compute milliseconds and drive PWM0. | |
// It is an 8 bit value that increments every 64 clock cycles and | |
// rolls over from 255 to 0. | |
// | |
// We repeatedly run the test code as the timer goes from 156 through 255 | |
// which gives use 64*100 clock cycles. | |
// | |
// In practice this works for timing operations that take from 1 to | |
// hundreds of clock cycles. The results get a little chunky after that | |
// since the last one will have gone a fair bit past the end period. | |
// | |
while( TCNT0 != 155); // wait for 155 to start | |
while( TCNT0 == 155); // wait until 155 ends | |
cli(); // turn off interrupts | |
while( TCNT0 > 150 ) { // that 150 acknowledges we may miss 0 | |
// vvvvvv---- your code to be timed | |
a = a*b; | |
// ^^^^^^---- your code to be timed | |
loops++; | |
} | |
sei(); // turn interrupts back on | |
Serial.print("loops: "); | |
Serial.print(loops,DEC); | |
Serial.print(" clocks: "); | |
Serial.print( (int) (( 100UL*64UL) / loops) - 8 /* empty loop cost */, DEC); | |
Serial.println(); | |
delay(500); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Timing 8bits fixed-point multiplications. The technique used is described | |
here : https://forum.arduino.cc/t/timing-the-little-things/47247 | |
this should print on an arduino Uno: | |
loops: 291 clocks: 13 | |
*/ | |
#include <FixedPoints.h> | |
#include <FixedPointsCommon.h> | |
SFixed<0, 7> a,b; | |
void setup() { | |
Serial.begin(9600); | |
a = SFixed<0,7>(0.25); | |
b = SFixed<0,7>(-0.5); | |
// This call is here so that the compiler does not inline the fixed_mul function | |
a = a*b; | |
} | |
void loop() | |
{ | |
unsigned long loops = 0; | |
// TCNT0 is the timer used to compute milliseconds and drive PWM0. | |
// It is an 8 bit value that increments every 64 clock cycles and | |
// rolls over from 255 to 0. | |
// | |
// We repeatedly run the test code as the timer goes from 156 through 255 | |
// which gives use 64*100 clock cycles. | |
// | |
// In practice this works for timing operations that take from 1 to | |
// hundreds of clock cycles. The results get a little chunky after that | |
// since the last one will have gone a fair bit past the end period. | |
// | |
while( TCNT0 != 155); // wait for 155 to start | |
while( TCNT0 == 155); // wait until 155 ends | |
cli(); // turn off interrupts | |
while( TCNT0 > 150 ) { // that 150 acknowledges we may miss 0 | |
// vvvvvv---- your code to be timed | |
a = a*b; | |
// ^^^^^^---- your code to be timed | |
loops++; | |
} | |
sei(); // turn interrupts back on | |
Serial.print("loops: "); | |
Serial.print(loops,DEC); | |
Serial.print(" clocks: "); | |
Serial.print( (int) (( 100UL*64UL) / loops) - 8 /* empty loop cost */, DEC); | |
Serial.println(); | |
delay(500); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Timing 16bits fixed-point multiplications. The technique used is described | |
here : https://forum.arduino.cc/t/timing-the-little-things/47247 | |
The fixed point multiplication is adapted from the AVR Instruction-set manual. | |
this should print on an arduino Uno: | |
loops: 100 clocks: 56 | |
*/ | |
typedef uint16_t sFixed; | |
sFixed fixed_mul(sFixed a, sFixed b) { | |
sFixed result; | |
asm ( | |
// We need a register that's always zero | |
"clr r2" "\n\t" | |
"fmuls %B[a],%B[b]" "\n\t" // Multiply the MSBs | |
"movw %A[result],__tmp_reg__" "\n\t" // Save the result | |
"fmul %A[a],%A[b]" "\n\t" // Multiply the LSBs | |
"adc %A[result],r2" "\n\t" // Do not forget the carry | |
"movw r18,__tmp_reg__" "\n\t" // The result of the LSBs multipliplication is stored in temporary registers | |
"fmulsu %B[a],%A[b]" "\n\t" // First crossed product | |
// This will be reported onto the MSBs of the temporary registers and the LSBs | |
// of the result registers. So the carry goes to the result's MSB. | |
"sbc %B[result],r2" "\n\t" | |
// Now we sum the cross product | |
"add r19,__tmp_reg__" "\n\t" | |
"adc %A[result],__zero_reg__" "\n\t" | |
"adc %B[result],r2" "\n\t" | |
"fmulsu %B[b],%A[a]" "\n\t" // Second cross product, same as first. | |
"sbc %B[result],r2" "\n\t" | |
"add r19,__tmp_reg__" "\n\t" | |
"adc %A[result],__zero_reg__" "\n\t" | |
"adc %B[result],r2" "\n\t" | |
"clr __zero_reg__" "\n\t" | |
: | |
[result]"+r"(result): | |
[a]"a"(a),[b]"a"(b): | |
"r2","r18","r19" | |
); | |
return result; | |
} | |
sFixed a,b; | |
void setup() { | |
Serial.begin(9600); | |
a = 0x7333; | |
b = 0x80FF; | |
// This call is here so that the compiler does not inline the fixed_mul function | |
a = fixed_mul(a, b); | |
} | |
void loop() | |
{ | |
unsigned long loops = 0; | |
// TCNT0 is the timer used to compute milliseconds and drive PWM0. | |
// It is an 8 bit value that increments every 64 clock cycles and | |
// rolls over from 255 to 0. | |
// | |
// We repeatedly run the test code as the timer goes from 156 through 255 | |
// which gives use 64*100 clock cycles. | |
// | |
// In practice this works for timing operations that take from 1 to | |
// hundreds of clock cycles. The results get a little chunky after that | |
// since the last one will have gone a fair bit past the end period. | |
// | |
while( TCNT0 != 155); // wait for 155 to start | |
while( TCNT0 == 155); // wait until 155 ends | |
cli(); // turn off interrupts | |
while( TCNT0 > 150 ) { // that 150 acknowledges we may miss 0 | |
// vvvvvv---- your code to be timed | |
a = fixed_mul(a,b); | |
// ^^^^^^---- your code to be timed | |
loops++; | |
} | |
sei(); // turn interrupts back on | |
Serial.print("loops: "); | |
Serial.print(loops,DEC); | |
Serial.print(" clocks: "); | |
Serial.print( (int) (( 100UL*64UL) / loops) - 8 /* empty loop cost */, DEC); | |
Serial.println(); | |
delay(500); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Timing 8bits fixed-point multiplications. The technique used is described | |
here : https://forum.arduino.cc/t/timing-the-little-things/47247 | |
this should print on an arduino Uno: | |
loops: 355 clocks: 10 | |
*/ | |
typedef uint8_t sFixed; | |
sFixed fixed_mul(sFixed a, sFixed b) { | |
sFixed result; | |
asm ( | |
"fmuls %[a],%[b]" "\n\t" | |
"mov %[result],__zero_reg__" "\n\t" | |
"clr __zero_reg__" "\n\t" | |
: | |
[result]"+r"(result): | |
[a]"a"(a),[b]"a"(b) | |
); | |
return result; | |
} | |
sFixed a,b; | |
void setup() { | |
Serial.begin(9600); | |
a = 0x73; | |
b = 0x81; | |
// This call is here so that the compiler does not inline the fixed_mul function | |
a = fixed_mul(a, b); | |
Serial.println(a, HEX); | |
} | |
void loop() | |
{ | |
unsigned long loops = 0; | |
// TCNT0 is the timer used to compute milliseconds and drive PWM0. | |
// It is an 8 bit value that increments every 64 clock cycles and | |
// rolls over from 255 to 0. | |
// | |
// We repeatedly run the test code as the timer goes from 156 through 255 | |
// which gives use 64*100 clock cycles. | |
// | |
// In practice this works for timing operations that take from 1 to | |
// hundreds of clock cycles. The results get a little chunky after that | |
// since the last one will have gone a fair bit past the end period. | |
// | |
while( TCNT0 != 155); // wait for 155 to start | |
while( TCNT0 == 155); // wait until 155 ends | |
cli(); // turn off interrupts | |
while( TCNT0 > 150 ) { // that 150 acknowledges we may miss 0 | |
// vvvvvv---- your code to be timed | |
a = fixed_mul(a,b); | |
// ^^^^^^---- your code to be timed | |
loops++; | |
} | |
sei(); // turn interrupts back on | |
Serial.print("loops: "); | |
Serial.print(loops,DEC); | |
Serial.print(" clocks: "); | |
Serial.print( (int) (( 100UL*64UL) / loops) - 8 /* empty loop cost */, DEC); | |
Serial.println(); | |
delay(500); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment