Sunday, July 31, 2016

Nusbio SPI

Overview


The Serial Peripheral Interface (SPI) bus is a communication protocol primarily in embedded systems.
A lot devices like an EEPROM, SD card reader, graphic screen (AKA OLED) and more support the SPI protocol.
It is generally not available for Windows easily, though it is available on the Raspberry PI via Python and C.
That is why I created Nusbio.net that offers in a simple way to talk SPI from Windows and .NET.



For more information see the

C# Class

This post explains the SPIEngine .NET class for the Nusbio device.


Wiring

Since Nusbio has 8 gpio pins, you can setup an SPI bus and control up to 5 SPI devices. I generally use the following:
  • Gpio0 - CLOCK
  • Gpio1 - MOSI
  • Gpio2 - MISO
  • Gpio3 - CS 1
  • Gpio4 - CS 2
  • Gpio5 - CS 3
  • Gpio6 - CS 4
  • Gpio7 - CS 5

Controlling more than 5 SPI devices is for now not possible due to a software limitation in the class SPIEngine, which will be fixed by the end of 2017.

Note that you could use Gpio6 and Gpio7 to setup an I2C bus and therefore control for example
  • 3 SPI devices
  • 127 I2C devices
  • Using the SPI bus you could add an analog to digital converter (ADC) like the MCP3008 and therefore also add 8 ADCs (ADC TutorialSensors Extension).




Software

For each SPI device on the bus you must create an object of the class SPIEngine. After that you call the
the method Transfer() to send or receive data. You do not need to call the method Select() and Unselect() when calling Transfer().

public SPIEngine(Nusbio nusbio, 
                 NusbioGpio selectGpio, 
                 NusbioGpio mosiGpio, 
                 NusbioGpio misoGpio, 
                 NusbioGpio clockGpio, 
                 NusbioGpio resetGpio = NusbioGpio.None);

public SPIResult Transfer(byte b);

public SPIResult Transfer(List<byte> bytes, 
                          bool select = true, 
                          bool optimizeDataLine = false);


public SPIMode Mode;

public enum SPIMode
{
    MODE_CPOL0_CPHA0 = 0,
    MODE_CPOL1_CPHA0 = 1,
    MODE_CPOL0_CPHA1 = 2,
    MODE_CPOL1_CPHA1 = 3
}

public void Select()
public void Unselect()



Samples


I2C EEPROM


Here is a basic sample reading the first 4 pages of the SPI EEPROM 25AA1024 which is a 128 k bytes EEPROM with a page size of 256 bytes (20 mHz). We are therefore transferring 1 k bytes of data from the EEPROM to the PC.



var _eeprom = new EEPROM_25AA1024(
    nusbio   : nusbio,
    clockPin : NusbioGpio.Gpio0,
    mosiPin  : NusbioGpio.Gpio1, 
    misoPin  : NusbioGpio.Gpio2,
    selectPin: NusbioGpio.Gpio3
    );

var r = _eeprom.ReadPage(0, _eeprom.PAGE_SIZE * 4);
if(r.Succeeded)
{
    var data = r.Buffer;
}

// ...
// Class 25AA1024
// ...
public override EEPROM_BUFFER ReadPage(int addr, int len = -1)
{
    if (len == -1)
        len = PAGE_SIZE;

    var eb = new EEPROM_BUFFER();
    int byteSent = 0;
    var spiBufferWrite = GetEepromApiReadBuffer(addr);
    var spiBufferRead = GetEepromApiDataBuffer(len);
    var buffer = new List<byte>();
    buffer.AddRange(spiBufferWrite);
    buffer.AddRange(spiBufferRead);

    var r = this._spi.Transfer(buffer);
    if (r.Succeeded)
    {
        eb.Succeeded = true;
        eb.Buffer = r.ReadBuffer.GetRange(spiBufferWrite.Length, r.ReadBuffer.Count - spiBufferWrite.Length).ToArray();
    }
    return eb;
}



See full source code of class EEPROM_25AAXXX_BASE.cs.


Performance Improvement

By default the SPI transfer rate using Nusbio and a Windows machine is limited around 15 Kb/s.
There are 3 ways improve performance transfer giving from 20 Kb/s to 28 Kb/s depending of what type of SPI device your are controlling

  1. If there is no MISO (Master In Slave Out) needed or in other way if we only send data from the PC to the SPI device. In the constructor pass the miso parameter as None, and when calling the method Transfer() set the paramter optimizeDataLine to true. This will increase the output speed by about 33%.
  2. To force an SPI EEPROM to send the next 64 bytes of data from an EEPROM to the PC,  EEPROMs generally require that the master send 64 0 as byte. 64 0 is equal to 64 x 8 (512) bit set to 0. There is no need to set the data line to 0, 512 times, once is enough. Based on this concept the class EEPROM_25AAXXX_BASE.cs contains the method ReadPageOptimized(), which implement the optimization. It is open source and complicated. But this increase the performance from 15 k byte/s to 28 k byte/s.
  3. This third way only works for control APA 102 RGB LED and is kind a pushy. It consist to use the same cycle to set the data and to set the clock data line high. It gives a transfer rate up to 20 Kb/S.
    See the our Github C# project on Github Extension.APA102_2_StripAdapter.

 

OLED, Data Command Pin and SPI

Some SPI OLED  driver may requires an extra pin called DataOrCommand (D/C). This is not par per say part of the SPI protocol, but it is needed, to achieve better performance the SPIEngine class offers the following methods. The methods allow to package buffers of type Data and buffers of type Command and then send the buffers as SPI buffers with limited USB operations.

public void TransferNoMiso(bool reverse, List buffer);
public void TransferNoMiso(byte dataOrCommandBit, bool reverse, List PackagedBuffers);
public void TransferNoMiso(int dataOrCommand, byte dataOrCommandBit, bool reverse, List buffer);

See our folder Oled on Github for more information. We do support the SH1106 and SSD1306 OLED driver.




APA 102 RGB LED and SPI

The RGB LED (multi color LED) of type APA 102 use the SPI protocol and are supported by Nusbio.
See our Tutorial page.
See the our Github C# project on Github Extension.APA102_2_StripAdapter.



SPI Modes


The 4 spi modes have been implemented, but only the first mode has been tested.

  • MODE_CPOL0_CPHA0
  • MODE_CPOL1_CPHA0
  • MODE_CPOL0_CPHA1
  • MODE_CPOL1_CPHA1

No comments:

Post a Comment