0

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);
}
  • I take it since you're wanting my response it's my library you are using? – Majenko Jul 28 '17 at 20:05
  • Do you have anything connected to pin D10? If so, what, and what mode are you using the pin in? – Majenko Jul 28 '17 at 20:17
  • @Majenko yes your library. pin D10 is connected to the CS of the display. And according to the display library it is used in output mode. – Ariser Jul 28 '17 at 20:48
  • It sounds like some form of conflict, certainly. If _spi->transfer() is hanging then it's most likely that the SPI transaction is never completing, which is something in the SPI library. It may be that your display library is doing things that affect the SPI library in some way. – Majenko Jul 28 '17 at 22:36
  • I would suggest starting with working expander code, then add each extra item until it fails. Then remove everything except the expander and whatever was last added and see if it still fails. If it does then post that code so we can find the conflict. – Majenko Jul 29 '17 at 7:57
1

So here is what I found five minutes ago.

I forgot to call MCP23S17::begin()

Simple that is.

Before that, I tried to rule out a whole lot of other things. It never came to my mind, that I could have missed such a vital initalisation.

What did I do to get to this point?

  • removed every other library using SPI
  • removed every code using I2C
  • removed every code using 1wire
  • removed every code using Interrupts
  • threw away 9 out of 10 files
  • removed 9 out of 10 calls for functions which seemed irrelevant for this problem.

None of these measures did anything to solve the problem. Only when I had my code reduced to the minimum, so I could dare to post it here, the single line caught my attention. So this Q&A is not really a technical or coding riddle but more a didactic play on how one can fool himself and what to do to locate errors.

But in the end I only found the culprit by strictly following Majenko's advice to remove everything until the code started to work again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.