user4358: I use a single MCP23S17 connected to an Arduino Uno. I use its port B for output and port A for input. When I first started to use this device I noticed, I could read pins, but using them as output failed. After a lot of debugging and trial and error I found out, that the IODIRx Register was never programmed. I then copied the respective code from the setup() routine — where it belongs IMHO — to the loop() routine.
And miraculously the IODIRx Register was written correctly. The code below contains the IODIRx programming snippet in the setup() as well as in loop(). But only in loop() it yields an effect. This means: The output will work only after the first traversal of loop() in my example.
The rest of the setup() routine obviously works, which means it is called at least. SPI is initialised correctly there. 
This drives me nuts. What the hell is a setup routine for, if you can't setup things there. And why on earth doesn't it work then? I don't do strange things there. 
#include <Arduino.h>
#include <Wire.h>   
#include <inttypes.h>
#include <SPI.h>
#include "flanschcontrol.h"
#define DEBUGOUTPUT
#define PROTOV2
typedef int elem_type;
#define ADDRESS (0)   
#define    OPCODEW       (0b01000000)  // Opcode for MCP23S17 with LSB (bit0) set to write (0), address OR'd in later, bits 1-3
#define    OPCODER       (0b01000001)  // Opcode for MCP23S17 with LSB (bit0) set to read (1), address OR'd in later, bits 1-3
#define    ADDR_ENABLE   (0b00001000)  // Configuration register for MCP23S17, the only thing we change is enabling hardware addressing
uint8_t PexSSPin=7;

void setup() {
   Serial.begin(9600);
    pinMode(PexSSPin, OUTPUT);
    SPI.begin();                          
    SPI.setClockDivider(2);   
    SPI.setBitOrder(MSBFIRST);            
    SPI.setDataMode(SPI_MODE0);           

    delay(1000);    
    PORTD &= 0b01111111;    // Slaveselect low

    SPI.transfer(OPCODEW | (ADDRESS << 1)); 
    SPI.transfer(IODIRB);
    SPI.transfer(0b10101010);
    PORTD |= 0b10000000;    // Slaveselect high
    delay(1000);
}

void loop() 
{
    PORTD &= 0b01111111;    // Slaveselect low
    SPI.transfer(OPCODEW | (ADDRESS << 1));             // Send the MCP23S17 opcode, chip address, and write bit
    SPI.transfer(GPIOB);
    SPI.transfer(0b00000000);
    PORTD |= 0b10000000;    // Slaveselect high
    Serial.println("0");
    delay(1000);

    PORTD &= 0b01111111;    // Slaveselect low
    SPI.transfer(OPCODEW | (ADDRESS << 1));             // Send the MCP23S17 opcode, chip address, and write bit
    SPI.transfer(GPIOB);
    SPI.transfer(0b11111111);
    PORTD |= 0b10000000;    // Slaveselect high
    Serial.println("ff");
    delay(1000);

    PORTD &= 0b01111111;    // Slaveselect low
    SPI.transfer(OPCODEW | (ADDRESS << 1));             // Send the MCP23S17 opcode, chip address, and write bit
    SPI.transfer(GPIOB);
    SPI.transfer(0b00001111);
    PORTD |= 0b10000000;    // Slaveselect high
    Serial.println("0f");
    delay(1000);

    PORTD &= 0b01111111;    // Slaveselect low
    SPI.transfer(OPCODEW | (ADDRESS << 1));             // Send the MCP23S17 opcode, chip address, and write bit
    SPI.transfer(GPIOB);
    SPI.transfer(0b11110000);
    PORTD |= 0b10000000;    // Slaveselect high
    Serial.println("f0");
    delay(1000);

    int value;

    PORTD &= 0b01111111;    // Slaveselect low
    SPI.transfer(OPCODER | (ADDRESS << 1));  // Send the MCP23S17 opcode, chip address, and read bit
    SPI.transfer(GPIOA);                      // Send the register we want to read
    value = SPI.transfer(0x00);               // Send any byte, the function will return the read value (register address pointer will auto-increment after write)
    value |= (SPI.transfer(0x00) << 8);       // Read in the "high byte" (portB) and shift it up to the high location and merge with the "low byte"
    PORTD |= 0b10000000;    // Slaveselect high
    Serial.print("pindata: ");
    Serial.println(value);
    delay(1000);    

    PORTD &= 0b01111111;    // Slaveselect low
    SPI.transfer(OPCODEW | (ADDRESS << 1)); 
    SPI.transfer(IODIRB);
    SPI.transfer(0b10101010);
    PORTD |= 0b10000000;    // Slaveselect high     
}

Definitions of some preprocessor thingies:
#define    IODIRA    (0x00)      // MCP23x17 I/O Direction Register
#define    IODIRB    (0x01)      // 1 = Input (default), 0 = Output
#define    GPIOA     (0x12)      // MCP23x17 GPIO Port Register
#define    GPIOB     (0x13)      // Value on the Port - Writing Sets Bits in the Output Latch


