Example #1
0
        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);
        }