private void WriteADCCorrections(NeuropixelsV1Configuration config) { for (int i = 0; i < config.ADCs.Length; i += 2) { var addr = (uint)Register.ADC01_00_OFF_THRESH + (uint)i / 2; var adc0 = (uint)config.ADCs[i].Offset << 10 | (uint)config.ADCs[i].Threshold; var adc1 = (uint)config.ADCs[i + 1].Offset << 10 | (uint)config.ADCs[i].Threshold; var val = adc1 << 16 | adc0; WriteManagedRegister(addr, val); } }
private void WriteAPGainCorrections(NeuropixelsV1Configuration config) { for (int i = 0; i < config.Channels.Length; i += 2) { var addr = (uint)Register.CHAN001_000_APGAIN + (uint)i / 2; var gain_fixed0 = (uint)(config.Channels[i].APGainCorrection * (1 << 14)); var gain_fixed1 = (uint)(config.Channels[i + 1].APGainCorrection * (1 << 14)); var val = gain_fixed1 << 16 | gain_fixed0; WriteManagedRegister(addr, val); } }
public void WriteConfiguration(NeuropixelsV1Configuration config, bool performReadCheck = false) { if (config.Channels.ToList().GetRange(192, 192).Any(c => c.Bank == Channel.ElectrodeBank.TWO)) { throw new ArgumentException("Electrode selection is out of bounds. Only bank 0 and 1 are valid for channels in range 192..383.", nameof(config)); } // Turn on calibration if necessary if (config.Mode != NeuropixelsV1Configuration.OperationMode.RECORD) { switch (config.Mode) { case NeuropixelsV1Configuration.OperationMode.CALIBRATE_ADCS: WriteByte((uint)RegAddr.CAL_MOD, (uint)CalMod.OSC_ACTIVE_AND_ADC_CAL); WriteByte((uint)RegAddr.OP_MODE, (uint)Operation.RECORD_AND_CALIBRATE); break; case NeuropixelsV1Configuration.OperationMode.CALIBRATE_CHANNELS: WriteByte((uint)RegAddr.CAL_MOD, (uint)CalMod.OSC_ACTIVE_AND_CH_CAL); WriteByte((uint)RegAddr.OP_MODE, (uint)Operation.RECORD_AND_CALIBRATE); break; case NeuropixelsV1Configuration.OperationMode.CALIBRATE_PIXELS: WriteByte((uint)RegAddr.CAL_MOD, (uint)CalMod.OSC_ACTIVE_AND_PIX_CAL); WriteByte((uint)RegAddr.OP_MODE, (uint)Operation.RECORD_AND_CALIBRATE); break; case NeuropixelsV1Configuration.OperationMode.DIGITAL_TEST: WriteByte((uint)RegAddr.OP_MODE, (uint)Operation.RECORD_AND_DIG_TEST); break; } } // Shank configuration // NB: ASIC bug, read_check on SR_CHAIN1 ignored WriteShiftRegister((uint)RegAddr.SR_CHAIN1, GenerateShankBits(config), false); // Gain and ADC corrections WriteLFPGainCorrections(config); WriteAPGainCorrections(config); WriteADCCorrections(config); ConfigProbeSN = config.ConfigProbeSN; // Base configurations var base_configs = GenerateBaseBits(config); WriteShiftRegister((uint)RegAddr.SR_CHAIN2, base_configs[0], performReadCheck); WriteShiftRegister((uint)RegAddr.SR_CHAIN3, base_configs[1], performReadCheck); // Configuration has been uploaded config.RefreshNeeded = false; }
// Convert Channels into BitArray private static BitArray GenerateShankBits(NeuropixelsV1Configuration config) { // Default var shank_config = new BitArray(SHANK_CONFIG_BITS, false); // If external reference is used by any channel shank_config[SHANK_BIT_EXT1] = config.Channels.Where(ch => ch.Reference == Channel.Ref.EXTERNAL && ch.ElectrodeNumber % 2 == 1).Any(); shank_config[SHANK_BIT_EXT2] = config.Channels.Where(ch => ch.Reference == Channel.Ref.EXTERNAL && ch.ElectrodeNumber % 2 == 0).Any(); // If tip reference is used by any channel shank_config[SHANK_BIT_TIP1] = config.Channels.Where(ch => ch.Reference == Channel.Ref.TIP && ch.ElectrodeNumber % 2 == 1).Any(); shank_config[SHANK_BIT_TIP2] = config.Channels.Where(ch => ch.Reference == Channel.Ref.TIP && ch.ElectrodeNumber % 2 == 0).Any(); // If internal reference is used by any channel var refs = BankToIntRef.Values.ToArray(); shank_config[refs[0]] = false; shank_config[refs[1]] = false; shank_config[refs[2]] = false; var b = config.Channels.Where(ch => ch.Reference == Channel.Ref.INTERNAL).Any(); shank_config[refs[(int)config.Channels[INTERNAL_REF_CHANNEL].Bank]] = b; // Update active channels for (int i = 0; i < config.Channels.Length; i++) { // Reference bits always remain zero if (i == INTERNAL_REF_CHANNEL) { continue; } var e = config.Channels[i].ElectrodeNumber; if (e != null) { int bit_idx = e % 2 == 0 ? 485 + ((int)e / 2) : // even electrode 482 - ((int)e / 2); // odd electrode shank_config[bit_idx] = true; } } return(shank_config); }
// Convert Channels & ADCs into BitArray private static BitArray[] GenerateBaseBits(NeuropixelsV1Configuration config) { // MSB [Full, standby, LFPGain(3 downto 0), APGain(3 downto0)] LSB BitArray[] base_configs = { new BitArray(BASE_CONFIG_BITS, false), // Ch 0, 2, 4, ... new BitArray(BASE_CONFIG_BITS, false) }; // Ch 1, 3, 5, ... // Channels section for (int i = 0; i < config.Channels.Length; i++) { var config_idx = i % 2; // References var ref_idx = config_idx == 0 ? (382 - i) / 2 * 3 : (383 - i) / 2 * 3; base_configs[config_idx][ref_idx + (int)config.Channels[i].Reference] = true; // Gains, standby, and filter var ch_opts_idx = PROBE_SRBASECONFIG_BIT_GAINBASE + ((i - config_idx) * 4); base_configs[config_idx][ch_opts_idx + 0] = Gains[config.Channels[i].APGain][0]; base_configs[config_idx][ch_opts_idx + 1] = Gains[config.Channels[i].APGain][1]; base_configs[config_idx][ch_opts_idx + 2] = Gains[config.Channels[i].APGain][2]; base_configs[config_idx][ch_opts_idx + 3] = Gains[config.Channels[i].LFPGain][0]; base_configs[config_idx][ch_opts_idx + 4] = Gains[config.Channels[i].LFPGain][1]; base_configs[config_idx][ch_opts_idx + 5] = Gains[config.Channels[i].LFPGain][2]; base_configs[config_idx][ch_opts_idx + 6] = config.Channels[i].Standby; base_configs[config_idx][ch_opts_idx + 7] = config.Channels[i].APFilter; // Correct? } int k = 0; foreach (var adc in config.ADCs) { if (adc.CompP < 0 || adc.CompP > 0x1F) { throw new ArgumentOutOfRangeException(String.Format("ADC calibration parameter CompP value of {0} is invalid.", adc.CompP)); } if (adc.CompN < 0 || adc.CompN > 0x1F) { throw new ArgumentOutOfRangeException(String.Format("ADC calibration parameter CompN value of {0} is invalid.", adc.CompN)); } if (adc.Cfix < 0 || adc.Cfix > 0xF) { throw new ArgumentOutOfRangeException(String.Format("ADC calibration parameter Cfix value of {0} is invalid.", adc.Cfix)); } if (adc.Slope < 0 || adc.Slope > 0x7) { throw new ArgumentOutOfRangeException(String.Format("ADC calibration parameter Slope value of {0} is invalid.", adc.Slope)); } if (adc.Coarse < 0 || adc.Coarse > 0x3) { throw new ArgumentOutOfRangeException(String.Format("ADC calibration parameter Coarse value of {0} is invalid.", adc.Coarse)); } if (adc.Fine < 0 || adc.Fine > 0x3) { throw new ArgumentOutOfRangeException(String.Format("ADC calibration parameter Fine value of {0} is invalid.", adc.Fine)); } var config_idx = k % 2; int d = k++ / 2; int comp_off = 2406 - 42 * (d / 2) + (d % 2) * 10; int slope_off = comp_off + 20 + (d % 2); BitArray comp_p = new BitArray(new byte[] { (byte)adc.CompP }); BitArray comp_n = new BitArray(new byte[] { (byte)adc.CompN }); BitArray cfix = new BitArray(new byte[] { (byte)adc.Cfix }); BitArray slope = new BitArray(new byte[] { (byte)adc.Slope }); BitArray coarse = (new BitArray(new byte[] { (byte)adc.Coarse })); BitArray fine = new BitArray(new byte[] { (byte)adc.Fine }); base_configs[config_idx][comp_off + 0] = comp_p[0]; base_configs[config_idx][comp_off + 1] = comp_p[1]; base_configs[config_idx][comp_off + 2] = comp_p[2]; base_configs[config_idx][comp_off + 3] = comp_p[3]; base_configs[config_idx][comp_off + 4] = comp_p[4]; base_configs[config_idx][comp_off + 5] = comp_n[0]; base_configs[config_idx][comp_off + 6] = comp_n[1]; base_configs[config_idx][comp_off + 7] = comp_n[2]; base_configs[config_idx][comp_off + 8] = comp_n[3]; base_configs[config_idx][comp_off + 9] = comp_n[4]; base_configs[config_idx][slope_off + 0] = slope[0]; base_configs[config_idx][slope_off + 1] = slope[1]; base_configs[config_idx][slope_off + 2] = slope[2]; base_configs[config_idx][slope_off + 3] = fine[0]; base_configs[config_idx][slope_off + 4] = fine[1]; base_configs[config_idx][slope_off + 5] = coarse[0]; base_configs[config_idx][slope_off + 6] = coarse[1]; base_configs[config_idx][slope_off + 7] = cfix[0]; base_configs[config_idx][slope_off + 8] = cfix[1]; base_configs[config_idx][slope_off + 9] = cfix[2]; base_configs[config_idx][slope_off + 10] = cfix[3]; } return(base_configs); }