User Tools

Site Tools


altso3


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
altso3 [2026/06/23 02:23] adminaltso3 [2026/07/18 04:17] (current) admin
Line 1: Line 1:
 ====== AltSO3 ====== ====== AltSO3 ======
  
 +Exploring modern alternatives to the Kenwood SO-3 TCXO. Watch this space, maybe?
  
-==== Programming ==== +{{:altso3:altso3_v001.jpeg?600 |}}
-Micropython code for programming the MS5351M. Not yet tested. +
- +
-<file python main.py> +
-import machine +
-import time +
- +
-I2C_ADDR = 0x60 # Default Si5351A I2C address +
-I2C_SDA_PIN = 8   # RP2040 GP8 +
-I2C_SCL_PIN = 9   # RP2040 GP9 +
- +
-def setup_si5351(i2c): +
-    def write_reg(reg, val): +
-        i2c.writeto_mem(I2C_ADDR, reg, bytes([val])) +
- +
-    # 1. Disable all outputs +
-    write_reg(3, 0xFF) +
- +
-    # 2. Power down all output drivers +
-    for reg in range(16, 24): +
-        write_reg(reg, 0x80) +
- +
-    # 3. Calculate and configure PLLA registers for 624 MHz +
-    # Multiplier: a=24, b=24, c=25 +
-    a_pll, b_pll, c_pll = 24, 24, 25 +
-    p1_pll = 128 * a_pll + int(128 * b_pll / c_pll) - 512 +
-    p2_pll = 128 * b_pll - c_pll * int(128 * b_pll / c_pll) +
-    p3_pll = c_pll +
- +
-    write_reg(26, (p3_pll >> 8) & 0xFF) +
-    write_reg(27, p3_pll & 0xFF) +
-    write_reg(28, ((p1_pll >> 16) & 0x03) (((p2_pll >> 16) & 0x03) << 4)) +
-    write_reg(29, (p1_pll >> 8) & 0xFF) +
-    write_reg(30, p1_pll & 0xFF) +
-    write_reg(31, (((p3_pll >> 16) & 0x0F) << 4) | ((p2_pll >> 16) & 0x0F)) +
-    write_reg(32, (p2_pll >> 8) & 0xFF) +
-    write_reg(33, p2_pll & 0xFF) +
- +
-    # 4. Calculate and configure MultiSynth 0 registers for divide-by-40 +
-    # Divider: a=40, b=0, c=1 +
-    a_ms, b_ms, c_ms = 40, 0, 1 +
-    p1_ms = 128 * a_ms + int(128 * b_ms / c_ms) - 512 +
-    p2_ms = 128 * b_ms - c_ms * int(128 * b_ms / c_ms) +
-    p3_ms = c_ms +
- +
-    write_reg(42, (p3_ms >> 8) & 0xFF) +
-    write_reg(43, p3_ms & 0xFF) +
-    write_reg(44, ((p1_ms >> 16) & 0x03) | (((p2_ms >> 16) & 0x03) << 4)) +
-    write_reg(45, (p1_ms >> 8) & 0xFF) +
-    write_reg(46, p1_ms & 0xFF) +
-    write_reg(47, (((p3_ms >> 16) & 0x0F) << 4) | ((p2_ms >> 16) & 0x0F)) +
-    write_reg(48, (p2_ms >> 8) & 0xFF) +
-    write_reg(49, p2_ms & 0xFF) +
- +
-    # 5. Connect MS0 to CLK0, Power Up, Integer Mode, PLLA Source, 8mA drive +
-    # 0x4F = 0b01001111 +
-    write_reg(16, 0x4F) +
- +
-    # 6. Reset PLLA +
-    write_reg(177, 0x20) +
- +
-    # 7. Enable CLK0 +
-    write_reg(3, 0xFE) +
- +
-    print("Success: Si5351A configured to output 15.6 MHz on CLK0 in RAM."+
- +
-def burn_to_nvram(i2c): +
-    """ +
-    WARNING: The Si5351A NVRAM is One-Time Programmable (OTP). +
-    This permanently burns the current RAM configuration into the chip. +
-    """ +
-    print("⚠️ WARNING: Initiating NVRAM burn sequence..."+
-    print("This is a One-Time Programmable (OTP) operation!"+
-    time.sleep(3) # Give user a chance to interrupt execution (Ctrl+C) if accidental +
-     +
-    def write_reg(reg, val): +
-        i2c.writeto_mem(I2C_ADDR, reg, bytes([val])) +
-         +
-    # Write 0xC0 to register 161 (NVM_WRITE) to trigger NVRAM burn +
-    write_reg(161, 0xC0) +
-    time.sleep(1) # Wait for NVM burn to complete +
-    print("✅ NVRAM burn sequence completed. This configuration is now permanent."+
- +
-if __name__ == "__main__": +
-    # Initialize I2C bus 0 +
-    i2c = machine.I2C(0, scl=machine.Pin(I2C_SCL_PIN), sda=machine.Pin(I2C_SDA_PIN), freq=400000) +
-     +
-    # 1. Configure the RAM first to test the output +
-    setup_si5351(i2c) +
-     +
-    # 2. ⚠️ DANGER ZONE: Uncomment the line below ONLY AFTER verifying the 15.6 MHz  +
-    # output with an oscilloscope or frequency counter. +
-    # burn_to_nvram(i2c) +
-</file> +
- +
-<file python mainv2.py> +
-import machine +
-import time +
- +
-I2C_ADDR = 0x60 +
-I2C_SDA_PIN = 8 +
-I2C_SCL_PIN = 9 +
- +
-# --- Si5351 Register Map --- +
-REG_ENABLE_CTRL = 3 +
-REG_CLK0_CTRL = 16 +
-REG_PLL_A_PARAMS = 26 +
-REG_MS0_PARAMS = 42 +
-REG_NVM_BURN = 161 +
-REG_PLL_RESET = 177 +
-REG_CRYSTAL_LOAD = 183 +
- +
-def calc_fractional_regs(a, b, c): +
-    """Calculates the 8 bytes of register data for Si5351 PLLs and MultiSynths.""" +
-    # Use floor division (//) for exact integer math, avoiding float inaccuracies +
-    p1 = 128 * a + ((128 * b) // c) - 512 +
-    p2 = 128 * b - c * ((128 * b) // c) +
-    p3 = c +
- +
-    # Return as a bytearray so it can be sent in a single I2C block write +
-    return bytes([ +
-        (p3 >> 8) & 0xFF, +
-        p3 & 0xFF, +
-        ((p1 >> 16) & 0x03) | (((p2 >> 16) & 0x03) << 4), +
-        (p1 >> 8) & 0xFF, +
-        p1 & 0xFF, +
-        (((p3 >> 16) & 0x0F) << 4) | ((p2 >> 16) & 0x0F), +
-        (p2 >> 8) & 0xFF, +
-        p2 & 0xFF +
-    ]) +
- +
-def setup(i2c): +
-    def write_reg(reg, val): +
-        i2c.writeto_mem(I2C_ADDR, reg, bytes([val])) +
- +
-    # 1. Disable all outputs and power down clocks safely +
-    write_reg(REG_ENABLE_CTRL, 0xFF) +
-    for reg in range(16, 24): +
-        write_reg(reg, 0x80) +
- +
-    # 2. Set Crystal Load Capacitance to 10pF +
-    # 0xD2 sets 10pF (11b) while preserving the required reserved bits (010010b) +
-    write_reg(REG_CRYSTAL_LOAD, 0xD2) +
- +
-    # 3. Configure PLLA (Multiplier: a=24, b=24, c=25) +
-    plla_regs = calc_fractional_regs(24, 24, 25) +
-    i2c.writeto_mem(I2C_ADDR, REG_PLL_A_PARAMS, plla_regs) +
- +
-    # 4. Configure MultiSynth0 (Divider: a=40, b=0, c=1) +
-    ms0_regs = calc_fractional_regs(40, 0, 1) +
-    i2c.writeto_mem(I2C_ADDR, REG_MS0_PARAMS, ms0_regs) +
- +
-    # 5. Power up CLK0, set integer mode, route to PLLA +
-    write_reg(REG_CLK0_CTRL, 0x4F) +
- +
-    # 6. Reset PLLA to apply frequency parameters +
-    write_reg(REG_PLL_RESET, 0x20) +
- +
-    # 7. Re-enable CLK0 Output +
-    write_reg(REG_ENABLE_CTRL, 0xFE) +
- +
-    print("Success: Si5351 configured for 15.6 MHz on CLK0."+
- +
-def burn(i2c): +
-    def write_reg(reg, val): +
-        i2c.writeto_mem(I2C_ADDR, reg, bytes([val])) +
-         +
-    print("Initiating NVM Burn sequence..."+
-    write_reg(REG_NVM_BURN, 0xC0) +
-    time.sleep(1) # Wait for NVM burn to complete +
-    print("NVM Burn complete. Settings are now permanent."+
- +
-if __name__ == "__main__": +
-    i2c = machine.I2C(0, scl=machine.Pin(I2C_SCL_PIN), sda=machine.Pin(I2C_SDA_PIN), freq=400000) +
-     +
-    setup(i2c) +
-     +
-    # Ensure VDD is stable at 3.3V before executing the burn process +
-    burn(i2c) +
-</file>+
altso3.1782181414.txt.gz · Last modified: by admin

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki