SPI Configuration and the various Modes - Netduino Plus 2 (and Netduino Plus 1) - Netduino Forums
   
Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

SPI Configuration and the various Modes

SPI Modes CPOL CPHA

  • Please log in to reply
7 replies to this topic

#1 Gutworks

Gutworks

    Advanced Member

  • Members
  • PipPipPip
  • 363 posts
  • LocationOttawa, Ontario

Posted 24 January 2013 - 08:03 PM

Hi everyone,   I've been trying to get a better grasp on using the Serial Peripheral Interface Bus as my knowledge of SPI has been mediocre at best. I'm hoping that some of the many geniuses in this community can help clarify the different SPI modes and help me to better understand the data that I'm seeing which I will post as a secondary question later.    From my limited understanding I believe there are 4 possible Modes when using SPI, each using different clock polarity (CPOL) and phase (CPHA) settings. I haven't been able to find a lot of information that shows how these settings translate over to the NETMF so here's my best shot, primarily due to the great information provided in a post by rcross.    If I understand correctly the Clock_IdleState parameter of the SPI Configuration class refers to the CPOL, and the Clock_Edge is the same as the CPHA. And if the various Modes for SPI are as follows:

Attached File  SPI_Modes.gif   2.48KB   18 downloads

  So here's the tricky part, at least for me; how does this translate to the Clock_IdleState and Clock_Edge? From what I can tell when CPOL is 0 it means the base clock value is 0, or in other words the Clock_IdleState is low when inactive, or false. When in this state and CPHA is 0, data is captured on the clock's rising edge (low to high transition). Or in other terms, the Clock_Edge is set to true to allow the data to be held stable on the rising edge.    Now this is where it gets confusing. When the CPOL base clock is set to 1, or Clock_IdleState is high when inactive, the CPHA settings are inverted. For instance in Mode 2 when the CPOL is 1, the Clock_IdleState becomes true, however the CPHA or Clock_Edge is now set to false.    Here is a table with the various Modes and the NETMF complimentary settings:

Attached File  NETMF_SPI_Modes.gif   4.83KB   12 downloads  

If I have made any errors or have grossly misunderstood these settings, please let me know.    Cheers, Steve


Edited by Gutworks, 02 January 2014 - 01:24 AM.


#2 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 25 January 2013 - 04:20 AM

Hello Steve.

I agree on the bad choice for the flags: since we're talking about "SPI" (nothing else than SPI), why not using the flags for which has been designed? An additional pair of flags leads only to a more confusion: that's the proof.

 

Anyway, I wrote something similar on the Wiki a time ago. It would be nice if you enrich/cut it in order to get an useful post.

http://wiki.netduino...le-74HC595.ashx

Cheers


Biggest fault of Netduino? It runs by electricity.

#3 Gutworks

Gutworks

    Advanced Member

  • Members
  • PipPipPip
  • 363 posts
  • LocationOttawa, Ontario

Posted 25 January 2013 - 08:44 PM

Mario, I had completely forgotten about your WIKI post. I mistakenly skipped over it recent days thinking it only focused on the shift registers,  forgetting it had a great SPI walk through. 

 

Right now I'm trying to find more information on how the the WriteRead() method works, and more specifically how to properly use this overloaded method:

 

public void WriteRead (UInt16[] writeBuffer,int writeOffset,int writeCount,UInt16[] readBuffer,int readOffset,int readCount,int startReadOffset) 

Also I'm been attempting to wrap my head around the ChipSelect_SetupTime, ChipSelect_HoldTime, and how the affect the SPI transmission. 

 

Thanks!

 

 

Thanks,

Steve



#4 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 25 January 2013 - 09:16 PM

Right now I'm trying to find more information on how the the WriteRead() method works, and more specifically how to properly use this overloaded method:

 

The key to understanding is to realize the SPI communication between master and slave happens over a circular buffer, so sending data from master to slave also 'pushes' data from slave to master, for example have a look at the image on wikipedia. The parameters writeOffset, writeCount resp. readOffset, readCount are just for convenience, to specify the part of buffer you want to write from/read to. The last parameter startReadOffset is used when you need to skip a few bytes that master reads from slave so they are not stored in the read buffer, usually because the slave needs to receive a few bytes first and then process them to know how to response - for example, if you send two bytes command, you can ignore two received bytes, which are received from slave before it has got and understood the command.

 

Also I'm been attempting to wrap my head around the ChipSelect_SetupTime, ChipSelect_HoldTime, and how the affect the SPI transmission.

 

SetupTime is the duration before SPI starts clocking out the data after chipselect is active, hold time is the duration for which the chipselect remains active after the transmission (clock) ends. Some slaves require certain delays after chipselect, so they can initialize/prepare for the reception.



#5 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 26 January 2013 - 07:10 AM

Quick update...

The new 4.2.2.1 firmware now supports the clock 'idle high' setting properly.

Here's a link to the new firmware:
Netduino Plus 2 4.2.2.1 firmware

Chris

#6 Gutworks

Gutworks

    Advanced Member

  • Members
  • PipPipPip
  • 363 posts
  • LocationOttawa, Ontario

Posted 26 January 2013 - 08:04 AM

Hi CW2,
 
Thanks for your great primer. It was very useful and quickly help me get my head wrapped around those settings. Originally in my SPI sample code I was simply creating an array with 3 bytes directly in the Write method (i.e. spi.WriteRead(new byte[] { 1, 2, 3 }); ). Because of that I never really got to see the effects of passing it an buffered array that would be commonly used in SPI communications. 
 
For example if one were to create two arrays to hold the data that will be sent and received as such:

sendBuffer = new byte[10];receiveBuffer = new byte[10];sendBuffer[0] = 0x01;sendBuffer[1] = 0x02;sendBuffer[2] = 0x03;spi.WriteRead(sendBuffer, receiveBuffer); //No offsets used

The resulting output would look like this:
Attached File  NP2_SPI-Mode_0-Offsets.jpg   65.78KB   49 downloads
 
And if instead I new I only need the first three meaningful bytes, I could use the offsets as such:

sendBuffer = new byte[10];receiveBuffer = new byte[10];sendBuffer[0] = 0x01;sendBuffer[1] = 0x02;sendBuffer[2] = 0x03;spi.WriteRead(sendBuffer, 0, 3, receiveBuffer, 0, 3, 0);

 
And the resulting output would look a lot cleaner:
Attached File  NP2_SPI-Mode_0-Offsets-3.jpg   62.11KB   52 downloads
 
 
 
As for the ChipSelect_SetupTime and ChipSelect_HoldTime I found that the setup and hold times seem to have a bit of padding when initialized at 0µs, which is mentioned in the Wiki. Interestingly enough the NETMF API documentation for SPI is a bit sparse and has some incorrect information. There it states, "The setup time for the chip select port, in milliseconds.", however we see with the logic anlazyer that it's in fact measured in microseconds. There's also a missing constructor for the Configuration class, but I won't get into that right now :)
 
Here's what Mode 0 and a setting of 0µs for both the ChipSelect_SetupTime and ChipSelect_HoldTime look like with the following code:

SPI.Configuration spiConfiguration = new SPI.Configuration(				     Pins.GPIO_PIN_D10, //Chip Select pin				     false,     // Chip Select Active State low				     0,         // Chip Select Setup Time 0us				     0,         // Chip Select Hold Time 0us				     false,     // Clock Idle State				     true,      // Clock Edge				     500,       // Clock Rate in kHz				     SPI_Devices.SPI1); //SPI ModuleSPI spi = new SPI(spiConfiguration);while (true){	spi.Write(new byte[] { 1, 2, 3 });}

 
And the output looks like this:
Attached File  NP2-SPI-Mode_0-ChipSelect_SetupTime-0.jpg   67.82KB   55 downloads
 
And by adding 20µs to each setting, we see this result:
Attached File  NP2-SPI-Mode_0-ChipSelect_SetupTime-20.jpg   65.16KB   37 downloads
 
Note that the additional 20µs to the ChipSelect_SetupTime did not translate into exactly 23.5625µs (3.5625µs + 20µs) but rather 18.6875µs. I don't believe it really has any adverse affect to the data, but curious none the less. 
 
Anyway, It's time for me to grab some shut eye. Thank you everyone for your input thus far. I'm learning a ton and will hopefully be able to pass some of that knowledge off to other people just starting to get their SPI feet wet. 

Cheers,

Steve

 

P.S. These tests were done with the latest Netduino Plus 2 Firmware, 4.2.2.1.



#7 supra

supra

    Advanced Member

  • Members
  • PipPipPip
  • 210 posts
  • LocationOntario, Canada

Posted 26 January 2013 - 01:19 PM

What does parameter do?

spi[color=rgb(102,102,0);].[/color][color=rgb(102,0,102);]Write[/color][color=rgb(102,102,0);]([/color][color=rgb(0,0,136);]new[/color] [color=rgb(0,0,136);]byte[/color][color=rgb(102,102,0);][][/color] [color=rgb(102,102,0);]{[/color] [color=rgb(0,102,102);]1[/color][color=rgb(102,102,0);],[/color] [color=rgb(0,102,102);]2[/color][color=rgb(102,102,0);],[/color] [color=rgb(0,102,102);]3[/color] [color=rgb(102,102,0);]});[/color]

 

[color=rgb(102,102,0);]Supra[/color]



#8 Nevyn

Nevyn

    Advanced Member

  • Members
  • PipPipPip
  • 1072 posts
  • LocationNorth Yorkshire, UK

Posted 26 January 2013 - 01:41 PM

What does parameter do?

spi[color=rgb(102,102,0);].[/color][color=rgb(102,0,102);]Write[/color][color=rgb(102,102,0);]([/color][color=rgb(0,0,136);]new[/color] [color=rgb(0,0,136);]byte[/color][color=rgb(102,102,0);][][/color] [color=rgb(102,102,0);]{[/color] [color=rgb(0,102,102);]1[/color][color=rgb(102,102,0);],[/color] [color=rgb(0,102,102);]2[/color][color=rgb(102,102,0);],[/color] [color=rgb(0,102,102);]3[/color] [color=rgb(102,102,0);]});[/color]

 

new byte[] { 1, 2, 3}

 

It creates a new array of bytes with three elements.  Element 0 is set to 1, element 1 is set to 2 etc.  It's a handy way of creating a new array without having to give it a name.

 

Regards,

Mark


To be or not to be = 0xFF

 

Blogging about Netduino, .NET, STM8S and STM32 and generally waffling on about life

Follow @nevynuk on Twitter






Also tagged with one or more of these keywords: SPI, Modes, CPOL, CPHA

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.