chipKIT® Development Platform

Inspired by Arduino™

SPI between UNO and Max

Created Fri, 29 Jul 2011 23:55:42 +0000 by drpap


drpap

Fri, 29 Jul 2011 23:55:42 +0000

I am trying to setup SPI communication between an Uno board and another microprocessor. To persuade myself that the SPI works (and also discover what I don't know about this), I am trying to first have an Uno32 communicate with a Max32 through SPI.

The following is how I have connected the boards:

UNO J8 pin 1 to MAX Pin50 [MISO] UNO J8 pin 5 to MAX Pin51 [MOSI] UNO J8 pin 3 to MAX Pin52 [SCLK]

I have set the jumpers on the UNO so it is master and on the MAX to be slave.

My question is, how do I handle synchronization between the boards, is this something that is taken care within the SPI library (so I just need to connect the CS line) or do I have to flip the line myself in order to synchronize the transfer?

Any help, or suggestions on how to get this to work would be greatly appreciated.


GeneApperson

Mon, 01 Aug 2011 01:05:18 +0000

There is an SPI signal called slave select (generally SS). A master generates the SS signal (and the clock). A slave receives the SS signal (and the clock). When SS is high, the interface is inactive. When the master wants to send something to the slave, it brings SS low. The master then sends bytes to the slave (simultaneously receiving bytes from the slave). When the master is done sending, it brings SS high. SS being low enables the slave to start receiving data from the master.

When the SPI controller in the PIC32 is set to slave mode, it automatically pays attention to the SS signal. When the SPI controller is in master mode, it doesn't automatically manage SS. Your program on the master must set the SS pin low before it starts sending data and set the pin high again when it is finished.

Some SPI slave devices perform actions on the falling or rising edge of SS. SPI analog to digital converters typically sample their input on the falling edge of SS. SPI digital to analog converters typically perform the conversion and set their output on the rising edge of SS.

Gene Apperson Digilent


drpap

Mon, 01 Aug 2011 19:41:14 +0000

Gene,

Thank you very much for your response. My understanding about SPI is consistent with what you are describing, and your answer about needing to flip the SS line myself (when in master mode) is helpful and the assumption I was operating under. Regarding the 'other side', it is another microprocessor.

To simplify things, I wrote my own SPI slave code on the other micro processor (non-PIC) so I have complete visibility onto what is happening on one side of the SPI. I then wrote a bit-banging version on the UNO side (in C) using pins separate from the SPI defaults and it was working fine, albeit too slow for what I need. But then when moving to the default Pins, it didn't work (and I did not call SPI.begin, as I was doing the protocol myself).

After a lot of head scratching I put the thing on a scope and realized that Pin 10 remains low, no matter what I set it in the software. I since replaced the bit-banging routines with the SPI library and when using a different SS pin, things are working fine.

So the question is, why isn't Pin 10 acting as it should?

I have JP5 and JP7 on the master side (upper two pins when looking at the board with the USB on the left). I also have tried JP4 on both positions (rebooting in between) but no reaction. I have tried configuring Pin 10 as output before calling the SPI.begin(), after calling SPI.begin(), both before and after, or neither. No matter what, it doesn't move.

I know I can just ignore the problem and use another pin, but not being able to use Pin10 means I can't use a single connector, which is a pain. I also don't like to have things go wrong and not have an idea of what is causing it, so with that in mind, any help would be appreciated.

Abbreviated version of the program I am using is below:


const int SPI_CLK = 13; const int SPI_CS = 10; const int SPI_MOSI = 11; const int SPI_MISO = 12;

int cnt;

void setup() { cnt = 0;
Serial.begin(115200);

pinMode(SPI_CS, OUTPUT);

SPI.begin(); SPI.setClockDivider(SPI_CLOCK_DIV128);

pinMode(SPI_CS, OUTPUT); digitalWrite(SPI_CS, 1); digitalWrite(SPI_CLK, 0);

}

void loop() { int dataOut; int dataIn; unsigned long t1, t2;

cnt++;

Serial.print("Ping - "); Serial.print(cnt); Serial.print(" "); Serial.println(cnt%128);

delay(1000);

dataIn = 0; dataOut = cnt % 128;

t1 = ReadCoreTimer(); digitalWrite(SPI_CS, 0); dataIn = SPI.transfer(dataOut); digitalWrite(SPI_CS, 1); t2 = ReadCoreTimer();

Serial.print("Sent "); Serial.print(dataOut); Serial.print(", got "); Serial.println(dataIn);

Serial.print("Time (microSecs): "); Serial.println( (t2-t1)/40); }


dangeljs

Mon, 01 Aug 2011 19:48:59 +0000

Is JP4 Set properly? It controls pin 10.

See this link:

http://www.digilentinc.com/Data/Products/CHIPKIT-UNO32/chipKIT-Uno32-Jumpers.pdf


drpap

Tue, 02 Aug 2011 01:53:47 +0000

As I indicated in my post, I have tried with JP4 in both positions; there doesn't seem to be any difference.


dangeljs

Tue, 02 Aug 2011 03:41:21 +0000

Sorry, my mind was reading JP6 for some reason. Not that this is a perminant solution but did you try direct driving the ports to see if they are working? RD4 or RG9. Set the TRIS bit to zero (output), then toggle the LAT bits to set the pin high or low. Just a thought.


drpap

Tue, 02 Aug 2011 04:38:52 +0000

You are right, that is the natural next step here.

Problem is, the whole idea with this arduino stuff is to abstract away such details. I already spend all this time to figure out that a "sketch" is what we used to call a program file, and "verifying" is what we used to call compile. And accessing I/O bits simply requires calling pinMode() followed by digitalRead() or digitalWrite() -:)

So, if I have to start going through the PIC data sheets and looking up port numbers and registers, pin locations, having to use excell spreadsheets to trace pin number etc., then what's the point of using the arduino-type libraries at all? Ok, soapbox off now.

I'll post what I find out - Thanks.


dangeljs

Tue, 02 Aug 2011 14:51:02 +0000

I ran the "blink" program on pin 10 and checked with a multimeter and was able to see the pin driven high and low so I would think the Arduino abstraction is working. This may be a better test for you.

I understand what you mean, I bought mine really because it was a cheap "starter kit" which allowed me to begin learning the 32-bit architecture. In trying to understand how the abstraction layer works on a low level I'm learning a lot about the PIC32. I'll eventually get completely away from the ardiuno implementation when my understanding is at a higher level, because I find it very inefficient.


GeneApperson

Tue, 02 Aug 2011 23:14:34 +0000

@drpap

On the Uno32, digital pin 10 is mapped to RD4 (bit 4 of PORTD). If you're interested, you can look this up yourself by looking in the file: pins_arduino_pic32_uno.cxx in the pic32 cores file under the hardware folder in your software installation. Among other things, this file defines the mapping of logical pin number to physical port and bit.

This pin mapping means that for digital pin 10 to work, you need to have JP4 in the RD4 position. If you have the jumper in the other position, the pin on the microcontroller will change, but it doesn't go out to the connector.

If the Uno32 is being an SPI master, and you are using digital pin 10 to control the slave select, JP4 should be in the RD4 position. If you have the Uno32 being an SPI slave, then JP4 should be in the RG9 position so that the connector pin maps to the slave select pin on the microcontroller. Microcontroller pin RG9 isn't given a logical pin number, so with JP4 in the RG9 position, there is no way to set the state of that connector pin using digitalWrite. (you could do it by explicitly writing to PORTG, but that bypasses the Arduino abstraction layer).

I apologize that this isn't explained sufficiently well in the board reference manual. I will revise the manual and add some additional text to explain this better.

Gene Apperson Digilent