@@ -421,6 +421,115 @@ void Configure_ClockGen(const clockconfig_t* config)
421
421
// 74.25 M= 2 N=11 Fvco=148.5 p=2 output = 74.25 (vfo=0)
422
422
}
423
423
424
+ void UpdatePLL (uint32_t pll , uint32_t m , uint32_t n , uint32_t pll_sel , uint32_t div , uint32_t y )
425
+ {
426
+ // pll = {1,2,3}
427
+ // m = {1,511}
428
+ // n = {1,4095}
429
+ // div = {1,127}
430
+ // y = {0,5}
431
+ /*
432
+ 1. Disable Y output
433
+ 2. Bypass PLLx
434
+ 3. Write new N/M values
435
+ 4. Disable bypass
436
+ 5. Set source PLL (Switch A)
437
+ 6. Write new Ydiv value
438
+ 7. Wait some arbitrary amount of time
439
+ 8. Re-enable Y (Switch B)
440
+ */
441
+ DEBUG (0 , "SetPLL(pll = %d, m = %d, n= %d, pll_sel = %d, div = %d, y = %d)" , pll , m , n , pll_sel , div , y );
442
+
443
+ // This PLL bit position is used in both register 3 and register 6
444
+ const uint8_t pll_conf_bit = 1 << (8 - pll );
445
+
446
+ DEBUG (2 , "Reading regs before switch" );
447
+ for (uint8_t addr = 0 ; addr < 24 ; addr ++ ) {
448
+ Read_CDCE906 (addr + 1 );
449
+ }
450
+
451
+ DEBUG (2 , "Making the switch" );
452
+
453
+ // Disable Y (keep nominal slew, non-inverted; Y div selection is reset)
454
+ Write_CDCE906 (19 + y , 0x30 );
455
+
456
+ // Bypass PLLx (read/modify/write to enable VCO bypass in the PLL MUX)
457
+ uint8_t reg3 = Read_CDCE906 (3 );
458
+ reg3 |= pll_conf_bit ;
459
+ Write_CDCE906 (3 , reg3 );
460
+
461
+ // Update M/N
462
+ uint8_t lo_m = m & 0xff ; // separate lower bytes
463
+ uint8_t lo_n = n & 0xff ;
464
+
465
+ uint8_t hi_m = (m >> 8 ) & 1 ; // isolate upper bits (1 for M, 4 for N)
466
+ uint8_t hi_n = (n >> (8 - 1 )) & (0xf << 1 ); // and move into place
467
+
468
+ uint8_t mn_base = 1 + (pll - 1 )* 3 ; // base register for PLL M/N settings
469
+
470
+ // read/modify/write keeping the upper 3 bits, which holds MUX/fVCOsel/PLL selection
471
+ uint8_t hi = Read_CDCE906 (mn_base + 2 ) & 0xe0 ;
472
+
473
+ Write_CDCE906 (mn_base + 0 , lo_m );
474
+ Write_CDCE906 (mn_base + 1 , lo_n );
475
+ Write_CDCE906 (mn_base + 2 , hi | hi_n | hi_m );
476
+
477
+ // Update VCO filter (read/modify/write, above 190Mhz we enable the fVCO filter)
478
+ const uint32_t fvco = 27000 * n / m ;
479
+ DEBUG (0 , "freq = %d" , fvco /div );
480
+ uint8_t reg6 = Read_CDCE906 (6 );
481
+ reg6 &= ~pll_conf_bit ;
482
+ reg6 |= (fvco > 190000 ) ? pll_conf_bit : 0 ;
483
+ Write_CDCE906 (6 , reg6 );
484
+
485
+ // Update source PLL (setting is split over registers 9 through 12)
486
+ uint8_t regPx = 9 + y ;
487
+ uint8_t shiftPx = 5 ;
488
+ switch (y )
489
+ {
490
+ case 2 : // reg 11
491
+ case 3 : // reg 11
492
+ case 4 : // reg 12
493
+ case 5 : // reg 12
494
+ regPx = 11 + y /4 ; // write reg 11/12
495
+ shiftPx = ((y & 1 ) ? 3 : 0 ); // odd Px in upper position
496
+ break ;
497
+ }
498
+
499
+ // Read/modify/write, updating the SWAPxy /Px
500
+ uint32_t valPx = Read_CDCE906 (regPx );
501
+ valPx &= ~(0x7 << shiftPx );
502
+ valPx |= (pll_sel << shiftPx );
503
+ Write_CDCE906 (regPx , valPx );
504
+
505
+ // Update Ydiv
506
+ Write_CDCE906 (13 + y , (div & 0x7f ));
507
+
508
+ // let clock settle
509
+ Timer_Wait (100 );
510
+
511
+ // Disable bypass PLLx (read/modify/write to mask the VCO bypass bit)
512
+ reg3 = Read_CDCE906 (3 );
513
+ reg3 &= ~pll_conf_bit ;
514
+ Write_CDCE906 (3 , reg3 );
515
+
516
+ // let clock settle
517
+ Timer_Wait (100 );
518
+
519
+ // Enable Y (nominal slew, non-inverted, static Ydiv selection, Yx enabled)
520
+ Write_CDCE906 (19 + y , 0x30 | 0x08 | (y & 7 ));
521
+
522
+ // let clock settle
523
+ Timer_Wait (100 );
524
+
525
+ DEBUG (2 , "Reading regs after switch" );
526
+ for (uint8_t addr = 0 ; addr < 24 ; addr ++ ) {
527
+ Read_CDCE906 (addr + 1 );
528
+ }
529
+
530
+ DEBUG (1 , "Switch done" );
531
+ }
532
+
424
533
void Write_CH7301 (uint8_t address , uint8_t data )
425
534
{
426
535
uint8_t rab = 0x80 | (address & 0x7F );
0 commit comments