Skip to content

Instantly share code, notes, and snippets.

@chr15m
Created October 30, 2025 13:03
Show Gist options
  • Save chr15m/922391517223cb3b9166547a70e09baa to your computer and use it in GitHub Desktop.
Save chr15m/922391517223cb3b9166547a70e09baa to your computer and use it in GitHub Desktop.
Control the SIDBlaster USB (SID chip controller) with Python via the ftdi_sio module
#!/usr/bin/env python3
"""
SIDBlaster USB - Serial Interface Demo
- Demonstrates reading and writing SID registers via serial port.
- The ftdi_sio module should be loaded and presenting on /dev/ttyUSB0.
- Tested on SIDBlaster-USB Tic Tac on Linux.
- Raspberry Pi should work too.
"""
import time
import serial
def read_sid_register(port, register):
"""Read a value from a SID register."""
read_command = 0x80 | (1 << 5) | register
port.write(bytes([read_command]))
response = port.read(1)
if len(response) == 1:
return response[0]
return None
def write_sid_register(port, register, value):
"""Write a value to a SID register."""
write_command = 0xC0 | (1 << 5) | register
port.write(bytes([write_command, value]))
time.sleep(0.001)
def main():
"SIDBlaster USB - Serial Interface Demo"
print(main.__doc__)
print("=" * len(main.__doc__))
port = serial.Serial(
port='/dev/ttyUSB0',
baudrate=500000,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
timeout=1
)
print(f"Opened {port.name} at {port.baudrate} baud\n")
# Test 1: Read POTX register
print("Test 1: Reading POTX register (25)")
print("-" * 40)
value = read_sid_register(port, 25)
if value is not None:
print(f"✅ Register 25 = 0x{value:02x} ({value})")
if value == 0xFF:
print("🎉 Correct! Unconnected paddle reads 0xFF\n")
else:
print(f"⚠️ Expected 0xFF but got 0x{value:02x}\n")
else:
print("❌ Failed to read register\n")
# Test 2: Play middle C
print("Test 2: Playing middle C (261.63 Hz)")
print("-" * 40)
middle_c_freq = 261.63
freq_value = int((middle_c_freq * 16777216) / 1000000)
freq_low = freq_value & 0xFF
freq_high = (freq_value >> 8) & 0xFF
print(f"Frequency value: {freq_value} (0x{freq_value:04x})")
print(f" Low byte: 0x{freq_low:02x}")
print(f" High byte: 0x{freq_high:02x}")
print("\nConfiguring SID Voice 1...")
write_sid_register(port, 0x00, freq_low) # Frequency low byte
write_sid_register(port, 0x01, freq_high) # Frequency high byte
write_sid_register(port, 0x02, 0x00) # Pulse width low byte
write_sid_register(port, 0x03, 0x08) # Pulse width high byte (50% duty cycle)
write_sid_register(port, 0x05, 0x09) # Attack/Decay (fast attack, medium decay)
write_sid_register(port, 0x06, 0x00) # Sustain/Release (zero sustain, fast release)
write_sid_register(port, 0x18, 0x0F) # Volume to maximum
print("Playing sawtooth wave for 250ms...")
write_sid_register(port, 0x04, 0x21) # Gate on, sawtooth waveform
time.sleep(0.25)
write_sid_register(port, 0x04, 0x20) # Gate off
time.sleep(0.1)
print("Playing pulse wave for 250ms...")
write_sid_register(port, 0x04, 0x41) # Gate on, pulse waveform
time.sleep(0.25)
write_sid_register(port, 0x04, 0x40) # Gate off
print("Notes stopped")
print("\nSilencing SID...")
write_sid_register(port, 0x18, 0x00) # Volume to zero
port.close()
print("\nDone!")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment