Arduino source code: DDS-oid fixed point calculations with long long integers
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
Long long integer exercise | |
Ed Nisley - KE4ZNU - May 2017 | |
Long long size = 8 bytes | |
.. value = [12345678 9abcdef0] | |
divided result = [01234567 89abcdef] | |
2^32 = [00000001 00000000] | |
125M = [00000000 07735940] | |
2^32 / 125M = [00000000 00000022] | |
Scaled fixed point tests | |
2^63 = [80000000 00000000] | |
2^63 / 125/2 M = [00000022 5c17d04d] | |
Integer: 34 | |
Fraction: 359738367 | |
Decimal: 34.359738367 | |
Hz Per Ct: 0.029103830 | |
60000: 60000.000000000 | |
60 kHz as count: 2061584.302070550 | |
0.1 Hz as count: 3.435973836 | |
60000.1 Hz as count: 2061587.738044387 | |
60000.1 Hz from count: 60000.078519806 | |
60000.2 Hz as count: 2061591.174018223 | |
60000.2 Hz from count: 60000.194935128 | |
60000.2 Hz rnd count: 60000.224038958 | |
Union size: 8 | |
TestFreq: [0000ea60 395a9e00] | |
Union ll: [0000ea60 395a9e00] | |
From union: 60000.224038958 | |
Buffer length: 15 | |
Trunc dec: 60000.224 |
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
// Long long integer exercise for 60 kHz crystal tester | |
//-- Helper routine for printf() | |
int s_putc(char c, FILE *t) { | |
Serial.write(c); | |
} | |
char Buffer[10+1+10]; // string buffer for long long conversions | |
#define ONEGIG 1000000000LL | |
uint64_t CtPerHz; // will be 2^32 / 125 MHz | |
uint64_t HzPerCt; // will be 125 MHz / 2^32 | |
uint64_t TenthHzCt; // 0.1 Hz in counts | |
struct ll_s { | |
uint32_t low; | |
uint32_t high; | |
}; | |
union ll_u { | |
uint64_t ll_64; | |
struct ll_s ll_32; | |
}; | |
//----------- | |
// Long long print-to-buffer helpers | |
// Assumes little-Endian layout | |
void PrintHexLL(char *pBuffer,uint64_t *pLL) { | |
sprintf(pBuffer,"%08lx %08lx",*((uint32_t *)pLL+1),(uint32_t)*pLL); | |
} | |
// converts 9 decimal digits | |
void PrintFractionLL(char *pBuffer,uint64_t *pLL) { | |
uint64_t Fraction; | |
Fraction = (uint32_t)*pLL; // copy 32 fraction bits, high order = 0 | |
Fraction *= ONEGIG; // times 10^9 for conversion | |
Fraction >>= 32; // align integer part in low long | |
sprintf(pBuffer,"%09lu",(uint32_t)Fraction); // convert low long to decimal | |
} | |
void PrintIntegerLL(char *pBuffer,uint64_t *pLL) { | |
sprintf(pBuffer,"%lu",*((uint32_t *)pLL+1)); | |
} | |
void PrintDecimalLL(char *pBuffer,uint64_t *pLL) { | |
PrintIntegerLL(pBuffer,pLL); | |
pBuffer += strlen(pBuffer); // pointer to end of integer part | |
*pBuffer++ = '.'; // drop in the decimal point, tick pointer | |
PrintFractionLL(pBuffer,pLL); | |
} | |
//----------- | |
void setup () | |
{ | |
Serial.begin (115200); | |
fdevopen(&s_putc,0); // set up serial output for printf() | |
Serial.println ("Long long integer exercise"); | |
Serial.println ("Ed Nisley - KE4ZNU - May 2017"); | |
unsigned long long LongLong; | |
uint64_t LongLong2; | |
LongLong = 0x123456789abcdef0LL; | |
printf("Long long size = %d bytes\n",sizeof(LongLong)); | |
printf(" .. value = [%08lx %08lx]\n",(long)(LongLong >> 32),(long)(LongLong & 0x00000000ffffffffLL)); | |
LongLong /= 16; | |
printf(" divided result = [%08lx %08lx]\n",(long)(LongLong >> 32),(long)LongLong); | |
LongLong = 1LL << 32; | |
printf(" 2^32 = [%08lx %08lx]\n",(long)(LongLong >> 32),(long)LongLong); | |
LongLong2 = 125000000LL; | |
printf(" 125M = [%08lx %08lx]\n",(long)(LongLong2 >> 32),(long)LongLong2); | |
LongLong /= LongLong2; | |
printf("2^32 / 125M = [%08lx %08lx]\n",(long)(LongLong >> 32),(long)LongLong); | |
Serial.println("Scaled fixed point tests"); | |
uint64_t TestFreq,TestCount; | |
CtPerHz = 1LL << 63; // start with 2^31 to avoid overflow | |
PrintHexLL(Buffer,&CtPerHz); | |
printf("2^63 = [%s]\n",Buffer); | |
CtPerHz /= 125000000LL / 2; // divided by 2 to to match 2^31 | |
PrintHexLL(Buffer,&CtPerHz); | |
printf("2^63 / 125/2 M = [%s]\n",Buffer); | |
PrintIntegerLL(Buffer,&CtPerHz); | |
printf("Integer: %s\n",Buffer); | |
PrintFractionLL(Buffer,&CtPerHz); | |
printf("Fraction: %s\n",Buffer); | |
PrintDecimalLL(Buffer,&CtPerHz); | |
printf("Decimal: %s\n",Buffer); | |
HzPerCt = 125000000LL; // 125 MHz / 2^32, directly to fraction part | |
PrintDecimalLL(Buffer,&HzPerCt); | |
printf("Hz Per Ct: %s\n",Buffer); | |
TestFreq = 60000LL << 32; | |
PrintDecimalLL(Buffer,&TestFreq); | |
printf("60000: %s\n",Buffer); | |
TestCount = 60000LL * CtPerHz; | |
PrintDecimalLL(Buffer,&TestCount); | |
printf("60 kHz as count: %s\n",Buffer); | |
TenthHzCt = CtPerHz / 10; // 0.1 Hz as counts | |
PrintDecimalLL(Buffer,&TenthHzCt); | |
printf("0.1 Hz as count: %s\n",Buffer); | |
TestCount += TenthHzCt; | |
PrintDecimalLL(Buffer,&TestCount); | |
printf("60000.1 Hz as count: %s\n",Buffer); | |
TestFreq = (TestCount >> 32) * HzPerCt; | |
PrintDecimalLL(Buffer,&TestFreq); | |
printf("60000.1 Hz from count: %s\n",Buffer); | |
TestCount = (60000LL * CtPerHz) + (2 * TenthHzCt); | |
PrintDecimalLL(Buffer,&TestCount); | |
printf("60000.2 Hz as count: %s\n",Buffer); | |
TestFreq = (TestCount >> 32) * HzPerCt; | |
PrintDecimalLL(Buffer,&TestFreq); | |
printf("60000.2 Hz from count: %s\n",Buffer); | |
TestFreq = ((TestCount + (TenthHzCt / 2)) >> 32) * HzPerCt; | |
PrintDecimalLL(Buffer,&TestFreq); | |
printf("60000.2 Hz rnd count: %s\n",Buffer); | |
union ll_u LongLongUnion, TempLLU; | |
printf("Union size: %d\n",sizeof(LongLongUnion)); | |
LongLongUnion.ll_64 = TestFreq; | |
PrintHexLL(Buffer,&TestFreq); | |
printf("TestFreq: [%s]\n",Buffer); | |
PrintHexLL(Buffer,&LongLongUnion.ll_64); | |
printf("Union ll: [%s]\n",Buffer); | |
TempLLU.ll_64 = LongLongUnion.ll_32.low; | |
TempLLU.ll_64 *= ONEGIG; // times 10^9 for conversion | |
TempLLU.ll_64 >>= 32; // align integer part in low long | |
sprintf(Buffer,"%lu.%09lu",LongLongUnion.ll_32.high,TempLLU.ll_32.low); | |
printf("From union: %s\n",Buffer); | |
sprintf(Buffer,"%lu.%09lu",LongLongUnion.ll_32.high,TempLLU.ll_32.low); | |
printf("Buffer length: %d\n",strlen(Buffer)); | |
Buffer[strlen(Buffer) - 9 + 3] = 0; | |
printf(" Trunc dec: %s\n",Buffer); | |
} | |
//----------- | |
void loop () { | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
More details on my blog at http://wp.me/poZKh-6Mm