24 IN / 48 OUT card for JMRI

nopxor Apr 16, 2018

  1. Ash

    Ash TrainBoard Member

    106
    67
    8
    Maybe... It depends on the source of the VCC supplied for the MCP23017. I was not comfortable using the +5v output of the Arduino and I noticed that LED signals and other accessories often use 12 volts.

    If you don't need 12 volts, then you can use a +5 volt source. The Darlington transistor array is switching to GND, so you don't need the +12v or +5v on the board, as long as you have the GND from that power source connected to the board. (see attached pdf - a few notes and diagrams)

    I did not research the power handling capacity of the MCP23017. I had found some diagrams that showed how to use a transistor to switch a LED. Then I found the transistor array which switches up to 500mA per output.

    One of my outstanding questions: Do I need to use the ULN2803 Darlington transistor array with MCP23017 for controlling signals and other LEDs, or will MCP23017 drive the signals/LEDs directly?

    I had stopped looking for an answer. The boards take some time to assemble, but the standardization on my layout makes adding another accessory quite simple. No Arduino code updates -- I connect the wires and then do all the setup/logic in JMRI.

    With your question, I see an answer:
    "You can connect a 3mm led or SMD directly to the ports of the MCP23017 using a 470 Ohm resistor to limit the current to +/- 10mA per port, higher currents can damage the MCP23017."​
    https://translate.google.com/transl...8/conexao-e-configuracao-da-interface-48.html

    On that same page, note the warning:
    IMPORTANT CAUTIONS BEFORE CONNECTING THE INTERFACE THROUGH THE ARDUINO USB PORT: If you have servos and signaling connected to the Interface, it is necessary to use the external 5V power supply. Servos and signaling can consume more current than the USB port on the Arduino Nano is capable of providing what can cause it to burn . Therefore, if programming via USB, connect the Interface to the 5V source or disconnect all servos and signals from the Interface.

    Here is another MCP23017 board (from DFRobot). Their product wiki has several examples, including LEDs. My guess is you may have hit on a simpler solution for LEDs. I look forward to your findings; I expect to start working on my fascia control panels before long.
    https://www.dfrobot.com/product-2002.html
    [​IMG]

    And the product wiki:
    https://wiki.dfrobot.com/Gravity: MCP23017 IIC to 16 Digital IO Expansion Module SKU: DFR0626
     

    Attached Files:

  2. Erik84750

    Erik84750 TrainBoard Member

    343
    136
    12
    Hi Ash,
    would it be possible to post the schematics please?
    Thanks,
    kind regards,
    Erik
     
  3. Erik84750

    Erik84750 TrainBoard Member

    343
    136
    12
    Continuing on post #29 I now have a sample set up of the complete board: motherboard loaded wit 1x PCA9685 and 1x MCP23017.
    The MCP23017 top connectors (left) connect to the 24in/48out board, post # 24.
    The PCA9685 top connectors (right) connect to the servo's.


    Program (still in develoment phase, is compiling correctly, and should work almost flawlessly):
    Beware: Adafruit MCP23017 library needs to be of the 1.x.x version.

    Code:
    [code]
    // door Stijn Rogiest
    
    #include <Adafruit_MCP23017.h>
    #include <Adafruit_PWMServoDriver.h>
    
    // Het aantal outputs wordt bepaald door MODULE_PAIR_COUNT * PIN_COUNT_PER_MODULE,
    //  want er zijn PIN_COUNT_PER_MODULE outputs per MCP23017/PCA9685 paar
    // Hoeveel MCP23017/PCA9685 paren er worden gebruikt
    #define MODULE_PAIR_COUNT 1
    // Het aantal pinnen per module dat gebruikt zal worden, max 16
    #define PIN_COUNT_PER_MODULE 16
    
    #define DRIVER_OSSC_FREQ 27000000
    #define DRIVER_PWM_FREQ 60
    
    #define STATE_NO_POLLING_DATA 0
    #define STATE_POLLING_LOW 1
    #define STATE_POLLING_HIGH 2
    #define servoMin 250
    #define servoMax 500
    // De pin van de eerste status led
    #define STATUS_LED_PIN_START 3
    // Het aantal milliseconden voordat de led weer uit gaat
    #define STATUS_LED_ON_TIME 1000
    
    uint8_t prevStates[MODULE_PAIR_COUNT][PIN_COUNT_PER_MODULE] = {STATE_NO_POLLING_DATA};
    Adafruit_MCP23017 *mcps[MODULE_PAIR_COUNT];
    Adafruit_PWMServoDriver *drivers[MODULE_PAIR_COUNT];
    
    unsigned long lastStatusLedSetTimes[MODULE_PAIR_COUNT] = {0};
    
    void setup()
    {
        for (uint8_t i = 0; i < MODULE_PAIR_COUNT; i++)
        {
            mcps[i] = new Adafruit_MCP23017();
            mcps[i]->begin(i); // De i2c adressen van de MCP23017 modules starten vanaf 0
            drivers[i] = new Adafruit_PWMServoDriver();
            drivers[i]->begin(24 + i); // De i2c adressen van de PCA9685 modules starten vanaf 24
            drivers[i]->setOscillatorFrequency(DRIVER_OSSC_FREQ);
            drivers[i]->setPWMFreq(DRIVER_PWM_FREQ);
        //  drivers[i]->setPWM(
    
            pinMode(i + STATUS_LED_PIN_START, OUTPUT);
        }
    }
    
    void loop()
    {
        for (uint8_t i = 0; i < MODULE_PAIR_COUNT; i++)
        {
            if (lastStatusLedSetTimes[i] != 0 && (lastStatusLedSetTimes[i] + STATUS_LED_ON_TIME) < millis())
            {
                digitalWrite(i + STATUS_LED_PIN_START, false);
                lastStatusLedSetTimes[i] = 0;
            }
    
            for (uint8_t p = 0; p < PIN_COUNT_PER_MODULE; p++)
            {
                // value: de digitale waarde van de p-de pin van de i-de MCP23017 module
                bool value = mcps[i]->digitalRead(p);
                // state: de state van de pin p
                uint8_t state = state ? STATE_POLLING_HIGH : STATE_POLLING_LOW;
                // prevState: de vorige state van de pin p, als prevState == STATE_NOTHING, dan is er geen vorige pin geweest
                uint8_t prevState = prevStates[i][p];
    
                if (prevState == STATE_NO_POLLING_DATA)
                {
                    prevStates[i][p] = state;
                    continue;
                }
    
                prevStates[i][p] = STATE_NO_POLLING_DATA;
    
                if (prevState != state)
                {
                    // De state was niet 2 keer hetzelfde, deze data is dirty, dus continue...
                    continue;
                }
    
                digitalWrite(i + STATUS_LED_PIN_START, true);
                lastStatusLedSetTimes[i] = millis();
    
                // Implementeer hier eigen logica...
                uint16_t pwm = value ? 0 : 4095;
    
                // Stel de pwm waarde in voor de p-de pin van de i-de PCA9685 module
                // pwn: de pwm waarde om naar de (i * MODULE_PAIR_COUNT + p) -de output te schrijven, 0 = helemaal uit, 4095 = helemaal aan
                drivers[i]->setPin(p, pwm);
            }
        }
    
        delay(500); // Het is misschien geen slecht idee om hier en daar een delay toe te voegen om de i2c bus niet te overbelasten
    }
    
    [/CODE]

    IMG_20220112_150923.jpg
     
    Last edited: Jan 12, 2022
    BigJake likes this.
  4. Erik84750

    Erik84750 TrainBoard Member

    343
    136
    12
    Hi Ash,

    I get a compile error with your code: "call of overloaded "begin(int) is ambiguous".

    Are you using version 1.x.x of the MCP library (which I am using)?

    What could be a solution for this error?

    Thanks and greetings!
    Erik
     
  5. Ash

    Ash TrainBoard Member

    106
    67
    8
    I used Arduino IDE 1.8.16
    version 1.3.0 Adafruit_MCP23017

    Check to see if the board numbers to match your setup?
    Perhaps:
    // Define MCP23017 modules
    mcp0.begin(0); // JMRI sensors _001-_016
    mcp1.begin(1); // JMRI turnouts or lights _017-_032
    mcp2.begin(2); // JMRI turnouts or lights _033-_048

    The PCA9685 board has turnouts _001-_016

    The numbering is unique. The input (sensors) board is mcp0; outputs are mcp1 and mcp2.
    I don't always have a board installed for mcp2, but I can connect one and it will be ready for use within JMRI (without updating the sketch).

    The JMRI numbering can be confusing, as the first 16 JMRI outputs are used for the PCA9685 board.

    I copied the code I posted on trainboard (#34). Selected board Nano. Compiled without issue.
    I did not attempt to run the code from the translated website.

    Note that my diagram which shows how to set the jumpers agrees with the updated define in this post --
    mcp0 should generally be
    mcp0.begin(0);
    But I had multiple boards; one had jumpers to update the address...
     
    Erik84750 likes this.
  6. Erik84750

    Erik84750 TrainBoard Member

    343
    136
    12
    Hi Ash, thank you very much for your prompt reply.
    MCP23017 library here also 1.3.0.
    Nano or Pro Mini are the same processor, so no issue there.
    I don't doubt you got it compiled, I am sure it must be something on my system.
    I will look into it the coming days and will let you know the results.
    Best of greetings,
    Erik
     
  7. Erik84750

    Erik84750 TrainBoard Member

    343
    136
    12
    Solved:
    Code:
    // Initialize I2C MCP23017
    
    Adafruit_MCP23017 mcp0;
    Adafruit_MCP23017 mcp1;
    Adafruit_MCP23017 mcp2;
    int addr1 = 0x00;
    int addr2 = 0x01;
    int addr3 = 0x02;
    
    void setup() {
      Serial.begin(9600);
      bus.begin(9600, SERIAL_8N2);
      pwm1.begin();
      // pwm2.begin();
      pwm1.setPWMFreq(60);
      // pwm2.setPWMFreq(60);
    
      // Define MCP23017 modules
      mcp0.begin(addr1);
      mcp1.begin(addr2);
      mcp2.begin(addr3);
    
       
      InitializePortsMCP23017();
      Serial.println("setup1 complete");
    }
    
    But why your code would compile with you and not with me is a mistery to me.
     
  8. Erik84750

    Erik84750 TrainBoard Member

    343
    136
    12
    I made an update on the 24 IN / 48 OUT board (originally bu nopxor, post #1 in this thread).

    1. I returned to the screw connectors originally used by nopxor. My previous design used pinheaders to save space and allow 2 PCB's out of the fab 100x100mm size. Draw-back is that these do not provide secure fitting. In this PCB version 6 I use however 0.1" connectors (not the 0.2" by nopxor), for space-savings.

    2. I added open drain mosfet output drivers. These mosfets are capable to switch 20A loads due to their incredible low on-resistance. However for obvious reasons (track width) only 2A is allowed. This however makes it possible to switch relays and other haevy loads directly from this board.

    The Arduno program (by nopxor) still is the same.

    The .brd file needs cleaning up of the top and bottom silkscreens. The coming days I will finalise this and upload the cleaned finished .brd file.
     

    Attached Files:

Share This Page