Project: SPI_MSTransfer

will be a beast im sure
think the 4.0 will be a beast no matter what but with SPI_MST, it will be interesting. :)

BTW. Out of curiosity I tried sending messages from the LC to 3.5 - doesn't work got CRC errors bad lengths on the LC. So I guess that on the Master side :)
 
Oh ? events() must run on master, but transfer16 should work on LC, all it does is queue, it doesnt actually send
the master must pull it from events()
if it doesnt work, does it work on the 3.x?

definately need to look over those LC timings when i get a chance :)
BTW I hope your pulling those slave messages at 300KHz? Don't expect anything past F&F mode to be working, which is why we set 8MHz for F&F and 300KHz for etc (for LC)
Ex, use teensy_gpio2 (300KHz) for events() (will run events() at 300KHz)
 
Ok. No I was originally using teensy.gpio. I changed it on the master to use teensy_gpio2 (300k):

On the master side didn't get anything from LC:
Code:
F&F (OT=10) OT_CALC==300  micros() _time==99620
F&F (OT=11) OT_CALC==300  micros() _time==99621
F&F (OT=12) OT_CALC==300  micros() _time==177
F&F (OT=12) OT_CALC==300  micros() _time==174

and then it just hung. On the slave side I got a whole bunch of these before it hung:
Code:
Bad LASTVAL TEST INCREMENT <<<<<<<<<<<<<<<<<<<< DIFF OF> -150.00
6230.00,6231.00,6232.00,6233.00,6234.00,6235.00,6236.00,6237.00,6238.00,6239.00,37,37 [25 ,0

Bad LASTVAL TEST INCREMENT <<<<<<<<<<<<<<<<<<<< DIFF OF> -160.00
6400.00,6401.00,6402.00,6403.00,6404.00,6405.00,6406.00,6407.00,6408.00,6409.00,38,38 [25 ,0

Bad CRC: 

Bad LASTVAL TEST INCREMENT <<<<<<<<<<<<<<<<<<<< DIFF OF> -180.00
6590.00,6591.00,6592.00,6593.00,6594.00,6595.00,6596.00,6597.00,6598.00,6599.00,39,39 [25 ,0

Bad LASTVAL TEST INCREMENT <<<<<<<<<<<<<<<<<<<< DIFF OF> -150.00
6750.00,6751.00,6752.00,6753.00,6754.00,6755.00,6756.00,6757.00,6758.00,6759.00,40,40 [25 ,0
 
Here are the sketches:
Master:
Code:
#include <SPI.h>
#include <SPI_MSTransfer.h>
#include "A_ConfigDefines.h"

//#define SPI_SPEED 30500
#define SPI_SPEED 8000000
#define OT_CALC   100*(30000000/SPI_SPEED)

SPI_MSTransfer teensy_gpio = SPI_MSTransfer("Serial", SPI_MST_CS, &SPI_MST_BUS, SPI_SPEED ); // bad with default timeouts
SPI_MSTransfer teensy_gpio2 = SPI_MSTransfer("Serial", SPI_MST_CS, &SPI_MST_BUS, 300000 );

void yield() {}

void setup() {
  
  Serial.begin(115200);
  while (!Serial && millis() < 2000 ) {}
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  teensy_gpio.debug(Serial);

  teensy_gpio2.onTransfer(myCallback);


#ifdef SPI_MST_SCK
  SPI_MST_BUS.setSCK( SPI_MST_SCK );
#endif
  SPI_MST_BUS.begin();
  delay(5000);
}

uint32_t OverTime = 0;
void loop() {
  static uint32_t _timer = millis();
  //static uint32_t _timer1 = micros();
  if ( !(millis() % 100) )  { teensy_gpio2.pinToggle(LED_BUILTIN); Serial.print("^LT"); delay(1); }
  if ( millis() - _timer >= 10) {
    _timer = millis();
    //_timer1 = micros();
    uint32_t _time = micros();
    
    uint16_t *buf;
    double MST_PrintVals[10];
    buf = (uint16_t *)MST_PrintVals;
    int ii = 0;
    static uint16_t __count = 0;
    static uint16_t __countB = 0;
    for ( uint32_t i = 0; i < sizeof(MST_PrintVals) / sizeof( MST_PrintVals[0]  ); i++ ) MST_PrintVals[i] = __count++;

    Serial.print("F&F (OT=");
    Serial.print( OverTime );
    Serial.print(")");
    _time = micros();

    __countB++;
    if ( __countB % 25 )
      teensy_gpio.transfer16((uint16_t *)MST_PrintVals, sizeof(MST_PrintVals) / 2, 60, 1); // DEBUGHACK output
    else
      teensy_gpio.transfer16((uint16_t *)MST_PrintVals, sizeof(MST_PrintVals) / 2, 55, 1);

    _time = micros() - _time;
    Serial.print(" OT_CALC==");
    Serial.print(OT_CALC);
    Serial.print("  micros() _time==");
    Serial.println(_time);
    if ( _time > OT_CALC ) OverTime++;
  }

  teensy_gpio2.events();
}

void myCallback(uint16_t *buffer, uint16_t length, AsyncMST info) {
  Serial.print("PacketID: "); Serial.println(info.packetID);
  Serial.print("Length: "); Serial.println(length);
  for ( uint16_t i = 0; i < length; i++ ) {
    Serial.print(buffer[i], HEX); Serial.print(" ");
  }
  Serial.println();
}

SLAVE:
Code:
#include <SPI_MSTransfer_Slave.h>

void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 5000 )
  { Serial.print( "Teensy NOT Online @ millis=" );
    Serial.println( millis() );
    delay(30);
  }
  Serial.print( "Teensy Online @ millis=" );
  Serial.println( millis() );
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);

  if ( ARM_DWT_CYCCNT == ARM_DWT_CYCCNT ) {
    Serial.print( "Cycle Counter Not Enabled :" );
    Serial.println( ARM_DWT_CYCCNT );
  }
  if ( ARM_DWT_CYCCNT == ARM_DWT_CYCCNT ) {
    // Enable CPU Cycle Count
    ARM_DEMCR |= ARM_DEMCR_TRCENA;
    ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
  }
  if ( ARM_DWT_CYCCNT != ARM_DWT_CYCCNT ) {
    Serial.print( "Cycle Counter Enabled! :" );
    Serial.println( ARM_DWT_CYCCNT );
  }

  slave.begin(SPI1);
  slave.onTransfer(myCallback);
}

void loop() {
  slave.events();

  static uint32_t _timer2 = millis();
  if ( millis() - _timer2 > 500 ) {
    _timer2 = millis();
    uint16_t buf[20];
    for ( uint16_t i = 0; i < 20; i++ ) buf[i] = random(0x10,0xFF);
    slave.transfer16(buf, 20, random(1,65534));
  }
}

static uint16_t last_packetID = 0;
elapsedMillis TogClk;
uint32_t TogCnt = 0;
uint32_t FaFCnt = 0;
void myCallback(uint16_t *buffer, uint16_t length, AsyncMST info) {
  if ( 55 == info.packetID ) {
    if ( 40 != length ) {
      Serial.print("Bad Length: "); Serial.println(length); // If this shows then the SPI Passed array size is nor wrong
    }
    else if ( 0 != info.error ) {
      Serial.println("\nBad CRC: ");
    }
    else {
      double* MST_PrintVals;
      MST_PrintVals = (double *)buffer;
      
      for(int i = 0; i<10; i++){
        Serial.print(MST_PrintVals[i]); Serial.print("  ");
      }
      Serial.println();
    }
  }

  else if ( 60 == info.packetID ) {
    if ( 40 != length ) {
      Serial.print("Bad Length: "); Serial.println(length); // If this shows then the SPI Passed array size is nor wrong
    }
    else if ( 0 != info.error ) {
      Serial.println("\nBad CRC: ");
    }
    else {
      double* MST_PrintVals;
      MST_PrintVals = (double *)buffer;
    
// This provides a terse output with error checked based on MASTER output to the 12 DOUBLE value Array
      {
        static uint16_t TogLast = 0;
        static uint16_t TogHz =0;
        static uint16_t FaFHz =0;
        static double LastVal = 100000;
        static uint32_t ChkErr = 0;
        static uint32_t CBcount = 0;
        //if ( digitalReadFast( LED_BUILTIN) != TogLast ) { 
        //  TogLast = !TogLast; 
        //  TogCnt++; 
        //}
        if ( TogClk >=1000 ) {
          TogClk -= 1000;
          TogHz = TogCnt;
          TogCnt = 0;
          FaFHz = FaFCnt;
          FaFCnt = 0;
        }
        if ( last_packetID != info.packetID ) {
          LastVal += 10;
          if ( LastVal > 65536 && LastVal < 100000 ) LastVal -= 65536;
        }
        elapsedMillis LastCB;
        double DiffMiss = 0;
        uint32_t ErrSeen = 0;
        CBcount++;
        FaFCnt++;
        for ( uint32_t ii = 0; ii < 10; ii++ ) {
          LastVal++;
          if ( 65536 == LastVal ) LastVal = 0;
          if ( LastCB > 10 || 100001 == LastVal || 100013 == LastVal ) LastVal = MST_PrintVals[ii];
          if ( LastVal != MST_PrintVals[ii] ) {
            DiffMiss = LastVal - MST_PrintVals[ii];
            ChkErr++;
            Serial.print("\nBad LASTVAL TEST INCREMENT <<<<<<<<<<<<<<<<<<<< DIFF OF> ");
            Serial.println( DiffMiss );
            LastVal = MST_PrintVals[ii];
            ErrSeen++;
          }
          if ( 0 != ErrSeen || 1 > ii ) {
            Serial.print( MST_PrintVals[ii] );
            Serial.print(",");
          }
          else {
            Serial.print(" #,");
          }
        }
        Serial.print( CBcount );
        Serial.print(",");
        Serial.print( ChkErr );
        Serial.print(" [");
        Serial.print( FaFHz );
        Serial.print(" ,");
        Serial.print( TogHz );
        Serial.println();
        LastCB = 0;
      }
      
    }
  }
  else {
    Serial.print("PacketID: ");
    Serial.println(info.packetID);
  }
  last_packetID = info.packetID;
}
 
hmm it didnt do that when i printed dwords 0-10, your code starts working then locks up

if I flash this to master:
Code:
#include <SPI.h>


#include <SPI_MSTransfer.h>
#include "A_ConfigDefines.h"

//#define SPI_SPEED 30500
#define SPI_SPEED 600000
#define OT_CALC   100*(30000000/SPI_SPEED)

SPI_MSTransfer teensy_gpio = SPI_MSTransfer("Serial", 43, &SPI2, 4000000 ); // bad with default timeouts
SPI_MSTransfer teensy_gpio2 = SPI_MSTransfer("Serial", 43, &SPI2, 300000 ); // bad with default timeouts
SPI_MSTransfer _spitest = SPI_MSTransfer("Serial2", 31, &SPI1, 1000000 ); // bad with default timeouts

void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 2000 ) {}
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  //teensy_gpio.onTransfer(myCallback);

#ifdef SPI_MST_SCK
  //  SPI_MST_BUS.setSCK( SPI_MST_SCK );
#endif
  //  digitalWrite(42, OUTPUT);
  //  digitalWrite(43, OUTPUT);
  //  SPI_MST_BUS.begin();
  delay(1000);
  //
  SPI.begin();
  pinMode(2, INPUT_PULLUP);



  teensy_gpio.debug(Serial);
  return;









  //  //
  //  Circular_Buffer<float, 16> myFloats;
  //  //  Circular_Buffer<float, 16, 10> myFloats2;
  //  //  Circular_Buffer<int, 16, 10> int2;
  //  myFloats.push_back(-3.14159);
  //  myFloats.push_back(-12.3456);
  //  myFloats.push_back(-78.91234);
  //  myFloats.push_back(-7.91234);
  //  myFloats.push_back(-11.91234);
  //  myFloats.push_back(-58.91234);
  //  myFloats.push_back(-18.91234);
  //  ////  int moo[2] = { 1, 2};
  //  ////  int2.push_front(moo, 2);
  //  ////  int2.push_front(moo, 2);
  //  ////  int2.push_front(moo, 2);
  //  //  //  int2.read();
  //  myFloats.list();
  //  //  //  Serial.println();
  //  //  int2.list();
  ////
  //
  //
  //
  //  while (1);
  Circular_Buffer<uint8_t, 4, 6> ca;
  uint8_t buf[6] = { 24, 25, 26, 3, 4, 5 };
  uint8_t buf1[6] = { 6, 7, 8, 9, 10, 11 };
  uint8_t buf2[6] = { 12, 13, 14, 15, 16, 17 };
  uint8_t buf3[6] = { 18, 19, 20, 21, 22, 23 };
  uint8_t buf4[6] = { 24, 25, 26, 27, 28, 29 };
  uint8_t buf5[6] = { 30, 31, 32, 33, 34, 35 };
  uint8_t buf6[6] = { 36, 37, 38, 39, 40, 41 };
  ca.push_back(buf, 6);
  ca.push_back(buf1, 6);
  ca.push_back(buf2, 6);
  ca.push_back(buf3, 6);
  ca.push_back(buf4, 6);
  ca.push_back(buf5, 6);
  ca.push_front(buf6, 6);
  Serial.print("LF: "); Serial.println(ca.length_front());
  Serial.print("LB: "); Serial.println(ca.length_back());

  Serial.print("T0: "); Serial.println(ca.front()[0]);
  Serial.print("T1: "); Serial.println(ca.front()[1]);
  Serial.print("T2: "); Serial.println(ca.front()[2]);

  ca.replace(buf, 6, 0, 1, 2);
  ca.list();
  ca.remove(0);
  ca.list();
  //    while (1);

  Circular_Buffer<float, 4, 6> flt;
  float _f[] = { 123.456789, 789.012345 };
  float _f1[] = { 333.78643, 69.11 };
  float _f2[] = { 88.02, 743.69 };
  flt.push_back(_f, 2);
  flt.push_back(_f1, 2);
  flt.push_back(_f2, 2);
  flt.list();
  //
  Serial.println(flt.length_front());
  Serial.println(flt.length_back());
  Serial.println(flt.peek_front()[1], 7);
  float dump[2];
  flt.pop_front(dump, 2);
  Serial.print(dump[0], 7); Serial.print(" : "); Serial.println(dump[1], 7);
  //
  Circular_Buffer<uint16_t, 8> k;
  Circular_Buffer<uint16_t, 8> l;
  k.push_back(4000);
  k.push_back(2);
  k.push_back(99);
  k.push_back(4000);
  k.push_back(399);
  k.push_back(4000);
  k.push_back(4000);
  k.push_back(4000);
  k.push_back(4000);
  k.list();
  //    while (1);

  //  k.pop_back();
  //  k.push_back(10);
  //  k.push_back(10);
  //  k.pop_back();
  //  k.pop_back();
  ////  k.pop_back();
  //  k.pop_back();
  //  k.push_back(49);
  //  k.push_front(55);

  uint8_t myArray[10] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 };
  bool fail_check = 0;
  for (uint16_t i = 0; i < sizeof(myArray) / sizeof(myArray[0]); i++) {
    if (myArray[i] < 9) {
      fail_check = 1;
      break;
    }
  }
  ( fail_check ) ? Serial.println("FAIL") : Serial.println("PASS");

  //Serial.println(SPI2.setCS(43));
  //Serial.println(SPI2.setCS(54));
  //      while (1);
  SPI1.begin();
  SPI1.setCS(31);
  SPI1.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
//  teensy_gpio.debug(Serial);

  return;
  while (1) {
    static bool flip = 0;
    flip = !flip;
    uint32_t value = 0;
    ( flip ) ? value = 0x4000FFFF : value = 0x40000000;
    //    transfer32(value, 31);
    delay(1000);
    Serial.print("VAL: "); Serial.println(digitalRead(2));
    uint8_t buf[4] = { 0x40, 0x00, (uint8_t)(value >> 8), (uint8_t)value }, bufr[4] = { 0 };

    uint16_t b[2] = { 0x4000, (uint16_t)(value) };

    // transfer16(b, nullptr, 2, 31);
    //    _spitest._transfer16(b, nullptr, 2);
    //    _spitest._transfer(buf, nullptr, 4);
    //    Serial.println(b[0]);
    //    Serial.println(b[1]);

    //    transfer(buf, bufr, 4, 31);
    //    Serial.println(bufr[0]);
    //    Serial.println(bufr[1]);
    //    Serial.println(bufr[2]);
    //    Serial.println(bufr[3]);

  }
}

void transfer16(uint16_t *buffer, uint16_t *retbuf, uint16_t length, uint8_t pcs) {
  for ( uint16_t i = 0; i < length; i++ ) {
    if ( i == length - 1 ) {
      SPI1_SR = SPI_SR_TCF;
      SPI1_PUSHR = buffer[i] | SPI_PUSHR_CTAS(1) | SPI_PUSHR_PCS(pcs);
      while (!(SPI1_SR & SPI_SR_TCF));
      if ( retbuf ) retbuf[i] = SPI1_POPR;
      break;
    }
    SPI1_SR = SPI_SR_TCF;
    SPI1_PUSHR = buffer[i] | SPI_PUSHR_CTAS(1) | SPI_PUSHR_PCS(pcs) | SPI_PUSHR_CONT;
    while (!(SPI1_SR & SPI_SR_TCF));
    if ( retbuf ) retbuf[i] = SPI1_POPR;
  }
}

void transfer(uint8_t *buffer, uint8_t *retbuf, uint16_t length, uint8_t pcs) {
  for ( uint16_t i = 0; i < length; i++ ) {
    if ( i == length - 1 ) {
      SPI1_SR = SPI_SR_TCF;
      SPI1_PUSHR = buffer[i] | SPI_PUSHR_CTAS(0) | SPI_PUSHR_PCS(pcs);
      while (!(SPI1_SR & SPI_SR_TCF));
      if ( retbuf ) retbuf[i] = SPI1_POPR;
      break;
    }
    SPI1_SR = SPI_SR_TCF;
    SPI1_PUSHR = buffer[i] | SPI_PUSHR_CTAS(0) | SPI_PUSHR_PCS(pcs) | SPI_PUSHR_CONT;
    while (!(SPI1_SR & SPI_SR_TCF));
    if ( retbuf ) retbuf[i] = SPI1_POPR;
  }
}



void transfer32(uint32_t val, uint8_t pcs) {
  SPI1_SR = SPI_SR_TCF;
  SPI1_PUSHR = (uint16_t)(val >> 16) | SPI_PUSHR_CTAS(1) | SPI_PUSHR_PCS(pcs);// | SPI_PUSHR_CONT;
  while (!(SPI1_SR & SPI_SR_TCF));
  SPI1_SR = SPI_SR_TCF;
  SPI1_PUSHR = (uint16_t)val | SPI_PUSHR_CTAS(1) | SPI_PUSHR_PCS(pcs);
  while (!(SPI1_SR & SPI_SR_TCF));
}



void myCallback(uint16_t *buffer, uint16_t length, AsyncMST info) {
  Serial.print("PacketID: "); Serial.println(info.packetID);
  Serial.print("Length: "); Serial.println(length);
  for ( uint16_t i = 0; i < length; i++ ) {
    Serial.print(buffer[i], HEX); Serial.print(" ");
  }
  //  Serial.println();
}

uint32_t OverTime = 0;
void loop() {
  static bool setOnce = 1;
  if ( setOnce ) {
    setOnce = 0;

  }
  static uint32_t _timer = millis();
//    teensy_gpio2.events();
  static uint32_t _t = millis();
  if ( millis() - _t >= 50 )  {
    _t = millis();
    uint16_t buf[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    uint32_t t = micros();
    teensy_gpio2.transfer16(buf, 10, 60, 1);
    Serial.println(micros() - t);
//Serial.println(teensy_gpio.digitalRead(13));
//    teensy_gpio.digitalWrite(13, !teensy_gpio.digitalRead(13));
//return;
    //    delay(10);
// teensy_gpio.digitalWrite(13,1);
//delay(50);
// teensy_gpio.digitalWrite(13,0);
//    teensy_gpio.println("Hello World!");
//        teensy_gpio2.pinToggle(LED_BUILTIN);
    //        teensy_gpio.println("Hello world!");
  }
  return;
  //  if ( micros() - _timer >= 9168250 ) {
  if ( micros() - _timer >= 30 ) {
    _timer = micros();
    uint32_t _time = micros();

    uint16_t *buf;
    double MST_PrintVals[12];
    buf = (uint16_t *)MST_PrintVals;
    int ii = 0;
    static uint16_t __count = 0;
    static uint16_t __countB = 0;
    for ( uint32_t i = 0; i < sizeof(MST_PrintVals) / sizeof( MST_PrintVals[0]  ); i++ ) MST_PrintVals[i] = __count++;
    Serial.print("F&F (OT=");
    Serial.print( OverTime );
    Serial.print(")");
    _time = micros();
    __countB++;
    if ( __countB % 25 ) {
      teensy_gpio.transfer16((uint16_t *)MST_PrintVals, sizeof(MST_PrintVals) / 2, 60, 1); // DEBUGHACK output
    }
    else {
      teensy_gpio.transfer16((uint16_t *)MST_PrintVals, sizeof(MST_PrintVals) / 2, 55, 1);
    }
    _time = micros() - _time;
    Serial.print(" OT_CALC==");
    Serial.print(OT_CALC);
    Serial.print("  micros() _time==");
    Serial.println(_time);
    if ( _time > OT_CALC ) OverTime++;
  }
}

Your slave sketch says (obviously)
Code:
Bad Length: 10
Bad Length: 10
Bad Length: 10
Bad Length: 10
Bad Length: 10
Bad Length: 10
Bad Length: 10
Bad Length: 10
Bad Length: 10
Bad Length: 10
Bad Length: 10
Bad Length: 10
Bad Length: 10
Bad Length: 10
Bad Length: 10

but it doesnt stop scrolling

ill look into it

9MHz F&F's work at least, but definately theres a timing issue somewhere, somewhere thats annoying to find :D
 
Last edited:
Thanks Tony. The two sketches as stands now is pretty much the same except for the ontransfer in the master and send in slave. Without those pieces the slave (LC) receives no problem. For my lc tests I was using 8Mhz and 400K with not much of a problem.
 
I put the delayMicroseconds(5) back in the core transfer16 and the F&F stabilized and toggle started working, there is a timing issue im sure :)

Toggle still works with 1uS delay before POPR, removing the delay breaks toggling led....

put 1uS delay and toggling works again

no wonder slave support for this chip is hard to come by, so frustrating :)
 
I've been reading online about the SPTEF flag in slave mode among similar chips and came upon this:
https://community.nxp.com/thread/342971

Aparently the SPTEF flag is not set again until next CS toggle, so no bytes are transfered after the initial one, this could be why F&F works
The first stage of the isr is reading only, while the second stage of the isr is to send one dword back (0xD0D0); The following other functions could fail because the SPTEF flag isnt being set again resulting in the DL and DH registers from being written to thus crashing, been looking through the datasheet as well,

The S register must be read with SPTEF set to 1 before writing data to the DH:DL register;
otherwise, the DH:DL write is ignored.

The S register is also a read only register on top of it, so if the SPTEF flag never gets set, writing to the master via DL/DH can be ignored..
something crazy going on hehe


I cannot believe that this was a conscious design decision of the chip designer, but have to assume that this is a bug, especially also because the RX side works as expected (meaning the KEA8 is capable of receiving multi bytes frames, it's just not capable of transmitting them).
 
After I disabled slave side queueing, re-enabling the events() on master didnt crash anymore. This means the slave (kinetisL) has issues sending a consistant stream of data back over the bus and the master is set to keep polling the circular buffer till it gets a valid crc queue data. The fact that the delay before POPR helps the LC, it's going through the ISR channels fine, but outputting not whats expected to the master
 
Mike, If I change Smaller to Fastest in compile, the "lockups stop" when I re-enable slave transfers to master. Is Smallest such a pest or what? lol

EDIT, I'm getting slave callbacks on master now!

DARN YOU SMALLEST COMPILE OPTION!!!!!!


Gonna try to remove SPI delay in core now 1 sec.

NO GO. Seems we have double trouble with the LC

#1, we can NOT use Smallest compile option, Fastest works, rest untested
#2, we need a tiny uS delay between the transfers!
 
I wonder if a delay added only to the first Transfer 16 would be enough to let the T_LC interrupt code trigger and activate? i.e. make a Transfer16_delay?
 
Actually, I just implemented my own kinetis version of write and writeread from the core, so i no longer depend on core's transfer16 version
I took the github version and added 2 transfer16 functions, one writes without delay (reading not necessary), reading sets 1uS delay

I added the SPIClass comparators in the class construction to support all SPI busses in master mode (SPI,SPI1,SPI2)
I changed all transfer16 functions in the library to use the local copy

I can simply just ifdef the 1uS delay if the master is compiled on a LC model. But, as it stands now, master is working with LC set to Fastest and using local transfer16 functions. For now ill leave it up for testing soon, few mins..
 
Like my constructor port selector?? :)

Code:
  if ( SPIWire == (SPIClass*)&SPI ) _spi_port_memorymap = 0x4002C000;
  if ( SPIWire == (SPIClass*)&SPI1 ) _spi_port_memorymap = 0x4002D000;
  if ( SPIWire == (SPIClass*)&SPI2 ) _spi_port_memorymap = 0x400AC000;

The memory map is used by the local transfer16 functions (currently set for kinetisK mcus)
Code:
uint16_t SPI_MSTransfer::_transfer16_write(uint16_t data) {
  (*(KINETISK_SPI_t *)_spi_port_memorymap).SR = SPI_SR_TCF;
  (*(KINETISK_SPI_t *)_spi_port_memorymap).PUSHR = data | SPI_PUSHR_CTAS(1);
  while (!((*(KINETISK_SPI_t *)_spi_port_memorymap).SR & SPI_SR_TCF)) ; // wait
  return (*(KINETISK_SPI_t *)_spi_port_memorymap).POPR;
}
uint16_t SPI_MSTransfer::_transfer16_writeread(uint16_t data) {
  (*(KINETISK_SPI_t *)_spi_port_memorymap).SR = SPI_SR_TCF;
  (*(KINETISK_SPI_t *)_spi_port_memorymap).PUSHR = data | SPI_PUSHR_CTAS(1);
  while (!((*(KINETISK_SPI_t *)_spi_port_memorymap).SR & SPI_SR_TCF)) ; // wait
  delayMicroseconds(1); 
  return (*(KINETISK_SPI_t *)_spi_port_memorymap).POPR;
}


heres the files that im currently running on a T3.6 and T LC

Code:
[ATTACH]13797._xfImport[/ATTACH]

[ATTACH]13798._xfImport[/ATTACH]
 
Mike, when you get back, your sketches now work fine and don't freeze with the above master library patch, we could probably have a function later on to enable LC mode for a master, where when its set, the object uses the delay set.
For example.

Your sketch:
at 1uS delay, at 8MHz, you'll get OTs slowly climbing, at 4MHz it's intermittant, both frequencies running smooth.
at 5uS delay, at 8MHz, it's intermittant, at 4MHz OT's seem to be staying at 0.

going a higher delay makes no difference in responses

Tim, the delay is for continuous transmission inside the ISR, not for the start, F&F’s were not affected by functionality, the LC takes its sweet time exchanging the data within its register, there is only one register for data input and data output
SPIx.DH and SPIx.DL,, for high and low byte, its possible the transmissions were too fast before the register could be both read and written to, whereas the kinetisK series have separate registers for read and writing (PUSHR and POPR)

So what I can conclude currently is the LC is capable of running efficiently at 4MHz with a 5uS delay per frame reading, where the transmission speed introduces no delay at all, this means, during an F&F period:

you have absolutely no delays, and only a single 5uS delay on the final dword reception

I'll mention it here now
events()
led toggling
2 way callbacks

all are working without the dreaded LC lockup. Just don't compile with "Smallest" option, which, unfortunately, is the default. I mentioned it earlier and forgot about it later, but that was the major crash issue with the LC

Tim, sending without receiving I already did them.
Only time it reads is when its getting a callback or ACK/DATA, thats where it uses the writeread function, the write version doesnt read, no uS delay there, the F&F's never read the data, so the 1uS doesnt apply to them:

Code:
    if ( fire_and_forget == 1 ) {
      SPI_assert();
      for ( uint16_t i = 0; i < data[1]; i++ ) _transfer16_write(data[i]);
      uint32_t timeout = millis();
      while ( _transfer16_writeread(0xFFFF) != 0xBABE && millis() - timeout < 100 );
      _transfer16_write(0xD0D0); // send confirmation
      SPI_deassert();
      return data[4]; // F&F, RETURN PACKETID
    }
3rd line writes only, no reading
5th line polls for 0xBABE dword (or timeout 100ms)
6th line sends a write only dismissal

thats about it
so the uS delay would be affecting the 5th line basically, for LC models ONLY
 
Last edited:
perhaps? not sure, now since the slave is half size as master, any ideas? :) (already checked compiler log seems clean)
 
It could be there was a problem all along and was hidden by spare unused space? That other one was just doing a buffer overwrite of 4 bytes.

Does it hang and die? Says it locks_up?

I did that sketch the other day that used the fault_isr's on memory fails. It could let you narrow it down. Setting Globals as you enter and exit code blocks and then print that on the fault. The demo has commented out code that spews to Serial# - but I found it to work on USB Serial with simple RAM faults. it dumps a few system values - but I'm not sure if that will tell you what happened where - may have stack pointer and the like - but would need to check that out and then reference it to the build output.

Let me see if I can go recreate a usable version for you to drop in.
 
Here is a documented copy of yield.cpp to APPEND TO CORE copy. Leave the yield() and add below. Then need to edit the other indicated core file, and then see last comment for usage in Sketch and other.


If the code FAULTS - it will dump out chosen info and then return to execution … in case that helps get more context of where it was?

Here is a Sample sketch that faults to show it working and how to use (and includes the code below at bottom) :: View attachment MemFault_2.ino

<edit>: Just noticed the DebSet()'s in that INO are not in the right IF() group - on T_LC it faults in the first IIRC - on the T_3.5/T_3.6 it faults in the second where the WORD crosses a boundary - I compile tested this on T_3.5 so the __LINE__ and info are not where the fault hit.

Code:
// Add this to :: \hardware\teensy\avr\cores\teensy3\yield.cpp
#define ser_print Serial.print
#define ser_print_hex32(a) Serial.print( a, HEX )
extern uint32_t DebInfo[];
extern "C" void UserFault( void ) {
	//#if 0 :: Pulled from : \hardware\teensy\avr\cores\teensy3\mk20dx128.c
	uint32_t addr;

	Serial.println(  "\n >>>> UserFault   >>>> UserFault   >>>> UserFault !!!!!!"  );
	for ( int ii=0; ii<10; ii++ ) {
		Serial.print(  ii  );
		Serial.print(  " == "  );
		Serial.println( DebInfo[ ii ] );
	}

	SIM_SCGC4 |= 0x00000400;
	UART0_BDH = 0;
	UART0_BDL = 26; // 115200 at 48 MHz
	UART0_C2 = UART_C2_TE;
	PORTB_PCR17 = PORT_PCR_MUX(3);
	ser_print("\nfault: \n??: ");
        asm("ldr %0, [sp, #52]" : "=r" (addr) ::);
        ser_print_hex32(addr);
        ser_print("\n??: ");
        asm("ldr %0, [sp, #48]" : "=r" (addr) ::);
        ser_print_hex32(addr);
        ser_print("\n??: ");
        asm("ldr %0, [sp, #44]" : "=r" (addr) ::);
        ser_print_hex32(addr);
        ser_print("\npsr:");
        asm("ldr %0, [sp, #40]" : "=r" (addr) ::);
        ser_print_hex32(addr);
        ser_print("\nadr:");
        asm("ldr %0, [sp, #36]" : "=r" (addr) ::);
        ser_print_hex32(addr);
        ser_print("\nlr: ");
        asm("ldr %0, [sp, #32]" : "=r" (addr) ::);
        ser_print_hex32(addr);
        ser_print("\nr12:");
        asm("ldr %0, [sp, #28]" : "=r" (addr) ::);
        ser_print_hex32(addr);
        ser_print("\nr3: ");
        asm("ldr %0, [sp, #24]" : "=r" (addr) ::);
        ser_print_hex32(addr);
        ser_print("\nr2: ");
        asm("ldr %0, [sp, #20]" : "=r" (addr) ::);
        ser_print_hex32(addr);
        ser_print("\nr1: ");
        asm("ldr %0, [sp, #16]" : "=r" (addr) ::);
        ser_print_hex32(addr);
        ser_print("\nr0: ");
        asm("ldr %0, [sp, #12]" : "=r" (addr) ::);
        ser_print_hex32(addr);
        ser_print("\nr4: ");
        asm("ldr %0, [sp, #8]" : "=r" (addr) ::);
        ser_print_hex32(addr);
        ser_print("\nlr: ");
        asm("ldr %0, [sp, #4]" : "=r" (addr) ::);
        ser_print_hex32(addr);
        ser_print("\n");
        asm("ldr %0, [sp, #0]" : "=r" (addr) ::);
	//#endif
}

/* in :: \hardware\teensy\avr\cores\teensy3\mk20dx128.c 
Add this to top >> :: [B]extern void UserFault( void );[/B] 

Replace :: 
[B]#endif
	while(1) {
[/B]
with ::
[B]#endif
	UserFault(  );
	int ii = 0;
	while ( ii < 10000 ) { // THIS processes output and attempts to return to CODE 
		ii++;
[/B]
*/

/* In sketch define::
[B]	uint32_t DebInfo[ 10 ];
	#define DebSet( a, b ) { DebInfo[ a ] = b; }
[/B]
	As needed or used in other files::
[B]	extern uint32_t DebInfo[ ];
	#define DebSet( a, b ) { DebInfo[ a ] = b; }
[/B]
	[U]// FOR USE:: 1st Param is array index 0-9  , 2nd Param is uint32_t value.
[/U]	  DebSet( 0,1 );
	  DebSet( 9,__LINE__ );
	// Use as appropriate to track location or data

*/

<edit>::
Anyway to use the 10 values works. One way might be to use the DebSet( ## ,__LINE__ ); and put unique ## for each file - then the __LINE__ will show you where it was last with a series of those one in each file.

Just thought it might be useful to keep an ordering value for each DebSet - then you could easily see which was last with a change to the print in UserFault()?
>> uint32_t DebInfo[ 20 ], DebCnt=0; #define DebSet( a, b ) { DebInfo[ a ] = b; DebInfo[ 10+a ] = DebCnt++; }

I did that - it seems good. Looking at my code the first and second fault is @16 - on the broken WORD - the others come because the code returns and it breaks on @32 with DWORD failures where I didn't add updates to DebInfo() in the sketch. Here is the updated part for yield.cpp:
Code:
extern uint32_t DebInfo[];
extern "C" void UserFault( void ) {
	//#if 0 :: Pulled from : \hardware\teensy\avr\cores\teensy3\mk20dx128.c
	uint32_t addr;

	Serial.println(  "\n >>>> UserFault   >>>> UserFault   >>>> UserFault !!!!!!"  );
	for ( int ii=0; ii<10; ii++ ) {
		Serial.print(  ii  );
		Serial.print(  " == "  );
		Serial.print( DebInfo[ ii ] );
[B]		Serial.print(  " CNT>> "  );
		Serial.println( DebInfo[ 10+ii ] );
[/B]	}

Output looks like this #9 says fault was after line#=76, etc:
>>>> UserFault >>>> UserFault >>>> UserFault !!!!!!
0 == 1 CNT>> 0
1 == 1 CNT>> 173
2 == 14 CNT>> 259
3 == 5 CNT>> 285
4 == 0 CNT>> 0
5 == 0 CNT>> 0
6 == 0 CNT>> 0
7 == 0 CNT>> 0
8 == 0 CNT>> 0
9 == 76 CNT>> 287
 
Last edited:
Here's what I noticed last night at 4MHz with only reading at 1uS delay, the OT's were very very intermittant, probably 1 every half hour or so, so before I went to bed I added the 5uS delay to the write section as well
I just got out of bed to check and it's still running at 4MHz without OT errors, still at 0 OT :)

seems the spi transfers themselves need a 5uS for read & write
This looks pretty stable to me so far.

Now, for the Smallest issue
Tim, what I noticed, and mentioned earlier, the total lockup occured as soon as the slave created a queue to send to master. So what I did was tell the slave to create a queue after 10 seconds, I could pretty much consistantly make it crash after 10 seconds, I should do that again and find out where it's crashing
 
Tim, it's partially cut off here, a bit lost i am hehe

Code:
Replace :: 
#endif
	while(1) {

with ::
#endif
	UserFault(  );
	int ii = 0;
	while ( ii < 10000 ) { // THIS processes output and attempts to return to CODE 
		ii++;

EDIT, trying to narrow down the code, it seems to lockup without even creating the queue at all, ::transfer16 is never actually entered
EDIT2, the hard fault happens as soon as the timer is triggered:

Code:
  static uint32_t _timer2 = millis();
  if ( millis() - _timer2 > 5000UL ) {
Serial.println("zzzzzzz5B6");

The text is never printed!
If I change the timer to 10000UL, it'll lockup after 10 seconds
the lockups occur at the same time it's triggered

what the heck?
 
Last edited:
Open this file :: \hardware\teensy\avr\cores\teensy3\mk20dx128.c

Look for the while (1 ) and exchange those lines from the #endif to the while open brace?

That part is optional - except for calling out to the UserFault. I can and did do it different - but this seemed most sure.
 
I added your snippet to yield, mk20dx128 etc, where it locks up nothing is reported. More interestingly, whenever i program the slave in this state I have to push the program button. Also, if I reboot/reprogram, the master continues fine
Whatever the slave is doing, it's actually holding back the master, which seems to be bus related. Example, if i hold the slave in reset or disconnect the slave during a lockup, only then will the master giving OT errors, but it seems that the SPI bus itself seems to be crashing and preventing the master from operation until the slave is either rebooted or unplugged..........

To simplify my words

when the slave locks up, the master locks up at that exact same moment, but the master wont timeout/give errors until the slave is rebooted, its as if the slave has the master at knifepoint lol

edit, it doesnt freeze when i commenting out:
Code:
    //    slave.transfer16(buf, 20, random(1, 65534));

But it also at that point never prints the Serial text before or after that event either...
 
OK, whats weird is it's not printing the Serialtext when it freezes before the hangup
I started throwing returns in places, here is where it freezes on Smallest:

Code:
_slave_pointer->SPI_MSTransfer_Slave::stmca.push_back(data, data[1]);

Heres the code breakup of that function:

Code:
  if ( multi ) {
    if ( init_ca ) _init();
    _cabuf[((tail)&(_size-1))][0] = length >> 8*sizeof(T);
    _cabuf[((tail)&(_size-1))][1] = length;
    memmove(_cabuf[((tail)&(_size-1))]+2,buffer,length*sizeof(T));
    if ( tail == ((head ^ _size)) ) head = ((head + 1)&(2*_size-1));
    tail = ((tail + 1)&(2*_size-1));
    if ( _available < _size ) _available++;
    return;
  }

Anything suspicious? Ill look through it
 
Back
Top