void ScanConnectedAmplifiers() { // Set sampling rate to highest value for maximum temporal resolution. ChangeSampleRate(AmplifierSampleRate.SampleRate30000Hz); // Enable all data streams, and set sources to cover one or two chips // on Ports A-D. evalBoard.SetDataSource(0, BoardDataSource.PortA1); evalBoard.SetDataSource(1, BoardDataSource.PortA2); evalBoard.SetDataSource(2, BoardDataSource.PortB1); evalBoard.SetDataSource(3, BoardDataSource.PortB2); evalBoard.SetDataSource(4, BoardDataSource.PortC1); evalBoard.SetDataSource(5, BoardDataSource.PortC2); evalBoard.SetDataSource(6, BoardDataSource.PortD1); evalBoard.SetDataSource(7, BoardDataSource.PortD2); var maxNumDataStreams = Rhythm.Net.Rhd2000EvalBoard.MaxNumDataStreams(evalBoard.IsUsb3()); for (int i = 0; i < maxNumDataStreams; i++) { evalBoard.EnableDataStream(i, true); } // Select RAM Bank 0 for AuxCmd3 evalBoard.SelectAuxCommandBank(BoardPort.PortA, AuxCmdSlot.AuxCmd3, 0); evalBoard.SelectAuxCommandBank(BoardPort.PortB, AuxCmdSlot.AuxCmd3, 0); evalBoard.SelectAuxCommandBank(BoardPort.PortC, AuxCmdSlot.AuxCmd3, 0); evalBoard.SelectAuxCommandBank(BoardPort.PortD, AuxCmdSlot.AuxCmd3, 0); // Since our longest command sequence is 60 commands, we run the SPI // interface for 60 samples (256 for usb3 power-of two needs). evalBoard.SetMaxTimeStep((uint)samplesPerBlock); evalBoard.SetContinuousRunMode(false); // Run SPI command sequence at all 16 possible FPGA MISO delay settings // to find optimum delay for each SPI interface cable. var maxNumChips = 8; var chipId = new int[maxNumChips]; var optimumDelays = new int[maxNumChips]; var secondDelays = new int[maxNumChips]; var goodDelayCounts = new int[maxNumChips]; for (int i = 0; i < optimumDelays.Length; i++) { optimumDelays[i] = -1; secondDelays[i] = -1; goodDelayCounts[i] = 0; } for (int delay = 0; delay < 16; delay++) { evalBoard.SetCableDelay(BoardPort.PortA, delay); evalBoard.SetCableDelay(BoardPort.PortB, delay); evalBoard.SetCableDelay(BoardPort.PortC, delay); evalBoard.SetCableDelay(BoardPort.PortD, delay); // Run SPI command sequence var dataBlock = RunSingleCommandSequence(); // Read the Intan chip ID number from each RHD2000 chip found. // Record delay settings that yield good communication with the chip. for (int chipIdx = 0; chipIdx < chipId.Length; chipIdx++) { int register59Value; var id = ReadDeviceId(dataBlock, chipIdx, out register59Value); if (id > 0) { chipId[chipIdx] = id; goodDelayCounts[chipIdx]++; switch (goodDelayCounts[chipIdx]) { case 1: optimumDelays[chipIdx] = delay; break; case 2: secondDelays[chipIdx] = delay; break; case 3: optimumDelays[chipIdx] = secondDelays[chipIdx]; break; } } } } // Now that we know which RHD2000 amplifier chips are plugged into each SPI port, // add up the total number of amplifier channels on each port and calculate the number // of data streams necessary to convey this data over the USB interface. var numStreamsRequired = 0; var rhd2216ChipPresent = false; for (int chipIdx = 0; chipIdx < chipId.Length; ++chipIdx) { switch (chipId[chipIdx]) { case ChipIdRhd2216: numStreamsRequired++; rhd2216ChipPresent = true; break; case ChipIdRhd2132: numStreamsRequired++; break; case ChipIdRhd2164: numStreamsRequired += 2; break; default: break; } } // If the user plugs in more chips than the USB interface can support, throw an exception if (numStreamsRequired > maxNumDataStreams) { var capacityExceededMessage = "Capacity of USB Interface Exceeded. This RHD2000 USB interface board can only support {0} amplifier channels."; if (rhd2216ChipPresent) { capacityExceededMessage += " (Each RHD2216 chip counts as 32 channels for USB interface purposes.)"; } capacityExceededMessage = string.Format(capacityExceededMessage, maxNumDataStreams * 32); throw new InvalidOperationException(capacityExceededMessage); } // Reconfigure USB data streams in consecutive order to accommodate all connected chips. int activeStream = 0; for (int chipIdx = 0; chipIdx < chipId.Length; ++chipIdx) { if (chipId[chipIdx] > 0) { evalBoard.EnableDataStream(activeStream, true); evalBoard.SetDataSource(activeStream, (BoardDataSource)chipIdx); if (chipId[chipIdx] == ChipIdRhd2164) { evalBoard.EnableDataStream(activeStream + 1, true); evalBoard.SetDataSource(activeStream + 1, (BoardDataSource)(chipIdx + BoardDataSource.PortA1Ddr)); activeStream += 2; } else { activeStream++; } } else { optimumDelays[chipIdx] = 0; } } // Now, disable data streams where we did not find chips present. for (; activeStream < maxNumDataStreams; activeStream++) { evalBoard.EnableDataStream(activeStream, false); } // Set cable delay settings that yield good communication with each // RHD2000 chip. var optimumDelayA = CableDelayA.GetValueOrDefault(Math.Max(optimumDelays[0], optimumDelays[1])); var optimumDelayB = CableDelayB.GetValueOrDefault(Math.Max(optimumDelays[2], optimumDelays[3])); var optimumDelayC = CableDelayC.GetValueOrDefault(Math.Max(optimumDelays[4], optimumDelays[5])); var optimumDelayD = CableDelayD.GetValueOrDefault(Math.Max(optimumDelays[6], optimumDelays[7])); evalBoard.SetCableDelay(BoardPort.PortA, optimumDelayA); evalBoard.SetCableDelay(BoardPort.PortB, optimumDelayB); evalBoard.SetCableDelay(BoardPort.PortC, optimumDelayC); evalBoard.SetCableDelay(BoardPort.PortD, optimumDelayD); cableLengthPortA = evalBoard.EstimateCableLengthMeters(optimumDelayA); cableLengthPortB = evalBoard.EstimateCableLengthMeters(optimumDelayB); cableLengthPortC = evalBoard.EstimateCableLengthMeters(optimumDelayC); cableLengthPortD = evalBoard.EstimateCableLengthMeters(optimumDelayD); // Return sample rate to original user-selected value. ChangeSampleRate(SampleRate); }