RobTillaart / MCP23S17

Arduino library for SPI based MCP23S17 16 channel port expander
MIT License
27 stars 11 forks source link

How to enable hardware SPI on ESP32-S3 for this MCP23S17 libary? #42

Closed Spaceballs3000 closed 5 months ago

Spaceballs3000 commented 5 months ago

I can get this library to work with SW SPI, but not HW SPI, i.e. MCP23S17 MCP(7,10,9,8,0); // <-- Works but software SPI.

But when I try with hardware vspi it doesn't work i.e. MCP23S17 MCP(10, &vspi); // <-- compiler doesn't like & MCP23S17 MCP(10, vspi); // <-- compiles, but crashes.

Here is the example HW SPI that sends bits out, but I'm not sure how to connect this to the MCP23S17 library.

#include <SPI.h>
#define VSPI_MISO   10
#define VSPI_MOSI   9
#define VSPI_SCLK   8
#define VSPI_SS     7

#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#define VSPI FSPI
#endif

static const int spiClk = 1000000; // 1 MHz
SPIClass * vspi = NULL;
void setup() {
  //initialise instances of the SPIClass attached to VSPI
  vspi = new SPIClass(VSPI);
  //alternatively route through GPIO pins of your choice
  vspi->begin(VSPI_SCLK, VSPI_MISO, VSPI_MOSI, VSPI_SS); //SCLK, MISO, MOSI, SS
  //set up slave select pins as outputs as the Arduino API doesn't handle automatically pulling SS low
  pinMode(vspi->pinSS(), OUTPUT); //VSPI SS
}

void loop() {
  spiCommand(vspi, 0b01110111); // use the SPI bus, junk data to illustrate usage
}

void spiCommand(SPIClass *spi, byte data) {
  //use it as you would the regular arduino SPI API
  spi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
  digitalWrite(spi->pinSS(), LOW); //pull SS slow to prep other end for transfer
  spi->transfer(data);
  digitalWrite(spi->pinSS(), HIGH); //pull ss high to signify end of data transfer
  spi->endTransaction();
}

(updated syntax highlight for readability)

RobTillaart commented 5 months ago

Thanks for the question, I will dive into this asap but it might take a few days.

RobTillaart commented 5 months ago

Please give this a try Code compiles for ESP32 but it is not tested with hardware yet Please let me know the results.

//
//    FILE: MCP23S17_test_connection_ESP32.ino
//  AUTHOR: Rob Tillaart
// PURPOSE: test MCP23S17 library
//     URL: https://github.com/RobTillaart/MCP23S17
//
// see issue #42 library

#include "MCP23S17.h"

const int selectPin = 10;

SPIClass * myspi = new SPIClass(FSPI);  

MCP23S17 MCP(selectPin, myspi);           //  HW SPI address 0x00

void setup()
{
  Serial.begin(115200);
  Serial.println();
  Serial.print("MCP23S17_LIB_VERSION: ");
  Serial.println(MCP23S17_LIB_VERSION);
  Serial.println();
  delay(100);

  myspi->begin();

  bool b = MCP.begin();
  Serial.println(b?"true":"false");

  int c = testConnection(MCP);
  Serial.print("connection: ");
  Serial.println(c);
}

void loop()
{
}

int testConnection(MCP23S17 & mcp)
{
  uint16_t magic_test_number = 0xABCD;

  //  Read the current polarity configuration to restore later
  uint16_t old_value;
  if (! mcp.getPolarity16(old_value)) return -1;

  //  Write the magic number to polarity register
  if (! mcp.setPolarity16(magic_test_number)) return -2;

  //  Read back the magic number from polarity register
  uint16_t temp;
  if (! mcp.getPolarity16(temp)) return -3;

  //  Write old configuration to polarity register
  if (! mcp.setPolarity16(old_value)) return -4;

  //  Check the magic connection test
  if (temp != magic_test_number) return -5;

  return 0;  //  OK
}

//  -- END OF FILE --
Spaceballs3000 commented 5 months ago

Running that code as is outputs this, over and over.

00:40:30.940 -> Rebooting... 00:40:30.940 -> ESP-ROM:esp32s3-20210327 00:40:30.940 -> Build:Mar 27 2021 00:40:30.940 -> rst:0xc (RTC_SW_CPU_RST),boot:0x8 (SPI_FAST_FLASH_BOOT) 00:40:30.940 -> Saved PC:0x403797d2 00:40:30.940 -> SPIWP:0xee 00:40:30.940 -> mode:DIO, clock div:1 00:40:30.940 -> load:0x3fce3818,len:0x508 00:40:30.940 -> load:0x403c9700,len:0x4 00:40:30.940 -> load:0x403c9704,len:0xad0 00:40:30.940 -> load:0x403cc700,len:0x29e4 00:40:30.940 -> entry 0x403c9880 00:40:31.072 -> 00:40:31.072 -> MCP23S17_LIB_VERSION: 0.5.2 00:40:31.072 -> 00:40:31.207 -> Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled. 00:40:31.207 -> 00:40:31.207 -> Core 1 register dump: 00:40:31.207 -> PC : 0x42002016 PS : 0x00060a30 A0 : 0x82001de8 A1 : 0x3fcec130
00:40:31.207 -> A2 : 0x00000000 A3 : 0x007a1200 A4 : 0x007a1200 A5 : 0xffffffff
00:40:31.207 -> A6 : 0x000000ff A7 : 0x3fc95a6c A8 : 0x82002ea5 A9 : 0x3fcec110
00:40:31.207 -> A10 : 0x00000000 A11 : 0x00000000 A12 : 0x3fc95a6c A13 : 0x00000000
00:40:31.207 -> A14 : 0x000000ff A15 : 0x3fc95a6c SAR : 0x00000020 EXCCAUSE: 0x0000001c
00:40:31.207 -> EXCVADDR: 0x0000001c LBEG : 0x420040e4 LEND : 0x420040f1 LCOUNT : 0x00000000
00:40:31.207 -> 00:40:31.207 -> 00:40:31.207 -> Backtrace: 0x42002013:0x3fcec130 0x42001de5:0x3fcec160 0x42001eb2:0x3fcec180 0x42001aa9:0x3fcec1a0 0x42004eda:0x3fcec1c0 00:40:31.207 -> 00:40:31.207 -> 00:40:31.207 -> 00:40:31.207 -> 00:40:31.207 -> ELF file SHA256: 71f48bab4ab95527 00:40:31.207 -> 00:40:31.207 -> Rebooting...

RobTillaart commented 5 months ago

Mmm not expected that,

Replace FSPI with VSPI or HSPI? Does it give same crash?

Spaceballs3000 commented 5 months ago

Using VSPI it crashes (note added in #include ) Using HSPI it crashes (note added in #include )

1:39:42.708 -> Rebooting... 01:39:42.708 -> ESP-ROM:esp32s3-20210327 01:39:42.708 -> Build:Mar 27 2021 01:39:42.708 -> rst:0xc (RTC_SW_CPU_RST),boot:0x8 (SPI_FAST_FLASH_BOOT) 01:39:42.708 -> Saved PC:0x403797d2 01:39:42.708 -> SPIWP:0xee 01:39:42.708 -> mode:DIO, clock div:1 01:39:42.708 -> load:0x3fce3818,len:0x508 01:39:42.708 -> load:0x403c9700,len:0x4 01:39:42.708 -> load:0x403c9704,len:0xad0 01:39:42.708 -> load:0x403cc700,len:0x29e4 01:39:42.708 -> entry 0x403c9880 01:39:42.836 -> 01:39:42.836 -> MCP23S17_LIB_VERSION: 0.5.2 01:39:42.836 -> 01:39:43.006 -> Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled. 01:39:43.006 -> 01:39:43.006 -> Core 1 register dump: 01:39:43.006 -> PC : 0x42002016 PS : 0x00060a30 A0 : 0x82001de8 A1 : 0x3fcec130
01:39:43.006 -> A2 : 0x00000000 A3 : 0x007a1200 A4 : 0x007a1200 A5 : 0xffffffff
01:39:43.006 -> A6 : 0x000000ff A7 : 0x3fc95a6c A8 : 0x82002ea5 A9 : 0x3fcec110
01:39:43.006 -> A10 : 0x00000000 A11 : 0x00000000 A12 : 0x3fc95a6c A13 : 0x00000000
01:39:43.006 -> A14 : 0x00000000 A15 : 0x00000000 SAR : 0x00000020 EXCCAUSE: 0x0000001c
01:39:43.006 -> EXCVADDR: 0x0000001c LBEG : 0x420040e4 LEND : 0x420040f1 LCOUNT : 0x00000000
01:39:43.006 -> 01:39:43.006 -> 01:39:43.006 -> Backtrace: 0x42002013:0x3fcec130 0x42001de5:0x3fcec160 0x42001eb2:0x3fcec180 0x42001aa9:0x3fcec1a0 0x42004eda:0x3fcec1c0 01:39:43.006 -> 01:39:43.006 -> 01:39:43.006 -> 01:39:43.006 -> 01:39:43.006 -> ELF file SHA256: f0a696c5210ed340 01:39:43.006 -> 01:39:43.006 -> Rebooting...

RobTillaart commented 5 months ago

mmm, no hardware setup to test (too busy with my own project deadlines coming weeks)

Just a guess - add SPI.begin(); before myspi->begin() , might be some initialization missing.

RobTillaart commented 5 months ago

From: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/fatal-errors.html#id4

01:39:43.006 -> Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.

LoadProhibited, StoreProhibited link These CPU exceptions happen when an application attempts to read from or write to an invalid memory location. The address which has been written/read is found in the EXCVADDR register in the register dump. If this address is zero, it usually means that the application has attempted to dereference a NULL pointer. If this address is close to zero, it usually means that the application has attempted to access a member of a structure, but the pointer to the structure is NULL. If this address is something else (garbage value, not in 0x3fxxxxxx - 0x6xxxxxxx range), it likely means that the pointer used to access the data is either not initialized or has been corrupted.

The EXCVADDR is not zero, so not a NULL pointer problem.

If this address is close to zero, it usually means that the application has attempted to access a member of a structure, but the pointer to the structure is NULL.

The EXCVADDR is 0x0000001c == 28 which is close enough to zero to be the issue.

to be continued.

RobTillaart commented 5 months ago

mmmm

try

void setup()
{
  Serial.begin(115200);
  Serial.println();
  Serial.print("MCP23S17_LIB_VERSION: ");
  Serial.println(MCP23S17_LIB_VERSION);
  Serial.println();
  delay(100);

  if (myspi == NULL)
  {
    Serial.println("NULL pointer problem");
    while(1);
  }
  myspi->begin();

...
Spaceballs3000 commented 5 months ago

adding SPI.begin(); before myspi->begin(); still crashes on either FSPI or VSPI

Spaceballs3000 commented 5 months ago

Crashes using

` void setup() { Serial.begin(115200); Serial.println(); Serial.print("MCP23S17_LIB_VERSION: "); Serial.println(MCP23S17_LIB_VERSION); Serial.println(); delay(100);

if (myspi == NULL) { Serial.println("NULL pointer problem"); while(1); } myspi->begin();

...

`

RobTillaart commented 5 months ago

A minimalistic test

//
//    FILE: MCP23S17_minimal_test_ESP32.ino
//  AUTHOR: Rob Tillaart
// PURPOSE: test MCP23S17 library
//     URL: https://github.com/RobTillaart/MCP23S17
//
// see issue #42 library

#include "MCP23S17.h"

const int selectPin = 10;

void setup()
{
  Serial.begin(115200);
  Serial.println(MCP23S17_LIB_VERSION);
  Serial.println();
  delay(100);

  SPIClass * myspi = new SPIClass(FSPI);  //  HSPI, VSPI ...

  if (myspi == NULL)
  {
    Serial.println("NULL pointer problem");
    while(1);
  }
  delay(100);

  MCP23S17 MCP(selectPin, myspi);

  myspi->begin();

  bool b = MCP.begin();
  Serial.println(b?"true":"false");
}

void loop()
{
}

//  -- END OF FILE --
RobTillaart commented 5 months ago

By having all code in setup, the initialization of the MCP23S17 object is explicit after the first print.

Spaceballs3000 commented 5 months ago

Pasted it as is, still crashes.

03:11:09.923 -> ESP-ROM:esp32s3-20210327 03:11:09.923 -> Build:Mar 27 2021 03:11:09.970 -> rst:0xc (RTC_SW_CPU_RST),boot:0x8 (SPI_FAST_FLASH_BOOT) 03:11:09.970 -> Saved PC:0x403797d2 03:11:09.970 -> SPIWP:0xee 03:11:09.970 -> mode:DIO, clock div:1 03:11:09.970 -> load:0x3fce3818,len:0x508 03:11:09.970 -> load:0x403c9700,len:0x4 03:11:09.970 -> load:0x403c9704,len:0xad0 03:11:09.970 -> load:0x403cc700,len:0x29e4 03:11:09.970 -> entry 0x403c9880 03:11:10.048 -> 0.5.2 03:11:10.048 -> 03:11:10.308 -> Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled. 03:11:10.308 -> 03:11:10.308 -> Core 1 register dump: 03:11:10.308 -> PC : 0x42001d6e PS : 0x00060a30 A0 : 0x82001b40 A1 : 0x3fcec110
03:11:10.308 -> A2 : 0x00000000 A3 : 0x007a1200 A4 : 0x007a1200 A5 : 0xffffffff
03:11:10.308 -> A6 : 0x000000ff A7 : 0x3fc95a50 A8 : 0x82002b39 A9 : 0x3fcec0f0
03:11:10.308 -> A10 : 0x00000000 A11 : 0x00000000 A12 : 0x3fc95a50 A13 : 0x00000000
03:11:10.308 -> A14 : 0x000000ff A15 : 0x3fc95a50 SAR : 0x00000020 EXCCAUSE: 0x0000001c
03:11:10.308 -> EXCVADDR: 0x0000001c LBEG : 0x42003d78 LEND : 0x42003d85 LCOUNT : 0x00000000
03:11:10.308 -> 03:11:10.308 -> 03:11:10.308 -> Backtrace: 0x42001d6b:0x3fcec110 0x42001b3d:0x3fcec140 0x42001c0a:0x3fcec160 0x42001a71:0x3fcec180 0x42004b6e:0x3fcec1c0 03:11:10.308 -> 03:11:10.308 -> 03:11:10.308 -> 03:11:10.308 -> 03:11:10.308 -> ELF file SHA256: 2f32fde9d2d7e1e8 03:11:10.308 -> 03:11:10.308 -> Rebooting...

RobTillaart commented 5 months ago

It looks like the same crash, so we must close in on the constructor. Time to think...

RobTillaart commented 5 months ago

Found this snippet about the ESP32-S3 in my MCP_DAC lib, which relates to the HSPI etc.

#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
#define FSPI  0
#define HSPI  1  
#else  
#define FSPI  1 //SPI bus attached to the flash (can use the same data lines but different SS)  
#define HSPI  2 //SPI bus normally mapped to pins 12 - 15, but can be matrixed to any pins  
#if CONFIG_IDF_TARGET_ESP32  
#define VSPI  3 //SPI bus normally attached to pins 5, 18, 19 and 23, but can be matrixed to any pins  
#endif  
#endif

Can you run this sketch?


//
//    FILE: ESP32_S3_SPI_test.ino
//  AUTHOR: Rob Tillaart
// PURPOSE: test
//     URL: https://github.com/RobTillaart/MCP23S17/issues/42

#include "SPI.h"

#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
#define FSPI  0
#define HSPI  1  
#else  
#define FSPI  1 //SPI bus attached to the flash (can use the same data lines but different SS)  
#define HSPI  2 //SPI bus normally mapped to pins 12 - 15, but can be matrixed to any pins  
#if CONFIG_IDF_TARGET_ESP32  
#define VSPI  3 //SPI bus normally attached to pins 5, 18, 19 and 23, but can be matrixed to any pins  
#endif  
#endif

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.println();
  delay(100);

  Serial.print("FSPI: \t");
  Serial.println(FSPI);
  Serial.print("HSPI: \t");
  Serial.println(HSPI);
  Serial.print("VSPI: \t");
  Serial.println(VSPI);
}

void loop()
{
}

//  -- END OF FILE --
Spaceballs3000 commented 5 months ago

VSPI doesn't work because CONFIG_IDF_TARGET_ESP32 isn't set. I commented the printf out, output is this.

12:50:04.511 -> C:\Users\\AppData\Local\Temp.arduinoIDE-unsaved202455-34568-10hqcqj.w4q3\sketch_jun5b\sketch_jun5b.ino 12:50:04.511 -> 12:50:04.604 -> FSPI: 0 12:50:04.604 -> HSPI: 1

RobTillaart commented 5 months ago

From: http://wiki.fluidnc.com/en/hardware/ESP32-S3_Pin_Reference

SPI The ESP32 S3 has four SPI interfaces which are:

The SPI2 (FSPI) default pins are:

SPI3 does not have default pin mappings because it can be mapped to any available gpio pins

Does it help if you

SPIClass * myspi = new SPIClass(SPI2);   //  or SPI3

MCP23S17 MCP(selectPin, myspi);           //  HW SPI address 0x00

----
 myspi->begin();  //  optional add pins to begin  (SCK, MISO, MOSI, SS)

Another line of thought is that the new SPIClass() call behaves not as expected (do not have an S3 to verify)

So a variation that does not use a pointer to the SPIClass object

SPIClass myspi = new SPIClass(HSPI);   //  or FSPI    
MCP23S17 MCP(selectPin, &myspi);           //  use the & address of myspi.

in setup() one line should change

 myspi.begin();  //  optional add pins to begin  (SCK, MISO, MOSI, SS)
Spaceballs3000 commented 5 months ago

Tried SPI2, but compile error error: 'SPI2' was not declared in this scope; did you mean 'SPI'? 18 | myspi = new SPIClass(SPI2);

Tried SPI3, but compile error error: 'SPI3' was not declared in this scope; did you mean 'SPI'?

Tried SPI, it compiles, but then crashes.

"So a variation that does not use a pointer to the SPIClass object" Compilation error: invalid user-defined conversion from 'SPIClass*' to 'const SPIClass&' [-fpermissive]

olkal commented 5 months ago

I don't think this is a library issue. There is no VSPI or HSPI on the S3, at least it's not mentioned in the data sheet. I have no issues running HW-SPI with the example sketches "as is" on my ESP-S3-WROOM. Just set the CS pin and leave out the spi pointer from the constructor like this: MCP23S17 MCP(10); and it should work. The SPI pin mapping may vary on different boards, if you're not sure you can run this code in setup() after SPI.begin():

  Serial.print("MOSI: ");
  Serial.println(MOSI);
  Serial.print("MISO: ");
  Serial.println(MISO);
  Serial.print("SCK: ");
  Serial.println(SCK);
Spaceballs3000 commented 5 months ago

Just using "MCP23S17 MCP(7);" does enable hardware SPI! checked with MCP.usesHWSPI() and oscilloscope. But then I can't remap these pins that I assigned on my PCB. MOSI=9; MISO=10; SCK=8;

RobTillaart commented 5 months ago

Just using "MCP23S17 MCP(7);" does enable hardware SPI! checked with MCP.usesHWSPI() and oscilloscope. But then I can't remap these pins that I assigned on my PCB. MOSI=9; MISO=10; SCK=8;

Those pins could be configurable with SPI.begin(), did you try?

SPI.begin(SCK, MISO, MOSI, 7);  

Optional leave out the last parameter (Select pin = 7) as that is already passed to the MCP object.

Spaceballs3000 commented 5 months ago

Tried this code, the IO expander doesn't respond, and SCK, MISO, MOSI still look wrong. Also tried SPI.begin(8,10,9);

#include "MCP23S17.h"
void setup() {
  delay(3100);
  Serial.begin(115200);
  Serial.println();
  Serial.print("MCP23S17_LIB_VERSION: ");
  Serial.println(MCP23S17_LIB_VERSION);
  delay(100);
  MCP23S17 MCP(7);
  MCP.setSPIspeed(1000000);

  SPI.begin(8,10,9,7); //MOSI=9; MISO=10; SCK=8; SS=7;

  Serial.print("getSPIspeed: ");
  Serial.println(MCP.getSPIspeed());  
  Serial.print("usesHWSPI: ");
  Serial.println(MCP.usesHWSPI());
  Serial.print("MOSI: ");
  Serial.println(MOSI);  
  Serial.print("MISO: ");
  Serial.println(MISO);
  Serial.print("SCK: ");
  Serial.println(SCK);
  while (1)
  {
    MCP.pinMode16(0);
    MCP.pinMode16(0xffff);
  }
}
void loop() {}

Outputs MCP23S17_LIB_VERSION: 0.5.2 getSPIspeed: 1000000 usesHWSPI: 1 MOSI: 11 MISO: 13 SCK: 12

RobTillaart commented 5 months ago
  Serial.print("MOSI: ");
  Serial.println(MOSI);  
  Serial.print("MISO: ");
  Serial.println(MISO);
  Serial.print("SCK: ");
  Serial.println(SCK);

These are hard coded constants in some header file, so they will always be the same,


the IO expander doesn't respond

The above code does only change the mode of the pins from input to output and back in a very tight loop. What response did you expect here?

try replace

  while (1)
  {
    MCP.pinMode16(0);
    MCP.pinMode16(0xffff);
  }

with

MCP.pinMode16(0);  //  set all pins output
  while (1)
  {
    MCP.write16(0xF00F); 
   delay(1000);
    MCP.write16(0x0FF0);
   delay(1000);
  }

If the MCP works it should show pulses on every line.

Spaceballs3000 commented 5 months ago

I edited the default board pinouts to match my PCB and it seems to be working now!

C:\Users\\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.0.0\variants\esp32s3\pins_arduino.h

It now prints out the correct MOSI/MISO/SCK/SS pins, and says usesHWSPI=1.

But I think I hit a new problem, the problem is that I have two IO expanders at address 0 and 1, but i can't talk to the IO expander at address 1, i.e. I can't set MCP23S17 MCP_B(11,10,9,8,1); and if I mix and match the two the CPU hangs.

Spaceballs3000 commented 5 months ago
  Serial.print("MOSI: ");
  Serial.println(MOSI);  
  Serial.print("MISO: ");
  Serial.println(MISO);
  Serial.print("SCK: ");
  Serial.println(SCK);

These are hard coded constants in some header file, so they will always be the same,

the IO expander doesn't respond

The above code does only change the mode of the pins from input to output and back in a very tight loop. What response did you expect here?

try replace

  while (1)
  {
    MCP.pinMode16(0);
    MCP.pinMode16(0xffff);
  }

with

MCP.pinMode16(0);  //  set all pins output
  while (1)
  {
    MCP.write16(0xF00F); 
   delay(1000);
    MCP.write16(0x0FF0);
   delay(1000);
  }

If the MCP works it should show pulses on every line.

Yeah I saw my mistake earlier and wasn't actually setting the output of the pins.

RobTillaart commented 5 months ago

@Spaceballs3000

But I think I hit a new problem, the problem is that I have two IO expanders with address 0 and 1.. but i can't talk to the IO expander at address 1, i.e. I can't set MCP23S17 MCP_B(11,10,9,8,1); and if I mix and match the two the CPU hangs.

If you have 2 MCP23S17's you must create two MCP23S17 objects, one for each expander. They may be connected on the same SPI bus and use the same SelectPin.

#include "MCP23S17.h"

void setup()
{
  delay(3100);
  Serial.begin(115200);
  Serial.println(MCP23S17_LIB_VERSION);

  delay(100);

  MCP23S17 MCP_A(7, 0);  //  set address 0 explicitly
  MCP23S17 MCP_B(7, 1);  //  set address 1 explicitly

  MCP_A.setSPIspeed(1000000);
  MCP_B.setSPIspeed(1000000);

  SPI.begin(8,10,9,7); //MOSI=9; MISO=10; SCK=8; SS=7;

  MCP_A.begin();
  MCP_B.begin();

  etc...
Spaceballs3000 commented 5 months ago

That did it! Adding MCP_A(11, 1) works.

Thank you for your patience in helping me!

Code below that works for me with two IO expanders.

#include "MCP23S17.h"
void setup() {
  delay(3100);
  Serial.begin(115200);
  Serial.println();
  Serial.print("MCP23S17_LIB_VERSION: ");
  Serial.println(MCP23S17_LIB_VERSION);  
  pinMode(12, OUTPUT); // RESET pin on IO-EXPANDER (set to output)
  digitalWrite(12,HIGH);  //Disable Reset on IO-EXPANDERs

  MCP23S17 MCP_A(7,0); //SS=7, Address = 0
  MCP23S17 MCP_B(11,1); //SS=11, Address = 1

  MCP_A.setSPIspeed(4000000);
  MCP_B.setSPIspeed(4000000);

  SPI.begin(8,10,9); //MOSI=9; MISO=10; SCK=8; SS=7;
  MCP_A.begin();
  MCP_B.begin();

  MCP_A.enableHardwareAddress();
  MCP_B.enableHardwareAddress();

  Serial.print("getSPIspeed: ");
  Serial.println(MCP_A.getSPIspeed());  
  Serial.print("usesHWSPI: ");
  Serial.println(MCP_A.usesHWSPI());

  //  test connection
  int c = testConnection(MCP_A);
  Serial.print("Connect A: ");
  Serial.println(c);
  c = testConnection(MCP_B);
  Serial.print("Connect B: ");
  Serial.println(c);

  MCP_A.pinMode16(0);
  MCP_B.pinMode16(0);
  while (1)
  {    
    MCP_A.write16(0x0000);
    MCP_B.write16(0x0000);
    delay(100);
    MCP_A.write16(0xffff);  
    MCP_B.write16(0xffff);   
    delay(100);
  }
}
void loop() {}

//
//  the connection test tries to write a magic number to a register
//  and read it back. If it is the same it is assumed to be connected
//
int testConnection(MCP23S17 & mcp)
{
  uint16_t magic_test_number = 0xABCD;

  //  Read the current polarity config to restore later
  uint16_t old_value;
  if (! mcp.getPolarity16(old_value)) return -1;

  //  Write the magic number to polarity register
  if (! mcp.setPolarity16(magic_test_number)) return -2;

  //  Read back the magic number from polarity register
  uint16_t temp;
  if (! mcp.getPolarity16(temp)) return -3;

  //  Write old config to polarity register
  if (! mcp.setPolarity16(old_value)) return -4;

  //  Check the magic connection test
  if (temp != magic_test_number) return -5;

  return 0;  //  OK
}

Output is

MCP23S17_LIB_VERSION: 0.5.2 getSPIspeed: 4000000 usesHWSPI: 1 Connect A: 0 Connect B: 0

RobTillaart commented 5 months ago

Good to hear your project works!

Today a new version 0.5.3 is released with ~30% faster 16 bit interface, might be interesting to verify.

RobTillaart commented 5 months ago

If no further questions remain, you may close the issue

Spaceballs3000 commented 5 months ago

Good to hear your project works!

Today a new version 0.5.3 is released with ~30% faster 16 bit interface, might be interesting to verify.

Before 0.5.2 just running this, would get me 60khz on the Select pin.

 MCP_A.setSPIspeed(4000000);
  while (1)
  {    
    MCP_A.write16(0x0000);
    MCP_A.write16(0xffff);  
  }

Running 0.5.3 I'm now getting 39.5khz on the Select pin, so slower.

Spaceballs3000 commented 5 months ago

Correction about it being slower, I didn't actually probe the IO Expander output itself, on 0.5.3 I get 19.77khz, on 0.5.2 I get 14.94khz! So looks like less traffic to the IO Expander, (I guessing less register chatter) and more setting pin outputs per sec!

Spaceballs3000 commented 5 months ago

Closing, as all my issue's were solved! Again thanks!

RobTillaart commented 5 months ago

Indeed the 16 bit interface only uses 4 bytes instead of 6 to read/ write two 8 bit registers. So communication time is ~30% down and thus The IO lines are ~30% faster.

Can you compare the SW SPI with the HW SPI for 0.5.3 in your setup?

Spaceballs3000 commented 5 months ago

Sure no problem! Running same program earlier but using SW SPI.

MCP23S17_LIB_VERSION: 0.5.2 getSPIspeed: 4000000 usesHWSPI: 0 4.8khz

MCP23S17_LIB_VERSION: 0.5.3 getSPIspeed: 4000000 usesHWSPI: 0 7.3khz

RobTillaart commented 5 months ago

Thanks for the quick test! so we know the optimization works for both HW and SW SPI.

Seeing your numbers, there is still a factor ~2.5 difference between the HW SPI and SW SPI.

FYI, I am working on an AVR optimization of SW SPI - same I used in https://github.com/RobTillaart/FastShiftOut - which would improve the SW SPI for AVR (UNO and MEGA) about a factor 2 (result of first tests). Note that on AVR the "portable" SW SPI is very slow, and even after optimization it is not as fast as HW SPI. When AVR works I might have a look into the optimization of SW SPI for ESP32.