Project: SPI_MSTransfer

Yup, look in your master output

your callback print is there from slave :)

and you got your 60 words from master printing to slave's callback

"/ 2, 55, 1));" <---------------- (1): overload, change to 0 or remove it entirely, to disable F&F, keep 1 there to keep F&F enabled for the master sending transfer16 method
 
defragster, if you take a peek in the 0_0_4, you'll see I'm working on the new UART access protocol for the 6 uarts of the slave as well as SerialUSB (7 total)

begin is already done, im working on the other basic ones, read/write etc

#Edit, just finished the read() method
 
To help account for multiple users this got set up in the 'other' thread using header: #include "A_ConfigDefines.h"

Initial #include "A_ConfigDefines.h":
Code:
#define defragster
// #define  tonton81

#if defined(tonton81)

#define SPI_MST_BUS		&SPI2
#define SPI_MST_CS 		43

#elif defined(defragster)

#define SPI_MST_BUS		&SPI
#define SPI_MST_CS 		15
#define SPI_MST_SCK 	14

#endif

With BOLD lines added/edited in MASTER to switch between out setups - where SLAVE so far is a common default:
Code:
#include <SPI.h>
#include <SPI_MSTransfer.h>
[B]#include "A_ConfigDefines.h"

SPI_MSTransfer teensy_gpio = SPI_MSTransfer("Serial", SPI_MST_CS, SPI_MST_BUS);
[/B]

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

[B]  #ifdef SPI_MST_SCK
  SPI.setSCK( SPI_MST_SCK );
  #endif
[/B]  SPI.begin();
}
 
cool :) I just added available and peek methods as well. gonna be nice having a setup like this with 2 high speed Serial access and 12 uarts :)
You'd probably have faster throughput through slave's USBSerial via the SPI_MSTransfer directly from the master!
 
Indeed - quite the potential with such fast Teensy interconnection!

It should be an easy port - I need to go drop this into the other thread to see the effect.
 
Here I go, attacking write support!

virtual size_t write(uint8_t val) { return write(&val, 1); }
virtual size_t write(const char *buffer, size_t size) { return write((const uint8_t *)buffer, size); }
virtual size_t write(const uint8_t *buf, size_t size);

You'll be able to write single bytes, character arrays, or uint8_t arrays to your given serial port (0 -> 6) 7 total:p

SUCCESS!

Serial.print("Write: "); Serial.println(teensy_gpio.write(0x55)); // <-- function returns bytes written, which should always be 1.

char _buf[] = "Hello World";
Serial.print("Write: "); Serial.println(teensy_gpio.write(_buf, sizeof(_buf))); // <-- function returns bytes written, which should be up to sizeof(buf)
 
Last edited:
LOL defragster

Code:
    char _buf[] = "Hello defragster! From master to USBSerial on Slave!";
    Serial.print("Write: "); Serial.println(teensy_gpio.write(_buf, sizeof(_buf)));

It appears in slave's USB serial console with a 90uS round trip :)
 
Nice! Will migrate the SPI as intended and then look for update. Though in that case the goal is to have the Slave do some heavy lifting 'dtostrf' code with direct USB output following that.
 
Well it's time for another nightly before my coffee trip, enjoy :)

Current methods added to release 0_0_5:

Code:
    virtual void      begin(uint32_t baudrate);
    virtual int       read();
    virtual int       available();
    virtual int       peek();
    virtual size_t    write(uint8_t val) { return write(&val, 1); } 
    virtual size_t    write(const char *buffer, size_t size) { return write((const uint8_t *)buffer, size); }
    virtual size_t    write(const uint8_t *buf, size_t size);

Control any of the 7 Serial ports accross your T3.5/6 slaves.

View attachment SPI_MSTransfer 0_0_5.zip

Just a reminder, you can use the current constructor to instantiate your Serial object:

SPI_MSTransfer myUSBSerial = SPI_MSTransfer("Serial", SPI_MST_CS, SPI_MST_BUS);

To use the slave's UART Serial3, just do:
SPI_MSTransfer myPortName = SPI_MSTransfer("Serial3", SPI_MST_CS, SPI_MST_BUS);

Then it's just a matter of:
myPortName.begin(115200);
myPortName.println("This is a test from the master");
Tony
 
Last edited:
Looking good ... Had time to make the prototype work: micros() _time==33 for 12 Dword transfer!

Just set test to 200 prints/sec no problem.

