fn vco_setup_fractional() {
        let rcc = MockRcc::new();

        let pllsrc = 16_000_000; // PLL source frequency eg. 16MHz crystal
        let pll_p_target = 48_000 * 256; // Target clock
        let pll_q_target = 48_000 * 128; // Target clock
        let pll_r_target = 48_000 * 63; // Target clock
        let output = pll_p_target; // PLL output frequency (P_CK)
        println!(
            "PLL2/3 {} MHz -> {} MHz",
            pllsrc as f32 / 1e6,
            output as f32 / 1e6
        );

        // ----------------------------------------

        // VCO Setup
        println!("Fractional");
        let (ref_x_ck, pll_x_m, pll_x_p, vco_ck_target) = vco_setup! {
            ITERATIVE: pllsrc, output, rcc, vcosel, pllrge
        };
        let input = pllsrc as f32 / pll_x_m as f32;

        // Feedback divider. Integer only
        let pll_x_n = vco_ck_target / ref_x_ck;
        let pll_x_fracn = calc_fracn(
            input as f32,
            pll_x_n as f32,
            pll_x_p as f32,
            output as f32,
        );
        println!("FRACN Divider {}", pll_x_fracn);
        // Resulting achieved vco_ck
        let vco_ck_achieved = calc_vco_ck(ref_x_ck, pll_x_n, pll_x_fracn);

        // Calulate additional output dividers
        let pll_x_q = calc_ck_div(
            PllConfigStrategy::Fractional,
            vco_ck_achieved,
            pll_q_target,
        );
        let pll_x_r = calc_ck_div(
            PllConfigStrategy::Fractional,
            vco_ck_achieved,
            pll_r_target,
        );

        // ----------------------------------------

        // Input
        println!("M Divider {}", pll_x_m);
        println!("==> Input {} MHz", input / 1e6);
        println!();

        println!("VCO CK Target {} MHz", vco_ck_target as f32 / 1e6);
        println!("VCO CK Achieved {} MHz", vco_ck_achieved as f32 / 1e6);
        println!();

        // Output
        let output_p = vco_ck_achieved as f32 / pll_x_p as f32;
        println!("P Divider {}", pll_x_p);
        println!("==> Output P {} MHz", output_p / 1e6);
        println!();

        // The P_CK should be very close to the target with a finely tuned FRACN
        //
        // The other clocks accuracy will vary depending on how close
        // they are to an integer fraction of the P_CK
        assert!(output_p <= pll_p_target as f32);
        let error = output_p - pll_p_target as f32;
        assert!(f32::abs(error) < (pll_p_target as f32 / 500_000.0)); // < ±.0002% = 2ppm error

        let output_q = vco_ck_achieved as f32 / pll_x_q as f32;
        println!("Q Divider {}", pll_x_q);
        println!("==> Output Q {} MHz", output_q / 1e6);
        println!();
        assert!(output_q <= pll_q_target as f32);

        let output_r = vco_ck_achieved as f32 / pll_x_r as f32;
        println!("R Divider {}", pll_x_r);
        println!("==> Output R {} MHz", output_r / 1e6);
        println!();
        assert!(output_r <= pll_r_target as f32);
    }
