10
10
* See the file COPYING for more details, or visit <http://unlicense.org>.
11
11
*/
12
12
13
+ /*
14
+ * PLL nominally runs at the same frequency as the timer's clock but with a
15
+ * 16.16 fixed-point representation. This allows for lots of precision in phase
16
+ * error calcuations. NOMINAL_PLL_PHASE_STEP is the PLL phase increment which
17
+ * causes the PLL to exactly equal the timer's frequency.
18
+ */
19
+ #define NOMINAL_PLL_PHASE_STEP (1 << 16)
20
+
13
21
/* A DMA buffer for running a timer associated with a floppy-data I/O pin. */
14
22
struct dma_ring {
15
23
/* Current state of DMA (RDATA):
@@ -33,7 +41,12 @@ struct dma_ring {
33
41
uint16_t cons ;
34
42
union {
35
43
uint16_t prod ; /* dma_rd: our producer index for flux samples */
36
- uint16_t prev_sample ; /* dma_wr: previous CCRx sample value */
44
+ struct {
45
+ uint32_t phase_step ; /* PLL period */
46
+ int32_t phase_integral ; /* PLL's running sum of phase errors */
47
+ uint32_t prev_bc_left ; /* PLL timestamp of left edge of previous bitcell */
48
+ uint32_t curr_bc_left ; /* PLL timestamp of left edge of current bitcell */
49
+ } wr ;
37
50
};
38
51
/* DMA ring buffer of timer values (ARR or CCRx). */
39
52
uint16_t buf [1024 ];
@@ -401,6 +414,10 @@ static void wdata_start(void)
401
414
}
402
415
403
416
dma_wr -> state = DMA_starting ;
417
+ dma_wr -> wr .phase_step = NOMINAL_PLL_PHASE_STEP ;
418
+ dma_wr -> wr .phase_integral = 0 ;
419
+ dma_wr -> wr .prev_bc_left = 0 ;
420
+ dma_wr -> wr .curr_bc_left = 0 ;
404
421
405
422
/* Start timer. */
406
423
tim_wdata -> egr = TIM_EGR_UG ;
@@ -643,13 +660,15 @@ static void IRQ_rdata_dma(void)
643
660
static void IRQ_wdata_dma (void )
644
661
{
645
662
const uint16_t buf_mask = ARRAY_SIZE (dma_rd -> buf ) - 1 ;
646
- uint16_t cons , prod , prev , next ;
663
+ uint16_t cons , prod ;
647
664
uint32_t bc_dat = 0 , bc_prod ;
648
665
uint32_t * bc_buf = image -> bufs .write_bc .p ;
649
666
unsigned int sync = image -> sync ;
650
667
unsigned int bc_bufmask = (image -> bufs .write_bc .len / 4 ) - 1 ;
651
- int curr , cell = image -> write_bc_ticks ;
652
668
struct write * write = NULL ;
669
+ uint32_t next_edge , distance_from_prev_bc_left , distance_from_curr_bc_left ;
670
+ uint32_t bc_step ;
671
+ int32_t phase_error ;
653
672
654
673
/* Clear DMA peripheral interrupts. */
655
674
dma1 -> ifcr = DMA_IFCR_CGIF (dma_wdata_ch );
@@ -669,27 +688,56 @@ static void IRQ_wdata_dma(void)
669
688
}
670
689
671
690
/* Process the flux timings into the raw bitcell buffer. */
672
- prev = dma_wr -> prev_sample ;
673
691
bc_prod = image -> bufs .write_bc .prod ;
674
692
bc_dat = image -> write_bc_window ;
675
693
for (cons = dma_wr -> cons ; cons != prod ; cons = (cons + 1 ) & buf_mask ) {
676
- next = dma_wr -> buf [cons ];
677
- curr = (int16_t )(next - prev ) - (cell >> 1 );
678
- if (unlikely (curr < 0 )) {
679
- /* Runt flux, much shorter than bitcell clock. Merge it forward. */
694
+ /* Calculate duration of a bitcell using the PLL's current period */
695
+ bc_step = dma_wr -> wr .phase_step * (uint32_t )image -> write_bc_ticks ;
696
+
697
+ /*
698
+ * Incoming sample ticks are shifted up 16-bits to match PLL's internal
699
+ * precision
700
+ */
701
+ next_edge = (uint32_t )dma_wr -> buf [cons ] << 16 ;
702
+
703
+ /*
704
+ * If this is the first pulse after WGATE was asserted, treat it as
705
+ * perfectly in phase.
706
+ */
707
+ if (dma_wr -> wr .prev_bc_left == 0 && dma_wr -> wr .curr_bc_left == 0 ) {
708
+ dma_wr -> wr .curr_bc_left = next_edge - (bc_step / 2 );
709
+ dma_wr -> wr .prev_bc_left = dma_wr -> wr .curr_bc_left - bc_step ;
710
+ }
711
+
712
+ /* By computing distance, wraparound is accounted for naturally. */
713
+ distance_from_prev_bc_left = next_edge - dma_wr -> wr .prev_bc_left ;
714
+
715
+ /* If the next edge would fall within the previous bitcell, ignore it. */
716
+ if (distance_from_prev_bc_left < (dma_wr -> wr .curr_bc_left - dma_wr -> wr .prev_bc_left ))
717
+ {
680
718
continue ;
681
719
}
682
- prev = next ;
683
- while ((curr -= cell ) > 0 ) {
720
+
721
+ /* Advance to the current bitcell */
722
+ distance_from_curr_bc_left = next_edge - dma_wr -> wr .curr_bc_left ;
723
+
724
+ /* Record zeros for each bitcell that passed before this pulse */
725
+ while (distance_from_curr_bc_left > bc_step )
726
+ {
684
727
bc_dat <<= 1 ;
685
728
bc_prod ++ ;
686
- if (!(bc_prod & 31 ))
687
- bc_buf [((bc_prod - 1 ) / 32 ) & bc_bufmask ] = htobe32 (bc_dat );
729
+
730
+ if (!(bc_prod & 31 ))
731
+ bc_buf [((bc_prod - 1 ) / 32 ) & bc_bufmask ] = htobe32 (bc_dat );
732
+
733
+ distance_from_curr_bc_left -= bc_step ;
734
+ dma_wr -> wr .curr_bc_left += bc_step ;
688
735
}
689
- curr += cell >> 1 ; /* remove the 1/2-cell bias */
690
- prev -= curr >> 2 ; /* de-jitter/precomp: carry 1/4 of phase error */
736
+
737
+ /* Record a one for this bitcell */
691
738
bc_dat = (bc_dat << 1 ) | 1 ;
692
739
bc_prod ++ ;
740
+
693
741
switch (sync ) {
694
742
case SYNC_fm :
695
743
/* FM clock sync clock byte is 0xc7. Check for:
@@ -704,6 +752,63 @@ static void IRQ_wdata_dma(void)
704
752
}
705
753
if (!(bc_prod & 31 ))
706
754
bc_buf [((bc_prod - 1 ) / 32 ) & bc_bufmask ] = htobe32 (bc_dat );
755
+
756
+ /*
757
+ * Calculate per-tick phase error.
758
+ *
759
+ * Start with total phase error accumulated since the last flux pulse.
760
+ * Assume that error was introduced evenly by each clock tick that
761
+ * occurred during that time. Divide the total phase error by the
762
+ * number of ticks to find average per-tick phase error.
763
+ */
764
+ phase_error = ((int32_t )distance_from_curr_bc_left - ((int32_t )bc_step / 2 )) / (int32_t )image -> write_bc_ticks ;
765
+
766
+ /* Adjust bitcell history for next iteration */
767
+ dma_wr -> wr .prev_bc_left = dma_wr -> wr .curr_bc_left ;
768
+ dma_wr -> wr .curr_bc_left += bc_step ;
769
+
770
+ /* Accumulate error into integral, saturating as necessary */
771
+ if (dma_wr -> wr .phase_integral > 0 && phase_error > INT32_MAX - dma_wr -> wr .phase_integral ) {
772
+ dma_wr -> wr .phase_integral = INT32_MAX ;
773
+ } else if (dma_wr -> wr .phase_integral < 0 && phase_error < INT32_MIN - dma_wr -> wr .phase_integral ) {
774
+ dma_wr -> wr .phase_integral = INT32_MIN ;
775
+ } else {
776
+ dma_wr -> wr .phase_integral += phase_error ;
777
+ }
778
+
779
+ /*
780
+ * Calculate next phase_step by applying a PI loop using the constants
781
+ * from the following analysis (based on
782
+ * https://www.dsprelated.com/showarticle/967.php):
783
+ *
784
+ * f_s = NCO base frequency
785
+ * k_p = phase detector gain
786
+ * k_nco = NCO feedback scaler
787
+ * zeta = loop dampening coefficient
788
+ * f_n = loop natural frequency
789
+ * k_l = proportional scaler
790
+ * k_i = integral scaler
791
+ *
792
+ * w_n = f_n * 2 * pi
793
+ * Ts = 1 / f_s
794
+ * k_l = 2 * zeta * w_n * Ts / (k_p * k_nco)
795
+ * k_i = w_n^2 * Ts^2 / (k_p * k_nco)
796
+ *
797
+ * Assumptions:
798
+ * f_s = 72,000,000 Hz
799
+ * k_p = 1.0
800
+ * k_nco = 1.0
801
+ * f_n = 1,440,000 Hz (2% of f_s to allow for moderate freq offset)
802
+ * zeta = 0.25 (strong jitter rejection for write precomp)
803
+ *
804
+ * Results:
805
+ * k_l = 0.06283185307 ~= 1/16
806
+ * k_i = 0.01579136704 ~= 1/64
807
+ */
808
+ dma_wr -> wr .phase_step = (uint32_t )(
809
+ (int32_t )NOMINAL_PLL_PHASE_STEP
810
+ + phase_error / 16
811
+ + dma_wr -> wr .phase_integral / 64 );
707
812
}
708
813
709
814
if (bc_prod & 31 )
@@ -718,14 +823,12 @@ static void IRQ_wdata_dma(void)
718
823
/* Initialise decoder state for the start of the next write. */
719
824
bc_prod = (bc_prod + 31 ) & ~31 ;
720
825
bc_dat = ~0 ;
721
- prev = 0 ;
722
826
}
723
827
724
828
/* Save our progress for next time. */
725
829
image -> write_bc_window = bc_dat ;
726
830
image -> bufs .write_bc .prod = bc_prod ;
727
831
dma_wr -> cons = cons ;
728
- dma_wr -> prev_sample = prev ;
729
832
}
730
833
731
834
/*
0 commit comments