Skip to content

Commit

Permalink
Merge pull request #332 from open-ephys/PassthroughTweaks
Browse files Browse the repository at this point in the history
Tweaks for passthrough devices and miniscope fixes
  • Loading branch information
jonnew authored Oct 15, 2024
2 parents 450f829 + a9e386f commit e49b3e1
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 50 deletions.
17 changes: 8 additions & 9 deletions OpenEphys.Onix1/ConfigureNeuropixelsV1e.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,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 @@ -168,8 +167,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 @@ -195,10 +194,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 = NeuropixelsV1.ProbeI2CAddress << 1;
deserializer.WriteByte((uint)DS90UB9xDeserializerI2CRegister.SlaveID1, alias);
Expand All @@ -212,16 +211,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 @@ internal static void ConfigureDeserializer(DeviceContext device)
// 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 @@ internal static void ConfigureDeserializer(DeviceContext device)
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
}
}
}

0 comments on commit e49b3e1

Please sign in to comment.