I have a rather voluminous sketch with a heap of source and header files.
Now I'm facing the problem, that controlling the MCP23S17 on my board fails in different ways within this sketch. This is rather awkward, because when I modify the sample sketch taken from this library to my needs, the port expander can be accessed and controlled without any problem.
what happens within my own sketch? If I initialise SPI myself before using any of the library methods, everything of my sketch and hardware but the port expander works flawlessly. I.e. all hardware does what it is intended to, only the pins of the port expander do nothing.
If I remove all SPI commands I inserted there to initialise SPI according to my needs, the code will fail during the first call to MCP23S17::pinMode(…). Fail means: The CPU crashes. It hangs inside this routine and keepalive-LED stops blinking, serial output is severed. As I don't have any means of debugging besides Serial.print(), I narrowed it down to the call of
_spi->transfer(cmd);
within
void MCP23S17::writeRegister(uint8_t addr)
So something from my other code must interfer with this call, somehow, so the CPU comes to a halt. What the heck do I have to look for?
Additional information:
- Portexpander chip select is tied to Pin 7 of Arduino Uno.
- Portexpander address i 0
- Other device connected to SPI: display
- Other notable devices: RTC (on I2C), lot of 1-wire devices.
Addendum following Majenko's suggestions, I reduced my code to reach functionality in this issue. I did not succeed. So I decided to post two antagonistic sketches, one crashing and one working. Spoiler: I found my coding flaw myself five minutes ago, I'm going to post it as answer later, but decided to go on writing this addendum as I had intended
Here comes the .ino-file of the failed sketch:
#include <SPI.h>
#include <MCP23S17.h>
#include "spin.h"
void setup() {
Serial.begin(9600);
Actors::setup();
Serial.println("setup finished");
}
void loop() {
Actors::service();
}
part of this are two further files, from which I removed everything possible: spin.h:
#ifndef _INC_SPIN
#define _INC_SPIN
#include <MCP23S17.h>
class Actors
{
private:
static const uint8_t PexSSPin;
protected:
static MCP23S17 portExp;
public:
static void setup();
static void service();
};
#endif
and spin.cpp:
#include "spin.h"
const uint8_t Actors::PexSSPin=7;
MCP23S17 Actors::portExp(&SPI, Actors::PexSSPin, 0);
void Actors::setup()
{
Serial.print(F("Ac:se#"));
Serial.print(".");
portExp.pinMode(2, INPUT); // not used. INPUT mode prevents damage due to accidental shorting
Serial.print(".");
portExp.pinMode(3, INPUT); // not used. INPUT mode prevents damago due to accidental shorting
Serial.print(".");
Serial.print(F("Ac:se!"));
}
void Actors::service()
{
Serial.print(F("Ac:sv#"));
Serial.print(F("Ac:sv!"));
}
As noted in my first part of the question this code comes to a halt during the first call to the pinMode() method of the portexpander. There's no serial output after the first pinMode call and the actors weren't working either (when there was useful code left).
On the contrary here comes a working sketch with the same library controlling the same port expander on the same hardware.
#include <MCP23S17.h>
#include <Arduino.h>
#ifdef __PIC32MX__
// chipKIT uses the DSPI library instead of the SPI library as it's better
#include <DSPI.h>
DSPI0 SPI;
#else
// Everytying else uses the SPI library
#include <SPI.h>
#endif
const uint8_t chipSelect = 7;
MCP23S17 Bank1(&SPI, chipSelect, 0);
uint16_t data;
void setup() {
Serial.begin(9600);
Bank1.begin();
Bank1.pinMode(8, OUTPUT);
Bank1.pinMode(9, OUTPUT);
Bank1.pinMode(10, OUTPUT);
Bank1.pinMode(11, OUTPUT);
Bank1.pinMode(12, OUTPUT);
Bank1.pinMode(13, OUTPUT);
Bank1.pinMode(14, OUTPUT);
Bank1.pinMode(15, OUTPUT);
// Bank2.pinMode(15, INPUT_PULLUP);
}
void loop() {
if (data==0)
{
data = 0xffff;
}
else
{
data = 0x0000;
}
Bank1.writePort(data);
delay(2000);
Serial.println(data);
}