Project: SPI_MSTransfer

yeah i didnt release the t3.x yet as im still playing with the LC stuff in it

but in case of the T3.x compatibility you can add more ADCs and touch sensors to your T4 projects :)
 
Teensy 3.x and LC support added! Up on github! :)

For LC, on master end, add a little delay between transfers using mySPI.delayTransfers(50); (50uS). if you specify 0 or leave at default 0, no delays are used. Only TeensyLC requires this to function properly, probably because the DH & DL registers are shared, while the T3.x/T4.x have separate registers. To be able to neatly add DLDH support on LC slave I created a functor to do the work instead of sprinkling ifdefs in the ISR.

Code:
SPI_MSTransfer_T4_FUNC void SPI_MSTransfer_T4_OPT::ifLC(uint16_t data) {
#if defined(KINETISL)
  while ( !::digitalReadFast(10) && !(SLAVE_S & SPI_S_SPTEF) );
  SLAVE_DH = data >> 8;
  SLAVE_DL = data;
#endif
}

Old ISR TDR code:
Code:
SLAVE_TDR = data[buffer_pos];

New ISR TDR code:
Code:
ifLC(SLAVE_TDR = data[buffer_pos]);

The RDR can stay as it is, it just reads both DH and DL directly:
Code:
#define SLAVE_RDR (((uint16_t)(SLAVE_DH << 8)) | SLAVE_DL)

:)

My current setup:
T4.0 master to T4.0 slave to diasy-chained TLC slave.

https://youtu.be/EPWOzXfrMCI
 
Last edited:
Just updated it again, the ifLC function has been abolished and replaced with a define :)

T4.x:
Code:
#define SLAVE_TDR(x) spiAddr[25] = (x)

T3.x:
Code:
#define SLAVE_TDR(x) spiAddr[13] = (x)

TLC:
Code:
#define SLAVE_TDR(x) \
    while ( !::digitalReadFast(10) && !(SLAVE_S & SPI_S_SPTEF) ); \
    (SLAVE_DH = (uint8_t)((x) >> 8)); \
    (SLAVE_DL = ((uint8_t)(x)));

Now the ISR just calls on all Teensies:
Code:
SLAVE_TDR(0xA5A5);

much cleaner than the previous call without needing to call a function:
Code:
ifLC(SLAVE_TDR = 0xA5A5);

:)
 
Just added a processing function for master end, instead of having duplicated code in all transfers, they simply pass in a pre-made buffer to it, it does the transfers, and returns a crc pass as well as returned data; Also added analogRead/Write(and Resolution) support as well.
 
Just added a processing function for master end, instead of having duplicated code in all transfers, they simply pass in a pre-made buffer to it, it does the transfers, and returns a crc pass as well as returned data; Also added analogRead/Write(and Resolution) support as well.

Wow Tony - you were busy last night. Good timing I was testing a T4 to a Teensy Micromod and it seems to be working without issue as well. Downloaded your updates this morning and testing with a T4.0 as master and T3.6 as slave (yeah I know over kill - just what I had handy) and seems to be working - right now trying an experiment.
 
@tonton81

Set up an experiment using T4.0 (Master) and T3.6(slave). Using the Slave to retrieve GPS data and send it to the Master upon receipt of a particulart packetID. Tried following you video (https://www.youtube.com/watch?v=NWsuD4hhnHs) to set up the callbacks etc. but something strange is going on. What I am seeing on the master is constant firing of the events:

Code:
121506
0 Queues.
121507
7 0 82 0 1939 4223 A127 C293 0 4200 0 0 165 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  --> Length: 36
 --> SlaveID: 4660
 --> PacketID: 1001
0 Queues.
121507
0 Queues.
121508
For the Master code I am using:
Code:
#include "SPI.h"

#include "SPI_MSTransfer_MASTER.h"
SPI_MSTransfer_MASTER<&SPI, 10, 0x1234> mySPI1234;
SPI_MSTransfer_MASTER<&SPI, 10, 0x4567> mySPI4567;

//define a struct of various data types
typedef struct MYDATA_t {
  int sats;
  int hdop; 
  float lat; 
  float longit;
  float alt;
  float speed;
  int course;
  long date;
  long time;
};

//define a struct joining MYDATA_t to an array of bytes to be stored
typedef union MYDATA4XFER_t {
 MYDATA_t datastruct;
 uint16_t Packet[sizeof(MYDATA_t)];
};
  
MYDATA4XFER_t mydata; //data to be written in memory


void setup() {
  Serial.begin(115200);
  SPI.begin();
  pinMode(10, OUTPUT);
  digitalWrite(10, 1);
  mySPI1234.begin();
  //mySPI4567.begin();
  mySPI1234.onTransfer(myCB);

}

void loop() {

  static uint32_t t = millis();
  if ( millis() - t > 1000 ) {
    Serial.println(millis());
    Serial.print(mySPI1234.events()); Serial.println(" Queues.");

    uint16_t buf[2] = { 0xBEEF, 0xD0D0 };
    //uint16_t buf2[5] = { 0xBEEF, 0xF7, 0xF8, 0xF9, 0xDEAD };
    mySPI1234.transfer16(buf, 2, 0x1000);
    //mySPI1234.transfer16(buf2, 5, 0x8000);
  }

}

void myCB(uint16_t *buffer, uint16_t length, AsyncMST info) {
  if(info.packetID == 0x1001) {
    for ( int i = 0; i < length; i++ ) {
      Serial.print(buffer[i], HEX); Serial.print(" ");
    }
    Serial.print(" --> Length: "); Serial.println(length);
    Serial.print(" --> SlaveID: "); Serial.println(info.slaveID);
    Serial.print(" --> PacketID: "); Serial.println(info.packetID, HEX);
  }
}
and for the slave:
Code:
#include "SPI_MSTransfer_T4.h"
SPI_MSTransfer_T4<&SPI, 0x1234> mySPI;
#include "GPS.h"

//define a struct of various data types
typedef struct MYDATA_t {
  int sats;
  int hdop;
  float lat;
  float longit;
  float alt;
  float speed;
  int course;
  long date;
  long time;
};

//define a struct joining MYDATA_t to an array of bytes to be stored
typedef union MYDATA4XFER_t {
  MYDATA_t datastruct;
  uint16_t Packet[sizeof(MYDATA_t)];
};

MYDATA4XFER_t mydata; //data to be written in memory

void setup() {
  while (!Serial && (millis() < 5000))
    ;  // wait for Arduino Serial Monitor
  Serial.println("\n\nUSB Host Testing - Serial");
  myusb.begin();

  mySPI.begin();
  mySPI.onTransfer(myCB);

  Serial.print("Testing TinyGPS library v. ");
  Serial.println(TinyGPS::library_version());
  Serial.println("by Mikal Hart");
  Serial.println();
  Serial.println("Sats HDOP Latitude  Longitude  Fix  Date       Time     Date Alt    Course Speed Card  Distance Course Card  Chars Sentences Checksum");
  Serial.println("          (deg)     (deg)      Age                      Age  (m)    --- from GPS ----  ---- to London  ----  RX    RX        Fail");
  Serial.println("-------------------------------------------------------------------------------------------------------------------------------------");
}

void loop() {
  myusb.Task();
  devices();

  mySPI.events();
  static uint32_t t = millis();
  if ( millis() - t > 1000 ) {
    Serial.print("millis: "); Serial.println(millis());
    t = millis();
  }

}

void myCB(uint16_t *buffer, uint16_t length, AsyncMST info) {

  if (info.packetID == 0x1000) {
    uint32_t arraySize = sizeof(MYDATA_t);
    //Serial.print(arraySize); Serial.println(" Array Size.");
    gps_data();
    if(mydata.datastruct.sats > 0)
      mySPI.transfer16(mydata.Packet, arraySize, 0x1001);
  } else {
    for ( int i = 0; i < length; i++ ) {
      Serial.print(buffer[i], HEX); Serial.print(" ");
    }
    Serial.print(" --> Length: "); Serial.print(length);
    Serial.print(" --> PacketID: "); Serial.println(info.packetID, HEX);
  }
}

void gps_data() {
  float flat, flon;
  unsigned long age, chars = 0;
  unsigned short sentences = 0, failed = 0;
  static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002;

  if (userial) {
    mydata.datastruct.sats = gps.satellites();
    print_int(gps.satellites(), TinyGPS::GPS_INVALID_SATELLITES, 5);
    mydata.datastruct.hdop = gps.hdop();
    print_int(gps.hdop(), TinyGPS::GPS_INVALID_HDOP, 5);
    gps.f_get_position(&flat, &flon, &age);
    mydata.datastruct.lat = flat; mydata.datastruct.longit = flon;
    print_float(flat, TinyGPS::GPS_INVALID_F_ANGLE, 10, 6);
    print_float(flon, TinyGPS::GPS_INVALID_F_ANGLE, 11, 6);
    print_int(age, TinyGPS::GPS_INVALID_AGE, 5);
    print_date(gps);
    mydata.datastruct.alt = gps.f_altitude();
    print_float(gps.f_altitude(), TinyGPS::GPS_INVALID_F_ALTITUDE, 7, 2);
    mydata.datastruct.course = gps.f_course();
    print_float(gps.f_course(), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
    mydata.datastruct.speed = gps.f_speed_mps();
    print_float(gps.f_speed_mps(), TinyGPS::GPS_INVALID_F_SPEED, 6, 2);
    print_str(gps.f_course() == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(gps.f_course()), 6);
    print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0xFFFFFFFF : (unsigned long)TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON) / 1000, 0xFFFFFFFF, 9);
    print_float(flat == TinyGPS::GPS_INVALID_F_ANGLE ? TinyGPS::GPS_INVALID_F_ANGLE : TinyGPS::course_to(flat, flon, LONDON_LAT, LONDON_LON), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
    print_str(flat == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(TinyGPS::course_to(flat, flon, LONDON_LAT, LONDON_LON)), 6);

    gps.stats(&chars, &sentences, &failed);
    print_int(chars, 0xFFFFFFFF, 6);
    print_int(sentences, 0xFFFFFFFF, 10);
    print_int(failed, 0xFFFFFFFF, 9);
    Serial.println();
    //smartdelay(100);
  }
}
not going to say anymore
 
Weird, works fine here, i changed on my slave to use 50 length random arrays and i set both master & 2 slaves to poll write at 10ms rates
 
Weird, works fine here, i changed on my slave to use 50 length random arrays and i set both master & 2 slaves to poll write at 10ms rates

Will try it again but just use the test examples in your video and see what happens in a bit. Anyway - you know me - always get strange results with the way I test :)

EDIT: Found the problem - my error forgot to set t = millis at the end of the loop - now its working as expected - we both missed that one :)
 
Last edited:
Ok finished my test case as described above:

Capture.PNG
 
I am having an issue where my code is hanging on startup until the chip select pin (pin 10) detects a rising edge. I have tried this on two different teensy 4.1s.
Here is the code that is hanging.


#include "SPI_MSTransfer_T4.h"
SPI_MSTransfer_T4<&SPI, 0x1234> mySPI;
int led = LED_BUILTIN;
void setup() {
Serial.begin(115200);
pinMode(led, OUTPUT);
while (!Serial){
digitalToggle(led);
delay(100);
}
mySPI.begin();
Serial.print("begin:"); Serial.println(millis());
mySPI.onTransfer(myCB);
Serial.print("spi: "); Serial.println(millis());

Serial.print("on rece:"); Serial.println(millis());


}
void loop() {
Serial.print("millis: "); Serial.println(millis());
digitalToggle(led);
delay(1000);
}
void myCB(uint16_t *buffer, uint16_t length, AsyncMST info) {
for ( int i = 0; i < length; i++ ) {
Serial.print(buffer, HEX); Serial.print(" ");
}
Serial.print(" --> Length: "); Serial.print(length);
Serial.print(" --> PacketID: "); Serial.println(info.packetID, HEX);
}
 
thats the master, have you tried the master slave examples as a start to make sure your wiring is okay? the examples do work so they will rule out if it's a software or hardware connection issue
 
I could use some advice with SPI_MSTransfer_T4. I got the GitHub SPI_MSTransfer_T4 repository and loaded the library. I have two T4.1 wired as as shown in the examples/wiring.md and the source code. I have checked the wiring for correctness and continuity. I uploaded the compiled the example MASTER.ino to the master and the compiled ~SLAVE.ino to the slave. In the serial monitor I see their outputs which are basically time stamps that indicate that they never connect. The master reports not finding the slave. I repeated everything several times and am out of things to try.

Physical layout: both T4.1s have headers and are plugged into a breadboard side by side. The connections are made with 90 mm jumpers. Connection continuity is checked on the component side of the T4.1s. They are USB plugged into a Windows 11 laptop. I'm running Arduino 1.8.19.

on compile I get in the message box the lines below in red - but it opens loader, permits upload and executes:

"In file included from \Arduino\libraries\SPI_MSTransfer_T4-main/SPI_MSTransfer_MASTER.h:60:0,
from \Arduino\libraries\SPI_MSTransfer_T4-main\examples\MASTER\MASTER.ino:3:
\Arduino\libraries\SPI_MSTransfer_T4-main/SPI_MSTransfer_MASTER.tpp: In instantiation of 'void SPI_MSTransfer_MASTER<port, cs_pin, slave_ID, spi_speed>::digitalWrite(uint8_t, bool) [with SPIClass* port = (& SPI); unsigned char cs_pin = 10u; long unsigned int slave_ID = 4660ul; long unsigned int spi_speed = 2000000ul; uint8_t = unsigned char]':
\Arduino\libraries\SPI_MSTransfer_T4main\examples\MASTER\MASTER.ino:29:35: required from here"

Thanks
Bob
 
make sure Teensy 4.1 is selected in arduino if not already done for that error

also do not use the GND pin located next to pin 0, you need to have both 4.1s connected with the GND pin located next to the 3.3v/5v pin. (this is only apprent when a 4.1 is set as master and the DSE bits are different than what is standard in the SPI library. You can try the alternate library which has this fixed for a sanity check to make sure your connections are good, SPI_MSTransfer_T4 which allows 2 way data and gpio control over SPI
 
Thanks for the response.

The IDE has Teensy 4.1 selected for the board. I'm using 1.8.19.

I removed the ground jumper from the grounds near pin 0. Unfortunately I still get the same result of "State1... No slaves detected".

DSE?

Do you need to start them in some order?

By alternate do you mean SPI_SLAVE_T4?

Is there any doc for this library?

Bob
 
just load master on one and slave on the other, if you dont see communication try swapping the MISO/MOSI lines around
 
I did load master on one and slave on the other and wired as documented. I swapped wires and got the same results of no slave detected on the master and time stamps from the slave.
Thanks
Bob
 
When i try to use adadruit neopixel library or the fast LED library for neopixels together with this library the spi transfer does not work. Is there anyway to fix this?
 
i can only assume the neopixels temporarily disable interrupts, which would interfere with simuletaneous transfers
 
If I am correct these libraries require the neopixels to be connected to a serial pin. But my project has neopixels connected to a digital pin is there a way to still make them work together with the spi communication?
 
If I am correct these libraries require the neopixels to be connected to a serial pin. But my project has neopixels connected to a digital pin is there a way to still make them work together with the spi communication?

It would take looking at the libraries.

This shows: libraries\WS2812Serial\examples\BasicTest\BasicTest.ino
Code:
// Usable pins:
//   Teensy LC:   1, 4, 5, 24
//   Teensy 3.2:  1, 5, 8, 10, 31   (overclock to 120 MHz for pin 8)
//   Teensy 3.5:  1, 5, 8, 10, 26, 32, 33, 48
//   Teensy 3.6:  1, 5, 8, 10, 26, 32, 33
//   Teensy 4.0:  1, 8, 14, 17, 20, 24, 29, 39
//   Teensy 4.1:  1, 8, 14, 17, 20, 24, 29, 35, 47, 53

Serial pins are just specific digital pins
 
Back
Top