SPI files/libraries - SPI, SPIN, SPIFIFO, ...

Status
Not open for further replies.

KurtE

Senior Member+
I am about to make another pass through my SPIN library to update it to make use of the new features and functionality of the newer SPI library, as portions of SPIN have logically now migrated into the main SPI library. Like one class to handle all SPI objects, like knowing which pins are valid for CS or MISO, MOSI, SCK...

It would be nice to be able to obsolete SPIN. Some of the features still in SPIN, not in SPI include:

Easy way to get to the SPI registers for the selected SPI port. This could be done by making the port() method public...

FIFO support - My motivation and test of the T3.6/5 and my first test was the ILI9341 display so I started form ili9341_t3 library, and extracted all of the stuff that was SPI port specific... Some of this was the FIFO stuff of the library, like pushing stuff onto the queue (PUSHR) and make sure it is not full, likewise check for popping things off of queue (POPR)...

Then made them work with ILI9341 code for all three busses. Where I found out the code relies on SPI queue size of 4... So I needed to modify as SPI1 and SPI2 have a queue size of 1... So code hung...

Recently I realized that some of this queue code has also been put into another header file (SPIFIFO.h), that is part of core. However this code again is hard coded for SPI object (KINETISK_SPI0) and also again code is hard coded to only work for queue size of 4. With lines like:
while (((KINETISK_SPI0.SR) & (15 << 12)) > (3 << 12))

So trying to figure out options, would be great if all of these could converge into one thing...

For now I will update SPIN... Wondering if SPIFIFO should be updated? Three classes? Or one class that is driven off of SPI class object?

Also FYI, I see three references to SPIFIFO1class in avr_emulation.h (friend class SPIFIFO1class;) and I don't think that class exists... Probably me in early 3.6 days...

There are also other SPI libraries as well, like DMASpi and maybe slave support, but these are probably separate subjects.

Thoughts?
 
Quick update: As I mentioned, I was thinking about updating SPIN library to be more like SPI now and only have one class instead of a base class with subclasses for each buss.

It is still a WIP and still needs some testing, but I put up a version in a temporary branch of it on github: https://github.com/KurtE/SPIN/tree/WIP-SPIN-1-CLASS

I am actually hoping over time, that enough of SPIN will be taken over by SPI, that it won't be needed. The main things in it that are not handled by SPI main library are: some query functions for hardware and buss specific things, like: FIFO queue size, DMA TX and RX for the Buss, a way to query for the hardware registers (i.e. make port() public instead of private). And the FIFO queue support like which is in SPIFIFO.h (except SPIN handles it for all three busses and functions are modified to know that queue size matters.)

I keep meaning to look at differences in code size between the multiple classes and single class.

That is old way:
SPINClass has method like: virtual uint8_t transfer(uint8_t data) = 0;
Where the SPIN0Class method was something like: uint8_t SPIN0Class::transfer(uint8_t data) {return SPI.transfer(data);}

So we are going through a virtual call to function hard coded to single object.

Versus now: inline void transfer(void *buf, size_t count) {spi().transfer(buf, count); }

Which inlined spi() returns reference to object we passed in to constructor and we then call it's method... My gut tells me it will be a wash, but might be interesting to see what code gets generated.
 
Questions/Wondering about SPIFIFO.h

So far I only see it defined/used in: SPIFIFO.h, which is included in avr_emaulation.cpp - to define some static variables that are used.
It is referenced in avr)emulation.h as being a friend of a couple of the emulation classes. and used in the library file: w5100.cpp

Now for the actual stuff in the header file:
Things I wonder include:

it defines HAS_SPIFIFO for all of the F_BUS speeds it checks for. Is there any BUS speed that the KINETISK would not have a FIFO? Should it not simply say if it is KINETISK then it has fifo?

Wonder if it really needs all of this BUS checking and defining base on BUS speed?

That is does it really need to do or should it muck around at all with the ctar for speed and the like in the begin method? The w5100 code does:
Code:
SPI.begin();
	SPIFIFO.begin(ss_pin, SPI_CLOCK_12MHz);  // W5100 is 14 MHz max
	SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
So the beginTrasaction() code will take care of setting the CTAR with baud rate and the like.

Also most of the begin SPIFIFO.begin() functionality then has to do with checking if the SS pin is a valid hardware CS pin and setup the IO pin for hardware usage, can be changed from:
Code:
		if (pin == 10) {         // PTC4
			CORE_PIN10_CONFIG = PORT_PCR_MUX(2);
			p = 0x01;
		} else if (pin == 2) {   // PTD0
			CORE_PIN2_CONFIG = PORT_PCR_MUX(2);
			p = 0x01;
		} else if (pin == 9) {   // PTC3
			CORE_PIN9_CONFIG = PORT_PCR_MUX(2);
			p = 0x02;
		} else if (pin == 6) {   // PTD4
			CORE_PIN6_CONFIG = PORT_PCR_MUX(2);
			p = 0x02;
		} else if (pin == 20) {  // PTD5
			CORE_PIN20_CONFIG = PORT_PCR_MUX(2);
			p = 0x04;
		} else if (pin == 23) {  // PTC2
			CORE_PIN23_CONFIG = PORT_PCR_MUX(2);
			p = 0x04;
		} else if (pin == 21) {  // PTD6
			CORE_PIN21_CONFIG = PORT_PCR_MUX(2);
			p = 0x08;
		} else if (pin == 22) {  // PTC1
			CORE_PIN22_CONFIG = PORT_PCR_MUX(2);
			p = 0x08;
		} else if (pin == 15) {  // PTC0
			CORE_PIN15_CONFIG = PORT_PCR_MUX(2);
			p = 0x10;
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
		} else if (pin == 26) {  
			CORE_PIN26_CONFIG = PORT_PCR_MUX(2);
			p = 0x01;
#endif
		} else {
			reg = portOutputRegister(pin);
			pinMode(pin, OUTPUT);
			*reg = 1;
			p = 0;
		}
to something like:
Code:
		if (SPI.pinIsChipSelect(pin)) { 
			p = SPI.setCS(pin);
		} else {
			reg = portOutputRegister(pin);
			pinMode(pin, OUTPUT);
			*reg = 1;
			p = 0;
		}
Obviously this code is still hard coded to SPI object. Does it make sense to make it work with SPI1 and SPI2? Which is what I have now in the SPIN object.
Would be nice to be able to enable libraries like the W5100 to be able to use different queues. But it may not be completely straight forward as you might think due to the differences in FIFO queue length. Example with ILI9341_t3 code, the code to read in a pixel would do something logically like:
PUSHR 0; PUSHR 0; PUSHR 0; POPR POPR POPR and then build the pixel with the three bytes popped. Which worked fine with SPI that has queue of 4, but fails on SPI1 and SPI2 as queue size 1.

Paul (or other) - Should I do the initial simplifying of this header? Not sure how well I can test it as I may not have any of these devices, unless I can test it with the beta Ethernet adapter, or I do have a T3.2 in a Sparkfun adapter with an Ethernet shield. Doe not have any name on it but the Ethernet connector says HANRUN HR911105A.

Edit: SPIFifo - Not sure a core file should depend on library like SPI?
 
Last edited:
KurtE - just a quick "thanks!', using your SPIN with ili9341. was the only solution accessible to my problem with using SPI0 for MCP23s17 bus.
 
KurtE - I've read many of your posts and think maybe your SPIN will help me. I'm programming a Teensy 3.6 using Teensy Loader 1.37 and trying to get a ST7735R display (GREENTAB) to function at the same time as my NRF25L+ Both work individually. My question is should I use try SPIN and ST7735_t3? If so; would you mind explaining the process a little? Thanks a bunch!
 
A couple of different things.

SPI is supposed to work with multiple devices on the same SPI buss... Assuming everyone is playing nice.

But it is sometimes nice to be able to use the other SPI busses. Again originally I created SPIN to help with my testing of the T3.6.

The main test library that used spin is my version of the ili9341_t3 library ..._t3n which uses spin, plus now has other things.... And since then I have created a version of Paul's ST7735_t3 library that uses SPIN. https://github.com/KurtE/ST7735_t3/tree/SPIN-Version

This version of the library requires you to also have SPIN installed.

If you use my version there is a constructor that takes a list of which pins to use and optionally which SPIN object:
Code:
T7735_t3(uint8_t CS, uint8_t RS, uint8_t SID, uint8_t SCLK, uint8_t RST = -1, SPINClass *pspin=(SPINClass*)(&SPIN));

You don't actually have to pass in which SPIN object to use as the common init code looks at the SID and SCLK pins and tries to find the first SPI buss that these pins are valid on and uses that buss. But if some how there are two SPI busses where these are valid but maybe the CS and RS are different (none yet), then you can code to use a specific one... So hopefully this will work for you. Just install the two libraries, and have your constructor updated to use the SPI1 or SPI2 pins... Hopefully it will work with your display. Some of the different displays act a little differently and have some different init strings that may need to be messed with.

Side Note:
Longer term, it would be nice to phase out Spin... That is starting with Teensyduino 1.37 the SPI class is setup where all of the SPI busses are instances of one class, like it is on the Arduino Due or M0. Also some of the code to check if pins are valid also was merged in from my SPIN code into SPI... So a lot of the basic stuff that I do in SPIN is now doable in SPI. But the FIFO queue stuff that is used in the T7735_t3 library has not been added to SPI. Actually some of the tables that I use in SPIN to drive it are, but have not been made easily accessible. Things like pointer to the kinetisk registers and FIFO queue size... SPI(0) has queue size of 4 and SPI1 and SPI2 have queue size of 1... So currently it would be easy to enhance the Adafruit_ version of the library to support multiple SPI busses and have it usable with different platforms, but harder to update the _t3 library as it uses knowledge of the internals of SPI hardware (fifo queue)
 
Thank you for your reply, Hope to give it a try. I do have another 3.6 and two ili9341 displays in the mail. I really want to get the multiple SPI bus stuff to work. Thanks again!
 
Success!!!

KurtE - Using your SPIN library and ST7735_t3 library I was able to use the display and the NRF25L+ simultaneously. I consider this a big accomplishment for a beginner such as I. Ended up using this for the display:

#define TFT_SCLK 32
#define TFT_MOSI 0
#define TFT_CS 6
#define TFT_DC 31
#define TFT_RST 1

ST7735_t3 tft = ST7735_t3(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);

and for the NRF25L+:
#define RADIO_CE 2 //CE pin
#define RADIO_CS 3 //CS pin

RF24 radio(RADIO_CE,RADIO_CS); //(CE,CSN)

Thank you so much for your assistance! :)
 
SPIN now running three separate SPI device types without issues: ILI9431 on SPIN1, 8*MCP23s17 on SPIN0, and a DAC MCP4822 on SPIN2. the MCP4822 DAC drives the Analogue synth pitch. The Teensy3.6 is also running three adafruit trellis buttonpads via I2C and using the onboard SD for memory patch read and write. amazing micro controller.
 
Status
Not open for further replies.
Back
Top