Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 11 of 11

Thread: Testing T4 and MCP23S17

  1. #1

    Testing T4 and MCP23S17

    I am testing an MCP23S17 with one rotary encoder for a bigger project. My intention is to Serial.print the inputs of the rotary encoder as a first step of testing. Unfortunately I get nothing, and therefore I'd be grateful for feedback where I'm going wrong, in particular the configuration of the MCP... Thanks in advance!

    The wiring looks like this:
    Click image for larger version. 

Name:	Kopplingsschema.jpg 
Views:	15 
Size:	28.3 KB 
ID:	28907

    Code:
    #include <Arduino.h>
    #include <SPI.h>
    
    // MCP23S17 registers
    constexpr uint8_t IODIRA = 0x00;    // IO direction  (0 = output, 1 = input (Default))
    constexpr uint8_t IPOLA = 0x02;     // IO polarity   (0 = normal, 1 = inverse)
    constexpr uint8_t GPINTENA = 0x04;  // Interrupt on change (0 = disable, 1 = enable)
    constexpr uint8_t DEFVALA = 0x06;   // Default comparison for interrupt on change (interrupts on opposite)
    constexpr uint8_t INTCONA = 0x08;   // Interrupt control (0 = interrupt on change from previous, 1 = interrupt on change from DEFVAL)
    constexpr uint8_t IOCON = 0x0A;     // IO Configuration: bank/mirror/seqop/disslw/haen/odr/intpol/notimp
    constexpr uint8_t GPPUA = 0x0C;     // Pull-up resistor (0 = disabled, 1 = enabled)
    constexpr uint8_t INFTFA = 0x0E;    // Interrupt flag (read only) : (0 = no interrupt, 1 = pin caused interrupt)
    constexpr uint8_t INTCAPA = 0x10;   // Interrupt capture (read only) : value of GPIO at time of last interrupt
    constexpr uint8_t GPIOA = 0x12;     // Port value. Write to change, read to obtain value
    constexpr uint8_t OLLATA = 0x14;    // Output latch. Write to latch output.
    
    constexpr uint8_t csPin = 10;
    constexpr uint8_t ports = 0x20;
    constexpr uint8_t interruptPin = 20;
    volatile bool interrupted = false;
    
    // ISR functions
    void handleInterrupt() {
        interrupted = true;
    }
    
    // Write to expander
    void expanderWrite(const uint8_t port, const uint8_t reg, const uint8_t data) {
        digitalWrite(csPin, LOW);
        SPI.transfer(port << 1);  // Write mode
        SPI.transfer(reg);
        SPI.transfer(data);
        digitalWrite(csPin, HIGH);
    }
    
    // Read from expander
    uint8_t expanderRead(const uint8_t port, const uint8_t reg) {
        uint8_t data = 0;
    
        digitalWrite(csPin, LOW);
        SPI.transfer((port << 1) | 1);  // Read mode
        SPI.transfer(reg);
        data = SPI.transfer(0);
        digitalWrite(csPin, HIGH);
    
        return data;
    }
    
    void setup() {
        Serial.begin(115200);
        SPI.begin();
    
        pinMode(csPin, OUTPUT);
        digitalWrite(csPin, HIGH);
    
        pinMode(interruptPin, INPUT_PULLUP);
        attachInterrupt(digitalPinToInterrupt(interruptPin), handleInterrupt, FALLING);
    
        // Config MCP:
        //  Banks segregated = 1
        //  mirror interrupts = 1
        //  disable sequential mode = 1
        //  slew rate disabled = 0
        //  no hardware adressing = 0
        //  no interrupt pin open drain = 0
        //  interrupt active high = 1
        //  not used = 0
    
        expanderWrite(ports, IOCON, 0b11100010);
    
        // Set PORT A registers
        expanderWrite(ports, IODIRA, 0b11111111);    // IO direction, 1 = input
        expanderWrite(ports, GPPUA, 0b11111111);     // Pull-up resistor, 1 = enabled
        expanderWrite(ports, IPOLA, 0b11111111);     // IO polarity, 1 = inverse
        expanderWrite(ports, GPINTENA, 0b11111111);  // Interrupt on change, 1 = enable
        expanderWrite(ports, INTCONA, 0b11111111);   // Interrupt control, 1 = interrupt on change compared with DEFVAL bits
        expanderWrite(ports, DEFVALA, 0b11111111);   // Interrupt comparison value 1 = interrupt on != 1
    }
    
    void loop() {
        if (interrupted == true) {
            interrupted = false;
            uint8_t portA = expanderRead(ports, GPIOA);
    
            for (uint8_t bit = 0; bit < 8; ++bit) {
                Serial.print(String(bitRead(portA, bit)));
            }
    
            Serial.println();
        }
    }

  2. #2
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    16,527
    See this thread - it uses a contributed library - and may have some info

    pjrc.com/threads/59937-New-MCP23S17-Library

  3. #3
    Thanks for your reply!

    I've looked at several mcp libraries, and I don't doubt their usefulness. However, I'd still need to know how to configure the mcp23s17 - provided that my wiring is correct - so even though I use a library codewise it leads me back to my original question regarding configuration for my particular wiring.

    Also, there may be errors in my circuit I'm still unaware of that could render any/all code useless.

  4. #4
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,108
    I don't see any SPI.beginTransaction() in your program to configure the SPI settings.

    Even if you intend to write all code from scratch, why not at least give a known-good library a run to check whether your hardware is connected properly?

  5. #5
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    16,527
    Looking at : github.com/tonton81/MCP23S17/blob/master/mcp23s17.tpp#L49 this shows:
    Code:
    MCP23S17_FUNC void MCP23S17_OPT::initDefaults() {
      for ( uint8_t addr = 0; addr < 8; addr++ ) {
        bus->beginTransaction(SPISettings(speed,MSBFIRST,SPI_MODE0));
    @tonton81 writes awesome code for a variety of things. As noted, it might be good to follow to test function if not use as a likely well written and tested library solution.

  6. #6
    Quote Originally Posted by PaulStoffregen View Post
    I don't see any SPI.beginTransaction() in your program to configure the SPI settings.
    Thanks for your feedback. I edited the code, but unfortunately no results:

    Code:
    SPISettings MCP(20000000, MSBFIRST, SPI_MODE0);
    
    // Write to expander
    void expanderWrite(const uint8_t port, const uint8_t reg, const uint8_t data) {
        SPI.beginTransaction(MCP);
        digitalWrite(csPin, LOW);
    
        SPI.transfer(port << 1);  // Write mode
        SPI.transfer(reg);
        SPI.transfer(data);
    
        digitalWrite(csPin, HIGH);
        SPI.endTransaction();
    }
    
    // Read from expander
    uint8_t expanderRead(const uint8_t port, const uint8_t reg) {
        uint8_t data = 0;
    
        SPI.beginTransaction(MCP);
        digitalWrite(csPin, LOW);
    
        SPI.transfer((port << 1) | 1);  // Read mode
        SPI.transfer(reg);
        data = SPI.transfer(0);
    
        digitalWrite(csPin, HIGH);
        SPI.endTransaction();
    
        return data;
    }
    (On a side note, if you don't define the SPISettings object, does the SPI class have default settings? If so, what are the default values?)

    Quote Originally Posted by PaulStoffregen View Post
    Even if you intend to write all code from scratch, why not at least give a known-good library a run to check whether your hardware is connected properly?
    I have tried alternatives to this code, for instance the adafruit MCP23xxx library. Regardless of using a well established library or using the code above, my conundrum is that i need guidance to configure the expanders IOCON and PORTA/B registries in either case. I understand that a library shows how to configure the hardware, my question regards what settings I need to make for my particular setup. And since there's a risk that my wiring isn't properly setup I wind up in a catch 22 situation. Currently there are too many combinations of variables for me to trial and error my way to a solution. This is why I ask about both code and wiring.

  7. #7
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    966
    Not for T4, but T3.5 - for an example of setting the pins on the 23s17 to input or output, here is an example of code using SUMOTOY's library, which is as simple as GPIOset input or output. https://github.com/mortonkopf/Teensy...b/main/chips.h

    the project that uses it is here: https://forum.pjrc.com/threads/64850...ght=mortonkopf

    SUMOTOY library is here: https://github.com/sumotoy/gpio_expander
    Last edited by mortonkopf; 07-13-2022 at 01:51 PM.

  8. #8
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    966

    schematic used


  9. #9
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    966
    Register settings here:

    Click image for larger version. 

Name:	MCP23S17-register-setup.png 
Views:	17 
Size:	91.1 KB 
ID:	28920

    https://orchardelica.com/wp/?p=695

  10. #10
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    966
    Another point regarding your schematic, I believe that the Reset pin should be tied to VDD, and not floating. this is how I run mine. The datasheet has "The on-chip POR circuit holds the device in reset until VDD has reached a high enough voltage to deactivate the POR circuit (i.e., release the device from reset)."
    https://ww1.microchip.com/downloads/.../20001952c.pdf

  11. #11
    Quote Originally Posted by mortonkopf View Post
    Another point regarding your schematic, I believe that the Reset pin should be tied to VDD, and not floating. this is how I run mine. The datasheet has "The on-chip POR circuit holds the device in reset until VDD has reached a high enough voltage to deactivate the POR circuit (i.e., release the device from reset)."
    https://ww1.microchip.com/downloads/.../20001952c.pdf
    You're absolutely right, good call! And thanks for your guidance for the settings, I'll look into it today!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •