Whats are the word lengths used by the SPI link?
16-bit words? 32-bit word?
Let me explain protocol.
It is not realtime - so you just prepare bulk buffer, then you execute transmit-receive operation, store buffer and then parse it.
So you can use 32-bit SPI while data could be aligned differently within frames.
SPI RESET sequence - rise MOSI and toggle SCK - that is treated as reset command and by default turns on chain of chips (i.e. all inputs are put to outputs OUT - chip is chaining)
Then - instructions for chaining accepted on bit-level
0 - is NOP - no instruction and ignored
100 - is 'break' chain - it is first broadcasted through whole chain and then - on final clock cycle chain is broken.
101 - establish asynchronous chain to next chip - all of SPI fill be forwarded to next chip in chain
110 - establish synchronous chain to next chip - the same as asynchronous but with additional registers for data - bits will be delayed by 2 in output! so give nop padding to frame of long chains
111 - DATA instruction
data instruction contains 1 byte that that has length in 32-bit words
and 16-bit address
So within single frame you can access any chip and execute data transmissions by to its internal addresses and get results using emit_data function.
For testing purpose - just break chain after reset and start talking to FIRST chip ALWAYS. SPI RESET is synchronization routine, because chip doesn't have global asynchronous reset and starts in undefined state. It is pretty safe however just to send many zeroes to overflow counters inside and get "in sync" with single chip.
----- Communication code snippet ----
unsigned char spibuf[16384]; /* Spi output buffer */
unsigned spibufsz = 0; /* Spi buffer size in bytes */
unsigned nonemit_value[128];
unsigned nonemit_pos[128];
unsigned nonemit_last = 0;
void emit_buf_reverse(const char *str, unsigned sz)
{
unsigned i;
for (i = 0; i < sz; i++) { // Reverse bit order in each byte!
unsigned char p = str
;
p = ((p & 0xaa)>>1) | ((p & 0x55) << 1);
p = ((p & 0xcc)>>2) | ((p & 0x33) << 2);
p = ((p & 0xf0)>>4) | ((p & 0x0f) << 4);
spibuf[spibufsz+i] = p;
}
spibufsz += sz;
printf("Adding %u to %u bytes (reverse)\n", sz, spibufsz);
}
void emit_buf(const char *str, unsigned sz)
{
unsigned i;
memcpy(&spibuf[spibufsz], str, sz); spibufsz += sz;
printf("Adding %u to %u bytes\n", sz, spibufsz);
}
void emit_break(void) { emit_buf("\x4", 1); }
void emit_fsync(void) { emit_buf("\x6", 1); }
void emit_fasync(void) { emit_buf("\x5", 1); }
void emit_data(uint16_t addr, const char *buf, uint16_t len)
{
unsigned char otmp[3];
if (len < 4 || len > 128) return; /* This cannot be programmed in single frame! */
len /= 4; /* Strip */
otmp[0] = (len - 1) | 0xE0;
otmp[1] = addr >> 8; otmp[2] = addr & 0xFF;
emit_buf(otmp, 3);
emit_buf_reverse(buf, len*4);
}
-------------------------------
that's it ? Is it clear to everyone ?