Project: SPI_MSTransfer

Hi tonton81,

You were right that a wire was missing, but the ground wire is the green one in my setup. I was missing the CS line, now added between 15 on 3.6, and 2 on 3.1. Now everything is working great! Sorry about the rookie error!


I'm hoping to use this to talk to multiple slaves, I will post my benchmarks as soon as I am able.
 
awesome, keep us posted. it should work with multiple slaves, make sure all the MISO/MOSI/SCK are all parallel, and run a different pin of master for each chipselect. get ready for 30mhz data transfers :)
 
I updated Post #1 to include link to GITHUB and added line to show GND must be connected.

Update on T_3.6 & T_3.1 pair : NO Master OT, but one Slave miscount after 27.6 M F&F's :: 54380.00, #, #, #, #, #, #, #, #, #, #, #,27644545,1
 
Very Good - 1 error :: 30,965,647 F&F's ++

If we only had a way to log the error behavior that wouldn't scroll off the screen :)

If nothing in the system uses pri # under 31 or more than - the value should be the same.

I want to drop down to lower SPI MHz - based on prior posts - it will start failing and we'll have no way of seeing internal details that might suggest why.

I need to fire up the CycleCounter to get a usable time base. Given that 100 bytes transfer in 50 uS - that resolution would be meaningless - and expensive. Even the T_3.1 will break that up into 96 points to see if the byte to byte are oddly timed or something.
 
Hey guys i know this is a bit off topic but it's too funny not to post.
My first master and slave SPI implementation on ATmega328P.
I even had a nickname for this ( MonsterSlaveDuino ).;)
AtmegaS1.jpgAtmegaS2.jpg
 
Started T_3.6 M to T_3.1 Slave at 12 MHz SPI and no errors at 600K F&F's. SPI transfer time is 94-95 uS, up from 51 uS at 30 MHz.
>> All but Total fail at 1 MHz and 3 MHz. Have another T_3.6 on breadboard and a T_LC I'll wire and try


@Chris O.- that looks unethical.

tonton81 - another pull request :: I checked in the TVslave.ino with defines.h file removed - but left in the #include :(

Also there I showed starting up the CPU CycleCounter. System (register?) value 'ARM_DWT_CYCCNT' can be used just like microseconds with uint32_t, it wraps in about 17.89 seconds at 240 MHz. I might start a 'ca' log if you don't.
 
a ca logger :p

A good place to show it used - low overhead. If the transaction succeeds - delete the entry. Leave it as a record when it fails.

Might be nice to have a message from Slave>Master:: SPI_delay( x ); // don't send for x micros though not sure where that goes?

Perhaps:: Both Master and Slave: on entry record uint32_t StartCCV=ARM_DWT_CYCCNT, then push this struct:
each event: ENUM { Start, Tx, Rx, ... , CRC Err, Resend, ... }
Xfer_Word#
Tx/Rx value
Time offset from :: ARM_DWT_CYCCNT - StartCCV
? Anything else of value ?

Context on post #835? NVIC Pri #?

Post #834 M&S F&F now no errors at 1.14 M
 
have the master send a simple array to slave and slave return it and master return it like ping pong, see where it fails :)
 
have the master send a simple array to slave and slave return it and master return it like ping pong, see where it fails :)

With added logging that could be a controlled way to see what the behavior is. The Master would have controlled send rate that would HALT on Error on either end. And either end could print the logged process details without causing more errors or having the log data interrupted by ongoing transfers.

Terminated my MS::T_3.6&T_3.1 with no errors at 17,232,121 :: 52112.00, #, #, #, #, #, #, #, #, #, #, #,17232121,0
 
Improvement to slave handling

Hi Tonton81,

For my uses with multiple slaves, the amount of them fluctuates throughout operation. In an ideal system, I can use the same handler to parse the data of each slave, but without knowing which slave the handler got data from, it's quite difficult. To solve this, I added the current chip_select data to AsyncMST and a corresponding line to events(). With this, the handler is able to distinguish which slave the data comes from with minimal changes to the code:

Inside SPI_MSTransfer.h
Code:
struct AsyncMST {
  uint16_t packetID = 0;
  uint8_t error = 0;
  uint8_t chip_select = -1;
};

Inside SPI_MSTransfer.cpp, around the line 1630:
Code:
          if ( buf[1] > 4 ) {
            uint16_t _slave_array[buf[3]];
            memmove (&_slave_array[0], &buf[5], buf[3] * 2 );
            AsyncMST info; info.packetID = buf[4];
	    info.chip_select = chip_select;      // The new line
            _master_handler(_slave_array, buf[3], info);
            spi_port->transfer16(0xD0D0); // send confirmation
            SPI_deassert(); return 0x00A6;
          }
 
Last edited:
why not include it in the array data? ahh okay thats good for identifying at master end, cuz slaves always have same CS
good idea

you don, t actually need to modify the cpp file
you can define it directly in the struct
when the struct is created the object is already assigned

Code:
struct AsyncMST {
  uint16_t packetID = 0;
  uint8_t error = 0;
  uint8_t chip_select = chip_select;
};

EDIT, the slave is not capturing so I added your method, but instead of chip_select we'll call it info.slave:

Code:
  Serial.print("Slave: "); Serial.println(info.slave);

H
Code:
struct AsyncMST {
  uint16_t packetID = 0;
  uint8_t error = 0, slave = -1;
};

CPP
Code:
            AsyncMST info; info.packetID = buf[4]; info.slave = chip_select;

output:
Code:
PacketID: 55
Length: 48
Slave: 43
0 0 C00 40EA 0 0 C20 40EA 0 0 C40 40EA 0 0 C60 40EA 0 0 C80 40EA 0 0 CA0 40EA 0 0 CC0 40EA 0 0 CE0 40EA 0 0 D00 40EA 0 0 D20 40EA 0 0 D40 40EA 0 0 D60 40EA
 
Last edited:
@linarism - that looks like a useful simple change! Whenever the Master is dealing with a message - it knows the Slave CS.

@tonton81: Is the problem at slower SPI rates the hardcoded timeout references or the delaymicroseconds()? Or perhaps at slower rates there is a need for an added delay where things flow more slowly?

I tried SPI at 30.5 KHz :: 30500 with these HamHanded edits and it starts working better at that speed:
//#define resTime_uS 2000 // was 50 >>> if ( micros() - timeout > resTime_uS ) {
//#define TxTime_ms 1000 // was 100 >>> while ( spi_port->transfer16(0xFFFF) != 0xBABE && millis() - timeout < TxTime_ms );
//#define _transfer_slowdown 100 // was ZERO

At that speed it still won't toggle the LED - but the F&F messages pass with misses of 1,2,4 or 5 sets [most often 1 or 2] instead of 8, 11, 12 or 17 missed messages.

With my lack of understanding of the code it is slow going recompiling Master and Slave randomly - perhaps that tip will point out the area to concentrate on?
 
ahh, maybe you think it could be possible the slower spi rates require more time to exchange (shift both ways completely) data? you seen an improvement?

I included linarism's implementation in the repo
 
Improvement is hard to measure without a custom test like you noted - or at least customizing the current setup which I did not do - just hoping I'd stumble on the right adjustment.

The current setup trying 500 Hz F&F is frustrated. The long delay(1000) on error takes a long time to watch a trend - but turning that down could open a flood gate.

I keep thinking knowing how long is spent where - post #836 - might show what happens too fast or too slow or where corrupted data appears if what is what is showing up.

The errors are detected on the Master side - rarely does the Slave print : DEBUG: [DATA] 9712 4 0 9716

First thing I did was trim the Master debug messages so they don't scroll too wide::
>> FAIL_Res #2 RETRY...FAIL_Res #3 RETRY...DBG: [S_CS 15] FAIL_RES #4 Tx ABORT. F&F (OT=399)micros() _time==110287
 
500khz master _time == 1885
750khz master _time == 1400
these are causing OT's to increment
threw me off while I'm checking timings
 
I got as far as this for logging.

Put CycleCounter Enable in .begin. Plan is record start and every transfer16 value. If the transfer works - delete the array, if not then index the array.

enum:: List of things expected to happen during a transfer
Start is enter master send or the slave ISR. [.data=PacketID]
WAIT is random in case there is a place to use it?
Rx or Tx event stores that value
CRCERR records that
TO1 is location 1 for a time out
TO2 is location 2 for a time out

On each event record .time = ARM_DWT_CYCCNT;

Code:
enum SPI_EV { START, WAIT, RX, TX, CRCERR, TO1, TO2 };
struct SPI_event {
  SPI_EV event;
  uint32_t time;
  uint16_t data;
}

Circular_Buffer<SPI_event, 12, 150> EventQ;
 
I think i have narrowed it down
I have 10khz spi working blinking led with a few modifications, its late now ill work on it tomorrow
btw, it has nothing to do with delay/delaymicroseconds...
 
no its a combo between the functions and isr crc checking routines

workaround, we kill that code and run without function crc

ill figure it out eventuallly :)

the fact i got it running at 10khz means were on the right track
the only mystery other than working on a fix is the big magic question, how was the high speed working on same code... we will find out that after its patched and will compare old vs new
 
Last edited:
Interesting to see the change. Wonder if the T_3.5 will run different for Mike? Found it to run well on the T_3.1. Didn't get wires for the T_LC yet.
 
yeah im pretty sure this will fix mike’s 3.5 issues, the fact he was getting intermittant successes and alot of errors seems to be pointed in that direction, its just a mystery as why its not occuring at high speeds, but i was never able to get below 8mhz without crashing on the 3.6m3.5s, so its pretty obvious i found that sweet spot

workaround requires all functions to be patched as well as isr
id rather fix this issue than just patching everything with a workaround

the good news is we dont need to delay(Microsecond)s the transfers, all that slow_down flag overhead can be removed for both high and low speed

i cant offer a workaround patch as that would require double time and function retesting, im testing only the stability of one at a time. im using the pintoggle to trace down and hunt the bug down, thats how i found it, in the end when its done and working the way it should, the corrections would need to follow the other methods
 
Back
Top