Skip to content

Commit

Permalink
Update FmcLinkController port voltage algorithm
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
jonnew authored and glopesdev committed Mar 27, 2024
1 parent 7a86756 commit 7eb7662
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 18 deletions.
37 changes: 22 additions & 15 deletions OpenEphys.Onix/OpenEphys.Onix/ConfigureFmcLinkController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ContextTask> Process(IObservable<ContextTask> source)
{
var deviceName = DeviceName;
Expand All @@ -59,21 +71,16 @@ public override IObservable<ContextTask> Process(IObservable<ContextTask> 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;
}
}
Expand All @@ -93,7 +100,7 @@ public override IObservable<ContextTask> Process(IObservable<ContextTask> source
});
}

static class FmcLinkController
internal static class FmcLinkController
{
public const int ID = 23;

Expand Down
29 changes: 26 additions & 3 deletions OpenEphys.Onix/OpenEphys.Onix/ConfigureHeadstage64.cs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -49,6 +55,23 @@ internal override IEnumerable<IDeviceConfiguration> 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
Expand Down

0 comments on commit 7eb7662

Please sign in to comment.