Rough sketch, on a PIC32:
//Basic operations:
// 1. 32-bit time base (TMR2/3): Timer 2/3 form a free-running 32-bit timebase for capturing and for 1pps generation (optional for debugging);
// 2. 32-bit input capture (IC1): Input capture 1 used to capture the 1pps, from which frequency measurements are taken;
// 3. 1pps generation(OC2, optional): OC2 in 32-bit mode used to generate a 1pps, for debugging and potential phase comparison with 1pps;
// 4. 16-bit PWM generation (OC1): used to drive the LO
// 5. oscillator to be disciplined is used to drive the mcu;
I can get it to cycle accurate - measuring its own crystal oscillator - to show that it works. I also got it to track a 1pps signal from a 12F675.
the use of 32-bit timer as the time base for capturing made life much easier, as you don't need to deal with atomicity.
the guts of the code:
Code: Select all
if (pps_arrived) { //new data as arrived
pps_arrived = 0; //reset the flag
ferr = freq - F_TGT; //capture the error term
ferr = avg_exp(ferr); //calculate the average error term
dc1 = ferr2dc16(ferr); //convert freq error to duty cycle (16bit)
pwm1_setdc(dc1); //update pwm1 duty cycle
fairly straight forward. the tricky part is that I did the math in terms of frequency error (measured frequency - the target frequency). the implementation is fairly minimalist - 20-ish files in the project and the main() has 50 lines of code + comments. the main loop has the few lines above + 4 lines for uart display. porting it to a blue pill would be fairly easy.
the next step is to hook up a real 1pps source to this thing and see how it goes.