/// <summary> /// Construct an SPI device attached to a particular module /// </summary> /// <param name="spiModule">The module this device is attached to</param> /// <param name="chipSelect">The chip select pin used by this device</param> /// <param name="chipSelectMode">The ChipSelectMode to use with this device</param> /// <param name="speedMhz">The speed to operate this device at</param> /// <param name="mode">The SpiMode of this device</param> public SpiDevice(Spi spiModule, SpiChipSelectPin chipSelect, ChipSelectMode chipSelectMode = ChipSelectMode.SpiActiveLow, double speedMhz = 6, SpiMode mode = SpiMode.Mode00) { ChipSelectMode = chipSelectMode; ChipSelect = chipSelect; _spi = spiModule; Frequency = speedMhz; Mode = mode; _spi.Enabled = true; ChipSelect.MakeDigitalPushPullOutAsync(); // Set the initial chip select state if (chipSelectMode == ChipSelectMode.PulseLowAtBeginning || chipSelectMode == ChipSelectMode.PulseLowAtEnd || chipSelectMode == ChipSelectMode.SpiActiveLow) { ChipSelect.DigitalValue = true; } else { ChipSelect.DigitalValue = false; } }
/// <summary> /// Construct an SPI device attached to a particular module /// </summary> /// <param name="SpiModule">The module this device is attached to</param> /// <param name="ChipSelect">The chip select pin used by this device</param> /// <param name="csMode">The ChipSelectMode to use with this device</param> /// <param name="SpeedMHz">The speed to operate this device at</param> /// <param name="mode">The SpiMode of this device</param> public SpiDevice(Spi SpiModule, Pin ChipSelect, ChipSelectMode csMode = ChipSelectMode.SpiActiveLow, double SpeedMHz = 1, SpiMode mode = SpiMode.Mode00) { this.ChipSelectMode = csMode; this.ChipSelect = ChipSelect; this.spi = SpiModule; this.Frequency = SpeedMHz; this.Mode = mode; this.ChipSelect.Mode = PinMode.PushPullOutput; spi.Enabled = true; }
/// <summary> /// Set up a ChainableShiftRegisterOutput connected to an SPI port. /// </summary> /// <param name="spiModule">the SPI module to use</param> /// <param name="latchPin">The latch pin to use</param> /// <param name="numBytes">The number of bytes to write to this device</param> /// <param name="mode">The SPI mode to use for all shift registers in this chain</param> /// <param name="csMode">The ChipSelectMode to use for all shift registers in this chain</param> /// <param name="speedMhz">The speed to use for all shift registers in this chain</param> public ChainableShiftRegisterOutput(Spi spiModule, SpiChipSelectPin latchPin, int numBytes = 1, double speedMhz = 6, SpiMode mode = SpiMode.Mode00, ChipSelectMode csMode = ChipSelectMode.PulseHighAtEnd) { spiDevice = new SpiDevice(spiModule, latchPin, csMode, speedMhz, mode); this.numBytes = numBytes; CurrentValue = new byte[numBytes]; lastValues = new byte[numBytes]; }
/// <summary> /// Send/receive data /// </summary> /// <param name="dataToWrite"> /// a byte array of the data to send. The length of the transaction is determined by the length of this array. /// </param> /// <param name="chipSelect">The chip select pin, if any, to use during this transaction.</param> /// <param name="chipSelectMode">The chip select mode to use during this transaction (if a CS pin is selected)</param> /// <param name="speedMhz">The speed to perform this transaction at.</param> /// <param name="burstMode"The burst mode (if any) to use.</param> /// <param name="spiMode">The SPI mode to use during this transaction.</param> /// <returns>An awaitable byte array with the received data.</returns> public async Task <byte[]> SendReceiveAsync(byte[] dataToWrite, SpiChipSelectPin chipSelect = null, ChipSelectMode chipSelectMode = ChipSelectMode.SpiActiveLow, double speedMhz = 6, SpiBurstMode burstMode = SpiBurstMode.NoBurst, SpiMode spiMode = SpiMode.Mode00) { var transactionLength = dataToWrite.Length; var returnedData = new byte[transactionLength]; if (Enabled != true) { Utility.Error("SPI module must be enabled before starting transaction", true); } if (chipSelect != null && chipSelect.SpiModule != this) { Utility.Error("Chip select pin must belong to this SPI module", true); } if (speedMhz > 0.8 && speedMhz < 6) { Debug.WriteLine( "NOTICE: automatically rounding up SPI speed to 6 MHz, due to a possible silicon bug. This bug affects SPI speeds between 0.8 and 6 MHz, so if you need a speed lower than 6 MHz, please set to 0.8 MHz or lower."); speedMhz = 6; } using (await _device.ComsLock.LockAsync().ConfigureAwait(false)) { var spi0Ckr = (int)Math.Round(24.0 / speedMhz - 1); if (spi0Ckr > 255.0) { spi0Ckr = 255; Debug.WriteLine( "NOTICE: Requested SPI frequency of {0} MHz is below the minimum frequency, and will be clipped to 0.09375 MHz (93.75 kHz).", speedMhz); } else if (spi0Ckr < 0) { spi0Ckr = 0; Debug.WriteLine( "NOTICE: Requested SPI frequency of {0} MHz is above the maximum frequency, and will be clipped to 24 MHz.", speedMhz); } var actualFrequency = 48.0 / (2.0 * (spi0Ckr + 1.0)); if (Math.Abs(actualFrequency - speedMhz) > 1) { Debug.WriteLine( "NOTICE: SPI module actual frequency of {0} MHz is more than 1 MHz away from the requested frequency of {1} MHz", actualFrequency, speedMhz); } if (dataToWrite.Length > 255) { throw new Exception("Maximum packet length is 255 bytes"); } var header = new byte[7]; header[0] = (byte)DeviceCommands.SpiTransaction; header[1] = (byte)(chipSelect?.PinNumber ?? 255); header[2] = (byte)chipSelectMode; header[3] = (byte)spi0Ckr; header[4] = (byte)spiMode; header[5] = (byte)burstMode; header[6] = (byte)transactionLength; // just send the header if (burstMode == SpiBurstMode.BurstRx) { await _device.SendPeripheralConfigPacketAsync(header).ConfigureAwait(false); } else { var dataToSend = new byte[transactionLength + header.Length]; Array.Copy(header, dataToSend, header.Length); Array.Copy(dataToWrite, 0, dataToSend, header.Length, transactionLength); var bytesRemaining = dataToSend.Length; var offset = 0; while (bytesRemaining > 0) { var transferLength = bytesRemaining > 64 ? 64 : bytesRemaining; var tmp = dataToSend.Skip(offset).Take(transferLength); await _device.SendPeripheralConfigPacketAsync(tmp.ToArray()).ConfigureAwait(false); offset += transferLength; bytesRemaining -= transferLength; } } // no need to wait if we're not reading anything if (burstMode != SpiBurstMode.BurstTx) { var bytesRemaining = transactionLength; var srcIndex = 0; while (bytesRemaining > 0) { var numBytesToTransfer = bytesRemaining > 64 ? 64 : bytesRemaining; var receivedData = await _device.ReceiveCommsResponsePacketAsync((uint)numBytesToTransfer) .ConfigureAwait(false); Array.Copy(receivedData, 0, returnedData, srcIndex, receivedData.Length); // just in case we don't get what we're expecting srcIndex += numBytesToTransfer; bytesRemaining -= numBytesToTransfer; } } } return(returnedData); }
/// <summary> /// Construct a shift register attached to an SPI port /// </summary> /// <param name="spiModule">The SPI module this shift register is attached to</param> /// <param name="latchPin">The latch pin to use</param> /// <param name="numPins">The number of pins on the shift register</param> /// <param name="mode">THe SPI mode to use with this shift register (and subsequent ones on this chain)</param> /// <param name="csMode">The chip select mode to use with this shift register (and subsequent ones on this chain)</param> /// <param name="speedMhz">The speed to operate this shift register (and subsequent ones on this chain) with</param> public ShiftOut(Spi spiModule, SpiChipSelectPin latchPin, int numPins = 8, SpiMode mode = SpiMode.Mode00, ChipSelectMode csMode = ChipSelectMode.PulseHighAtEnd, double speedMhz = 1) : base(spiModule, latchPin, numPins / 8, speedMhz, mode, csMode) { setup(numPins); }