Pages: [1]   Go Down
Author Topic: i2c and SPI together  (Read 1318 times)
0 Members and 1 Guest are viewing this topic.
SoCal
Offline Offline
Newbie
*
Karma: 0
Posts: 34
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I've looked around these boards, and darned if I can see if anyone has been able to implement SPI and I2C (master) in the same sketch.

What I find is that as soon as I run SPI.begin();, I2c stops responding.

As a matter of fact, if I just set digital pin 11 to output - DDRB=40 ; - it kills I2C. In other words DDRB=32 ; (digital pin 13 is output) and I2C is fine. DDRB=40 ; (digital pins 13 and 11 are output) and I2C is dead.

Why would the IO status of pin 11 have anything to do with I2C?!

At the moment, I'm working to redo the necessary functionality of Wire until I either A) discover what the problem with Wire is, and fix it, or B) redo it myself.

So, who else has SPI and I2C working side-by-side? Thanks!
Logged

Thumbs Up!
Gene Knight

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 546
Posts: 27363
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Anyone using the adafruit RTC/SD shield would have both working together.

What arduino board do you have?
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

SoCal
Offline Offline
Newbie
*
Karma: 0
Posts: 34
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm using the LinkSprite Diamondback Arduino-Wifi board, and trying to add on the LSM303 Compass / Tiltmeter from Sparkfun. I had the problem with the Wifi + Compass combo sketches, and substituted the sketch from the examples for the SPI barometric pressure sensor. After it executes SPI.begin, the I2C gets stuck in an infinite loop.

I'm new at this, and just kinda combined the Compass and SPI sketches:

#include <SPI.h>
#include <Wire.h>
#include <LSM303DLH.h>

LSM303DLH compass;

void setup() {
  Serial.begin(57600);
  Wire.begin();
  compass.enable();
//  SPI.begin();
  DDRB=40 ;
 ...
Logged

Thumbs Up!
Gene Knight

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 502
Posts: 19085
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

There is no particular reason why it shouldn't work, and indeed I got SPI and I2C to work together between two Unos.

Master:

Code:
// Written by Nick Gammon
// July 2011
// SPI/I2C master

#include <SPI.h>
#include <Wire.h>
#include "pins_arduino.h"

#define SLAVE_ADDRESS 42

// command we might send
#define CMD_ID     1

void setup (void)
{
  Wire.begin();  
  Serial.begin(115200);  // start serial for output
  
  // Put SCK, MOSI, SS pins into output mode
  // also put SCK, MOSI into LOW state, and SS into HIGH state.
  // Then put SPI hardware into Master mode and turn SPI on
  SPI.begin ();
  // Slow down the master a bit
  SPI.setClockDivider(SPI_CLOCK_DIV16);
  
}  // end of setup


void loop (void)
{

  char c;

  // enable Slave Select
  digitalWrite(SS, LOW);    // SS is pin 10

  // send test string
  for (const char * p = "Hello, world!\n" ; c = *p; p++)
    SPI.transfer (c);

  // disable Slave Select
  digitalWrite(SS, HIGH);

  delay (200);  // 200 mS delay

  Wire.beginTransmission (SLAVE_ADDRESS);
  Wire.send (CMD_ID);
  Wire.endTransmission ();
  
  Wire.requestFrom (SLAVE_ADDRESS, 1);  
  
  if (Wire.available ())
    {
    Serial.print ("Slave is ID: ");
    Serial.println (Wire.receive (), DEC);
    }
  
  delay (1000);  // 1 second delay
}  // end of loop

Slave:

Code:

// Written by Nick Gammon
// July 2011
// SPI/I2C slave

#include "pins_arduino.h"
#include <Wire.h>

char buf [100];
volatile byte pos;
volatile boolean process_it;

// command we might get
#define CMD_ID     1
#define MY_ADDRESS 42

char command;

void setup (void)
{
  Serial.begin (115200);   // debugging

  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);
  
  // turn on SPI in slave mode
  SPCR |= _BV(SPE);
  
  // get ready for an interrupt
  pos = 0;   // buffer empty
  process_it = false;

  // now turn on interrupts
  SPCR |= _BV(SPIE);
  
  Wire.begin (MY_ADDRESS);
  Wire.onReceive (receiveEvent);  // interrupt handler for incoming messages
  Wire.onRequest (requestEvent);  // interrupt handler for when data is wanted

}  // end of setup


// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte c = SPDR;  // grab byte from SPI Data Register
  
  if (!process_it)
    {
    // add to buffer if room
    if (pos < sizeof buf)
      {
      buf [pos++] = c;
      
      // example: newline means time to process buffer
      if (c == '\n')
        process_it = true;
        
      }  // end of room available
  } // if not waiting for previous one to be processed
  
}  // end of interrupt routine SPI_STC_vect

// main loop - wait for flag set in interrupt routine
void loop (void)
{
  if (process_it)
    {
    buf [pos] = 0;  
    Serial.println (buf);
    pos = 0;
    process_it = false;
    }  // end of flag set
    
}  // end of loop

void receiveEvent (int howMany)
 {
   command = Wire.receive ();  // remember command for when we get request
} // end of receiveEvent


void requestEvent ()
{
 switch (command)
   {
   case CMD_ID:      Wire.send (0x55); break;   // send our ID

   }  // end of switch
  
}  // end of requestEvent

I connected together pins 10 .. 13 (for SPI) A4/A5 (for I2C) and +5V and Gnd.

Then uploaded both sketches and opened the serial monitor on each one.

One of them echoed back the "hello, world" that was being sent by SPI:

Code:
Hello, world!

Hello, world!

Hello, world!

Hello, world!

Hello, world!

Hello, world!

Hello, world!

Hello, world!

Hello, world!


The other one echoes back the slave ID that was requested by I2C:

Code:
Slave is ID: 85
Slave is ID: 85

The slave uses interrupts to process both SPI and I2C incoming.
Logged


Global Moderator
Offline Offline
Brattain Member
*****
Karma: 502
Posts: 19085
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

As a matter of fact, if I just set digital pin 11 to output - DDRB=40 ; - it kills I2C. In other words DDRB=32 ; (digital pin 13 is output) and I2C is fine. DDRB=40 ; (digital pins 13 and 11 are output) and I2C is dead.

Personally I wouldn't be doing this:

Code:
DDRB=40 ;

For one thing it isn't clear which bits you are changing (as 40 is decimal). 0x28 would be slightly better. But why not do the pinMode function calls? That makes it much more self-documenting. Then you are not changing other pins which might have been initialized elsewhere (eg. in compass.enable(); ).

However you don't even need to change any pin modes. SPI.begin () does that. As explained in the Atmega328 manual on page 168:

Quote
When the SPI is enabled, the data direction of the MOSI, MISO, SCK, and SS pins is overridden according to Table 18-1 on page 168. For more details on automatic port overrides, refer to ”Alternate Port Functions” on page 80.
Logged


Topsham, Vermont USA
Offline Offline
Edison Member
*
Karma: 33
Posts: 1926
... in The Woods In Vermont
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Nick, THANKS for explaining this; I didn't understand it...

One of the details that can Bite!

Regards, Terry King
...In The Woods In Vermont
terry@yourduino.com
Logged

Regards, Terry King terry@yourduino.com  - Check great prices, devices and Arduino-related boards at http://YourDuino.com
HOW-TO: http://ArduinoInfo.Info

SoCal
Offline Offline
Newbie
*
Karma: 0
Posts: 34
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Oh, Arrgh. Sorry!

It was a, um,  intershield short between a header to attach a daughter board that was put in with the long pins *down*, and the ICSP pins sticking *up*. Hence the Digital Pin 11 (PB3) connection. (Darned reliable short! I've had connectors that didn't mate as reliably as these shorted pins did.)

OK, so far I've done this, I've attached Rx to Rx, I've bought shields with incompatible pin usage (The motor shield is a real pin hog! That's way too little utility for way too many pins!).

Is there a directory of classic beginners' stupidity out there, or do we all have to make it up for ourselves?
Logged

Thumbs Up!
Gene Knight

Pages: [1]   Go Up
Jump to: