Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tweaks for passthrough devices and miniscope fixes #332

Merged
merged 7 commits into from
Oct 15, 2024
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
17 changes: 8 additions & 9 deletions OpenEphys.Onix1/ConfigureNeuropixelsV1e.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,7 @@ public override IObservable<ContextTask> Process(IObservable<ContextTask> source
var serializer = new I2CRegisterContext(device, DS90UB9x.SER_ADDR);

// set I2C clock rate to ~400 kHz
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.SCLHIGH, 20);
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.SCLLOW, 20);
DS90UB9x.Set933I2CRate(device, 400e3);

// read probe metadata
var probeMetadata = new NeuropixelsV1eMetadata(serializer);
Expand All @@ -167,8 +166,8 @@ public override IObservable<ContextTask> Process(IObservable<ContextTask> source
var deviceInfo = new NeuropixelsV1eDeviceInfo(context, DeviceType, deviceAddress, probeControl);
var shutdown = Disposable.Create(() =>
{
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO10, NeuropixelsV1e.DefaultGPO10Config);
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO32, NeuropixelsV1e.DefaultGPO32Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio10, NeuropixelsV1e.DefaultGPO10Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio32, NeuropixelsV1e.DefaultGPO32Config);
});
return new CompositeDisposable(
DeviceManager.RegisterDevice(deviceName, deviceInfo),
Expand All @@ -194,10 +193,10 @@ static void ConfigureDeserializer(DeviceContext device)
device.WriteRegister(DS90UB9x.DATALINES0, 0x3245106B); // Sync, psb[0], psb[1], psb[2], psb[3], psb[4], psb[5], psb[6],
device.WriteRegister(DS90UB9x.DATALINES1, 0xFFFFFFFF);

DS90UB9x.Initialize933SerDesLink(device, DS90UB9xMode.Raw12BitHighFrequency);

// configure deserializer I2C aliases
var deserializer = new I2CRegisterContext(device, DS90UB9x.DES_ADDR);
uint coaxMode = 0x4 + (uint)DS90UB9xMode.Raw12BitHighFrequency; // 0x4 maintains coax mode
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.PortMode, coaxMode);

uint alias = NeuropixelsV1e.ProbeAddress << 1;
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.SlaveID1, alias);
Expand All @@ -211,16 +210,16 @@ static void ConfigureDeserializer(DeviceContext device)
static void ResetProbe(I2CRegisterContext serializer, uint gpo10Config)
{
gpo10Config &= ~NeuropixelsV1e.Gpo10ResetMask;
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO10, gpo10Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio10, gpo10Config);
Thread.Sleep(1);
gpo10Config |= NeuropixelsV1e.Gpo10ResetMask;
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO10, gpo10Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio10, gpo10Config);
}

static uint TurnOnLed(I2CRegisterContext serializer, uint gpo23Config)
{
gpo23Config &= ~NeuropixelsV1e.Gpo32LedMask;
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO32, gpo23Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio32, gpo23Config);

return gpo23Config;
}
Expand Down
19 changes: 9 additions & 10 deletions OpenEphys.Onix1/ConfigureNeuropixelsV2e.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,8 @@ public override IObservable<ContextTask> Process(IObservable<ContextTask> source
var gpo10Config = EnableProbeSupply(serializer);

// set I2C clock rate to ~400 kHz
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.SCLHIGH, 20);
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.SCLLOW, 20);

DS90UB9x.Set933I2CRate(device, 400e3);

// read probe metadata
var probeAMetadata = ReadProbeMetadata(serializer, NeuropixelsV2e.ProbeASelected);
var probeBMetadata = ReadProbeMetadata(serializer, NeuropixelsV2e.ProbeBSelected);
Expand Down Expand Up @@ -210,7 +209,7 @@ public override IObservable<ContextTask> Process(IObservable<ContextTask> source
var deviceInfo = new NeuropixelsV2eDeviceInfo(context, DeviceType, deviceAddress, gainCorrectionA, gainCorrectionB);
var shutdown = Disposable.Create(() =>
{
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO10, NeuropixelsV2e.DefaultGPO10Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio10, NeuropixelsV2e.DefaultGPO10Config);
SelectProbe(serializer, NeuropixelsV2e.NoProbeSelected);
});
return new CompositeDisposable(
Expand All @@ -237,10 +236,10 @@ static void ConfigureDeserializer(DeviceContext device)
device.WriteRegister(DS90UB9x.DATALINES0, 0xFFFFF8A6); // NP A
device.WriteRegister(DS90UB9x.DATALINES1, 0xFFFFF97B); // NP B

DS90UB9x.Initialize933SerDesLink(device, DS90UB9xMode.Raw12BitHighFrequency);

// configure deserializer I2C aliases
var deserializer = new I2CRegisterContext(device, DS90UB9x.DES_ADDR);
uint coaxMode = 0x4 + (uint)DS90UB9xMode.Raw12BitHighFrequency; // 0x4 maintains coax mode
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.PortMode, coaxMode);

uint alias = NeuropixelsV2e.ProbeAddress << 1;
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.SlaveID1, alias);
Expand All @@ -257,7 +256,7 @@ static uint EnableProbeSupply(I2CRegisterContext serializer)
SelectProbe(serializer, NeuropixelsV2e.NoProbeSelected);

// turn on analog supply and wait for boot
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO10, gpo10Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio10, gpo10Config);
System.Threading.Thread.Sleep(20);
return gpo10Config;
}
Expand All @@ -269,16 +268,16 @@ static NeuropixelsV2eMetadata ReadProbeMetadata(I2CRegisterContext serializer, b
}
static void SelectProbe(I2CRegisterContext serializer, byte probeSelect)
{
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO32, probeSelect);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio32, probeSelect);
System.Threading.Thread.Sleep(20);
}

static void ResetProbes(I2CRegisterContext serializer, uint gpo10Config)
{
gpo10Config &= ~NeuropixelsV2e.GPO10ResetMask;
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO10, gpo10Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio10, gpo10Config);
gpo10Config |= NeuropixelsV2e.GPO10ResetMask;
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO10, gpo10Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio10, gpo10Config);
}

static void ConfigureProbeStreaming(I2CRegisterContext i2cNP)
Expand Down
25 changes: 12 additions & 13 deletions OpenEphys.Onix1/ConfigureNeuropixelsV2eBeta.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,11 @@ public override IObservable<ContextTask> Process(IObservable<ContextTask> source
var serializer = new I2CRegisterContext(device, DS90UB9x.SER_ADDR);
var gpo10Config = NeuropixelsV2eBeta.DefaultGPO10Config;
var gpo32Config = NeuropixelsV2eBeta.DefaultGPO32Config;
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO10, gpo10Config);
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO32, gpo32Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio10, gpo10Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio32, gpo32Config);

// set I2C clock rate to ~400 kHz
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.SCLHIGH, 20);
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.SCLLOW, 20);
DS90UB9x.Set933I2CRate(device, 400e3);

// read probe metadata
var probeAMetadata = ReadProbeMetadata(serializer, ref gpo32Config, NeuropixelsV2eBeta.SelectProbeA);
Expand All @@ -170,7 +169,7 @@ public override IObservable<ContextTask> Process(IObservable<ContextTask> source
// REC_NRESET and NRESET go high on both probes to take the ASIC out of reset
// TODO: not sure if REC_NRESET and NRESET are tied together on flex
gpo10Config |= NeuropixelsV2eBeta.GPO10ResetMask | NeuropixelsV2eBeta.GPO10NResetMask;
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO10, gpo10Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio10, gpo10Config);
System.Threading.Thread.Sleep(20);

// configure probe streaming
Expand Down Expand Up @@ -227,7 +226,7 @@ public override IObservable<ContextTask> Process(IObservable<ContextTask> source

// toggle probe LED
gpo32Config = (gpo32Config & ~NeuropixelsV2eBeta.GPO32LedMask) | (EnableLed ? 0 : NeuropixelsV2eBeta.GPO32LedMask);
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO32, gpo32Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio32, gpo32Config);

// Both probes are now streaming, hit them with a mux reset to (roughly) sync.
// NB: We have found that this gives PCLK-level synchronization MOST of the time.
Expand All @@ -238,8 +237,8 @@ public override IObservable<ContextTask> Process(IObservable<ContextTask> source
var deviceInfo = new NeuropixelsV2eDeviceInfo(context, DeviceType, deviceAddress, gainCorrectionA, gainCorrectionB);
var shutdown = Disposable.Create(() =>
{
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO10, NeuropixelsV2eBeta.DefaultGPO10Config);
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO32, NeuropixelsV2eBeta.DefaultGPO32Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio10, NeuropixelsV2eBeta.DefaultGPO10Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio32, NeuropixelsV2eBeta.DefaultGPO32Config);
});
return new CompositeDisposable(
DeviceManager.RegisterDevice(deviceName, deviceInfo),
Expand All @@ -265,10 +264,10 @@ static void ConfigureDeserializer(DeviceContext device)
device.WriteRegister(DS90UB9x.DATALINES0, 0x00007654); // NP A
device.WriteRegister(DS90UB9x.DATALINES1, 0x00000123); // NP B

DS90UB9x.Initialize933SerDesLink(device, DS90UB9xMode.Raw12BitHighFrequency);

// configure deserializer I2C aliases
var deserializer = new I2CRegisterContext(device, DS90UB9x.DES_ADDR);
uint coaxMode = 0x4 + (uint)DS90UB9xMode.Raw12BitHighFrequency; // 0x4 maintains coax mode
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.PortMode, coaxMode);

uint alias = NeuropixelsV2eBeta.ProbeAddress << 1;
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.SlaveID1, alias);
Expand All @@ -293,17 +292,17 @@ static void SelectProbe(I2CRegisterContext serializer, ref uint gpo32Config, byt
NeuropixelsV2eBeta.SelectProbeB => gpo32Config & ~NeuropixelsV2eBeta.ProbeSelectMask,
_ => gpo32Config
};
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO32, gpo32Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio32, gpo32Config);
System.Threading.Thread.Sleep(20);
}

static void SyncProbes(I2CRegisterContext serializer, uint gpo10Config)
{
gpo10Config &= ~NeuropixelsV2eBeta.GPO10NResetMask;
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO10, gpo10Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio10, gpo10Config);

gpo10Config |= NeuropixelsV2eBeta.GPO10NResetMask;
serializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.GPIO10, gpo10Config);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.Gpio10, gpo10Config);
}

static void ConfigureProbeStreaming(I2CRegisterContext i2cNP)
Expand Down
2 changes: 2 additions & 0 deletions OpenEphys.Onix1/ConfigureUclaMiniscopeV4.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,15 @@ override protected bool CheckLinkState(DeviceContext device)
const int FailureToWriteRegister = -6;
try
{
ConfigureUclaMiniscopeV4Camera.ConfigureSerializer(ds90ub9x);
ConfigureUclaMiniscopeV4Camera.ConfigureCameraSystem(ds90ub9x, Camera.FrameRate, Camera.InterleaveLed);
}
catch (ONIException ex) when (ex.Number == FailureToWriteRegister)
{
return false;
}

Thread.Sleep(150);
var linkState = device.ReadRegister(PortController.LINKSTATE);
return (linkState & PortController.LINKSTATE_SL) != 0;
}
Expand Down
21 changes: 10 additions & 11 deletions OpenEphys.Onix1/ConfigureUclaMiniscopeV4Camera.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Drawing.Design;
using System.Reactive.Disposables;
using System.Reactive.Subjects;
using System.Threading;
using System.Xml.Serialization;
using Bonsai;

Expand Down Expand Up @@ -190,15 +189,10 @@
// acquisition. For this reason, the frame start needs to be marked.
device.WriteRegister(DS90UB9x.MARK, (uint)DS90UB9xMarkMode.VsyncRising);

// set I2C clock rate to ~100 kHz
var deserializer = new I2CRegisterContext(device, DS90UB9x.DES_ADDR);
deserializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.SCLHIGH, 0x7A);
deserializer.WriteByte((uint)DS90UB9xSerializerI2CRegister.SCLLOW, 0x7A);

// configure deserializer I2C aliases
uint coaxMode = 0x4 + (uint)DS90UB9xMode.Raw12BitLowFrequency; // 0x4 maintains coax mode
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.PortMode, coaxMode);
DS90UB9x.Initialize933SerDesLink(device, DS90UB9xMode.Raw12BitLowFrequency);

var deserializer = new I2CRegisterContext(device, DS90UB9x.DES_ADDR);

uint i2cAlias = UclaMiniscopeV4.AtMegaAddress << 1;
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.SlaveID1, i2cAlias);
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.SlaveAlias1, i2cAlias);
Expand All @@ -212,16 +206,21 @@
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.SlaveAlias3, i2cAlias);
}

internal static void ConfigureSerializer(DeviceContext device)
{
DS90UB9x.Set933I2CRate(device, 80e3); //This is an arbitrary value that is proven to work, we need to test speed vs reliability vs bno sampling speed
}

internal static void ConfigureCameraSystem(DeviceContext device, UclaMiniscopeV4FramesPerSecond frameRate, bool interleaveLed)
{
const int WaitUntilPllSettles = 200;

Check warning on line 216 in OpenEphys.Onix1/ConfigureUclaMiniscopeV4Camera.cs

View workflow job for this annotation

GitHub Actions / build (debug, ubuntu-latest)

The variable 'WaitUntilPllSettles' is assigned but its value is never used

Check warning on line 216 in OpenEphys.Onix1/ConfigureUclaMiniscopeV4Camera.cs

View workflow job for this annotation

GitHub Actions / build (debug, ubuntu-latest)

The variable 'WaitUntilPllSettles' is assigned but its value is never used

Check warning on line 216 in OpenEphys.Onix1/ConfigureUclaMiniscopeV4Camera.cs

View workflow job for this annotation

GitHub Actions / build (debug, windows-latest)

The variable 'WaitUntilPllSettles' is assigned but its value is never used

Check warning on line 216 in OpenEphys.Onix1/ConfigureUclaMiniscopeV4Camera.cs

View workflow job for this annotation

GitHub Actions / build (debug, windows-latest)

The variable 'WaitUntilPllSettles' is assigned but its value is never used

Check warning on line 216 in OpenEphys.Onix1/ConfigureUclaMiniscopeV4Camera.cs

View workflow job for this annotation

GitHub Actions / build (release, ubuntu-latest)

The variable 'WaitUntilPllSettles' is assigned but its value is never used

Check warning on line 216 in OpenEphys.Onix1/ConfigureUclaMiniscopeV4Camera.cs

View workflow job for this annotation

GitHub Actions / build (release, ubuntu-latest)

The variable 'WaitUntilPllSettles' is assigned but its value is never used

Check warning on line 216 in OpenEphys.Onix1/ConfigureUclaMiniscopeV4Camera.cs

View workflow job for this annotation

GitHub Actions / build (release, windows-latest)

The variable 'WaitUntilPllSettles' is assigned but its value is never used

Check warning on line 216 in OpenEphys.Onix1/ConfigureUclaMiniscopeV4Camera.cs

View workflow job for this annotation

GitHub Actions / build (release, windows-latest)

The variable 'WaitUntilPllSettles' is assigned but its value is never used

// set up Python480
var atMega = new I2CRegisterContext(device, UclaMiniscopeV4.AtMegaAddress);
WriteCameraRegister(atMega, 16, 3); // Turn on PLL
Thread.Sleep(WaitUntilPllSettles);
//Thread.Sleep(WaitUntilPllSettles); //This sometimes has good effects, sometimes adverse, we just might want to redo this entire section (see issue #331 )
WriteCameraRegister(atMega, 32, 0x7007); // Turn on clock management
Thread.Sleep(WaitUntilPllSettles);
//Thread.Sleep(WaitUntilPllSettles);
WriteCameraRegister(atMega, 199, 666); // Defines granularity (unit = 1/PLL clock) of exposure and reset_length
WriteCameraRegister(atMega, 200, 3300); // Set frame rate to 30 Hz
WriteCameraRegister(atMega, 201, 3000); // Set Exposure
Expand Down
53 changes: 46 additions & 7 deletions OpenEphys.Onix1/DS90UB9x.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
namespace OpenEphys.Onix1
using System;
using System.Threading;

namespace OpenEphys.Onix1
{
static class DS90UB9x
{
Expand Down Expand Up @@ -29,6 +32,28 @@ static class DS90UB9x
// unmanaged default serializer / deserializer I2C addresses
public const uint DES_ADDR = 0x30;
public const uint SER_ADDR = 0x58;

internal static void Initialize933SerDesLink(DeviceContext device, DS90UB9xMode dataMode) //also valid for 913
{
Thread.Sleep(100); // Empirical. The gateware seems to need some milliseconds to get i2c initialized.

var deserializer = new I2CRegisterContext(device, DES_ADDR);
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.PortSel, 0x01); // Enable port 0
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.PortMode, 0x4 + (uint)dataMode); // 0x4 maintains coax mode
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.I2CConfig, 0b01011000); // 7: i2c pass all (0), 6: i2c pass (1), 5: auto_ack (0), 4: BC enable (1), 3: BC crc en (1), 2: reserved (0) 1:0: bc freq (00) 2.5Mbps
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.SerAlias, SER_ADDR << 1);
// Enable backchannel GPIO on deserializer. It is then the serializer task to decide if using them or use manual output
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.GpioCtrl0, 0x10);
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.GpioCtrl0, 0x32);
}

