Smartpin mode sync serial pin issues
I'm dabbling with smartpins for the first time. I have a SPI connection between a Raspberry PI 4 and the P2. The PI is the Controller, P2 is device (I prefer that over master/slave).
I can see the clock and data lines working. I generate random data on the CODI-line, and both CLK and CODI look great on the scope.
So I pulled up the smart pin documentation by Jon Titus and learned about the sync serial pin mode. I use his example to sample from the clock-pin with the following pasm method:
con
CLK = 10
CODI = 11
pri spi_test()
org
' output on pins 56-59
mov dirb, ##$0f00_0000
.smartpin
dirl #CODI 'Reset receiver Smart Pin
wrpin sync_rx_mode, #CODI 'Set sync receiver mode
wxpin #%1_00111, #CODI 'Set receiver to sample on B-
' input edge
dirh #CODI 'Enable Smart-Pin sync receiver
.test_loop
testp #CODI wc 'Wait in loop IN flag = set
nop
if_nc jmp #.test_loop 'If no C flag, repeat testing
rqpin rcvd_data, #CODI 'Put 32-bit data (see text) in
mov outb, rcvd_data 'Send 8 bit data to LEDs
jmp #.test_loop 'Continue to rcv and display
' data
sync_rx_mode long %0000_0101_000_0000000000000_01_11101_0
rcvd_data long $00
end
According to the documentation the BBBB selects normal logic, -1 from the pin number - and CLK is pin 10.
Now when I look at the CODI-line with my scope, the signal is severely dampened.
Any idea what's going on here?
Also: currently clock is not touched in any way, as I figured that it would by default be an input, and that's that. But is this correct, or do I need some sort of smartpin-input-mode for CLK as well?
Comments
Given that Parallax compilers have smart pin constants built in (that I think are available in FlexSpin, too), I think it wise to use them instead of manually declaring them. Here's a little Spin demo (easy to translate to PASM) that works, and shows how to deal with MSBFIRST and LSBFIRST values.
Note that I used a couple F-F jumper wires to connect my output pins to my input pins so that I didn't have to so anything unnecessary with the sync rx setup.
m := P_SYNC_RX ' spi rx mode m |= ((SCKI-CIDO) & %111) << 24 ' add SCK offset (B pin) x := %0_00000 | (8-1) ' sample ahead of b pin rise, 8 bits pinstart(CIDO, m, x, 0) ' configure smart pin pinfloat(CIDO) ' reset/disable until used pinfloat(SCKI) ' make SCK an input
Okay, your "sync_rx_mode" is selecting pin - 3 for inputB. So that won't work. And %TT=%01 is also wrong. That sets the output driven when the smartpin is on.
This exact listing has a familiar ring to it. Someone else not long ago did exactly the same. Maybe best not to follow Mr Titus's examples. Avoid hand-coding the bit patterns when there is prebuilt ones ready to go. Less errors then.
Here's the correct pin mode:
sync_rx_mode long P_MINUS1_B | P_SYNC_RX
In your case the rx data pin was driving its output, having a fight with the device at the other end.
Inputs are always operating. Although they can be diverted and also changed type. Default input type is plain logic level; can be changed via the %P..P bit-field. %AAAA and %BBBB is your diverters, they select which inputs to look at.
@JonnyMac @evanh Thank you for the suggestion to use the constants. This did in fact do the trick. I'm in general a fan of doing this, however you have to start somewhere, so using examples you think can be trusted as stepping stone is to be expected I believe.
I will comment on the document and reference this thread.
Next step: streaming the expected 768 into RAM or LUT.
Bob Dury will be much better for book style examples. He's a recent arrival but has been putting in a lot of hours on testing each one. He's always asking on the forum about finer details of certain instructions - https://forums.parallax.com/discussion/173558/notes-on-propeller-might-be-helpful-for-new-user#latest
As a follow-up on this, I'm currently struggling to read the data using the smartpin. I transfer it into the LUT (as it's 768 bytes both in/out), and from there print it on the console for now.
The following is the core SPI device routine that waits for CS to be asserted, and then attempts to read data in 32 bit words. This works somewhat but the data in the lut does not look as expected. My current assumption is that somehow the inner loop not working as expected and simply spins to read the last received bytes. But this might be wrong.
pri spi() org ' reset our pointers mov incoming_p, #0 mov outgoing_p, #SPI_BUFFER_SIZE dirl #CODI 'Reset receiver Smart Pin wrpin sync_rx_mode, #CODI 'Set sync receiver mode wxpin #%1_11111, #CODI ' Acquire 32 bits, and dirh #CODI 'Enable Smart-Pin sync receiver ' SPI receive loop .wait_cs_low testp #CS wz nop if_z jmp #.wait_cs_low .input_loop testp #CODI wc 'Wait in loop IN flag = set nop if_nc jmp #.input_loop 'If no C flag, repeat testing rqpin rcvd_data, #CODI rev rcvd_data wrlut rcvd_data, incoming_p add incoming_p, #1 testp #CS wz nop if_nz jmp #.input_loop ret sync_rx_mode long P_MINUS1_B | P_SYNC_RX rcvd_data long $00 incoming_p long $00 outgoing_p long SPI_BUFFER_SIZE end
The data I'm sending are 768 bytes counting from 0 to 768 (which of course get truncated to 0..255). See
void fillBuffer(uint8_t *pBuffer) { uint8_t counter = 0; for (size_t i = 0; i < sizeOfInputFrame(kDefaultSampleCount); ++i) { pBuffer[i] = counter++; } }
So what I would expect are three times the bytes 0..255 after another.
However the data I print out looks like this:
FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF FCFDFEFF:FCFDFEFF:FCFDFEFF:FCFDFEFF
This is the last LONG transferred, repeated over. I can kind of verify this when changing the data in my buffer like this:
void fillBuffer(uint8_t *pBuffer) { uint8_t counter = 0xff; for (size_t i = 0; i < sizeOfInputFrame(kDefaultSampleCount); ++i) { pBuffer[i] = counter--; } }
This just reverts the data, so three blocks from 255..0.
I get this:
3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:3020100:3020100:3020100 3020100:F0E0D0C:F0E0D0C:F0E0D0C F0E0D0C:F0E0D0C:F0E0D0C:F0E0D0C F0E0D0C:F0E0D0C:F0E0D0C:F0E0D0C F0E0D0C:F0E0D0C:F0E0D0C:F0E0D0C
So most of the values are what would be expected:
3, 2, 1, 0
the last 4 bytes transferred.
But what is also visible: every now and then there is other data interspersed. But also repeated.
My intuition was that maybe I need to use rdpin instead of rqpin to acknowledge and wait for the next full long to arrive.
But when changing this instruction, the system stops working - I presume I'm stuck inside the loop.
Any hints very welcome.
A quick follow-up: my idea that the input_loop is too fast I could confirm by counting the number of read longs and printing the number - I spin ~4500 times instead of the expected 192.
You're on to it.
Definitely need to test the smartpin's (CODI) IN state to identify if new data received. And use RDPIN, instead of RQPIN, to clear IN state.
@evanh as usual, once writing things up (and talking to my partner over burger & fries about my day, she's an engineer, too), my palm and my face connected. So I powered up my machine again, and of course I have to use rdpin, but then need to also count the actual words and terminate my loop. Otherwise I'd be stuck on the last transmission. Doh, to quote a famous fictional father.
I will try and setup streaming the output buffer from LUT next, steel yourself against the next barrage of questions
For completeness sake, here is a buffer output, exactly as expected:
FFFEFDFC:FBFAF9F8:F7F6F5F4:F3F2F1F0 EFEEEDEC:EBEAE9E8:E7E6E5E4:E3E2E1E0 DFDEDDDC:DBDAD9D8:D7D6D5D4:D3D2D1D0 CFCECDCC:CBCAC9C8:C7C6C5C4:C3C2C1C0 BFBEBDBC:BBBAB9B8:B7B6B5B4:B3B2B1B0 AFAEADAC:ABAAA9A8:A7A6A5A4:A3A2A1A0 9F9E9D9C:9B9A9998:97969594:93929190 8F8E8D8C:8B8A8988:87868584:83828180 7F7E7D7C:7B7A7978:77767574:73727170 6F6E6D6C:6B6A6968:67666564:63626160 5F5E5D5C:5B5A5958:57565554:53525150 4F4E4D4C:4B4A4948:47464544:43424140 3F3E3D3C:3B3A3938:37363534:33323130 2F2E2D2C:2B2A2928:27262524:23222120 1F1E1D1C:1B1A1918:17161514:13121110 F0E0D0C:B0A0908:7060504:3020100 FFFEFDFC:FBFAF9F8:F7F6F5F4:F3F2F1F0 EFEEEDEC:EBEAE9E8:E7E6E5E4:E3E2E1E0 DFDEDDDC:DBDAD9D8:D7D6D5D4:D3D2D1D0 CFCECDCC:CBCAC9C8:C7C6C5C4:C3C2C1C0 BFBEBDBC:BBBAB9B8:B7B6B5B4:B3B2B1B0 AFAEADAC:ABAAA9A8:A7A6A5A4:A3A2A1A0 9F9E9D9C:9B9A9998:97969594:93929190 8F8E8D8C:8B8A8988:87868584:83828180 7F7E7D7C:7B7A7978:77767574:73727170 6F6E6D6C:6B6A6968:67666564:63626160 5F5E5D5C:5B5A5958:57565554:53525150 4F4E4D4C:4B4A4948:47464544:43424140 3F3E3D3C:3B3A3938:37363534:33323130 2F2E2D2C:2B2A2928:27262524:23222120 1F1E1D1C:1B1A1918:17161514:13121110 F0E0D0C:B0A0908:7060504:3020100 FFFEFDFC:FBFAF9F8:F7F6F5F4:F3F2F1F0 EFEEEDEC:EBEAE9E8:E7E6E5E4:E3E2E1E0 DFDEDDDC:DBDAD9D8:D7D6D5D4:D3D2D1D0 CFCECDCC:CBCAC9C8:C7C6C5C4:C3C2C1C0 BFBEBDBC:BBBAB9B8:B7B6B5B4:B3B2B1B0 AFAEADAC:ABAAA9A8:A7A6A5A4:A3A2A1A0 9F9E9D9C:9B9A9998:97969594:93929190 8F8E8D8C:8B8A8988:87868584:83828180 7F7E7D7C:7B7A7978:77767574:73727170 6F6E6D6C:6B6A6968:67666564:63626160 5F5E5D5C:5B5A5958:57565554:53525150 4F4E4D4C:4B4A4948:47464544:43424140 3F3E3D3C:3B3A3938:37363534:33323130 2F2E2D2C:2B2A2928:27262524:23222120 1F1E1D1C:1B1A1918:17161514:13121110 F0E0D0C:B0A0908:7060504:3020100