Skip to content

Instantly share code, notes, and snippets.

@ednisley
Created May 21, 2017 23:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ednisley/514aacba692934c0e5dec95a26355ecc to your computer and use it in GitHub Desktop.
Save ednisley/514aacba692934c0e5dec95a26355ecc to your computer and use it in GitHub Desktop.
Arduino source code: DDS-oid fixed point calculations with long long integers
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
// 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 () {
}
@ednisley
Copy link
Author

More details on my blog at http://wp.me/poZKh-6Mm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment