Last active
July 28, 2022 04:18
-
-
Save ericfont/847ce9a645cf1d3ee89cf1508e926a0f to your computer and use it in GitHub Desktop.
fixed-point-sine outputs on Trinket M0+ to DAC at rate of 291 kHz per sample
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
/* | |
Fixed-point sine by Andrew Steadman copied from https://www.nullhardware.com/blog/fixed-point-sine-and-cosine-for-embedded-systems/ | |
Implements the 5-order polynomial approximation to sin(x). | |
@param i angle (with 2^15 units/circle) | |
@return 16 bit fixed point Sine value (4.12) (ie: +4096 = +1 & -4096 = -1) | |
The result is accurate to within +- 1 count. ie: +/-2.44e-4. | |
*/ | |
int16_t sin_fixedpoint(int16_t i) | |
{ | |
i <<= 1; | |
uint8_t c = i<0; //set carry for output pos/neg | |
if(i == (i|0x4000)) // flip input value to corresponding value in range [0..8192) | |
i = (1<<15) - i; | |
i = (i & 0x7FFF) >> 1; | |
enum {A=3370945099UL, B=2746362156UL, C=292421UL}; | |
enum {n=13, p=32, q=31, r=3, a=12}; | |
uint32_t y = (C*((uint32_t)i))>>n; | |
y = B - (((uint32_t)i*y)>>r); | |
y = (uint32_t)i * (y>>n); | |
y = (uint32_t)i * (y>>n); | |
y = A - (y>>(p-q)); | |
y = (uint32_t)i * (y>>n); | |
y = (y+(1UL<<(q-a-1)))>>(q-a); // Rounding | |
return c ? -y : y; | |
} | |
//Cos(x) = sin(x + pi/2) | |
#define cos_fixedpoint(i) sin_fixedpoint((int16_t)(((uint16_t)(i)) + 8192U)) | |
// rest of test code by Eric Fontaine: | |
void setup() { | |
analogWriteResolution(10); // Set analog out resolution to max, 10-bits | |
analogReadResolution(12); // Set analog input resolution to max, 12-bits | |
Serial.begin(9600); | |
} | |
void loop() { | |
uint32_t start_microseconds = micros(); | |
for( int i=0; i<32768; i++) { | |
// very slow math library call | |
//int16_t biased_sin = (sin(i * 2 * PI / 32768.0f) + 1.0f) * 511.5f; | |
// much faster integer fixed point sine function | |
// convert 13-bit signed value to 10-bit unsigned from 0..1023 centered around 511.5 | |
int16_t biased_sin = (sin_fixedpoint(i) + 4096) * 1023 >> 13; | |
analogWrite(A0, biased_sin); | |
} | |
uint32_t end_microseconds = micros(); | |
uint32_t microseconds = end_microseconds - start_microseconds; | |
uint32_t nanoseconds_per_compute = microseconds * 1000 / 32768; | |
uint32_t clockcycles_per_compute = microseconds * 48 / 32768; | |
Serial.printf("%d total µs, averaging %d ns or %d clocks per compute.\n", microseconds, nanoseconds_per_compute, clockcycles_per_compute); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment