diff --git a/OpenEphys.Onix1/ConfigureNeuropixelsV1e.cs b/OpenEphys.Onix1/ConfigureNeuropixelsV1e.cs index 353e618..8ab8d9e 100644 --- a/OpenEphys.Onix1/ConfigureNeuropixelsV1e.cs +++ b/OpenEphys.Onix1/ConfigureNeuropixelsV1e.cs @@ -141,8 +141,7 @@ public override IObservable Process(IObservable 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); @@ -167,8 +166,8 @@ public override IObservable Process(IObservable 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), @@ -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); @@ -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; } diff --git a/OpenEphys.Onix1/ConfigureNeuropixelsV2e.cs b/OpenEphys.Onix1/ConfigureNeuropixelsV2e.cs index f9e710a..4336dcc 100644 --- a/OpenEphys.Onix1/ConfigureNeuropixelsV2e.cs +++ b/OpenEphys.Onix1/ConfigureNeuropixelsV2e.cs @@ -137,9 +137,8 @@ public override IObservable Process(IObservable 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); @@ -210,7 +209,7 @@ public override IObservable Process(IObservable 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( @@ -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); @@ -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; } @@ -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) diff --git a/OpenEphys.Onix1/ConfigureNeuropixelsV2eBeta.cs b/OpenEphys.Onix1/ConfigureNeuropixelsV2eBeta.cs index 40cfb0c..1e317e4 100644 --- a/OpenEphys.Onix1/ConfigureNeuropixelsV2eBeta.cs +++ b/OpenEphys.Onix1/ConfigureNeuropixelsV2eBeta.cs @@ -150,12 +150,11 @@ public override IObservable Process(IObservable 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); @@ -170,7 +169,7 @@ public override IObservable Process(IObservable 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 @@ -227,7 +226,7 @@ public override IObservable Process(IObservable 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. @@ -238,8 +237,8 @@ public override IObservable Process(IObservable 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), @@ -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); @@ -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) diff --git a/OpenEphys.Onix1/ConfigureUclaMiniscopeV4.cs b/OpenEphys.Onix1/ConfigureUclaMiniscopeV4.cs index 6ff9ba7..7b77cda 100644 --- a/OpenEphys.Onix1/ConfigureUclaMiniscopeV4.cs +++ b/OpenEphys.Onix1/ConfigureUclaMiniscopeV4.cs @@ -158,6 +158,7 @@ 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) @@ -165,6 +166,7 @@ override protected bool CheckLinkState(DeviceContext device) return false; } + Thread.Sleep(150); var linkState = device.ReadRegister(PortController.LINKSTATE); return (linkState & PortController.LINKSTATE_SL) != 0; } diff --git a/OpenEphys.Onix1/ConfigureUclaMiniscopeV4Camera.cs b/OpenEphys.Onix1/ConfigureUclaMiniscopeV4Camera.cs index bd78385..8911167 100644 --- a/OpenEphys.Onix1/ConfigureUclaMiniscopeV4Camera.cs +++ b/OpenEphys.Onix1/ConfigureUclaMiniscopeV4Camera.cs @@ -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; @@ -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); @@ -212,6 +206,11 @@ 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; @@ -219,9 +218,9 @@ internal static void ConfigureCameraSystem(DeviceContext device, UclaMiniscopeV4 // 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 diff --git a/OpenEphys.Onix1/DS90UB9x.cs b/OpenEphys.Onix1/DS90UB9x.cs index 56a2eca..4d92cbd 100644 --- a/OpenEphys.Onix1/DS90UB9x.cs +++ b/OpenEphys.Onix1/DS90UB9x.cs @@ -1,4 +1,7 @@ -namespace OpenEphys.Onix1 +using System; +using System.Threading; + +namespace OpenEphys.Onix1 { static class DS90UB9x { @@ -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 @@ -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, @@ -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 @@ -102,5 +141,5 @@ enum DS90UB9xDirection { Input = 0, Output = 1 - } + } }