connect multiple devices in spi...(problem in selecting slave select pins)

hi…
i have connected arduino uno to mcp23s08(spi expander) arduino as master and mcp23s08 as slave where 10 th pin as slave select pin…it worked…

now i need to connect another mcp23s08 to arduino uno …which pin can be used as slave select pin…i have tried with 9 th pin but it did not work…(when i connect to 10th pin it is working and when connected to 9th it is not working)

which pins on arduino can be used inorder to select multiple slaves…

please help me …thanks in advance…

/*
 
  Code to test MCP23S08 SPI B-bit I/O expander

  See:
     
     <http://code.rancidbacon.com/LearningAboutArduinoMCP23S08>

     <http://www.arduino.cc/en/Tutorial/SPIEEPROM>

  Current features:
  
      * Read input pins
      
      * Set output pins
      
      * Write output pins
      
      * Gratuitous LED fiddling

      * Terrible hacked-together code
*/

// Define SPI-related pins
#define PIN_DATA_OUT 11 // MOSI (Master Out / Slave In)
#define PIN_DATA_IN  12 // MISO (Master In / Slave Out)
#define PIN_SPI_CLOCK  13 // SCK (Serial Clock) 
#define PIN_SLAVE_SELECT 10 // SS (Slave Select)

byte deviceOpcodeRead = 0;
byte deviceOpcodeWrite = 0; // TODO: handle this better?

byte pinState = B00000000;

unsigned long clk = 0;


void setup () {
  Serial.begin(9600);
  Serial.println("Setup enter...");

  Serial.print("SPCR: "); Serial.println(SPCR, BIN);

  // Configure SPI
  //   Configure I/O pins
  pinMode(PIN_DATA_OUT, OUTPUT);
  pinMode(PIN_DATA_IN, INPUT);
  pinMode(PIN_SPI_CLOCK, OUTPUT);
  pinMode(PIN_SLAVE_SELECT, OUTPUT);
  
  digitalWrite(PIN_SLAVE_SELECT, HIGH); // Disable slave
  
  //    Configure SPI Control Register (SPCR) (All values initially 0)
  //     Bit  Description
  //       7  SPI Interrupt Enable    -- disable  (SPIE --> 0)
  //       6  SPI Enable              -- enable   (SPE  --> 1)
  //       5  Data Order              -- MSB 1st  (DORD --> 0) (Slave specific)
  //       4  Master/Slave Select     -- master   (MSTR --> 1)
  //       3  Clock Polarity          --          (CPOL --> 0) (Slave specific) ("Mode")
  //       2  Clock Phase             --          (CPHA --> 0) (Slave specific)
  //       1  SPI Clock Rate Select 1 -- }        (SPR1 --> 0) 
  //       0  SPI Clock Rate Select 0 -- } fOSC/4 (SPR0 --> 0) ("Fastest" but see SPI2X in SPSR)
  SPCR = (1<<SPE)| (1<<MSTR);

  Serial.print("SPCR: "); Serial.println(SPCR, BIN);
  
  // Clear previous data and status (TODO: Determine if necessary/better way.)
  // (Based on Playground SPI example.)
  byte dummy;
  dummy = SPSR;
  dummy = SPDR;
  delay(10);
    
  // Serial.println((1 << SPIF), BIN);
  
# define SLAVE_ADDRESS_BASE    (B01000 << 3)
# define SLAVE_ADDRESS_BIT_A1  (0 << 2)  // TODO: Allow non-zero and define constants 
# define SLAVE_ADDRESS_BIT_A0  (0 << 1)  // TODO: Allow non-zero and define constants 
# define SLAVE_ADDRESS         (SLAVE_ADDRESS_BASE|SLAVE_ADDRESS_BIT_A1|SLAVE_ADDRESS_BIT_A0)

# define CONTROL_BIT_READ 1
# define CONTROL_BIT_WRITE 0

# define REG_IODIR 0x00
# define REG_IOPOL 0x01

# define REG_GPIO 0x09

        
//  byte deviceOpcode = 0;
  
  //TODO: Reset slave?
  
  deviceOpcodeRead = (SLAVE_ADDRESS | CONTROL_BIT_READ);
  deviceOpcodeWrite = (SLAVE_ADDRESS | CONTROL_BIT_WRITE);
  
  Serial.print("Device opcode (read): ");
  Serial.println(deviceOpcodeRead, BIN);

  Serial.print("Device opcode (write): ");
  Serial.println(deviceOpcodeWrite, BIN);

/*
  digitalWrite(PIN_SLAVE_SELECT, LOW); // Enable slave
  spi_transfer(deviceOpcode);
  // spi_transfer(REG_IODIR);  // The register we want to read
  // spi_transfer(REG_IOPOL);  // The register we want to read
  spi_transfer(REG_GPIO);  // The register we want to read
  
  // int data; // Correct type?
  byte data; // Correct type?
  //unsigned long data; // Correct type?
  data = spi_transfer(0xFF); // Transfer dummy byte to get response
  digitalWrite(PIN_SLAVE_SELECT, HIGH); // Disable slave
*/

  byte iodirVal = 0;

  Serial.print("IODIR response: ");
  iodirVal = getRegister(deviceOpcodeRead, REG_IODIR);
  Serial.println(iodirVal, BIN);  
  
  byte newVal = 0;
  // newVal = iodirVal & B01111111;
  
  // newVal = B01111111;
  newVal = B00001111;
  
  Serial.print("newVal: ");
  Serial.println(newVal, BIN);  
  
  setRegister(deviceOpcodeWrite, REG_IODIR, newVal);
  
  Serial.print("IODIR response: ");
  iodirVal = getRegister(deviceOpcodeRead, REG_IODIR);
  Serial.println(iodirVal, BIN);  
  
  //setRegister(deviceOpcodeWrite, REG_GPIO, B10000000); // on 
  //setRegister(deviceOpcodeWrite, REG_GPIO, B00000000); // off
  setRegister(deviceOpcodeWrite, REG_GPIO, pinState);
  
  Serial.print("Initial GPIO response: ");
  Serial.println(getRegister(deviceOpcodeRead, REG_GPIO), BIN);
  
  Serial.println("Setup exit...");
  
  clk = millis();
}

byte getRegister(byte targetDeviceOpcode, byte registerAddress) {

  digitalWrite(PIN_SLAVE_SELECT, LOW); // Enable slave
  spi_transfer(targetDeviceOpcode);
  spi_transfer(registerAddress);  // The register we want to read
  
  byte data; // Correct type?
  data = spi_transfer(0xFF); // Transfer dummy byte to get response
  digitalWrite(PIN_SLAVE_SELECT, HIGH); // Disable slave
 
  return data;
} 

void setRegister(byte targetDeviceOpcode, byte registerAddress, byte value) {
  // TODO: Do Better?

  digitalWrite(PIN_SLAVE_SELECT, LOW); // Enable slave
  spi_transfer(targetDeviceOpcode);
  spi_transfer(registerAddress);  // The register we want to write
  spi_transfer(value);
  
  digitalWrite(PIN_SLAVE_SELECT, HIGH); // Disable slave
} 


// From Playground
char spi_transfer(volatile char data)
{
  SPDR = data;                    // Start the transmission
  while (!(SPSR & (1<<SPIF)))     // Wait for the end of the transmission
  {
  };
  return SPDR;                    // return the received byte
}


byte buttonState = 0; 


void loop() {
  
  if (pinState && ((millis() - clk) > 750)) {
    // pinState = B00000000;
    pinState = (pinState >> 1) & B11110000;
    setRegister(deviceOpcodeWrite, REG_GPIO, pinState);
    clk = millis() - 500;    
  }
  
  // Serial.println(getRegister(deviceOpcodeRead, REG_GPIO), BIN);
  
  buttonState = (getRegister(deviceOpcodeRead, REG_GPIO) & B00000001);
    
  // Serial.println(buttonState, BIN);  
   
  //if (buttonState && !pinState) { // TODO: mask off pin(s) we're interested in & do better.
  if (buttonState) {
    // pinState = B10000000;
    // pinState = B11110000; // Note: You need to set as outputs remember!
    if (!(pinState & B10000000)) { // Compare to top-most output bit
      pinState = (pinState << 1) | B00010000; // Add bottom-most output bit
    }
    setRegister(deviceOpcodeWrite, REG_GPIO, pinState);
    delay(75);
    clk = millis();
  } /*
  else if (!buttonState && pinState) {
    pinState = B00000000;
    setRegister(deviceOpcodeWrite, REG_GPIO, pinState);    
  } 
  */
    
  delay(50);

Why not use the SPI library?

You can use pin 9, as long as pin 10 is kept as an output.

http://www.gammon.com.au/spi

Hi Nick.. Thats a great forum..it helped me alot.. Thanks for the reply..which logic analyzer did u use for debugging..

http://www.saleae.com/logic/

I have a similar problem with the SS pin. I'm controlling the TLC5940 using only portB. My connections are as follows: Pin 13: SCLK, SPI clock running at max speed of 8MHz Pin 12: MODE, used as general I/O goes high during startup, but must remain low for the duration of the program Pin 11: SDAT, SPI data out- shifts out data to the chain of TLC5940 chips Pin 10: GSCLK, controlled by timer 1- runs fast PWM mode to output a 16MHz square wave Pin 9: BLANK, controlled by timer 0- interrupt vector strobes the blank pin once for every 4096 pulses of GSCLK Pin 8: XLAT, shift register latch- strobes high upon completion of a full data shift

My problem is that when I do an SPI transfer, it tries to use pin 10 as the slave select. This is neither necessary nor desirable as it temporarily disables my GSCLK square wave. How might I disassociate pin 10 from the SPI hardware?

I have tried both using the SPI library and the following setup/transfer sequence:

SPCR = b01010000  //enable SPI, set as master, set clock to divide by 4
SPSR = b00000001  //enable 2x speed, multiply clock by 2 (final SPI frequency is 16MHz/2)

void transfer(uint8_t data) {
  SPDR = data;  //Send one byte over SPI
  while (!(SPSR & _BV(SPIF)));  //Wait for the transfer to complete before continuing
}

My GSCLK is setup in the following manner:

void SetupGSCLK() {
  TCCR1A = B00100011;  //COM1A1 COM1A0 COM1B1 COM1B0 reserved reserved WGM11 WGM10
  TCCR1B = B00011001;  //noise_filter rising/falling_edge reserved WGM13 WGM12 CS12 CS11 CS10
  TCCR1C = B00000000;  //Control Register C
  TIMSK1 = B00000000;  //Interrupt Mask Register
  TIFR1 = B00000000;  //Interrupt Register
  OCR1A = B00000001;  //Output Compare Register 1A, defines max value of counter
  OCR1B = B00000000;  //Output Compare Register 1B, GSCLK goes low when counter reaches this value
}

linemouth: My problem is that when I do an SPI transfer, it tries to use pin 10 as the slave select. This is neither necessary nor desirable as it temporarily disables my GSCLK square wave.

No it doesn't.

byte SPIClass::transfer(byte _data) {
  SPDR = _data;
  while (!(SPSR & _BV(SPIF)))
    ;
  return SPDR;
}

Nothing there about pin 10.

However the hardware requires pin 10 (on the Atmega328) to be an output, that's all. After that you can use whatever pin you like as a SS pin.

I'm sure this happens- And I've now tried it again with the SPI library, and it doesn't disrupt my GSCLK. However, when I write directly to SPDR as shown in the transfer code, it does pull pin 10 low. I do have it configured as an output. So that works, but it tells me that there's something else going on behind the scenes.

linemouth: However, when I write directly to SPDR as shown in the transfer code, it does pull pin 10 low.

Prove it.