Will migrate later.
 
Just noticed these flying by on occasion. Some minutes NONE - often one is followed by another after a couple succeed:
micros() _time==32
returned value 55
micros() _time==32
returned value 55
micros() _time==33
Resending packet, CRC fail / Out of Sync
returned value 55
micros() _time==32
returned value 55
micros() _time==32
returned value 55
micros() _time==33
returned value 55
micros() _time==33
returned value 55
micros() _time==33
returned value 55
micros() _time==33
Resending packet, CRC fail / Out of Sync
returned value 55
micros() _time==32
returned value 55

One time I uploaded new code ( mostly the posted sample? ) to Slave and it didn't pick up with sync from running master - may have interrupted mid transfer? Does the Master timeout/recover fully when Slave dies on feedback?

It has always resumed sync the other few times though. Will keep an eye on that.

If there is some status on error (Master and Slave) you could leave in for Debug that would be cool. [ perhaps do "#define coutD Serial" and "#ifdef coutD" around debug code so the debug can be enabled and directed at compile time ? ]
 
they are the resend packet, previously displayed as “resend” i just put that text for debug,

for master recovery on slave missing i havnt added that support yet but i can add it
 
Last edited:
the fact from what i can understand, a single resend fixes the issue leads me to believe that because of the high frequency, or possibly glitchy spi lines, it may not be code related. max resends is at 3 and ive never seen it hit more than 1 so its basically a correction, either way, that debug message happens here:

the master sends it’s spi packets via spi.transfer16() from core after asserting, isr fires and then after the packet is injected, the master pumps the port woth a steady stream of (im not home) something like 0xAAF5 and waits for the 0xAA06 to stream in. this AA06 packet is an ACK saying the CRC passed the checkpoint before it enters the switch statement

this part is in very early stages of the ISR so really think SPI can have minor isssues with transfers, but not enough to be corrected

and i would rather not comment about it possibly being a core issue with transfer16, i dont want to offend paul, he knows more about those registers than I do :p
 
id also like to point out, at 24 mhz, on my slightly longer jumper cables seen in my vids, if i move teensy to left of breadbord ill get tons of those resends with no more data functionality until i hover it away from my esp/teensy setup, most of the times its the wires or breadboard, i got mine in a position that seems okay at 24mhz so i leave it there while i do the tests but this as well shows that it can be line issues, perhaps we should try to terminate the spi lines and see if it makes a difference? so far its not enough to worry about but it can be looked at over time, ill try some macguiver resistor work tomorrow and see what happens
 
oh one more other thing, if you begin(baud) the slave and while it runs you reprogram the slave and it boots up, yeah you wont see anything, thats cus serial wasnt enabled

i plan to incorporate what i did with the esp, which is, if a slave has ever rebooted, the master user will have a callback to put all the init data inside, and shall the slave ever reboot, the master will notice it asap and reconfigure slave accordingly

i agree resend should be in debug, i just like to see it for validity purposes while testing, to check the frequency of it, especially on my spaghetti desk o wiring :)
 
Last edited:
Another thing i want to do is overide the print(ln) methods, currently they send 1 byte at a time using write
i will have them work with the new buffer method of write to send the prints as a single shot

ill fix that when i get home later, so prints can go as fast as buffered writes do (a single transaction vs 1 transaction per byte)
 
Noted the debug add in case it helps understand the failure points. I suppose it is rude having the 'resend' - but good to know it happens.

Supposing it doesn't now ... I was going to add having the callback sent on failed messages with zero len or some notice (packet ID 0xffffff?) of error would make sense - it could call the obj.debug() then to log or correct it as desired.

As far as restart - since this is Teensy that should be up to Teensy reset() to reconfigure? Maybe a unique SLAVE versus SLAVE_AUTO?

My SPI lines are a few inches - but do go through a breadboard. Picture in this post: forum.pjrc threads uNav-AHRS
 
the handler doesnt run an invalid packet, currently a failed CRC is poped from queue while FIFO continues. valid packets fire callback. i could also print it out to debug before its dropped.. but you probably wont have much, if any, bad

not sure on your reconfigure paragraph but if you want auto configure you call it when u need it or dont if you dont
 
i will upgrade the hotplug
ability to release master to free running loop shall 3 functions consecutively NAK for the same slave which will block all functions being accessed until events() is able to redetect the slave again

itll be very hard to get 3 in a row, you cant even get more than one resend normally, if it gets to 3 a counter is hit, 3 strikes and presumed offline

once this is done, you have the ability to hardware/software sleep your slaves as needed, and wake when needed, if you do that sort of thing :)
 
When I scanned the note on restart reconfigure it sounded 'automatic'. As long as it is setup() controlled that is right.

Anything to 'release Master' in unexpected/worst case and reset is good. I don't know what happened - but AFAIK it did stop [may have been Slave that was stopped] until I gave another reset - that's what made me think of debug recording to catch that.

Handler should get notice of invalid packet was my thought: On a failed (CRC or other) packet - perhaps leave 'breadcrumb' in callback queue a debug message with state/status info? I wrote my callback so far to only act on the packet #55, but if I found a packet case of '-1' that could go into obj.debug() for debugging info so the failure type/cause could be tracked down, resolved, or ignored but handled?

>> You understand 1000% better than I do but perhaps a 'reserved' 'Packet ID' for each expected error { CRC, Incomplete receive, memory alloc fail, ? } , and one unknown. For each of those "perhaps there are 4"? create a static/fixed 'x' word entry array where one field is an incremented count and the others are event details for obj.debug(). Then the callback will have a fixed data pointer to that record table of : Fail Count, detail #1, detail #2, ... ? Then when error packet is pulled there would be a record to go with it to ignore or display.

Is all of this is done using runtime alloc memory and magic C++ garbage memory? All of my programming was "C" and nothing dynamic or 'tricky' was allowed so I never learned that stuff, which suits general Teensy usage and limited RAM microcontrollers better. So reading your code is teaching me stuff - and I haven't gotten to do that much yet.

Planned to add a Blink Slave LED heartbeat in the Master code. That would show the Master SPI link is working with a CRC checked ACK response required once per second.

Looks like I am out of dev time for today ... and late for sleep already. Prototype Master/Slave edit sending 12 uint32_t values has been running for hours, sending every 5 ms. I modified the sample to arrange for 32 bit array of 12 elements to be incremented and sent like you had on uint16_t's - then I receive and do the same in the slave to display and all is well - and that is all I need to put in the Target sketch - but ... tomorrow.
 
yeah your post is alot to take in to future upgrades, we’ll get there eventually :)

optionally, if your interested, we could queue the failed crcs from f&f (if any) and spew in debug monitor when your ready to view it, therefore, no printout, no problems
 
yeah your post is alot to take in to future upgrades, we’ll get there eventually :)

optionally, if your interested, we could queue the failed crcs from f&f (if any) and spew in debug monitor when your ready to view it, therefore, no printout, no problems

Plenty of future for sure - you've already made it too good for what I wanted :) :) :)

Event queue since it is there sounds good - can be ignored, counted, or displayed depending on the situation. Was hoping to suggest something sensible that would be easy - a bit more than ignoring errors and a way to log them without having them spew and go away. Something that would make it east to record error state as a queued event and try to recover or get back to work. As we KNOW - within the _isr() is not the place to push out random I/O. Also the sooner anything simple it there - the faster it will be self diagnosing.

Right now my display is scrolling through 200 lines/ minutes - actually 400 since both are two lines per event. Even if I see one and stop the scroll it takes page up many times to find it - if I'm not watching - it is lost ...

Master USB will be coutD/Debug/Serial - but Slave USB/Serial will be talking to a program that will get confused if given anything but the formatted data stream.

Getting it there safely in 32-33 uS is Amazingly 7 times faster than just the processing and formatting time the Master now uses - then pushing that expanded data out USB does influence system performance with so much else going on ( Serial GPS and i2c IMU with interrupts ). I just changed Slave display of 12 HEX uint32_t's to add 6 filler chars and the decimal version as well and at 200 MSTransfers/sec - the USB is flowing smoothly - with the Master Teensy sending almost 40 chars between two lines at the same time.

Very promising - night chores done - even later now than 90 minutes ago . . .
 
Woah! Good news!
I upgraded println() method instead of doing byte by byte it now does the entire payload transfer and printout to the slave's uarts


Old function:
Code:
size_t teensquitto::println(const char *p) {
  while (*p) {
    char c = *p++;
    write(c);
  }
  write('\n');
  return 0;
}


New function:
Code:
size_t SPI_MSTransfer::println(const char *p) {
  char _text[strlen(p)+1]; for ( uint16_t i = 0; i < strlen(p); i++ ) _text[i] = p[i]; _text[sizeof(_text)-1] = '\n'; write(_text,sizeof(_text));
}

Results?

I was getting, for the same char array, 36uS via write(buf,size) method, and 230uS via the byte-by-byte method println function went by...

After changing it, I get identical timing via write and print
36uS write, 36uS prints :)

Here's the corrections I did, i did both print & println methods! :)

Code:
size_t SPI_MSTransfer::print(const char *p) {
  write(p,strlen(p));
}
size_t SPI_MSTransfer::println(const char *p) {
  char _text[strlen(p)+1]; for ( uint16_t i = 0; i < strlen(p); i++ ) _text[i] = p[i]; _text[sizeof(_text)-1] = '\n'; write(_text,sizeof(_text));
}
 
29 micros at 48MHz sending "Hello World" println and write(buf..., 25uS for led toggle, and 13uS for pinmode
but yeah, alot more resends, but........ the led is not skipping a beat!
im eye'ing the led blinking once/sec and it's good lol
This is a beast!

Code:
d: 27
p: 12
Available: 0
Peek:  ################## Packet Resent ##############
-1
Read: -1
30
31
d: 26
p: 13
Available: 0
Peek: -1
Read: -1
102
29
d: 26
p: 12
Available: 0
Peek: -1
Read: -1
30
29
d: 25
p: 12
Available: 0
Peek: -1
Read: -1
29
 ################## Packet Resent ##############
50912
d: 26
p: 13
Available: 0
Peek:  ################## Packet Resent ##############
-1
Read: -1
30
30
d: 25
p: 12
Available: 0
Peek: -1
Read: -1
30
 ################## Packet Resent ##############
50912
d: 25
p: 12
Available: 0
Peek: -1
Read: -1
30
29
d: 26
p: 12
Available: 0
Peek: -1
Read: -1
29
29
d: 25
p: 12
Available: 0
Peek: -1
Read: -1
29
30
d: 25
p: 12
Available: 0
Peek: -1
Read: -1
30
30
d: 26
p: 13
Available: 0
Peek: -1
Read: -1
29
29
d: 26
p: 12
Available: 0
Peek: -1
Read: -1
29
30
d: 25
p: 13
Available: 0
Peek: -1
Read: -1
30
29
d: 25
p: 12
Available: 0
Peek: -1
Read: -1
30
30
d: 26
p: 80021
Available: 0
Peek: -1
Read: -1
30
29
d: 26
p: 13
Available: 0
Peek: -1
Read: -1
 ################## Packet Resent ##############
50943
29
d: 26
p: 13
Available: 0
Peek:  ################## Packet Resent ##############
-1
Read: -1
29
31
d: 26
p: 12
Available: 0
Peek: -1
Read:  ################## Packet Resent ##############
-1
30
29
d: 26
p: 13
Available: 0
Peek: -1
Read: -1
30
29
d: 26
p: 12
Available: 0
Peek: -1
Read: -1
30
29
d: 25
p: 12
Available: 0
Peek: -1
Read: -1
30
30
d: 25
p: 12
Available: 0
Peek: -1
Read: -1
30
29
d: 26
p: 12
Available: 0
Peek: -1
Read: -1
29
29
d: 25
p: 12
Available: 0
Peek: -1
Read: -1
29
29
d: 25
p: 12
Available: 0
Peek: -1
Read: -1
 ################## Packet Resent ##############
50943
 ################## Packet Resent ##############
50997
d: 25
p: 12
Available: 0
Peek: -1
Read:  ################## Packet Resent ##############
-1
30
29
d: 26
p: 13
Available: 0
Peek: -1
Read: -1
29
29
d: 26
p: 13
Available: 0
Peek: -1
Read: -1
29
29
d: 26
p: 13
Available: 0
Peek: -1
Read: -1
30
29
d: 25
p: 12
Available: 0
Peek: -1
Read: -1
29
29
d: 25
p: 12
Available: 0
Peek: -1
Read: -1
29
30
d: 26
p: 12
Available: 0
Peek: -1
Read: -1
30
30
d: 26
p: 13
Available: 0
Peek: -1
Read: -1
30
 ################## Packet Resent ##############
50838
d: 25
p: 12
Available: 0
Peek: -1
Read: -1
29
30
d: 26
p: 12
Available: 0
Peek: -1
Read: -1
30
29
 
Back
Top