Project: SPI_MSTransfer

I'm working on the standalone slave file, so far with a blank sketch and no contructor (simple really) we have this:
Code:
Sketch uses 42752 bytes (67%) of program storage space. Maximum is 63488 bytes.
Global variables use 5628 bytes (68%) of dynamic memory, leaving 2564 bytes for local variables. Maximum is 8192 bytes.

Current sketch code:
Code:
#include <SPI_MSTransfer_Slave.h>

void setup() {
  slave.begin( );
  slave.onTransfer(myCallback);
}

void loop() {
  slave.events();
}

void myCallback(uint16_t *buffer, uint16_t length, AsyncMST info) {
  for ( uint16_t i = 0; i < length; i++ ) {
    Serial.print(buffer[i]);
    Serial.print(" ");
  } Serial.println();
}
 
How about now? I'm adding options for the slave that the user specify what his slave will be using when compiling:

This is with Wire support undefined.
Code:
Sketch uses 27852 bytes (43%) of program storage space. Maximum is 63488 bytes.
Global variables use 4140 bytes (50%) of dynamic memory, leaving 4052 bytes for local variables. Maximum is 8192 bytes.

Thats with a define for MST_USE_WIRE, if defined, it loads the slave code for it, otherwise it's not included

This is with Wire and EEPROM undefined
Code:
Sketch uses 24852 bytes (39%) of program storage space. Maximum is 63488 bytes.
Global variables use 4136 bytes (50%) of dynamic memory, leaving 4056 bytes for local variables. Maximum is 8192 bytes.
 
Awesome! it can be done within the sketch now!

Code:
#define MST_USE_WIRE
#define MST_USE_EEPROM

#include <SPI_MSTransfer_Slave.h>

if they are not defined (BEFORE #including), the master wont be able to control those resources. No need to edit the H file.
 
This now with the control over the other SPI ports:

Code:
//#define MST_USE_WIRE
//#define MST_USE_EEPROM
//#define MST_USE_SPI

#include <SPI_MSTransfer_Slave.h>

Code:
Sketch uses 21092 bytes (33%) of program storage space. Maximum is 63488 bytes.
Global variables use 4116 bytes (50%) of dynamic memory, leaving 4076 bytes for local variables. Maximum is 8192 bytes.

Switched to "No USB":
Code:
Sketch uses 17580 bytes (27%) of program storage space. Maximum is 63488 bytes.
Global variables use 2664 bytes (32%) of dynamic memory, leaving 5528 bytes for local variables. Maximum is 8192 bytes.
 
Another test on LC:

Code:
#define MST_USE_SERIAL1
#define MST_USE_SERIAL2
#define MST_USE_SERIAL3

Sketch uses 17480 bytes (27%) of program storage space. Maximum is 63488 bytes.
Global variables use 2664 bytes (32%) of dynamic memory, leaving 5528 bytes for local variables. Maximum is 8192 bytes.


Code:
//#define MST_USE_SERIAL1
//#define MST_USE_SERIAL2
//#define MST_USE_SERIAL3

Sketch uses 14420 bytes (22%) of program storage space. Maximum is 63488 bytes.
Global variables use 2644 bytes (32%) of dynamic memory, leaving 5548 bytes for local variables. Maximum is 8192 bytes.


Code:
#define MST_USE_SERIAL1
//#define MST_USE_SERIAL2
//#define MST_USE_SERIAL3

Sketch uses 15744 bytes (24%) of program storage space. Maximum is 63488 bytes.
Global variables use 2652 bytes (32%) of dynamic memory, leaving 5540 bytes for local variables. Maximum is 8192 bytes.

Seems each port resource to control costs ~ 1K handling :)
 
Update: wow the LC is a picky chip. 6MHz? I'm running 10 dword transfer16's F&F @ 8MHz at 45uS intervals, I'll play more with it when I have time but gotta goto work :)
 
What is the rate of the messages? Typical rates might be 30 Hz to update a display - or 1000 Hz to read an MPU sensor (10 Words) - one being larger messages the other being small.

Pushing any faster leaves the T_LC less time for useful processing.
 
the max it can run is 8mhz at 45uS, i have to patch some areas of the code for the other stuff tho, but so far with testing only F&F its not crashing at all!
the console doesnt seem very fast tho, ill play with it later, maybe its cpu is being taxed
 
8 MHz is SPI speed? In Slave mode - or T_LC Master and Slave? How many F&F messages per second is the rate I was wondering about.
 
oh, while debugging inset it to 30uS f&f loops, yeah, max push at 8mhz on a LC which we were aiming for 6 :p

im only doing f&f, no events or leds, i need to tweak some registers in the scopes, picky picky LC
at least the F&F is right at top of ISR, so only 2 places to tweak it to the right spot, ill have to follow down to tweak the rest, fun fun :)

T3.6 is controlling the LC
 
50 uS message time and 30 uS delay? That would be 12,000 messages per second? A stress test - not surprising if the 48 MHz T_LC might be a bit taxed!

Just for reference to see how many unused cycles might be in that test - where USB is faster:

On T_LC I just did a USB print of 40 Bytes for 1 second groups - doing nothing else ( cnt++ and check elapsed time in while) with 12 MBit USB results in about 21,700 prints per second
ABCD ABCD ABCD ABCD LMNO LMNO LMNO_54C1
One second 10 DWORD Cnt=21697

Doing 10 second runs without a pause it gets : 212,667 or 21,300 per second - that ~400 drop shows more of the buffer empty time.
 
indeed, the new file is called SPI_MSTransfer_Slave.cpp/h

for now i compile the master with the LCv2 update and use the separated slave library on slave for testing, so i test against a free running master while debugging slave end

only when im done the slave library will i start stripping the master of slave code
might take a few days, but this morning alone i stripped it pretty bare and barely gained much ram. only when i added the defines for the slave resources started recovering the memory for LC. I will keep the defines in the H file regardless, I don’t think the compiler properly uses a sketch define in a library

before you mentioned 2mhz is faster than uart, i ended up getting to 8mhz, but we all know uart dont have callbacks for data handling :)

ill back it up before continuing to make sure i dont mess it up, if its only used for f&f only in its current state its good to go, but wanna finish the rest of the isr timings, it was ~ 55-60uS before, when i stopped setting the slave transfer dword while just reading from master for the main entry, it dropped to 45 and kept running smooth. this is why we need to tweak it :)
 
Stepwise can be best to keep track of the changes and spread the work out - no rush.

As noted before the libraries are compiled Independently With No Regard to what the sketch has for #defines. Libs are compiled with all defines required in advance and then archived for use by any Sketch!

unless it is a Command Line define during compile - all needed elements must be in the files referenced to complete the compile, and libraries by definition don't look into any sketch directory.

The sketch includes the Lib Header so the Linker can work things out, but the Lib compiles with only "its" files.
 
note: The T_LC can run faster with FASTER PC USB service … These are counts for 10 second runs.

T_3.6 Alone : ABCD ABCD ABCD ABCD LMNO LMNO LMNO_3407B >> TEN second 10 DWORD Cnt=213115
T_3.6 and T_LC on USB2 HUB:: >> TEN second 10 DWORD Cnt=171166
T_LC alone on a USB3 port: >> TEN second 10 DWORD Cnt=242625

Both running :
T_LC on USB3 >> Cnt=242626
and T_3.6 on Hub [USB2 or USB3] >> Cnt=213212
or T_3.6 on USB3 >> Cnt=285497
 
Code:
[ATTACH]13772._xfImport[/ATTACH]

1) Putting this here for reference. Don't use it on the 3.x series yet I'm moving things around.
2) Do not flash this one on the master

Test purposes

Only use for transfer16 F&F's (overload 1)
Do NOT use events() or led toggling for now, I need time to work on the timings

This copy is the one running at 8MHz

Do not use the constructor on the slave, there is no more constructor. Once it's #included, you just need put slave.begin() in setup
Use LC pins 0,5,6,20 (SPI1)
 
LOL, lack of sleep, coffee, and overworked, I found one bug already

Code:
                  if ( ( !sSPI_port ) ? SPI0_S & SPI_S_SPRF : SPI1_S & SPI_S_SPRF ) {
                    if ( (( !sSPI_port ) ? ((uint16_t)(SPI0_DH << 8) | SPI0_DL) : ((uint16_t)(SPI1_DH << 8) | SPI1_DL)) == 0xD0D0 ) break;
                    uint16_t val = buf[ ( buf_pos > buf[1] ) ? buf_pos = 0 : buf_pos++];
                    ( !sSPI_port ) ? SPI0_DH = val >> 8 : SPI1_DH = val >> 8;
                    ( !sSPI_port ) ? SPI0_DL = [COLOR="#FF0000"]val >> 8[/COLOR] : SPI1_DL = val;
                  }
should just be val. Fixed all copies.
 
That's four conditioned tests around the same (sSPI_port) . . . pretty and compact - even if it does hide bugs well :)

wondering if doing this might be more clear and faster?
IF (sSPI_port) {}
ELSE {}
 
probably, ill add that to my todo list, i just wanted a quick conversion to start with :)

luckily theres only 2 spi ports on LC, so we only need to compare two (since both ports can be slaved in MST)

also need decide on a selector
slave.begin(1); ?
slave.begin(“SPI1”)?

the good thing about functions is we can throw back an error if a overload doesnt match, and output possibilities.

ex, if a user goes “”slave.begin(“SPI2”); on LC, we could output to console an error saying he can only choose SPI or SPI1, unlike a constructor, which would create an object that wouldnt work due to a non match, or console output :)
 
Last edited:
Hi tonton81,
Decided to come back to life and start playing with hardware again. Anyway trying to catch up here. Just for reference which zip file should I use for testing purposes?

As for the calling nomenclature I would go with SPI or SPI1. Anyway to do it with enumeration so we don't have to use the quotes?

Thanks
Mike
 
the last one is only for f&f testing on spi1, there is a weird issue im working on where the lc rancomly stops and continues in slave mode, whats funny is “Smallest” (default) seems to make the LC crash fast, changing optimizing to “Fastest” seems to get it working but random pauses, its real finicky
 
Tim, how about this?

Code:
#elif defined(KINETISL) //////////////////////////////////////////////////////////////
        if ( (*(KINETISL_SPI_t *)spi_mst_spi_addr).S & SPI_S_SPRF ) {
          if ( ((uint16_t)((*(KINETISL_SPI_t *)spi_mst_spi_addr).DH << 8) | (*(KINETISL_SPI_t *)spi_mst_spi_addr).DL) == 0xD0D0 ) {
            (*(KINETISL_SPI_t *)spi_mst_spi_addr).C1 &= ~SPI_C1_SPTIE; return;
          }
          (*(KINETISL_SPI_t *)spi_mst_spi_addr).DH = 0xBA;
          (*(KINETISL_SPI_t *)spi_mst_spi_addr).DL = 0xBE;
          (*(KINETISL_SPI_t *)spi_mst_spi_addr).S;
        }
      }
#endif ///////////////////////////////////////////////////////////////////////////////

single call, the SPI port address is set from begin() (spi_mst_spi_addr) and used throughout the ISR :)
So selecting 0 or 1 in setup works in the same ISR code
 
Nice: I could sooner figure out what that is doing - and way less conditional behavior.

The '?' ternary is compact - but more cryptic and results in If/Else code delay and jumping.

Are you testing with that already?

Odd the T_LC is not running reliably/consistently. Especially with 8MHz SPI being better than 6MHz if the problem is the T_LC 'keeping up'. Would be nice to have an SPI aware Scope/Analyzer to monitor the process.

Are you running T_LC to T_LC MST? I wonder if it would change where the one half was a T_3.5/3.6 with known/tested behavior?
 
no, the master is working fine
the issues are LC related

But it's good to know we can dynamically swap SPI ports through memory addresses, I learned that this morning :)
 
Back
Top