From 7eb766269c1bfd4d3ff3a86b52251f48c3d107a5 Mon Sep 17 00:00:00 2001 From: jonnew Date: Wed, 24 Jan 2024 16:42:20 -0500 Subject: [PATCH] Update FmcLinkController port voltage algorithm - Expose more parameters of its operation - Final link check after setting offset voltage - From testing it was found that headstage-64 needs a very large amount of time to reach an acceptable votlage level to be considered off (nearly 10 seconds) - A new virtual SetPortVoltage method was introduced in the base link controller to allow headstages to change the procedure depending on its needs. In the case of headstage-64, a two-step procedure with a long wait time after turning port voltage off, and a very large offset voltage applied after lock. --- .../ConfigureFmcLinkController.cs | 37 +++++++++++-------- .../OpenEphys.Onix/ConfigureHeadstage64.cs | 29 +++++++++++++-- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/OpenEphys.Onix/OpenEphys.Onix/ConfigureFmcLinkController.cs b/OpenEphys.Onix/OpenEphys.Onix/ConfigureFmcLinkController.cs index a0b90a86..79ed3019 100644 --- a/OpenEphys.Onix/OpenEphys.Onix/ConfigureFmcLinkController.cs +++ b/OpenEphys.Onix/OpenEphys.Onix/ConfigureFmcLinkController.cs @@ -28,15 +28,27 @@ public ConfigureFmcLinkController() [Description("Specifies the maximum link voltage at which the hub is expected to operate.")] public double MaxVoltage { get; set; } + [Description("Specifies the voltage step size when searching for a SERDES lock.")] + public double VoltageIncrement { get; set; } = 0.2; + [Description("Specifies an optional link voltage offset to ensure stable operation after lock is established.")] public double VoltageOffset { get; set; } = 0.2; - protected virtual bool CheckLinkState(DeviceContext context) + protected virtual bool CheckLinkState(DeviceContext device) { - var linkState = context.ReadRegister(FmcLinkController.LINKSTATE); + var linkState = device.ReadRegister(FmcLinkController.LINKSTATE); return (linkState & FmcLinkController.LINKSTATE_SL) != 0; } + protected virtual void SetPortVoltage(DeviceContext device, uint voltage) + { + const int WaitUntilVoltageSettles = 200; + device.WriteRegister(FmcLinkController.PORTVOLTAGE, 0); + Thread.Sleep(WaitUntilVoltageSettles); + device.WriteRegister(FmcLinkController.PORTVOLTAGE, voltage); + Thread.Sleep(WaitUntilVoltageSettles); + } + public override IObservable Process(IObservable source) { var deviceName = DeviceName; @@ -59,21 +71,16 @@ public override IObservable Process(IObservable source var hasLock = false; var minVoltage = (uint)(MinVoltage * 10); var maxVoltage = (uint)(MaxVoltage * 10); - var safetyVoltage = (uint)(VoltageOffset * 10); - for (uint voltage = minVoltage; voltage <= maxVoltage; voltage += 2) - { - const int WaitUntilVoltageSettles = 200; - device.WriteRegister(FmcLinkController.PORTVOLTAGE, 0); - Thread.Sleep(WaitUntilVoltageSettles); - device.WriteRegister(FmcLinkController.PORTVOLTAGE, voltage); - Thread.Sleep(WaitUntilVoltageSettles); + var voltageOffset = (uint)(VoltageOffset * 10); + var voltageIncrement = (uint)(VoltageIncrement * 10); + for (uint voltage = minVoltage; voltage <= maxVoltage; voltage += voltageIncrement) + { + SetPortVoltage(device, voltage); if (CheckLinkState(device)) { - device.WriteRegister( - FmcLinkController.PORTVOLTAGE, - voltage + safetyVoltage); - hasLock = true; + SetPortVoltage(device, voltage + voltageOffset); + hasLock = CheckLinkState(device); break; } } @@ -93,7 +100,7 @@ public override IObservable Process(IObservable source }); } - static class FmcLinkController + internal static class FmcLinkController { public const int ID = 23; diff --git a/OpenEphys.Onix/OpenEphys.Onix/ConfigureHeadstage64.cs b/OpenEphys.Onix/OpenEphys.Onix/ConfigureHeadstage64.cs index 78b86d83..f1799b41 100644 --- a/OpenEphys.Onix/OpenEphys.Onix/ConfigureHeadstage64.cs +++ b/OpenEphys.Onix/OpenEphys.Onix/ConfigureHeadstage64.cs @@ -1,19 +1,25 @@ using System.Collections.Generic; using System.ComponentModel; +using System.Threading; namespace OpenEphys.Onix { public class ConfigureHeadstage64 : HubDeviceFactory { PortName port; - readonly ConfigureFmcLinkController LinkController = new(); + readonly ConfigureHeadstage64LinkController LinkController = new(); public ConfigureHeadstage64() { + // TODO: The issue with this headstage is that its locking voltage is far, far lower than the voltage required for full + // functionality. Locking occurs at around 2V on the headstage (enough to turn 1.8V on). Full functionality is at 5.0 volts. + // Whats worse: the port voltage can only go down to 3.3V, which means that its very hard to find the true lowest voltage + // for a lock and then add a large offset to that. Port = PortName.PortA; LinkController.HubConfiguration = HubConfiguration.Standard; - LinkController.MinVoltage = 5.0; - LinkController.MaxVoltage = 7.0; + LinkController.MinVoltage = 3.3; + LinkController.MaxVoltage = 6.0; + LinkController.VoltageOffset = 3.4; } [Category(ConfigurationCategory)] @@ -49,6 +55,23 @@ internal override IEnumerable GetDevices() yield return Bno055; yield return TS4231; } + + class ConfigureHeadstage64LinkController : ConfigureFmcLinkController + { + protected override void SetPortVoltage(DeviceContext device, uint voltage) + { + // TODO: It takes a huge amount of time to get to 0, almost 10 seconds. + // The best we can do at the moment is drive port voltage to minimum which + // is an active process and then settle from there to zero volts. + const int WaitUntilVoltageOffSettles = 4000; + const int WaitUntilVoltageOnSettles = 100; + device.WriteRegister(FmcLinkController.PORTVOLTAGE, 33); + device.WriteRegister(FmcLinkController.PORTVOLTAGE, 0); + Thread.Sleep(WaitUntilVoltageOffSettles); + device.WriteRegister(FmcLinkController.PORTVOLTAGE, voltage); + Thread.Sleep(WaitUntilVoltageOnSettles); + } + } } public enum PortName