New issue
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
Sayma HMC830: update interface and register writes. #1068
Changes from all commits
2621782
ddb4752
2db8280
a154089
3c9f64c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,3 @@ | ||
/* | ||
* HMC830 config: | ||
* 100MHz input, 1.2GHz output | ||
* fvco = (refclk / r_divider) * n_divider | ||
* fout = fvco/2 | ||
* | ||
* HMC7043 config: | ||
* dac clock: 600MHz (div=2) | ||
* fpga clock: 150MHz (div=8) | ||
* sysref clock: 9.375MHz (div=128) | ||
*/ | ||
|
||
mod clock_mux { | ||
use board_misoc::csr; | ||
|
||
|
@@ -30,27 +18,6 @@ mod clock_mux { | |
mod hmc830 { | ||
use board_misoc::{csr, clock}; | ||
|
||
const HMC830_WRITES: [(u8, u32); 18] = [ | ||
(0x0, 0x20), | ||
(0x1, 0x2), | ||
(0x2, 0x2), // r_divider | ||
(0x5, 0x1628), | ||
(0x5, 0x60a0), | ||
(0x5, 0xe110), | ||
(0x5, 0x2818), | ||
(0x5, 0xf88), | ||
(0x5, 0x7fb0), | ||
(0x5, 0x0), | ||
(0x6, 0x303ca), | ||
(0x7, 0x14d), | ||
(0x8, 0xc1beff), | ||
(0x9, 0x153fff), | ||
(0xa, 0x2046), | ||
(0xb, 0x7c061), | ||
(0xf, 0x81), | ||
(0x3, 0x30), // n_divider | ||
]; | ||
|
||
fn spi_setup() { | ||
unsafe { | ||
while csr::converter_spi::idle_read() == 0 {} | ||
|
@@ -112,19 +79,65 @@ mod hmc830 { | |
Ok(()) | ||
} | ||
|
||
pub fn init() -> Result<(), &'static str> { | ||
pub fn init() { | ||
// Configure HMC830 for integer-N operation | ||
// See "PLLs with integrated VCO- RF Applications Product & Operating | ||
// Guide" | ||
spi_setup(); | ||
info!("loading configuration..."); | ||
for &(addr, data) in HMC830_WRITES.iter() { | ||
write(addr, data); | ||
} | ||
info!("loading HMC830 configuration..."); | ||
|
||
write(0x0, 0x20); // software reset | ||
write(0x0, 0x00); // normal operation | ||
write(0x6, 0x307ca); // integer-N mode (NB data sheet table 5.8 not self-consistent) | ||
write(0x7, 0x4d); // digital lock detect, 1/2 cycle window (6.5ns window) | ||
write(0x9, 0x2850); // charge pump: 1.6mA, no offset | ||
write(0xa, 0x2045); // for wideband devices like the HMC830 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess you are OK with not doing a review of the values, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra reviews are always welcome. However, in this case I don't think it's necessary. I've checked this all through against the data sheet carefully and tested it on my hardware. I'm inclined to say that if it works reliably on other HW as well then further review isn't worth the time it would take (but if you have spare time then go for it!). |
||
write(0xb, 0x7c061); // for HMC830 | ||
|
||
// VCO subsystem registers | ||
// NB software reset does not seem to reset these registers, so always | ||
// program them all! | ||
write(0x5, 0xf88); // 1: defaults | ||
write(0x5, 0x6010); // 2: mute output until output divider set | ||
write(0x5, 0x2818); // 3: wideband PLL defaults | ||
write(0x5, 0x60a0); // 4: HMC830 magic value | ||
write(0x5, 0x1628); // 5: HMC830 magic value | ||
write(0x5, 0x7fb0); // 6: HMC830 magic value | ||
write(0x5, 0x0); // ready for VCO auto-cal | ||
|
||
info!(" ...done"); | ||
} | ||
|
||
pub fn set_dividers(r_div: u32, n_div: u32, m_div: u32, out_div: u32) { | ||
// VCO frequency: f_vco = (f_ref/r_div)*(n_int + n_frac/2**24) | ||
// VCO frequency range [1.5GHz, 3GHz] | ||
// Output frequency: f_out = f_vco/out_div | ||
// Max PFD frequency: 125MHz for integer-N, 100MHz for fractional | ||
// (mode B) | ||
// Max reference frequency: 350MHz, however f_ref >= 200MHz requires | ||
// setting 0x08[21]=1 | ||
// | ||
// :param r_div: reference divider [1, 16383] | ||
// :param n_div: VCO divider, integer part. Integer-N mode: [16, 2**19-1] | ||
// fractional mode: [20, 2**19-4] | ||
// :param m_div: VCO divider, fractional part [0, 2**24-1] | ||
// :param out_div: output divider [1, 62] (0 mutes output) | ||
info!("setting HMC830 dividers..."); | ||
write(0x5, 0x6010 + (out_div << 7) + (((out_div <= 2) as u32) << 15)); | ||
write(0x5, 0x0); // ready for VCO auto-cal | ||
write(0x2, r_div); | ||
write(0x4, m_div); | ||
write(0x3, n_div); | ||
|
||
info!(" ...done"); | ||
} | ||
|
||
pub fn check_locked() -> Result<(), &'static str> { | ||
info!("waiting for HMC830 lock..."); | ||
let t = clock::get_ms(); | ||
info!("waiting for lock..."); | ||
while read(0x12) & 0x02 == 0 { | ||
if clock::get_ms() > t + 2000 { | ||
error!(" lock timeout. Register dump:"); | ||
error!("lock timeout. Register dump:"); | ||
for addr in 0x00..0x14 { | ||
// These registers don't exist (in the data sheet at least) | ||
if addr == 0x0d || addr == 0x0e { continue; } | ||
|
@@ -142,10 +155,11 @@ mod hmc830 { | |
pub mod hmc7043 { | ||
use board_misoc::csr; | ||
|
||
const DAC_CLK_DIV: u32 = 2; | ||
const FPGA_CLK_DIV: u32 = 8; | ||
const SYSREF_DIV: u32 = 128; | ||
const HMC_SYSREF_DIV: u32 = SYSREF_DIV*8; // Must be <= 4MHz | ||
// All frequencies assume 1.2GHz HMC830 output | ||
const DAC_CLK_DIV: u32 = 2; // 600MHz | ||
const FPGA_CLK_DIV: u32 = 8; // 150MHz | ||
const SYSREF_DIV: u32 = 128; // 9.375MHz | ||
const HMC_SYSREF_DIV: u32 = SYSREF_DIV*8; // 1.171875MHz (must be <= 4MHz) | ||
|
||
// enabled, divider, analog phase shift, digital phase shift | ||
const OUTPUT_CONFIG: [(bool, u32, u8, u8); 14] = [ | ||
|
@@ -315,7 +329,9 @@ pub fn init() -> Result<(), &'static str> { | |
/* do not use other SPI devices before HMC830 SPI mode selection */ | ||
hmc830::select_spi_mode(); | ||
hmc830::detect()?; | ||
hmc830::init()?; | ||
hmc830::init(); | ||
hmc830::set_dividers(1, 24, 0, 2); // 100MHz ref, 1.2GHz out | ||
hmc830::check_locked()?; | ||
|
||
hmc7043::enable()?; | ||
hmc7043::detect()?; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That part of the comment shouldn't be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I'm happy to revert that change.
My thinking was:
* fvco = (refclk / r_divider) * n_divider
that's information is now here, which seems like a better place for it: https://github.com/hartytp/artiq/blob/2621782f8c6bcf05f0e0ca85df42704922e5945b/artiq/firmware/libboard_artiq/hmc830_7043.rs#L113
That information is now here https://github.com/hartytp/artiq/blob/2621782f8c6bcf05f0e0ca85df42704922e5945b/artiq/firmware/libboard_artiq/hmc830_7043.rs#L161-L182 and here https://github.com/hartytp/artiq/blob/2621782f8c6bcf05f0e0ca85df42704922e5945b/artiq/firmware/libboard_artiq/hmc830_7043.rs#L335
Personally, I don't like duplicating this kind of information in comments at the top of the file, since it's easy for people to forget to update them when changing the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To check, which bit of the comment do you want back?
or this bit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry. I meant just the hmc7043 comment should not get lost.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I'll reintroduce that if you'd prefer.
This still seems a bit redundant to me given https://github.com/hartytp/artiq/blob/ddb47524fb030c88ed4bd82f8dfdbd602ffd7366/artiq/firmware/libboard_artiq/hmc830_7043.rs#L159-L180 What about I just add the frequencies to the comments where the divider values are defined?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perfect. I just wanted to avoid having to calculate the frequencies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done