public byte[] Write(IDigitalOut DeviceSelect, byte[] Data, int DataLength) { DeviceSelect.SetOutput(false); byte[] DataReturn = RaspberryPi.SPIRW(BusNum, Data, DataLength); DeviceSelect.SetOutput(true); return(DataReturn); }
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= /// <summary> /// Enables the SPI slave device which uses a GPIO pin as a slave select. /// /// NOTE on how this works. When using a GPIO pin as a slave select line /// we still need to open a SPIDev device because we need a device to /// send the data to. The way SPIDev works each spidev device is /// fundamentally associated with a particular slave select line and /// this cannot be changed. The GPIO line will be used as a separate /// slave select but the spidev device specific slave select will also /// be asserted whenever the device is writtent to. /// /// In order to use a GPIO as a slave select you must ignore and not /// electrically attach anything to the slave select pin the SPIDEV /// device uses as it will be asserted on each write. /// /// In other words, the SPIDev device is needed to shift the data in /// and out, however you must ignore its internal slave select line /// entirely if you wish to use GPIO based slave selects. Otherwise /// any device attached to it will be receive every write to the /// SPIPort no matter which GPIO slave select is also asserted. /// /// </summary> /// <returns>ssHandle - the handle for the Slave Device or null for fail</returns> ///// <param name="spiSlaveDeviceIn">The GPIO of the pin we use as the slave select</param> /// <param name="output"> The <see cref="IDigitalOut"/> to prepare for SPI CS use. </param> /// <history> /// 16 Sep 17 Cai Biesinger - Modified for Scarlet: Switched from direct GPIO control to IDigitalOut. /// 21 Dec 14 Cynic - Originally written /// </history> public void EnableSPIGPIOSlaveDevice(IDigitalOut output) { // get first slave device. We need to check we have one SPISlaveDeviceHandle ssHandle = PortDevice; // sanity check if (ssHandle == null) { throw new Exception("At least one non GPIO Slave Device must be enabled first."); } // set this high by default, most modes have slave selects high and go low to activate output.SetOutput(true); //Console.WriteLine("SPIPort GPIO Slave Device Enabled: "+ gpioEnum.ToString()); // record that we opened this slave device (so we can close it later) SlaveDevices.Add(output); }
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= /// <summary> /// Writes/Reads a buffer out/in to/from an SPI Slave Device. /// /// Note that the TO/FROM's and IN/OUT's in the above line are there because /// the SPI protocol always reads a byte for every byte sent. If you send a /// byte you get a byte. If you do not sent a byte you will never receive /// a byte since this code operates as an SPI Master. Thus if you only /// wish to receive you must send an equivalent number of bytes. The /// bytes you send are determined by the Slave. Sometimes this is just /// 0x00 and sometimes it represents an address to read - exactly what you, /// send is entirely slave device implementation dependent. /// /// If you only wish to transmit, not receive, just use NULL for your /// rxBuffer. The SPI port will still receive, of course, but you will /// not be bothered by it. /// /// NOTE: the Slave Select is set when you opened the port. The rule is /// one slave to one SPISlaveDeviceHandle. /// /// </summary> /// <param name="ssHandle">The SPI Slave Device handle to write to</param> /// <param name="txByteBuf">The buffer with bytes to write</param> /// <param name="rxByteBuf">The buffer with bytes to receive. Can be NULL</param> /// <param name="numBytes">The number of bytes to send/receive /// <history> /// 16 Sep 17 Cai Biesinger - Modified for Scarlet: switching from file descriptor GPIO to IDigitalOut. /// 21 Dec 14 Cynic - Originally written /// </history> public void SPITransfer(IDigitalOut output, byte[] txByteBuf, byte[] rxByteBuf, int numBytes) { int spiFileDescriptor = -1; int ioctlRetVal = -1; // sanity check if (output == null) { throw new Exception("Null IDigitalOut object"); } if (txByteBuf == null) { throw new Exception("Null tx buffer"); } if (numBytes <= 0) { throw new Exception("numBytes <= 0"); } // set up our file descriptor // use the descriptor of the first non-GPIO slave select // we find. // get first slave device. We need the file descriptor SPISlaveDeviceHandle firstHandle = PortDevice; // sanity check if (firstHandle == null) { throw new Exception("At least one non GPIO Slave Device must be enabled."); } // use this descriptor spiFileDescriptor = firstHandle.SpiDevFileDescriptor; // the data needs to be in unmanaged global memory // so the spidev driver can see it. This allocates // that memory. We MUST release this! IntPtr txBufPtr = Marshal.AllocHGlobal(numBytes + 1); IntPtr rxBufPtr = Marshal.AllocHGlobal(numBytes + 1); try { // copy the data from the tx buffer to our pointer Marshal.Copy(txByteBuf, 0, txBufPtr, numBytes); // create and fill in the contents of our transfer struct spi_ioc_transfer xfer = new spi_ioc_transfer(); xfer.tx_buf = txBufPtr; xfer.rx_buf = rxBufPtr; xfer.len = (UInt32)numBytes; xfer.speed_hz = 0; //(UInt16)ssHandle.SpeedInHz; xfer.delay_usecs = 0; // ssHandle.DelayUSecs; xfer.bits_per_word = 0; // ssHandle.BitsPerWord; xfer.cs_change = 0; // ssHandle.CSChange; xfer.pad = 0; // lower the slave select output.SetOutput(false); try { // this is an external call to the libc.so.6 library ioctlRetVal = ExternalIoCtl(spiFileDescriptor, SPI_IOC_MESSAGE_1, ref xfer); } finally { // raise the slave select // CaiB 2017-09-16: Chenged this to true, BBBCSIO never released SS. output.SetOutput(true); } // did the call succeed? if (ioctlRetVal < 0) { // it failed throw new Exception("ExternalIoCtl on device " + output + " failed. retval=" + ioctlRetVal.ToString()); } // did the caller supply a receive buffer if (rxByteBuf != null) { // yes they did, copy the returned data in Marshal.Copy(rxBufPtr, rxByteBuf, 0, numBytes); } } finally { // Free the unmanaged memory. Marshal.FreeHGlobal(txBufPtr); Marshal.FreeHGlobal(rxBufPtr); } }