SPI communication between Parallax P2 and Raspberry Pi
disha_sudra Posts: 31
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
So, is there any sample code, example or reference link available for P2 to work with SPI?
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).
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:
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.
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.
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.
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:
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.