// Generates a header with precalculated best dividers for PWMAudio at // standard clock frequencies and audio rates. // #include #include #include void find_pacer_fraction(int F_CPU, int target, uint16_t *numerator, uint16_t *denominator) { const uint16_t max = 0xFFFF; /*Cache last results so we dont have to recalculate*/ static int last_target; static uint16_t bestNum; static uint16_t bestDenom; /*Check if we can load the previous values*/ if (target == last_target) { *numerator = bestNum; *denominator = bestDenom; return; } float targetRatio = (float)F_CPU / target; float lowestError = 10000000; for (uint16_t denom = 1; denom < max; denom++) { uint16_t num = (int)((targetRatio * denom) + 0.5f); /*Calculate numerator, rounding to nearest integer*/ /*Check if numerator is within bounds*/ if (num > 0 && num < max) { float actualRatio = (float)num / denom; float error = fabsf(actualRatio - targetRatio); if (error < lowestError) { bestNum = num; bestDenom = denom; lowestError = error; if (error == 0) { break; } } } } last_target = target; *numerator = bestNum; *denominator = bestDenom; } int main(int argc, char **argv) { (void) argc; (void) argv; int M = 1000000; int fsys[] = {50*M, 100*M, 120*M, 125*M, 128*M, 133*M, 150*M, 176*M, 200*M, 225*M, 240*M, 250*M, 276*M, 300*M}; int freq[] = {8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000}; FILE *f = fopen("../libraries/PWMAudio/src/PWMAudioPrecalc.h", "w"); fprintf(f, "// Generated by tools/makepacer.cpp, do not edit\n"); fprintf(f, "typedef struct {\n"); fprintf(f, " uint32_t freq;\n"); fprintf(f, " uint16_t n;\n"); fprintf(f, " uint16_t d;\n"); fprintf(f, "} PWMPacerPrecalc;\n"); for (int i = 0; i < sizeof(fsys)/sizeof(fsys[0]); i++) { fprintf(f, "#%s F_CPU == %d\n", i == 0 ? "if" : "elif", fsys[i]); fprintf(f, "static const PWMPacerPrecalc __PWMAudio_pacer[] = {"); for (int j = 0; j < sizeof(freq)/sizeof(freq[0]); j++) { uint16_t n, d; find_pacer_fraction(fsys[i], freq[j], &n, &d); fprintf(f, "{%d, %d, %d}", freq[j], n, d); if (j < sizeof(freq)/sizeof(freq[0]) - 1) { fprintf(f, ", "); } } fprintf(f, "};\n"); } fprintf(f, "#else\n"); fprintf(f, "const PWMPacerPrecalc __PWMAudio_pacer[] = {{1, 1, 1}}; // Invalid, should never match\n"); fprintf(f, "#endif\n"); fclose(f); }