/// Test PFD input frequency PLL and VCO output frequency
Test PFD input frequency PLL and VCO output frequency
Test PFD input frequency PLL and VCO output frequency
fn vco_setup_fractional() {
        let rcc = MockRcc::new();
        let pllsrc = 16_000_000; // PLL source frequency eg. 16MHz crystal
        let pll_p_target = 48_000 * 256; // Target clock
        let pll_q_target = 48_000 * 128; // Target clock
        let pll_r_target = 48_000 * 63; // Target clock
        let output = pll_p_target; // PLL output frequency (P_CK)
        println!(
            "PLL2/3 {} MHz -> {} MHz",
            pllsrc as f32 / 1e6,
            output as f32 / 1e6
        );
        // ----------------------------------------
        // VCO Setup
        println!("Fractional");
        let (ref_x_ck, pll_x_m, pll_x_p, vco_ck_target) = vco_setup! {
            ITERATIVE: pllsrc, output, rcc, vcosel, pllrge
        };
        let input = pllsrc as f32 / pll_x_m as f32;
        // Feedback divider. Integer only
        let pll_x_n = vco_ck_target / ref_x_ck;
        let pll_x_fracn = calc_fracn(
            input as f32,
            pll_x_n as f32,
            pll_x_p as f32,
            output as f32,
        );
        println!("FRACN Divider {}", pll_x_fracn);
        // Resulting achieved vco_ck
        let vco_ck_achieved = calc_vco_ck(ref_x_ck, pll_x_n, pll_x_fracn);
        // Calulate additional output dividers
        let pll_x_q = calc_ck_div(
            PllConfigStrategy::Fractional,
            vco_ck_achieved,
            pll_q_target,
        );
        let pll_x_r = calc_ck_div(
            PllConfigStrategy::Fractional,
            vco_ck_achieved,
            pll_r_target,
        );
        // ----------------------------------------
        // Input
        println!("M Divider {}", pll_x_m);
        println!("==> Input {} MHz", input / 1e6);
        println!();
        println!("VCO CK Target {} MHz", vco_ck_target as f32 / 1e6);
        println!("VCO CK Achieved {} MHz", vco_ck_achieved as f32 / 1e6);
        println!();
        // Output
        let output_p = vco_ck_achieved as f32 / pll_x_p as f32;
        println!("P Divider {}", pll_x_p);
        println!("==> Output P {} MHz", output_p / 1e6);
        println!();
        // The P_CK should be very close to the target with a finely tuned FRACN
        //
        // The other clocks accuracy will vary depending on how close
        // they are to an integer fraction of the P_CK
        assert!(output_p <= pll_p_target as f32);
        let error = output_p - pll_p_target as f32;
        assert!(f32::abs(error) < (pll_p_target as f32 / 500_000.0)); // < ±.0002% = 2ppm error
        let output_q = vco_ck_achieved as f32 / pll_x_q as f32;
        println!("Q Divider {}", pll_x_q);
        println!("==> Output Q {} MHz", output_q / 1e6);
        println!();
        assert!(output_q <= pll_q_target as f32);
        let output_r = vco_ck_achieved as f32 / pll_x_r as f32;
        println!("R Divider {}", pll_x_r);
        println!("==> Output R {} MHz", output_r / 1e6);
        println!();
        assert!(output_r <= pll_r_target as f32);
    }
fn vco_setup_fractional ( ) { let rcc = MockRcc :: new ( ) ; let pllsrc = 16_000_000 ; // PLL source frequency eg. 16MHz crystal let pll_p_target = 48_000 * 256 ; // Target clock let pll_q_target = 48_000 * 128 ; // Target clock let pll_r_target = 48_000 * 63 ; // Target clock let output = pll_p_target ; // PLL output frequency (P_CK) println ! ( " " pllsrc as f32 1e6 output as f32 1e6 ) ; // ---------------------------------------- // VCO Setup println ! ( " " ) ; let ( ref_x_ck , pll_x_m , pll_x_p , vco_ck_target ) = vco_setup ! { ITERATIVE pllsrc output rcc vcosel pllrge } ; let input = pllsrc as f32 / pll_x_m as f32 ; // Feedback divider. Integer only let pll_x_n = vco_ck_target / ref_x_ck ; let pll_x_fracn = calc_fracn ( input as f32 , pll_x_n as f32 , pll_x_p as f32 , output as f32 , ) ; println ! ( " " pll_x_fracn ) ; // Resulting achieved vco_ck let vco_ck_achieved = calc_vco_ck ( ref_x_ck , pll_x_n , pll_x_fracn ) ; // Calulate additional output dividers let pll_x_q = calc_ck_div ( PllConfigStrategy :: Fractional , vco_ck_achieved , pll_q_target , ) ; let pll_x_r = calc_ck_div ( PllConfigStrategy :: Fractional , vco_ck_achieved , pll_r_target , ) ; // ---------------------------------------- // Input println ! ( " " pll_x_m ) ; println ! ( " " input 1e6 ) ; println ! ( ) ; println ! ( " " vco_ck_target as f32 1e6 ) ; println ! ( " " vco_ck_achieved as f32 1e6 ) ; println ! ( ) ; // Output let output_p = vco_ck_achieved as f32 / pll_x_p as f32 ; println ! ( " " pll_x_p ) ; println ! ( " " output_p 1e6 ) ; println ! ( ) ; // The P_CK should be very close to the target with a finely tuned FRACN // // The other clocks accuracy will vary depending on how close // they are to an integer fraction of the P_CK assert ! ( output_p pll_p_target as f32 ) ; let error = output_p - pll_p_target as f32 ; assert ! ( f32 abs ( error ) ( pll_p_target as f32 500_000.0 ) ) ; // < ±.0002% = 2ppm error let output_q = vco_ck_achieved as f32 / pll_x_q as f32 ; println ! ( " " pll_x_q ) ; println ! ( " " output_q 1e6 ) ; println ! ( ) ; assert ! ( output_q pll_q_target as f32 ) ; let output_r = vco_ck_achieved as f32 / pll_x_r as f32 ; println ! ( " " pll_x_r ) ; println ! ( " " output_r 1e6 ) ; println ! ( ) ; assert ! ( output_r pll_r_target as f32 ) ; }
Test PFD input frequency PLL and VCO output frequency
Test PFD input frequency PLL and VCO output frequency