Help with SPIN bidirectional SPI > 32 bits

in Propeller 1
I looked through the obex and nothing jumped out at me so I thought I'd ask for some help. What I need to do is shift synchronous serial data out, LSB first, while simultaneously shifting data in, LSB first. (I'm pretty sure the data in is LSB, the code I have now shifts in MSB but pretty sure it does the reversal in the calling method.) It needs to be variable number of bits and handle multi-long transfers. The other must have is pure spin.
One of the problems I'm having is with endian-ness.. I still need to handle how ASCII hex string is parsed into the longs and since they're both up in the air right now I just keep getting lost. I'm probably not describing the problem 100% so here's an example. The original code is able to shift variable number of bits in/out, up to 1 long.
I think this code could work, just compute how many times to loop. What I really want to do is pass a pointer to the array. Not sure how it should return the data though. This returned data needs to be optionally compared against an expected output data, with a mask. That should be farily simple once I figure out how to get data in and out. Understanding this shift problem should help with writing the parsing code.
Right now I have this written to theoretically work with 32 bit data. SIR is never more than 8 bits for this chip though.
One of the problems I'm having is with endian-ness.. I still need to handle how ASCII hex string is parsed into the longs and since they're both up in the air right now I just keep getting lost. I'm probably not describing the problem 100% so here's an example. The original code is able to shift variable number of bits in/out, up to 1 long.
PRI Shift_Array(array, num_bits) : ret_value | i
{
Shifts an array of bits into the TAP while reading data back out.
This method is called when the TAP state machine is in the Shift_DR or Shift_IR state.
}
ret_value := 0
repeat i from 1 to num_bits
outa[TDI] := array & 1 ' Output data to target, LSB first
array >>= 1
ret_value <<= 1
ret_value |= ina[TDO] ' Receive data, shift order depends on target
if (i == num_bits) ' If at final bit...
outa[TMS] := 1 ' Go to Exit1
TCK_Pulse
I think this code could work, just compute how many times to loop. What I really want to do is pass a pointer to the array. Not sure how it should return the data though. This returned data needs to be optionally compared against an expected output data, with a mask. That should be farily simple once I figure out how to get data in and out. Understanding this shift problem should help with writing the parsing code.
Right now I have this written to theoretically work with 32 bit data. SIR is never more than 8 bits for this chip though.
ifnot str.stringCompareCS(c, @SIR) ' sir always 8 bits
{
if ck > 32 ' SIR > 32 bits not supported, only 8 bit SIR testing
pst.str(string(13,10,"SIR > 32 Clocks"))
return
}
tdi := nu.FromStr(long[p][2], nu#HEX)
isTdo := false
isMask := false
{
pst.str(String(13,10))
pst.str(@commandbuffer)
pst.str(String(13,10,"parameters = "))
pst.dec(n)
pst.str(String(13,10))
pst.dec(t)
}{
repeat i from 1 to t
pst.str(long[p][(i*2)])
pst.hex(nu.FromStr(long[p][(i*2)], nu#HEX),2)
pst.str(String(" "))
}
if n == 5
ifnot str.stringCompareCS(long[p][3], string("TDO"))
tdo := nu.FromStr(long[p][4], nu#HEX)
isTdo := true
if n == 7
ifnot str.stringCompareCS(long[p][3], string("TDO"))
tdo := nu.FromStr(long[p][4], nu#HEX)
isTdo := true
ifnot str.stringCompareCS(long[p][5], string("MASK"))
mask := nu.FromStr(long[p][6], nu#HEX)
isMask := true
elseifnot str.stringCompareCS(long[p][5], string("TDO"))
tdo := nu.FromStr(long[p][6], nu#HEX)
isTdo := true
if n == 9
if str.stringCompareCS(long[p][3], string("SMASK"))
pst.str(string("bad data format"))
return
if str.stringCompareCS(long[p][5], string("TDO"))
pst.str(string("bad data format"))
return
if str.stringCompareCS(long[p][7], string("MASK"))
pst.str(string("bad data format"))
return
tdo := nu.FromStr(long[p][6], nu#HEX)
mask := nu.FromStr(long[p][8], nu#HEX)
isTdo := true
isMask := true
'' lets debug all this stuff above for a basic sanity check
{
pst.str(string(13,10,"CLOCKS "))
pst.dec(ck)
pst.str(string(" TDI"))
pst.str(nu.ToStr(tdi, nu#HEX))
if isTdo
pst.str(string(" TDO"))
pst.str(nu.ToStr(tdo, nu#HEX))
if isMask
pst.str(string(" MASK"))
pst.str(nu.ToStr(mask, nu#HEX))
}
result := jtag.Send_Instruction(tdi ,ck)
if isTdo
result ^= tdo
if isMask
result &= mask
ifnot result '' DEBUG SUCESS OR FAIL HERE!!
pst.str(String("SIR COMPARE FAIL"))
Comments
PRI Shift_Array(inarrayaddress, outarrayaddress, num_bits) : ret_value | i, j { Shifts an array of bits into the TAP while reading data back out. This method is called when the TAP state machine is in the Shift_DR or Shift_IR state. } ret_value := 0 repeat i from 1 to num_bits j :=(( i - 1) >> 32) << 2 outa[TDI] := long[inarrayaddress + j] & 1 ' Output data to target, LSB first long[inarrayaddress + j] >>= 1 long[outarrayaddress + j] <<= 1 long[outarrayaddress + j] |= ina[TDO] ' Receive data, shift order depends on target if (i == num_bits) ' If at final bit... outa[TMS] := 1 ' Go to Exit1 TCK_Pulse ....
*edit
Looking at that again, this doesn't seem quite right...:
j :=( i >> 32) << 2
I think the divide is 32, so the right shift would be 6? Not sure about the left shift...The math is escaping me at the moment. Perhaps when the twins go to sleep.
PRI Shift_Large_Array(inarrayaddress, outarrayaddress, num_bits) | i, j, n { Shifts an array of bits into the TAP while reading data back out. This method is called when the TAP state machine is in the Shift_DR or Shift_IR state. } n := num_bits -1 repeat i from 0 to n j :=(i >> 5) outa[TDI] := long[inarrayaddress] [j] & 1 ' Output data to target, LSB first long[inarrayaddress] [j] >>= 1 long[outarrayaddress] [j] <<= 1 long[outarrayaddress] [j] |= ina[TDO] ' Receive data, shift order depends on target if (i == n) ' If at final bit... outa[TMS] := 1 ' Go to Exit1 TCK_Pulse
my thought was every 32 bit I need a new long. but then I got confused with you starting at 1 not 0. And then things got out of plan.
I guess you are right with >>5
So yeah - that's what I MEANT to say...
but basically if you provide a address of an input array of size n and the address of an output array of the same size it should do it.
In fact, if you do not need the data in the send buffer again, you could even use the same array, and it will replace bit by bit the 'to send' bit with the 'received' bit
Enjoy!
Mike
It was a lot closer than where I was going. I do need the data in the send buffer again because once the TDI is sent, the receive is optionally compared against TDO (with a mask). I know I'm just overthinking things and trying to make it harder than it is. I haven't tested this method yet but it does look like it should work. I ran the edge cases through a calc and got the expected results. Basic sanity checks. I'm not sure how much overhead precomputing n saves.
I can't remember what else I was looking at but there was something that used bidirectional spi. Hopefully when I run across it again this will work for that too!
Mike