internal static void Set933I2CRate(DeviceContext device, double i2cRate)
{
var serializer = new I2CRegisterContext(device, SER_ADDR);
var sclTimes = (uint)Math.Round(1.0 / (100e-9 * i2cRate));
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.SclHigh, sclTimes);
serializer.WriteByte((uint)DS90UB933SerializerI2CRegister.SclLow, sclTimes);
}
}

enum DS90UB9xTriggerMode : uint
Expand Down Expand Up @@ -65,6 +90,12 @@ enum DS90UB9xMarkMode : uint
enum DS90UB9xDeserializerI2CRegister
{
PortMode = 0x6D,
PortSel = 0x4C,
I2CConfig = 0x58,
GpioCtrl0 = 0x6E,
GpioCtrl1 = 0x6F,

SerAlias = 0x5C,

SlaveID1 = 0x5E,
SlaveID2 = 0x5F,
Expand All @@ -83,12 +114,20 @@ enum DS90UB9xDeserializerI2CRegister
SlaveAlias7 = 0x6C,
}

enum DS90UB9xSerializerI2CRegister
enum DS90UB933SerializerI2CRegister
{
GPIO10 = 0x0D,
GPIO32 = 0x0E,
SCLHIGH = 0x0A,
SCLLOW = 0x0B
Gpio10 = 0x0D,
Gpio32 = 0x0E,
SclHigh = 0x11,
SclLow = 0x12
}

enum DS90UB953SerializerI2CRegister
{
GpioData = 0x0D,
GpioIOControl = 0x0E,
SclHigh = 0x0B,
SclLow = 0x0C
}

enum DS90UB9xMode
Expand All @@ -102,5 +141,5 @@ enum DS90UB9xDirection
{
Input = 0,
Output = 1
}
}
}