Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion gateware/src/rs/hal/src/polysynth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,11 @@ macro_rules! impl_polysynth {
self.registers.midi_read().read().bits()
}

pub fn usb_midi_host(&mut self, enable: bool, cfg_id: u8, endpt_id: u8) {
pub fn usb_host_vbus(&mut self, enable: bool) {
self.registers.usb_midi_host().write(|w| unsafe { w.host().bit(enable) } );
}

pub fn usb_host_midi(&mut self, cfg_id: u8, endpt_id: u8) {
self.registers.usb_midi_cfg().write(|w| unsafe { w.value().bits(cfg_id) } );
self.registers.usb_midi_endp().write(|w| unsafe { w.value().bits(endpt_id) } );
}
Expand Down
7 changes: 5 additions & 2 deletions gateware/src/rs/hal/src/tusb322.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,12 @@ impl<I2C: I2c> TUSB322Driver<I2C> {
})
}

pub fn disable_term(&mut self) -> Result<(), I2C::Error> {
self.write_register(0x0A, 0x01)
}

pub fn set_mode(&mut self, mode: TUSB322Mode) -> Result<(), I2C::Error> {
// First disable termination
self.write_register(0x0A, 0x01)?;
self.disable_term()?;

// Set mode (device/host)
let mode_bits = match mode {
Expand Down
49 changes: 34 additions & 15 deletions gateware/src/top/polysyn/fw/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,12 +250,14 @@ impl App {
let pmod = EurorackPmod0::new(peripherals.PMOD0_PERIPH);
let i2cdev = I2c0::new(peripherals.I2C0);
let pca9635 = Pca9635Driver::new(i2cdev);
let synth = Polysynth0::new(peripherals.SYNTH_PERIPH);
let drive_smoother = OnePoleSmoother::new(0.05f32);
let reso_smoother = OnePoleSmoother::new(0.05f32);
let diffusion_smoother = OnePoleSmoother::new(0.05f32);
let touch_controller = MidiTouchController::new();
let cc_mapper = build_cc_mapper(&opts);
let mut synth = Polysynth0::new(peripherals.SYNTH_PERIPH);
synth.usb_host_midi(1, 1);
synth.usb_host_vbus(false); // default, but set anyway...
Self {
ui: ui::UI::new(opts, TIMER0_ISR_PERIOD_MS,
encoder, pca9635, pmod),
Expand Down Expand Up @@ -338,7 +340,7 @@ fn main() -> ! {
let i2cdev = I2c0::new(peripherals.I2C0);
let mut tusb322 = TUSB322Driver::new(i2cdev);
tusb322.soft_reset().ok();
tusb322.set_mode(TUSB322Mode::Dfp).ok();
tusb322.disable_term().ok();

//
// Create App instance
Expand All @@ -364,8 +366,8 @@ fn main() -> ! {

let mut last_jack = pmod.jack();

let mut usb_cc_attached_as_src = false;
let mut last_attached_state = AttachedState::NotAttached;
let mut last_opt_host_enabled = false;

loop {

Expand All @@ -379,34 +381,51 @@ fn main() -> ! {
let save_opts = app.ui.opts.misc.save_opts.poll();
let wipe_opts = app.ui.opts.misc.wipe_opts.poll();

// USB Host: Disable DFP terminations if `MISC->usb-host` option is off
//
// This stops us supplying VCONN on the CC pins for e-tagged cables, fixing an
// edge case where we may backpower VBUS due to the following bug on
// early Tiliqua R5.1s: https://github.com/apfaudio/tiliqua-hardware/issues/1
//

let opt_host_enabled = app.ui.opts.misc.usb_host.value == UsbHost::On;
if last_opt_host_enabled != opt_host_enabled {
if opt_host_enabled {
tusb322.soft_reset().ok();
tusb322.set_mode(TUSB322Mode::Dfp).ok();
} else {
tusb322.disable_term().ok();
app.synth.usb_host_vbus(false);
}
}
last_opt_host_enabled = opt_host_enabled;

// Type-C hotplugging detection
//
// Only enable VBUS if the TUSB322 Type-C controller says we are attached as:
// - Attached.SRC
// - Attached.ACCESSORY && AccessoryType.DebugDfp
//
// It seems some USB-C adapters will enumerate as a DebugDfp accessory. Enabling VBUS
// is still safe in this situation, as we can only land in DebugDfp if the CC
// controller is sure we are a DFP. It's not sufficient to just check
// Attached.ACCESSORY as we could also enumerate as an UFP accessory against a host!
//
// This is essentially a safeguard against applying VBUS if we're accidentally connecting host<->host.
// Due to the same hardware bug as above, Tiliqua's host port in DFP mode may
// have the TUSB322I see some rare adapter combinations as `DebugDfp` accessories,
// rather than `Attached.SRC`. To work around this, we still power VBUS on `DebugDfp`.
//

if let Ok(ctrl) = tusb322.read_connection_status_control() {
if let Ok(conn) = tusb322.read_connection_status() {
// Only update on valid reads to reduce risk of unintended toggling mid-stream
if ctrl.attached_state != last_attached_state {
info!("USB hotplug: {:?} | {:?}", ctrl, conn);
info!("USB CC hotplug: {:?} | {:?}", ctrl, conn);
last_attached_state = ctrl.attached_state;
}
let debug_dfp = (ctrl.attached_state == AttachedState::AttachedAccessory) &&
(conn.accessory == AccessoryType::DebugDfp);
usb_cc_attached_as_src = ctrl.attached_state == AttachedState::AttachedSrc || debug_dfp;
// Check how we are attached
let attached_src = ctrl.attached_state == AttachedState::AttachedSrc;
let attached_debug_dfp =
(ctrl.attached_state == AttachedState::AttachedAccessory) &&
(conn.accessory == AccessoryType::DebugDfp);
app.synth.usb_host_vbus(opt_host_enabled && (attached_src || attached_debug_dfp));
}
}
let usb_vbus_enabled = usb_cc_attached_as_src && (app.ui.opts.misc.usb_host.value == UsbHost::On);
app.synth.usb_midi_host(usb_vbus_enabled, 1, 1);

//
// Copy out all the bits of state we need for drawing
Expand Down
Loading