SPI basic transactions

Status
Not open for further replies.

ben10teensy

Well-known member
To better understand the logic of SPI devices I have some questions that may also be helpful to others with the same confusion.
Also my device does not have a written library.

This link is to the teensy spi information:
https://www.pjrc.com/teensy/td_libs_SPI.html

From reading this over I want to understand whats going on, on the basic usage

SPI.begin() ## This starts the SPI

SPI.beginTransaction(SPISettings(clockspeed, MSBFIRST, SPI_MODE0)) ## This sets SPI settings

digitalWrite(SSpin, LOW) ## This Sets the Chipselect pin LOW or HIGH depending on the device to start that particular device communication

SPI.transfer(data) ## This sends data to What?

SPI.endTransaction() ## this terminates the SPI


My device has Register Banks, and Addresses.

would I code this

SPI.transfer(BANK)

then I could read through the registers with

SPI.transfer(register)

If i have 3 registers , How would I read a particular register?

a = SPI.transfer(register)

thanks for the help
 
It would be really good to know which SPI you use, and if a datasheet is available.. if you want help :)
SPI is only about DATA - it does not know about banks or registers. This is device-specific.
 
OK what i'm kinda dealing with is a datasheet that cannot be released.
So i'm trying to figure this out.
With analog devices ofcourse you see its value on the pin
How would you explain the stream , does it have to be parsed? what signals do we look for ?

not sure if thats the right thinking.

As in this function from the spi page

int digitalPotWrite(int address, int value) {
// take the SS pin low to select the chip:
digitalWrite(slaveSelectPin,LOW);
// send in the address and value via SPI:
SPI.transfer(address);
SPI.transfer(value);
// take the SS pin high to de-select the chip:
digitalWrite(slaveSelectPin,HIGH);
}

this selects an address then writes a value
how would I
select an address and read a value ?
 
"value = transfer(0x00); <- the 0x00 is ok in most cases, but not all. that depends on your device."

So this would be the value read?

and if i had to change addresses lets say its
01
02
03

would that function run completley through? would each number have an initial value placeholder?
and i would pull up or down the SS between reads of different addresses?
Or would it stream in then after reading a bunch, then I pull SS up or down?
 
SPI.beginTransaction(SPISettings(clockspeed, MSBFIRST, SPI_MODE0)) ## This sets SPI settings

Yes, it establishes the settings. It also prevents other libraries (which use interrupts) from accessing the SPI, until you do SPI.endTransaction(). That's a non-issue if you don't have any other libs accessing SPI, but it's an important safety feature which you get automatically by using this function. It's good practice to complete your communication and call SPI.endTransaction() as soon as possible, then actually do something with whatever data you communicated.

SPI.transfer(data) ## This sends data to What?

The "data" byte is transmitted to the MOSI (or DOUT) pin while 8 clocks pulses are generated on the SCK pin. Whatever signal happens to be on the MISO (or DIN) pin is captured as well, though you don't have to use it if you don't care.

This is how SPI works. Data output and input always happen together. Most SPI chips expect you to send them commands and do not send you anything useful during those clocks, so you would just ignore the return value when sending if those cases. Many chips that give you data ignore whatever you send, so when receiving it's common to send 0 or 255.

There are a huge number of SPI chips, all with their own expectations about which bytes you send and receive.

Almost all (but there are a few exceptions) SPI chips need you to drive their chip select (or SS) signal low before any data transfer, and then bring it high when you're done. While this is the norm, there are some chips which need extra clock pulses after the chip select is high, where data is usually ignored or expected to be a specific value during those extra clocks.

It's up to you to use the right combination of digitalWrite and SPI.transfer to communication with whatever chip you're using.

When it comes to communication with humans, we're much more flexible than SPI chips. But still, some ways work better than others. When you leave out details, like even the part number of the chip you're using, you cut off opportunity for people to better help you. Likewise for posting the actual code you've written. Instead, only a rather generic message like this can be written. If I or others happen to know of any specific issues with the chip you're using, or there's some subtle but important issue with your code, or some related thing has been misunderstood, you lose the chance to get help with the questions you didn't know to ask....
 
As Frank mentioned, SPI is simply a mechanism to transfer data.
That is all that is really defined is, when you do something like: x = SPI.transfer(y);

Since you are using the SPI library it is assumed you are the SPI master. So it will drive the clock signal at the specified clock speed, in the correct order (MSB or LSB) and with a value of 1 either being High or LOW and maybe when the data is valid (leading or trailing edge) (depending on mode). The Master (teensy) will stream out the bits of Y on the MOSI (or SDO) pin and it will stream in data on the MISO(also known as SDI), and will return the data into the Y register.

With SPI there may be multiple slave devices and the way they know the data is for them and/or expected from them is their Chip Select pin is asserted.

That is more or less all the system knows.

So then each device may setup it's on structure on what these data bytes mean...

Some devices may expect a command from the host, which will produce N bytes of data to return. Some do this by special values, or timing. Others do it by having another data pin, which is used to tell the device if the byte sent to it should be interpreted as a command or as data. Example of this is the ILI9341 display.

So you need to understand your actual device in order to know how to do things like set the bank and read a register.
 
Thats a very good explanation , my apologies for the lack of information, I do understand you are all trying to help with my limited knowledge and lack of code.
I have a non-disclosure-agreement so I do not want to get in any trouble, and I'm currently talking with different programmers on how much this could cost to get going.
I just wanted to get the ball rolling. but I really appreciate you all always answering our sometimes dumb questions
 
So even if Y was sent through the from the Master
I will read the value from Y after the first send .. In theory?
 
So even if Y was sent through the from the Master
I will read the value from Y after the first send .. In theory?

I only touched SPI once - in this code : github.com/PaulStoffregen/XPT2046_Touchscreen

This tells the SPI Touch to send the X,Y and pressure data values needed. Not sure if it will help you - but with comments it was enough for me to understand Paul's code and do some mods to it when I added the interrupt enabled processing.

The command goes out - whenever data goes out data comes in - but it is behind on the incoming data. This is where knowing your device commands and response details are critical. Knowing what commands and how much data and in what format it is returned in what order.
 
High-jacking, but perhaps useful for ben10teensy as well:
The Teensy page at https://www.pjrc.com/teensy/td_libs_SPI.html includes the paragraph:
Slave Select Signal

Any digital pin can be used for a SS (slave select) signal. The SPI library does not control the SS signals, because devices differ on when this is used, whether it is held low for multiple transfers or for each individual transfer, and so on. Control SS with digitalWrite().
However, the SS pin must either be configured as an output, or if it is an input, it must remain low during the SPI transfer. Unconfigured pins default to input, and a pin with no signal can easily "float" to random voltages due to electrical noise. Always configure the SS pin as an output, or make sure it remains low.

Most SPI devices are designed to work together with others, where SCK, MISO, and MOSI are shared. Each chip needs a separate SS signal. Only the selected chip will communicate. The others ignore SCK and MOSI, and avoid driving MISO when they are not selected.
My current add-on board design uses pin 10 for another function - yet I want to use Teensy 3.6's SD card slot.

Can I reassign the Slave Select pin for SPI with the SD card on Teensy 3.6?
Can I then use pin 10 for something else? (it's a "ready for data" signal used by another SPI device)

(If I need to change pin usage, I'll do that now before soldering on the just-arrived OshPark boards.)
 
For the most part with normal apps using standard SPI (which is using SPI as the master) library you can use any digital pin as a chip select pin.
You simply need to set the pin to be digital and typically set it high when not in use and low when your SPI output is supposed to go to the device.

However there are a few libraries, like the ili9341_t3 library that uses some of the more advanced SPI functionality of the KinetisK boards (T3.x). With this library you need to use 1 or 2 of the hardware CS pins... The above mentioned library currently requires 2 CS pins, whereas my ili9341_t3n library can use 2, but also works with just 1 for the DC pin...

Why these boards have a hardware SPI queue that allows you to queue a few items to be output and the queue entries have the ability to control hardware CS pins... Can explain more if needed, but again for most programs using the SPI library you are free to use other pins...
 
Thanks. What's the PIN number for the SD card's Chip Select? or is it even exposed as a pin on the Teensy?
 
If you are using the SD port on the Teensy 3.5 or 3.6 it does not use SPI, it has it's own hardware support, which is hopefully faster.

If you look at any of the example programs you should see things like this in the comments:

Code:
// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
// Teensy audio board: pin 10
// Teensy 3.5 & 3.6 on-board: BUILTIN_SDCARD
// Wiz820+SD board: pin 4
// Teensy 2.0: pin 0
// Teensy++ 2.0: pin 20
So to use it in your program for SD use the BUILTIN_SDCARD

However if you are asking can I use the underlying IO pins for other things, the answer is yes - If you build an adapter to get to the IO pins. Which are IO pins 58-63. And many of these pins have other functions which can be used (alternate pins) for things like Serial1 or Serial5 or SPI1

But again if use are using this for the SDCARD the underlying system is using the SDHC interface (pins in Mode 4) and not SPI (Mode 2)...
 
I think I get it.
I ran this line of code
Code:
  Serial.printf("BUILTIN_SDCARD = %d\n", BUILTIN_SDCARD);
to see that BUILTIN_SDCARD = 254 (and not 10).

Cool. My board design will work!

The "Mode X" designation you speak of is new to me. Does this relate to SPI_MODE0 - SPI_MODE3 at
Code:
https://www.arduino.cc/en/Reference/SPI
, or to the 4 color-coded pin labels on the Teensy 3.6 reference card?

Either way, thanks @KurtE.
I think I'm in good shape!
 
If you look in the SPI code the #==254 is probably a flag to use the alternate access Mode - on the unique pins noted above, wholly unique and different from any of the other SPI buses
 
Search and you can find :: wiki/Serial_Peripheral_Interface_Bus#Mode_numbers

And indeed - processor specific code that bypasses standard SPI init:
Code:
  uint8_t init(uint8_t sckRateID, uint8_t chipSelectPin) {
    #if defined(__MK64FX512__) || defined(__MK66FX1M0__)
    if (chipSelectPin == BUILTIN_SDCARD) {
      chipSelectPin_ = BUILTIN_SDCARD;
      uint8_t ret = KinetisSDHC_InitCard();
      type_ = KinetisSDHC_GetCardType();
      return (ret == 0) ? true : false;
    }
    #endif
    return SD_init(sckRateID, chipSelectPin);
  }
 
That's good news and clever design.
Thanks

And the "Modes?"

Sorry, I did not mean to confuse things. If you are asking about what I meant by Pins in different Modes... Almost every IO pin is setup on processor to be able to do different things, depending on how the Pin is configured... Sometimes mentioned as Mode sometimes mentiond as Alternate... When we first started testing on the T3.6 in the beta, I and several others made tables and the like to show this. Example from
my Excel spreadsheet

Code:
On-board SD card (dedicated 4-bit SDIO)										
----------------		
				[B]ALT0		ALT1		ALT2		ALT3		ALT4		ALT5		ALT6		ALT7[/B]
58	PTE0	ADC1_SE4a	ADC1_SE4a	PTE0		SPI1_PCS1	UART1_TX	SDHC1_D1	TRACE_CLKOUT	I2C1_SDA	RTC_CLKOUT
59	PTE1	ADC1_SE5a	ADC1_SE5a	PTE1/LLWU_P0	SPI1_SOUT	UART1_RX	SDHC0_D0	TRACE_D3	I2C1_SCL	SPI1_SIN
60	PTE2	PTE2/LLWU_P1	ADC1_SE6a	PTE2/LLWU_P1	SPI1_SCK	UART1_CTS_b	SDHC0_DCLK	TRACE_D2		
61	PTE3	ADC1_SE7a	ADC1_SE7a	PTE3		SPI1_SIN	UART1_RTS_b	SDHC0_CMD	TRACE_D1			SPI1_SOUT
62	PTE4	DISABLED			PTE4/LLWU_P2	SPI1_PCS0	UART3_TX	SDHC0_D3	TRACE_D0		
63	PTE5	DISABLED			PTE5		SPI1_PCS2	UART3_RX	SDHC0_D2			FTM3_CH0
Sorry pretty quick cut/paste from my excel document, so not all of the columns may align properly:
But in this ALT0(Mode) typically implies Analog, ALT1 - Digital, ALT2 - SPI, ALT3 - Serial, ALT4 - SDHC, 5-?, 6 - I2C, 7 - Depends (alternate SPI in couple cases here)

But again sorry, this digressed from your main topic. My main point was when you use on on board SDCard you are not using SPI (ALT 2), but instead SDHC (ALT 4)
 
Got it.
In one sense, I just want it to work.
(But in the back of my mind, it's cool to see how this stuff works)
 
Status
Not open for further replies.
Back
Top