SPI communication between Parallax P2 and Raspberry Pi
disha_sudra
Posts: 43
in C/C++
Hello,
I'm trying to transfer data from Raspberry Pi (As a master) to Parallax P2. I've attached Rpi code rpi_master_spi.cpp I have tried with Arduino Mega as a slave, I'm able to communicate bidirectionally from this code. Now I want to use Parallax P2 as a slave. I've checked shift_in() and shift_out() functions, but it's not working for me. I have used below pins of parallax P2
SCK 24
DATA 25
SS 26
So, is there any sample code, example or reference link available for P2 to work with SPI?
cpp
546B
Comments
For the P2 you will want to look into smart pins. In Spin2, you would start with something like this
Assuming the RPi CPOL is 0, you could setup the SPI input like this:
This SUGGESTED code (two versions) is based on other things I've worked on, but I have not used the P2 as a SPI slave with another device. Ultimately, you'll probably want a cog that monitors the SPI input and updates a buffer on the fly (like serial objects do).
Hi JonnyMac,
Thanks for reply. I tried this code. However I'm unable to communicate.
I want to set clock frequency of P2 same as Raspberry Pi. And receive data from Raspberry Pi.
Can you please explain in details about how should the m and x be selected. And what is the role of SCLK particularly.
I've saved above code as testcode.spin2 and used it in c code as below.
The details can be found here:
-- https://docs.google.com/document/d/1gn6oaT5Ib7CytvlZHacmrSbVBJsD9t_-kmvjd7nUR6o/edit#heading=h.53grmlqytmbv
I use variable m for the smart pin mode (in this case synchronous RX), and x and y are the registers used by the smart pin (y is 0 in this case). I have used smart pin synchronous RX many times, but always with an internally generated clock. This should not be an issue, though, because the smart pin setup links the clock pin (an input) to the MISO pin. The only restriction is the delta in pin #s. You need to make sure that your clock pin is within 3 pins of the MISO and MOSI that it might be affecting.
There is no reason to run the P2 at the same clock speed as the RPi. In fact, you might try slowing your SPI output on the RPi. When a byte is received by the P2, it has to fix and store it before the next rising clock edge. A logic analyzer will be helpful here. Also, why not write test code to get one byte from RPi to P2 before you try 50? This is a common problem with programmers: jumping directly to the end goal instead of working their way there. I've been coding the Propeller for a long time, and I still do it very incrementally. The process only seems slower -- what I find is that incremental development eliminates bugs before they can become buried in a lot of code.
Have a look at the attached demo. It uses one Spin cog to simulate the RPi:
After I got things working with one byte at a time I added a second byte of output to the master.
The slave cog uses an external clock (from the master cog) and monitors its CS; when this drops it waits for a byte to come it or CS to go back high. When a byte comes in it is read from the smart pin, fixed (for MSBFIRST), and written to the buffer. Here's the Spin-only version.
After the SPI RX pin is setup (associated with the external clock), it drops into a loop that waits for CS to drop and then writes incoming bytes to the buffer. It works, but is only good for the demo because we know two bytes are coming.
As I said earlier, doing things incrementally is a good way to go. Once all the Spin2 code was working, I converted the ending repeat loop to this inline pasm fuction. It does the same, but will return the number of bytes the were received while CS was low.
All the code is in the demo. Please, please, please, give it a try before converting it to another language. Go slowly.
As you already owe me a beer or an ice cream , I will leave adding the MISO mechanism to you. It should be no problem. Ultimately, you could create a SPI slave object with circular buffers and the ability to read as many bytes as one wants. Have a look at jm_fullduplexserial.spin2 for ideas on circular buffers and using head and tail pointers.
Hi @JonnyMac
Thank you for the solution. I have run this demo code. Got an error pr0 register.
I replaced pr0 with its address as given below
But, I am not getting exact data sent from Raspberry-pi. So what am I doing wrong here? Can you please suggest?
PR0..PR7 are user registers in the Spin2 interpreter -- I thought FlexProp understood these registers. That said, it's easy to add a local variable (I wouldn't use a hard address as you're doing; no telling what's at that address under FlexProp). As you can see, with a small adjustmet for FlexProp, the demo works there, too.
Now I suggest you get a logic analyzer and see what's coming out of your Raspberry Pi. I set the SPI clock back to 1MHz and captured the output from my master cog which sends a count value, and 255-count in each CS frame. Here's the capture:
I think I've done all I can given your limited information and feedback.
-- "I am not getting exact data sent from Raspberry-pi" is not helpful to those from whom you're asking for help.
Programming can be fiddly. Time to fiddle until you understand what's going on with your hardware. Good luck with your project.
Thank you for your valuable help.
Hello @disha_sudra,
You can try this "C programming language" method to receive the data from Rpi to propeller 2 using SPI protocol.
PR0..PR7 symbols were added to Flex suite as of v5.9.15 - the latest release.
v5.9.15 fixes a bug or two with inline Pasm too.
Have you tested that with physical signals? It seems like when the CS line drops and the CLK line goes high, the code is going to be in a very tight loop that blasts values to the data[] array -- there seems to be nothing stopping the code from generating a bunch of samples from the same clock pulse, and this will continue as long as CS is low. The P2 smart pin SPI feature takes care of this; we simply wait check to see if a byte as been received. When that is not the case, we can check the state of the CS line to see if the master is done sending. And with mode 0 SPI, you want to sample right before the rising clock edge, not while it's high. If I'm wrong, please tell me -- I understand C, but I don't use it with the Propeller.
I don't like to post untested code (especially in a language I don't use regularly, and never on the Propeller), but maybe the C version with smart pin SPI looks like this:
I have .14 -- will look for the latest. Thanks for the tip.
Can you add a small delay on the RPi between CS dropping and bits going out? Maybe there is a race condition.
Hi @JonnyMac
As per your suggestion I've used smart pins and created a function for receiving.
I am using P_SYNC_RX as per your suggestion in previous post.
I am attaching my RPi code and P2 code in c++.
RPI Frequency: 5 MHZ
P2 Frequency: 200 MHZ
With above mentioned frequency setup I'm getting proper data for buffer size from 10 to 255 bytes, but when I increases buffer size on RPi from 255 to 500 or more then I am getting garbage data on P2. same thing happen if I change the clock frequency of RPI or P2. I need to setup RPI spi Frequency to 10 MHZ for high speed data transfer. So if some one can point what I am doing wrong here then it will be great help. I am new to P2 and smart pin configuration. Thank you.
Code for P2:
Code for R-pi:
Disha,
Give this a try. It compiles but I've not tested it with any hardware.
PS: The inner loop is 14 sysclock ticks. That's fast enough to keep up with the smallest recommended oversampling of 3. Therefore max bitrate is 200 MHz / 3 = 66 Mbit/s. PPS: Although sysclock/5 is probably the more reliable figure, which means up to 200 / 5 = 40 Mbit/s.
PPPS: Oversampling is needed factor here because the Prop2 doesn't provide external synchronous clocking for any I/O. The SPI clock input pin is just another data I/O pin, same as the SPI data pins. If the clocking source (RPi in this case) is not common to the Prop2's internal clock then the I/O has to be treated as asynchronously sampled. Which means all the usual sampling aliasing problems rare up.
I have tested this code with hardware setup. I have setup Rpi frequency to 10MHz. First I have sent 10 Bytes of buffer from Rpi to P2 but most of time receiving garbage data and also tested with large buffer size (Approx 100KB) but result was same. I've to send 1 to 5 Mbyte of image data.
Thank you so much for your valuable reply.
Hmm, maybe still need to sort out CPOL/CPHA and the likes. Any idea what the RPi is sending as?
Oh, with the DIRH placed after CS low detection, it does need a small amount of time from CS low until smartpin is accepting serial data. Maybe 10 sysclocks, 50 ns post-CS-low. If SPI clocks start in less time then it'll be a mess.
Maybe better to enable the smartpin earlier ...
EDIT: I've added an extra step to check for a prior low CS level. This allows for an earlier enable of the smartpin.
EDIT2: After reading some of Jon's earlier postings I noticed another timing improvement - check for rising CS loop exit only when smartpin buffer is empty. Updated my code to incorporate that too.
PS: The forum's formatting doesn't work. Attached file instead:
Final slave code is presented in other topic - https://forums.parallax.com/discussion/comment/1543798/#Comment_1543798
'Twas a much more intensive exercise than I was expecting. It really kind of caught me off guard. I didn't dig out the scope partly because of the fiddliness of hooking it up, which cost me more time chasing my tail.
Using below code of P2 I have measured time to receive one buffer(of 19200 bytes) that is 13 millisecond. How can I increase the speed? One more question I have, if the SPI frequency of P2 differ than _clkfreq, then how can I achieve maximum SPI clock frequency?
In R-Pi I have taken :
Below is P2's code for communication with R-Pi.
Decrease CLK_DIV. EDIT: Oh, you've cut'n'paste from different methods. CLK_DIV isn't actually used by the code.
Yes, mismatched clocks is a limitation. It would be preferable to have a common whole-board reference system clock for both CPUs.
Aside from that there is also a significant lag in the Prop's I/O that you won't see in other SPI slave devices. This has to be worked around to get decent speed. And will take the form of using prior clock cycle to predict later data need. NOTE: A down side of this strategy is any gaps in the master clock will mess up the timing. Ie: Doesn't follow proper SPI clocking rules at all.
Reading your code, it looks like it's mostly from what I'd posted back in March - Gone back and found that now too.
That was written to actually follow SPI clock rules and tested to work up to sysclock/5. Or at least that's what the notes say. I'd really forgotten it worked that well.
So, with that 340 MHz sysclock, you should be fine using, say, a 60 MHz SPI master clock from the RPi.
Question: Why do you need a small file sent so fast?
Hello @evanh , Is there any config parameter we can set in P2 to setup SPI clock frequency to receive data from Raspberry pi? For example if we want to use 20 MHZ Clock frequency for SPI communication then in RPI we can set that frequency as per @disha_sudra's code, But in P2 how can we set it?
Nope, as a slave it just follows the clock. That's one reason why it's tricky to be a slave without a real SPI port.
Looking at my old programs from back in March, I can see I've also written an "always-on" slave too. It uses a whole Cog. It can handle both transmit and receive functions. I don't know if it was finished though ... It can't have been finish, it'd need a command set - and that definitely isn't there.
I could finish it as an example. Do you have a spare cog?
@evanh
As per your comment #18, I tried with my_shift_in() function to continuously receive data from R-Pi. I have used level shifter between them, and able to receive data of 19200 bytes buffer in about 2 to 4 milliseconds at 110 MHz clock speed of R-Pi. When I removes level shifter and directly connect P2 to R-Pi I am not able to receive data buffer by buffer. Is it possible to receive buffer in less than 2 milliseconds and steady time for all buffer?
Yes, I have.
Is that the SPI clock rate? If so then I'm impressed. And I assume your Prop2 is at 340 MHz and therefore achieving just short of sysclock/3. SPI receiver smartpin has proven to be good for that. Transmitter not so much - because of the lag issue.
Question: Is disha_sudra and chintan_joshi the same person?
We are working together on same project.