user10794: You've fallen for the old "slave select pin is already low" trick!
Let me show you. First we add a line to bring pin 2 high before starting the sequence (for logic analyzer triggering):
pinMode (2, OUTPUT);     // <--- pin 2 output
delay(1000);    
PORTD |= bit (2);        // <--- pin 2 HIGH
PORTD &= 0b01111111;     // Slaveselect low
SPI.transfer(OPCODEW | (ADDRESS << 1)); 
SPI.transfer(IODIRB);
SPI.transfer(0b10101010);
PORTD |= 0b10000000;    // Slaveselect high
delay(1000);

This is the logic analyzer output of running your sketch:

Notice how SS is low all the time, and thus the chip does not respond to the command?

Now we add a line before the SPI.begin
PORTD |= 0b10000000;    // Slaveselect high
SPI.begin();                          
SPI.setClockDivider(2);   
SPI.setBitOrder(MSBFIRST);            
SPI.setDataMode(SPI_MODE0);           

Now look at the results:

This time you get the transition of SS from high to low, the chip notices it, and we have a valid SPI transaction.
So without bringing SS high, the first thing you sent was always going to fail.

It was nothing to do with it being in setup - it couldn't be. After all the logic is basically this:
init ();
setup ();
while (true) 
  loop ();


Personally I wouldn't hard code all those bit patterns throughout the code. What if you change the slave select pin one day?
How about:
digitalWrite (PexSSPin, LOW);
/// write to chip
digitalWrite (PexSSPin, HIGH);

Isn't that much more readable? And easier to change later?

4358: 

<p>I use a single MCP23S17 connected to an Arduino Uno. I use its port B for output and port A for input. When I first started to use this device I noticed, I could read pins, but using them as output failed. After a lot of debugging and trial and error I found out, that the IODIRx Register was never programmed. I then copied the respective code from the setup() routine — where it belongs IMHO — to the loop() routine.</p>

<p>And miraculously the IODIRx Register was written correctly. The code below contains the IODIRx programming snippet in the setup() as well as in loop(). But only in loop() it yields an effect. This means: The output will work only after the first traversal of loop() in my example.</p>

<p>The rest of the setup() routine obviously works, which means it is called at least. SPI is initialised correctly there. </p>

<p>This drives me nuts. What the hell is a setup routine for, if you can't setup things there. And why on earth doesn't it work then? I don't do strange things there. </p>

<pre class="lang-C++ prettyprint-override"><code>#include &lt;Arduino.h&gt;
#include &lt;Wire.h&gt;   
#include &lt;inttypes.h&gt;
#include &lt;SPI.h&gt;
#include "flanschcontrol.h"
#define DEBUGOUTPUT
#define PROTOV2
typedef int elem_type;
#define ADDRESS (0)   
#define    OPCODEW       (0b01000000)  // Opcode for MCP23S17 with LSB (bit0) set to write (0), address OR'd in later, bits 1-3
#define    OPCODER       (0b01000001)  // Opcode for MCP23S17 with LSB (bit0) set to read (1), address OR'd in later, bits 1-3
#define    ADDR_ENABLE   (0b00001000)  // Configuration register for MCP23S17, the only thing we change is enabling hardware addressing
uint8_t PexSSPin=7;

void setup() {
   Serial.begin(9600);
    pinMode(PexSSPin, OUTPUT);
    SPI.begin();                          
    SPI.setClockDivider(2);   
    SPI.setBitOrder(MSBFIRST);            
    SPI.setDataMode(SPI_MODE0);           

    delay(1000);    
    PORTD &amp;= 0b01111111;    // Slaveselect low

    SPI.transfer(OPCODEW | (ADDRESS &lt;&lt; 1)); 
    SPI.transfer(IODIRB);
    SPI.transfer(0b10101010);
    PORTD |= 0b10000000;    // Slaveselect high
    delay(1000);
}

void loop() 
{
    PORTD &amp;= 0b01111111;    // Slaveselect low
    SPI.transfer(OPCODEW | (ADDRESS &lt;&lt; 1));             // Send the MCP23S17 opcode, chip address, and write bit
    SPI.transfer(GPIOB);
    SPI.transfer(0b00000000);
    PORTD |= 0b10000000;    // Slaveselect high
    Serial.println("0");
    delay(1000);

    PORTD &amp;= 0b01111111;    // Slaveselect low
    SPI.transfer(OPCODEW | (ADDRESS &lt;&lt; 1));             // Send the MCP23S17 opcode, chip address, and write bit
    SPI.transfer(GPIOB);
    SPI.transfer(0b11111111);
    PORTD |= 0b10000000;    // Slaveselect high
    Serial.println("ff");
    delay(1000);

    PORTD &amp;= 0b01111111;    // Slaveselect low
    SPI.transfer(OPCODEW | (ADDRESS &lt;&lt; 1));             // Send the MCP23S17 opcode, chip address, and write bit
    SPI.transfer(GPIOB);
    SPI.transfer(0b00001111);
    PORTD |= 0b10000000;    // Slaveselect high
    Serial.println("0f");
    delay(1000);

    PORTD &amp;= 0b01111111;    // Slaveselect low
    SPI.transfer(OPCODEW | (ADDRESS &lt;&lt; 1));             // Send the MCP23S17 opcode, chip address, and write bit
    SPI.transfer(GPIOB);
    SPI.transfer(0b11110000);
    PORTD |= 0b10000000;    // Slaveselect high
    Serial.println("f0");
    delay(1000);

    int value;

    PORTD &amp;= 0b01111111;    // Slaveselect low
    SPI.transfer(OPCODER | (ADDRESS &lt;&lt; 1));  // Send the MCP23S17 opcode, chip address, and read bit
    SPI.transfer(GPIOA);                      // Send the register we want to read
    value = SPI.transfer(0x00);               // Send any byte, the function will return the read value (register address pointer will auto-increment after write)
    value |= (SPI.transfer(0x00) &lt;&lt; 8);       // Read in the "high byte" (portB) and shift it up to the high location and merge with the "low byte"
    PORTD |= 0b10000000;    // Slaveselect high
    Serial.print("pindata: ");
    Serial.println(value);
    delay(1000);    

    PORTD &amp;= 0b01111111;    // Slaveselect low
    SPI.transfer(OPCODEW | (ADDRESS &lt;&lt; 1)); 
    SPI.transfer(IODIRB);
    SPI.transfer(0b10101010);
    PORTD |= 0b10000000;    // Slaveselect high     
}
</code></pre>

<p>Definitions of some preprocessor thingies:</p>

<pre class="lang-C++ prettyprint-override"><code>#define    IODIRA    (0x00)      // MCP23x17 I/O Direction Register
#define    IODIRB    (0x01)      // 1 = Input (default), 0 = Output
#define    GPIOA     (0x12)      // MCP23x17 GPIO Port Register
#define    GPIOB     (0x13)      // Value on the Port - Writing Sets Bits in the Output Latch
</code></pre>
 10794: 

<p>You've fallen for the old "slave select pin is already low" trick!</p>

<p>Let me show you. First we add a line to bring pin 2 high before starting the sequence (for logic analyzer triggering):</p>

<pre class="lang-C++ prettyprint-override"><code>pinMode (2, OUTPUT);     // &lt;--- pin 2 output
delay(1000);    
PORTD |= bit (2);        // &lt;--- pin 2 HIGH
PORTD &amp;= 0b01111111;     // Slaveselect low
SPI.transfer(OPCODEW | (ADDRESS &lt;&lt; 1)); 
SPI.transfer(IODIRB);
SPI.transfer(0b10101010);
PORTD |= 0b10000000;    // Slaveselect high
delay(1000);
</code></pre>

<p>This is the logic analyzer output of running your sketch:</p>

<p><a href="https://i.stack.imgur.com/c2IPr.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/c2IPr.png" alt="Slave select low"></a></p>

<p>Notice how SS is low all the time, and thus the chip does not respond to the command?</p>

<hr>

<p>Now we add a line <strong>before</strong> the <code>SPI.begin</code></p>

<pre class="lang-C++ prettyprint-override"><code>PORTD |= 0b10000000;    // Slaveselect high
SPI.begin();                          
SPI.setClockDivider(2);   
SPI.setBitOrder(MSBFIRST);            
SPI.setDataMode(SPI_MODE0);           
</code></pre>

<p>Now look at the results:</p>

<p><a href="https://i.stack.imgur.com/Xu2HN.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Xu2HN.png" alt="Slave select high"></a></p>

<p>This time you get the transition of SS from high to low, the chip notices it, and we have a valid SPI transaction.</p>

<p>So without bringing SS high, the <strong>first</strong> thing you sent was always going to fail.</p>

<hr>

<p>It was nothing to do with it being in <code>setup</code> - it couldn't be. After all the logic is basically this:</p>

<pre class="lang-C++ prettyprint-override"><code>init ();
setup ();
while (true) 
  loop ();
</code></pre>

<hr>

<p>Personally I wouldn't hard code all those bit patterns throughout the code. What if you change the slave select pin one day?</p>

<p>How about:</p>

<pre class="lang-C++ prettyprint-override"><code>digitalWrite (PexSSPin, LOW);
/// write to chip
digitalWrite (PexSSPin, HIGH);
</code></pre>

<p>Isn't that much more readable? And easier to change later?</p>
