|
// 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 () { |
|
|
|
} |
|
|
|
|