We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FabGL/src/fabutils.cpp
Line 1753 in 1ad2713
I offer to simplify function APLLCalcParams to reduce computation time.
Here is example of possible alternative:
output:
f=25.175000MHz APLLCalcParams.steps=160 sdm0=235 sdm1= 17 sdm2= 6 o_div= 2 a= 1 b= 0 of=25.174980MHz err= 19.8 ppm=-0.79 sdm0=236 sdm1= 17 sdm2= 6 o_div= 2 of=25.175018MHz err= 18.0 ppm= 0.71
code:
#include <stdio.h> #include <math.h> //--------------------------------------------------------------------------- #define FABGLIB_XTAL 40000000 #define FABGLIB_USE_APLL_AB_COEF 0 typedef unsigned char uint8_t; //typedef long long int64_t; struct APLLParams { uint8_t sdm0; uint8_t sdm1; uint8_t sdm2; uint8_t o_div; }; template <typename T> const T & tmax(const T & a, const T & b) { return (a < b) ? b : a; } template <typename T> const T & tmin(const T & a, const T & b) { return !(b < a) ? a : b; } template <typename T> const T & tclamp(const T & v, const T & lo, const T & hi) { return (v < lo ? lo : (v > hi ? hi : v)); } void floatToFraction(double value, int maxDen, int * num, int * den) { int64_t a, h[3] = { 0, 1, 0 }, k[3] = { 1, 0, 0 }; int64_t x, d, n = 1; while (value != floor(value)) { n <<= 1; value *= 2; } d = value; for (int i = 0; i < 64; ++i) { a = n ? d / n : 0; if (i && !a) break; x = d; d = n; n = x % n; x = a; if (k[1] * a + k[0] >= maxDen) { x = (maxDen - k[0]) / k[1]; if (x * 2 >= a || k[1] >= maxDen) i = 65; else break; } h[2] = x * h[1] + h[0]; h[0] = h[1]; h[1] = h[2]; k[2] = x * k[1] + k[0]; k[0] = k[1]; k[1] = k[2]; } *den = k[1]; *num = h[1]; } static void APLLCalcParams(double freq, APLLParams *params, uint8_t * a, uint8_t * b, double* out_freq, double* error) { int steps=0; double FXTAL = FABGLIB_XTAL; *error = 999999999; double apll_freq = freq*2; for (int o_div=0;o_div<=31;++o_div) { int idivisor = (2*o_div + 4); for (int sdm2 = 4; sdm2 <= 8; ++sdm2) { // from tables above int minSDM1 = (sdm2 == 4 ? 192 : 0); int maxSDM1 = (sdm2 == 8 ? 128 : 255); // apll_freq = XTAL * (4 + sdm2 + sdm1 / 256) / divisor -> sdm1 = (apll_freq * divisor - XTAL * 4 - XTAL * sdm2) * 256 / XTAL int startSDM1 = ((apll_freq * idivisor - FXTAL * 4.0 - FXTAL * sdm2) * 256.0 / FXTAL); #if FABGLIB_USE_APLL_AB_COEF for (int isdm1 = tmax(minSDM1, startSDM1); isdm1 <= maxSDM1; ++isdm1) { #else int isdm1 = startSDM1; { #endif steps++; int sdm1 = isdm1; sdm1 = tmax(minSDM1, sdm1); sdm1 = tmin(maxSDM1, sdm1); // apll_freq = XTAL * (4 + sdm2 + sdm1 / 256 + sdm0 / 65536) / divisor -> sdm0 = (apll_freq * divisor - XTAL * 4 - XTAL * sdm2 - XTAL * sdm1 / 256) * 65536 / XTAL int sdm0 = ((apll_freq * idivisor - FXTAL * 4.0 - FXTAL * sdm2 - FXTAL * sdm1 / 256.0) * 65536.0 / FXTAL); // from tables above sdm0 = (sdm2 == 8 && sdm1 == 128 ? 0 : tmin(255, sdm0)); sdm0 = tmax(0, sdm0); // dividend inside 350-500Mhz? double dividend = FXTAL * (4.0 + sdm2 + sdm1 / 256.0 + sdm0 / 65536.0); if (dividend >= 350000000 && dividend <= 500000000) { // adjust output frequency using "b/a" double oapll_freq = dividend / idivisor; // Calculates "b/a", assuming tx_bck_div_num = 1 and clkm_div_num = 2: // freq = apll_clk / (2 + clkm_div_b / clkm_div_a) // abr = clkm_div_b / clkm_div_a // freq = apll_clk / (2 + abr) => abr = apll_clk / freq - 2 uint8_t oa = 1, ob = 0; #if FABGLIB_USE_APLL_AB_COEF double abr = oapll_freq / freq - 2.0; if (abr > 0 && abr < 1) { int num, den; floatToFraction(abr, 63, &num, &den); ob = tclamp(num, 0, 63); oa = tclamp(den, 0, 63); } #endif // is this the best? double ofreq = oapll_freq / (2.0 + (double)ob / oa); double err = freq - ofreq; if (abs(err) < abs(*error)) { *params = (APLLParams){(uint8_t)sdm0, (uint8_t)sdm1, (uint8_t)sdm2, (uint8_t)o_div}; *a = oa; *b = ob; *out_freq = ofreq; *error = err; if (err == 0.0) goto leave; } } } } } leave: printf("APLLCalcParams.steps=%d\n",steps); } //--------------------------------------------------------------------------- typedef struct calc_fabc_s { int sm[3],odiv,freq; } calc_fabc_t; enum { calc_fabc_f_min = 5645162, calc_fabs_hole_head = 83333334, calc_fabs_hole_tail = 87500000, calc_fabc_f_max = 125000000 }; // fmin=5.645162MHz fmax=125MHz without range [83333334,87500000) // f in [5645162..83333333]+[87500000..125000000] max(ppm)=0.9 void calc_fabc(unsigned f,calc_fabc_t *p) { unsigned d,d1,d2,abc,fx,qm,q,s; unsigned long long lq; p->freq=0; fx=40000000; d1=(175000000-1+f)/f; d2=250000000/f; if (d1<2) d1=2; if (d2>31) d2=31; for(d=d1;d<=d2;d++) { lq=f*d; lq<<=17; abc=lq/fx; lq-=(unsigned long long)abc*fx; q=lq; if (2*q>fx) { q=fx-q; s=1; } else s=0; if (d==d1 || q<qm) { qm=q; abc+=s; p->sm[2]=(abc>>16)-4; p->sm[1]=(abc>>8)&255; p->sm[0]=abc&255; p->odiv=d-2; q/=2*d; q+=32768; q>>=16; if (s) q+=f; else q=f-q; p->freq=q; } } } //--------------------------------------------------------------------------- void test_apll() { double f=25.175e6; APLLParams prm[1]{}; calc_fabc_t p[1]{}; uint8_t a,b; double of,err; printf("f=%.6fMHz\n",f*1e-6); APLLCalcParams(f,prm,&a,&b,&of,&err); printf("sdm0=%3d sdm1=%3d sdm2=%2d o_div=%2d ", prm->sdm0,prm->sdm1,prm->sdm2,prm->o_div); printf("a=%2d b=%2d of=%.6fMHz err=%5.1f ppm=%5.2f\n", a,b,of*1e-6,abs(err),(of-f)/f*1e6); int N=2; // a=1 b=0 calc_fabc(N*f,p); p->freq/=N; printf("sdm0=%3d sdm1=%3d sdm2=%2d o_div=%2d" " of=%.6fMHz err=%5.1f ppm=%5.2f\n", p->sm[0],p->sm[1],p->sm[2],p->odiv,p->freq*1e-6, abs(p->freq-f),(p->freq-f)/f*1e6); } //--------------------------------------------------------------------------- int main(int argc, char *argv[]) { test_apll(); return 0; }
ps: ESP32 has hardware floats, but double will be calculated in software. So the calculation time will be even more longer.
The text was updated successfully, but these errors were encountered:
No branches or pull requests
FabGL/src/fabutils.cpp
Line 1753 in 1ad2713
I offer to simplify function APLLCalcParams to reduce computation time.
Here is example of possible alternative:
output:
code:
ps: ESP32 has hardware floats, but double will be calculated in software. So the calculation time will be even more longer.
The text was updated successfully, but these errors were encountered: