chipKIT® Development Platform

Inspired by Arduino™

Data transmission between UNOs

Created Mon, 23 Apr 2012 14:32:32 +0000 by xray_drifter


xray_drifter

Mon, 23 Apr 2012 14:32:32 +0000

I am trying send and receive data between two UNOs. Initially, I was using PORTE to send from one board and PORTE to receive at the other board. And everytime when finished reading 256 points data (array filled up), will then perform another actions. Have been tweaking timer parameters, and some sort of indicator flag with other pins to indicate data ready to read, but the receiving board will still mis-read couple of bits likely due to the two boards are not fully synchronized.

Therefore, I have decided to try using SPI since I remember article data can be sent/receive fully synchronized. I was following UNO32 reference manual to setup both the master and slave, but manual doesn't seem to have example on how to actually send and receive data. So, I am wondering if you any of you have successfully setup SPI between two UNOs, and tx/rx data in synch? If yes, would you mind sharing your setup and code?

I have also contacted diligent and they suggested perhaps I should look into Wire libaray with I2C. If you have experience using I2C to tx/rx between UNOs, I would appreciate if you share your setup as well....

Thanks in advance!


xray_drifter

Mon, 23 Apr 2012 20:17:12 +0000

Attempted using I2C for the first time with no luck. Can you guys let me know if I was doing right?

JP6, JP8 set to SDA,SCL

UNO #1 UNO#2 A4 <-------------> A4 A5 <-------------> A5

Each wires are conntected with a 10k pull up resistor to 5V.

I loaded the "master_writer" to UNO#1 and "slave_reciever" to UNO#2 from MPIDE Wire example. Now serial monitor is not showing anything. What do you think could be wrong?

I tried changing the address to 9 in both slave and master, now serial monitor does show something, but doesn't seem to coorespond to the data being sent from master...... :(

Help!


les1943

Mon, 23 Apr 2012 20:50:50 +0000

Why 10k to 5v ? , suggest 2.2k to 3.3v for the pullups.


avenue33

Mon, 23 Apr 2012 20:57:14 +0000

Are the grounds connected?


xray_drifter

Tue, 24 Apr 2012 00:58:54 +0000

Thanks for your reply. As you can tell, I am a complete newbie in this. I chose 10k because there was a tutorial in youtube using 10k, but that was for Arduino. Do you think my ground should be grounded to a common ground?

About the connection and using the example, does it seem okay to you? Do you have to do any modification? I don't understand why changing the address would have an affect, unless UNO32 is fixed to use address ID of 4 as default?

Do you know what is the maximum speed of transmission using I2C? Many many thanks gusy! I am need lots of help to get pass this hurdle..


les1943

Tue, 24 Apr 2012 08:14:57 +0000

The resistors are not that critical depends on the I2C speed but up to the 3.3v for 2 unos , as avenue33 has suggested its the ground that is the problem , I assumed (bad thing) they were commoned...............

I have not used UNO as a slave only as master with EEPROM , I2C speed seems a bit of a grey area with cK

what is your 2 uno project ?


xray_drifter

Tue, 24 Apr 2012 12:23:51 +0000

Connected to common ground, and changed to 2.2k resistor, but still no luck...

I am looking at the "slave_receiver" code, under receiveEvent, void receiveEvent(int howMany) { while(1 < Wire.available()) { char c=Wire.receiver(); Serial.print(c); } int x = Wire.receive(); Serial.println(x); }

After changed changed the slave address to some other value (to 42), serial monitor starts showing some print out... But looking at the code above, under this portion:

[color=#4000FF]while(1 < Wire.available()) { char c=Wire.receiver(); Serial.print(c); }[/color]

should have been printing some text, followed by some other number in this statement: [color=#4000FF] int x = Wire.receive(); Serial.println(x);[/color] Now serial monitor is only showing some number, meaning it was never able to run within the while loop for some reason??

I am just trying to send some digitized/modulated audio signal from one UNO and retreive it at the other. A simple communication device I am trying to make to help me learn...

I don't mind not using Wire.h library as long as I can get it working... Would you guys have something you can share with me?


Ryan K

Wed, 25 Apr 2012 10:28:29 +0000

Hello,

I'm not quite sure you have the Unos setup properly. You will need to jumper JP6 and JP8 to the RG3 and RG2 positions respectively and then connect A4 and A5 of J7 of the different unos together or you could just connect those pins to the corresponding ones on the second uno. uno 1: RG3 pin <---> uno 2: RG3 pin and so forth. RG3 and RG2 are the I2C lines. As for the addressing it shouldn't matter except that I think 0 is the general call address and that there are a few reserved addresses. It should be safe to use an address of like 8 - 119.

I suggested using the wire library simply because there already was the master_writer and slave_receiver demos that would accomplish what you want.

Best Regards, Ryan K Digilent


xray_drifter

Wed, 25 Apr 2012 14:05:59 +0000

Hello Ryan, Thanks for getting back to me and everyone's feedback. I think I am getting a hang of it. Now I am in the process of testing different baud rate. I am guessing I only need to change I2C1BRG at the master UNO?

Another question is, I have to make small modification of the slave receiver code in order to make it work. It seems like under receiveEvent handler, the "Wire.available()" is always 0? Which never able to get out of the while loop... Perhaps if anyone can tell me more about what Wire.available() does?


xray_drifter

Wed, 25 Apr 2012 18:19:29 +0000

Still having trouble adjusting bus speed..

Can someone what to do to set it to 1Mhz mode?
I2C1BRG ==> ? what other parameters?

Do I need to use different resistors? I have read somewhere saying for 1Mhz mode to work, we need to use 1k resistor..

thanks so much!!


les1943

Wed, 25 Apr 2012 19:03:08 +0000

Xray , this may be some help. its from the 24LC256 I2C eeprom data sheet.

2.2 Serial Data (SDA) This is a bidirectional pin used to transfer addresses and data into and out of the device. It is an open drain terminal. Therefore, the SDA bus requires a pull-up resistor to VCC (typical 10 k for 100 kHz, 2 k for 400 kHz and 1 MHz). For normal data transfer, SDA is allowed to change only during SCL low. Changes during SCL high are reserved for indicating the Start and Stop conditions.

VCC being 3.3v ?

Les


xray_drifter

Wed, 25 Apr 2012 19:56:23 +0000

Thanks for your reassurance. I am guessing 1k with 3.3V Vcc should be fine?

How about parameters?

I tried doing this: I2C1BRG=38 DISSLW=1 PBCLK=0

based on equation in PIC32 reference manual:

I2CxBRG = (PBCLK / FSCL x 2) - 2

but still no luck of getting it to 1Mhz...


les1943

Wed, 25 Apr 2012 20:39:29 +0000

suggest u try a 2k pullup to data and same to clock link ? not looked at pic data sheet yet......

have now .

------ from pic 32 data sheet ----------- OSCCON REG

bit 20-19 PBDIV<1:0>: Peripheral Bus Clock (PBCLK) Divisor bits 11 = PBCLK is SYSCLK divided by 8 (default) 10 = PBCLK is SYSCLK divided by 4 01 = PBCLK is SYSCLK divided by 2 00 = PBCLK is SYSCLK divided by 1


so PBCLK is 80Mhz / 8 = 10MHZ (DEFAULT)

1M for I2C1BRG = PBCLK / 1

I2C1BRG=10

could be wrong ?


Ryan K

Thu, 26 Apr 2012 00:00:13 +0000

Hello,

So yes you will only need to change the I2C1BRG to change the the baud rate of the transmission.

As for Wire.available() all that does is check to see if there is data in the receive array that has not been received using Wire.receive(). As for the actual receive and send functionality, that is all done via interrupts.

PBCLK = 10MHz (default)

I2C1BRG = (PBCLK / (FSCL * 2)) - 2 = (10 / (1 *2)) - 2 = 3

A 1K pullup might be too strong, I would suggest using that 2K just in case.

Best Regards, Ryan K Digilent


xray_drifter

Thu, 26 Apr 2012 00:08:59 +0000

Thanks guys! Just for my own curiosity, would you why resistance would have affect towards bus speed?


Ryan K

Thu, 26 Apr 2012 00:27:39 +0000

Hello,

Well there are a bunch of issues with resistance. With too low of a resistance on the pullup you'll run into some issues such as the current draw when the line is pulled low and whether or not the device can pull the line low enough. (lower resistance = stronger pull up) On the other hand if you increase the resistance too far you'll run into longer rise times and possibly not having the idle voltage be high enough to register a '1'. This page seems to have a decent explanation:

http://www.sparkfun.com/tutorials/218

Best Regards, Ryan K Digilent


xray_drifter

Thu, 26 Apr 2012 01:18:29 +0000

Thanks again, Ryan!


les1943

Thu, 26 Apr 2012 08:52:45 +0000

[attachment=1]i2cwave.jpg[/attachment]

X-ray The data is sampled around mid clock cycle (350ns) pull up and line cap effects slope of signal . Dont expect to drive long wires at 1M

Les.

Ryan , if you load BRG=3 into I2C clock prescaler down counter at 10M you get 3.3 Mhz ?? [attachment=0]i2ccount.jpg[/attachment]


xray_drifter

Thu, 26 Apr 2012 14:10:41 +0000

I tried changing I2C1BRG to 3, and it froze... I found out I can lower I2C1BRG to 36, and it will still work. As soon as I set I2C1BRG to 35, it freezes...

Interestingly, with I2C1BRG set to 38, SCL in scope showing a period of 1us?

It seems like the equation

I2C1BRG = (PBCLK / (FSCL * 2)) - 2

38  = (80 / (1 * 2)) - 2

PBCLK seems to be at 80Mhz, even without adjusting PBDIV ??!!!  That shouldn't be right???  

But even the SCL is showing period of 1 MHz, the period of the 32 points received sine wave is about 1ms?

So, each sample is having an interval of 1ms / 32 ~=31us

Why so slow given the SCL showing 1Mhz? :(


les1943

Thu, 26 Apr 2012 15:20:56 +0000

Xray... Yes just serial.print (hex) OSCCON you get 1053322 this sets PBCLK to 80Mhz

do the same for default I2C1BRG you get 390 (dec) 80M / 390 = apx 205128 is this 100k baud ?

There is a table in data sheet DS61116 but not for 80M ?

looks like you cracked it 38 = 1M clock

I said it was a grey area...


xray_drifter

Thu, 26 Apr 2012 16:15:24 +0000

Xray... Yes just serial.print (hex) OSCCON you get 1053322 this sets PBCLK to 80Mhz do the same for default I2C1BRG you get 390 (dec) 80M / 390 = apx 205128 is this 100k baud ? There is a table in data sheet DS61116 but not for 80M ? looks like you cracked it 38 = 1M clock I said it was a grey area...

I did a Serial.print((OSCCON & 0x00180000),HEX)

and that showed as 0, looks like PBDIV set to 80MHz by default?

I also tried changing PBDIV, but looks like it would take the change. Perhaps there are some other parameters that go with it in order to accept the change?

Now, assuming with I2C1BRG = 38 really set I2C baud rate @ 1MHz, why is my 32 points sinewave showing with such low frequency??


xray_drifter

Thu, 26 Apr 2012 17:46:34 +0000

Perhaps I am still unsure about these macros

beginTransmission() send() receive() endTransmission()

For each time we use Wire.send(), does it need to begin with Wire.beginTransmission, and ends with Wire.endTransmission()?

And about using Wire.receive, it must be used within onReceive() handler?
Since onReceive() handler triggered when data received, I can just do x = Wire.receive() without using an If state with 1<Wire.available()? Am I correct?

Sorry, still struggling with the idea that SCL showing 1Mhz, but actual data rate is way below... Really doubt I was using the library correctly


les1943

Thu, 26 Apr 2012 18:09:26 +0000

Xray, only a guess, I presume char = 8 bits to I2C , overhead (time) includes addresses and acks / naks

You cannot write to OSCCON without some system register manipulation it is protected.

Change your data type to bytes ?

Les


xray_drifter

Thu, 26 Apr 2012 18:31:48 +0000

Thanks Les, let me try that...


les1943

Thu, 26 Apr 2012 19:47:13 +0000

Xray Just reading about I2C operation... SW can re-send if NACKs received this could be what is extending messages. was the slew rate disabled for the 1Mhz?

Don't think u should change PBDIV as this clock is used elsewhere

Les

The info is there , can we understand it !


xray_drifter

Thu, 26 Apr 2012 20:29:41 +0000

Thanks for remind me, let me check the slew rate setting too. It should be disabled if using 1Mhz according to the documentation...

Somehow, I tried fidling with the code..

in the main loop

void loop(){
	for(int i=0;i&lt;32;i++){
		Wire.beginTransmission(42);
		Wire.send(sinetable[i] - 128);
		Wire.endTransmission();
	}
}

I modified to:

void loop(){
	Wire.beginTransmission(42);
	for(int i=0;i&lt;32;i++){
		Wire.send(sinetable[i] - 128);
	}
	Wire.endTransmission();
}

That seems to cut down the sampling time by half, but not close enough.... I guess that goes back to your comment about "Wire.beginTransmission(42)" sends the slave's address and waits for an ACK. The modification changed to only sending address at the beginning, then send out the whole sinewave, without having to send address for each byte of data..

I am wondering if there is parameter we can set to reduce the number of ACK/NACK? Like only ACK/NACK after x number of packet sent....


les1943

Thu, 26 Apr 2012 22:53:29 +0000

Xray ... That seems to be hard wired into I2C bus protocol....

24.3.1.5ACKNOWLEDGE (A) OR NOT ACKNOWLEDGE (N) All data byte transmissions must be Acknowledged (ACK) or Not Acknowledged (NACK) by the receiver. The receiver will pull the SDAx line low for an ACK or release the SDAx line for a NACK. The Acknowledge is a one-bit period using one SCLx clock.

ack & nack are only one clock period. have you scoped the data , is it square-ish or slope-y ? still think you may have retries going on...

Bed time.......


Ryan K

Thu, 26 Apr 2012 23:26:56 +0000

Hello,

Sorry about the whole I2C1BRG = 3 thing, I had assumed that the PBCLK was running at 10 MHz (bad assumption). It would freeze since the I2C module only operates up to 1MHz. As for only sending ACK/NACK after a certain number of bytes. I don't think that is possible, I2C requires that each byte is ACK or NACK. Therefore there is going to be some overhead per byte being sent.

As for resending the data, it looks like the Wire library just sends the stop condition and exits out with an error code if it receives a NACK. Doing a rough estimation I would expect you to be transmitting the whole sine wave at around ~3KHz is this close to what you are seeing?

1MHz (SCL) / (33 bytes * 10 SCL ) = ~3KHz

the 10 SCL is 9 clocks + overhead which is a very rough estimate. If you need to go faster than that, we'll probably have to switch over to SPI.

Best Regards, Ryan K Digilent


xray_drifter

Fri, 27 Apr 2012 04:14:17 +0000

You don't know how much I appreciate your help, you guys are just awesome!

Yes,the sine wave at this point is received at 2khz, so some what close to 3k.. But I would probably need it to be faster than that. So, if anyone has a sample code to send/receive between two UNO would be extremely helpful! I hope it synch up nicely like i2c does..

Again, thanks for confirming adjusting ack/nack is out of the question


xray_drifter

Fri, 27 Apr 2012 04:15:58 +0000

I mean sample code to tx/rx between UNO using SPI


les1943

Fri, 27 Apr 2012 08:12:05 +0000

Plan B ....

see you on the SPI forum :)

Les


xray_drifter

Fri, 27 Apr 2012 17:36:21 +0000

I actually searched quite extensively on SPI before Ryan suggested using I2C, but I just couldn't find any example on using SPI as a communication between 2 UNOs.. I guess all I need is an example like the one provided for I2C.... Without that sample code, it would have been impossible for me to figure out..


les1943

Fri, 27 Apr 2012 21:42:50 +0000

Where to start.. The wiki says SPI library works , looks like you need a assign a select pin for each slave . you explored the examples in SPI library ?

some stuff here http://www.chipkit.org/forum/viewtopic.php?f=17&t=845&hilit=SPI


Ryan K

Fri, 27 Apr 2012 23:20:43 +0000

Hello,

The issue with SPI is nothing to do with sending the data. It has to do with the other side, the slave. I don't believe that the SPI or DSPI libraries have implemented functionality for acting as a slave device, so that code will have to be made from scratch. It shouldn't be too hard though and if I have some time over the weekend I'll make something really quick.

Best Regards, Ryan K Digilent


xray_drifter

Mon, 30 Apr 2012 12:50:09 +0000

In the meantime, I will keep trying to squeeze more out of I2C.. One thing I realized, looks like we can only do 32 times Wire.send() before ending transmission and begin another fresh transmission.

Before I have something like:

Wire.beginTransmission(9);
for(int i=0;i&lt;256;i++){
    Wire.send(i);
}
Wire.endTransmission();

When looking at the receive side, I was only seeing received value until 31, and restart over.

Then I have to get around by changing to:

Wire.beginTransmission(9);
for(int i=0; i&lt;256; i++){
    Wire.send(i);
    
     if( i % 32 == 0) {
         Wire.endTransmission();
         Wire.beginTransmission(9);
     }
}

I am wondering the 32 transmission before resend is preset by the Wire.h library, or that is internal with the board?


les1943

Mon, 30 Apr 2012 13:57:30 +0000

Ten out of ten for perseverance , have you calculated how long the complete sequence should be...


xray_drifter

Mon, 30 Apr 2012 19:23:00 +0000

Hello Les, Thanks for thinking with me. I am assuming you suggested me tocalculate the number of samples to be sent per sequence? My application requires sending 256 samples across before executing other routines... That's why I have included that if(x % 32 == 0), just to reset the begin/end transmission....

Yes, I have been fiddling around with I2C1BRG and ADC sampling rate, but I believe the 1MHz baud rate seems to be the bottleneck of my application... Hopefully, someone (Ryan) can help me with simple to use SPI sample code....


Ryan K

Wed, 09 May 2012 02:49:50 +0000

Hello,

I finally had time to get to writing the sample code. Sorry but it's very rough hopefully it can get you started though. It is between a Uno32 and a Max32 but that shouldn't matter. The jumpers for JP4 should both be set to RG9 on the UNOs.

Master code:

#include &lt;DSPI.h&gt;

DSPI0 spi;

uint8_t    rgbSnd[5] = {1, 2, 3, 4, 5};
uint8_t    rgbRcv[5];

void setup()
{
  spi.begin();
  spi.setSpeed(250000);
}

void loop()
{
  /* Bring SS low to begin the transaction.
  */
  spi.setSelect(LOW);

  /* Wait 10us for Pmod to become ready
  */
  Delay10us();

  /* Send the data to the Pmod and get the response.
  */
  spi.transfer(5, rgbSnd, rgbRcv);
  
  /* Bring SS high to end the transaction.
  */
  spi.setSelect(HIGH);
  
  delay(1000);
}

/* ------------------------------------------------------------ */
/***  Delay10us
**
**  Parameters:
**    none
**
**  Return Value:
**    none
**
**  Errors:
**    none
**
**  Description:
**    Delay loop for ~10uS
*/

void
Delay10us()
  {
  volatile int		cnt;

  for (cnt = 0; cnt &lt; 100; cnt++) {
  }

}

Slave Code:

#include &lt;DSPI.h&gt;

DSPI0 spi;

uint8_t    rgbSnd[5];
uint8_t    rgbRcv[5];
int i;

void setup()
{
  spi.begin();
  spi.setSpeed(250000);
  SPI2CONbits.ON = 0;
  rgbRcv[0] = SPI2BUF;
  SPI2CONbits.MSTEN = 0;
  SPI2CONbits.ON = 1;
  Serial.begin(9600);
}

void loop()
{
   for (i = 0; i &lt; 5; i++)
   {
     rgbRcv[i] = spiComm(rgbSnd[i]);
   }
   for(i = 0; i &lt; 5; i++)
   {
     Serial.println(rgbRcv[i], DEC);
   }
}

uint8_t spiComm(uint8_t bVal)
{
  while ((SPI2STAT &amp; (1 &lt;&lt; _SPISTAT_SPITBE)) == 0) {
  }
  SPI2BUF = bVal;

  while ((SPI2STAT &amp; (1 &lt;&lt; _SPISTAT_SPIRBF)) == 0) {
  }

  return SPI2BUF;
}

Hopefully this gets you through. You can change the baud rate in the spi.setSpeed() function in the setup. Let me know if you run into any issues.

Best Regards, Ryan K Digilent


xray_drifter

Wed, 09 May 2012 15:20:50 +0000

Thanks Ryan. That will help me tremendously! Quick question for you though, is there a reason you choose to use DSPI.h over SPI.h?

Another question is, I remember reading somewhere saying JP4 should be set to RD4 for master. I assume DSPI.h is different that way?

And is there anyway I can map SS port to some other pin? I am hoping I can free up RD4 for other purpose...

Thanks again,

Henry


Ryan K

Fri, 11 May 2012 00:44:22 +0000

Hello Henry,

Looking at the schematic if you attach the J8 headers together it doesn't matter what JP4 is set to.

I chose DSPI because frankly I like it better. It was written separately by Digilent and it was tailored for the PIC32 part. The original SPI library was made in the intention to add compatibility with Arduino. DSPI would also be the library where changes Digilent feels should be added for additional spi functionality would be pushed out. I plan to add functionality for DSPI to transmit 8, 16 and 32 bit data widths.

As for mapping the SS pin to a different one. You can do that by using the begin(uint8_t pin) or setPinSelect(uint8_t pin) functions. The default pin is RG9 for DSPI0

Best Regards, Ryan Digilent


xray_drifter

Mon, 14 May 2012 02:13:51 +0000

Thanks Ryan, I think I am getting much closer to the result I want. Another question if you don't mind. Why do we need to have a delay of 1s after setting ss pin high in each loop? I tried lowering it to 1ms, and that seems to cause the slave side to overflow (checked SPIROV).. Is there anyway we can avoid using delay?


Ryan K

Mon, 14 May 2012 11:50:23 +0000

Hello,

The reason that there is a delay on the master side is to allow the slave side to do it's Serial.println() of the data. That function is really slow but if you omit that on the slave side you should be able to reduce/remove the delay on the master side altogether.

Best Regards, Ryan K Digilent