Go Down

Topic: Weird issue with MUX Shield II and 20 LEDs project (Read 2798 times) previous topic - next topic

_Roms_

Hi all,

My 1st post here. I'm running into this crazy weird issue - any help would be appreciated!!! :)

My Project
I'm building this 20-LEDs project, I wrote a small software for editing the LED patterns and animation. The frames are uploaded to the EEPROM with a 1st sketch and then read by a 2nd sketch that turns on each LED and controls the timing, loops, etc.

The Issue
Here's my problem: each individual LED turns on/off nicely (see video below) but when 2 or more LEDs are lit, I get some weird patterns.

This simple video summarizes it well: https://www.youtube.com/watch?v=XLDbFfPZhLc

The simplest case is when I turn LEDs 1+2+3 at once, I get 1+3. When I turn 6+7+8 I get 3+8... This is driving me nuts!

What Could Be Wrong?!
1. Software?
I checked the code and I'm 99% confident it is not the problem (I output the DigitalWrite calls and I get the expected result). Is it possible the chip gets desynchronized and executes instructions in the wrong order?

2. Hardware?
I initially suspected I created a soldering bridge in the MUX but I checked carefully and is doesn't seem to be the case. My only hypethesis at this stage is that the MUX is somehow not working as it should.

Or maybe the MUX doesn't support multiple simultaneout output signals? the documentation (Mux_Shield_II_User_Guide) says it does.

3. Next Steps?
I'm thinking I should try to remove the MUX and see if I can get LEDs 1+2+3 using the Arduino directly. This would tell me if the MUX is the problem...


Specs
Here're the specs:
- Arduino UNO R3
- MUX Shield II with first 2 rows attached to individual LEDs
- The code looks like this (this is a small snippets, as I'm pretty sure it's a hardware issue)

Code (extract)
Code: [Select]

// example of EEPROM value, starting at 32:
//  0x4,  0x0,  0xe8,  0x3,  0x1,  0x0,  0x0,  0x1c,  0x0,  0x0,  0x3,  0x80,  0x0,  0x0,  0xe,  0x0,  0x0,  0x0,  0xe,  0x0,  0x0

#include <MuxShield.h>
#include <EEPROM.h>
# define EEPROM_START 32   // start address of structure in EEPROM

//Initialize the Mux Shield
MuxShield muxShield;

static byte bit_io_mapping[20][2] = {\
  {1, 0}, // left, tile 00 -> IO1 PIN0
  {1, 1}, // left, tile 01 -> IO1 PIN1
  {1, 2}, // left, tile 02 -> IO1 PIN2
  {1, 3}, // left, tile 03 -> IO1 PIN3
  {1, 4}, // left, tile 04 -> IO1 PIN4
  {1, 5}, // left, tile 05 -> IO1 PIN5
  {1, 6}, // left, tile 06 -> IO1 PIN6
  {1, 7}, // left, tile 07 -> IO1 PIN7
  {2, 0}, // left, tile 08 -> IO2 PIN0
  {2, 1}, // left, tile 09 -> IO2 PIN1
  {1, 10}, // right, tile 00 -> IO1 PIN10
  {2, 3}, // right, tile 01 -> IO1 PIN11
  {1, 12}, // right, tile 02 -> IO1 PIN12
  {1, 13}, // right, tile 03 -> IO1 PIN13
  {1, 14}, // right, tile 04 -> IO1 PIN14
  {1, 15}, // right, tile 05 -> IO1 PIN15
  {1, 11}, // right, tile 06 -> IO2 PIN3
  {2, 2}, // right, tile 07 -> IO2 PIN2
  {1, 8}, // right, tile 08 -> IO1 PIN8
  {1, 9}}; // right, tile 09 -> IO1 PIN9


// set the state of the relays
void set_relays(unsigned long relay_state)
{
  // Turn off all relay gates by toggling all IO 1 and 2 outputs
 
  for (int j = 1 ; j < 4 ; j++)
    for (int i = 0 ; i < 16 ; i++)
      muxShield.digitalWriteMS(j, i, HIGH);       
   
  // read the 20 first bits and active the correct LED 
  bool is_active = false;
  for (int i = 0 ; i < 20; i++)
  {   
    is_active = bitRead(relay_state, i);
    if (is_active)
    {
      muxShield.digitalWriteMS(bit_io_mapping[i][0], bit_io_mapping[i][1], is_active ? LOW : HIGH);
      Serial.println(" led #" + String(i) + " IO" + String(bit_io_mapping[i][0]) + "PORT" + String(bit_io_mapping[i][1]));
    }   
  }
}

// load an animation stored in the Arduino's EEPROM
bool run_animation(unsigned int &eeprom_address)
{
  unsigned int nb_frames = 0;
  unsigned int speed = 0;
  unsigned long frame = 0;
  unsigned long f[4];
  byte nb_loops = 0; 
 
  Serial.println("loading animation from EEPROM " + String(eeprom_address));
 
  // nb frames (2 bytes = Arduino's unsigned int)   
  byte b1 = EEPROM.read(eeprom_address++); // Reads a byte from the EEPROM
  byte b2 = EEPROM.read(eeprom_address++);
  nb_frames = (b2 << 8) | b1; 
  Serial.println("  nb_frames = " + String(nb_frames));
 
  // speed (2 bytes = Arduino's unsigned int)
  b1 = EEPROM.read(eeprom_address++); // Reads a byte from the EEPROM
  b2 = EEPROM.read(eeprom_address++);
  speed = (b2 << 8) | b1;
  Serial.println("  speed = " + String(speed));
 
  // nb loops (1 byte = BYTE)
  nb_loops = EEPROM.read(eeprom_address++);
  Serial.println("  nb_loops = " + String(nb_loops));
  unsigned int start_address = eeprom_address;
  for (int loop_idx = 0 ; loop_idx < nb_loops ; loop_idx++)
  {
    eeprom_address = start_address; // reset the read address for the next loop
    // animation frame #
    for (int frame_idx = 0 ; frame_idx < nb_frames ; frame_idx++)
    {   
      // tiles (20 bits encoded on 4 bytes)
      for (int i = 0 ; i<4 ; i++)
        f[i] = EEPROM.read(eeprom_address++);
             
      frame = (unsigned long)((f[0] << 24) | (f[1] << 16) | (f[2] << 8) | f[3]);
      set_relays(frame);     
      delay(speed);     
    }   
  } 
}

void setup()
{
  Serial.begin(9600);
 
  // Set I/O 1, I/O 2, and I/O 3 as digital outputs
  muxShield.setMode(1, DIGITAL_OUT); 
  muxShield.setMode(2, DIGITAL_OUT);
  muxShield.setMode(3, DIGITAL_OUT);
   
  // Turn off all relay gates by toggling all IO 1 and 2 outputs
  for (int j = 1 ; j < 4 ; j++)
    for (int i=0 ; i<16 ; i++)
      muxShield.digitalWriteMS(j, i, HIGH);
}

void loop()
{
  unsigned int eeprom_address = EEPROM_START;
  run_animation(eeprom_address);
}


Here're some pictures of the setup (my friends are laughing at it but I built it to be robust and flexible)

Any help would be welcome! I'm getting a bit desperate now! :)
Thanks
-Romain

_Roms_

Update - I removed the MUX and connected 5 LEDs directly to the arduino's pins 6, 7, 8, 9 and 10.
Using the same code, it works perfectly well.

Now I know it is the MUX, but why????

Paul__B







Well, it looks nice, this is all very well and good asking questions like this, but the first absolutely essential thing I have to ask is - what is the circuit schematic of this so-called "MUX Shield II" because I for one have never heard of it.

That may be just me, but I don't know how many others here know of it either, which would likely be the reason why you are not getting a deluge of answers. :smiley-lol:

_Roms_

Hi Paul, guys,

Sorry, I thought this was a super standard shield card. Here's some more information. Also, now finally... I know for sure the problem is the MUX.

Mayhew Lab's MUX Shield II


Attached is the PDF file with schematics.

Hardware Description
Hardware Description
The Mux Shield is an input and output (I/O) expander for Arduino platforms. It contains 48 connections for increasing the number of analog inputs, digital inputs, and digital outputs. These 48 connections are split up into three 16-pin rows: I/O1, I/O2, and I/O3. Each of these rows may be independently set as analog inputs, digital inputs, or digital outputs in firmware or by using solder jumpers. That means you could have 16 analog inputs, 16 digital inputs, and 16 digital outputs simultaneously, or 32 digital outputs and 16 analog inputs simultaneously, or 48 digital outputs simultaneously, etc. Each 16-pin row cannot have split functionality - i.e. having 3 analog inputs and 13 digital outputs on row I/O1 is not possible. The Mux Shield uses Arduino digital pins 2, 4, 6, 7, analog input pins A0, A1, A2, and optionally uses digital pins 8, 10, 11, 12.

The Mux Shield uses TI 74HC4067 analog multiplexers (mux's) for input functionality and TI 74HC595 shift registers for output functionality. Control lines are used in different ways depending on whether the I/O row is to be an input or an output. If the I/O row is set as an input, the control lines are used as address lines to the mux's. If the row is an output, the control lines are used as clock and latch lines to the shift registers. See the Pin Descriptions section for more details on how these lines are used.

It's about $25 on Amazon.com

_Roms_

I just realized... could it be because I'm not using the 5V / GRND pins located on the upper-right side of the picture???

Right now, I'm using the following wiring scheme on the MUX:


Paul__B

OK, two questions spring to mind.

What are you using to power it at 5 V?  It appears you have the same power supply powering the light array itself, the relay board, and the UNO as all 5 V lines are connected together.

I removed the MUX and connected 5 LEDs directly to the Arduino's pins 6, 7, 8, 9 and 10.
Using the same code, it works perfectly well.
I cannot see how the same code can simply control LEDs on the outputs, or control the multiplexer as the latter requires shiftOut() instructions?

_Roms_

Hi Paul,

Good point - after you mentioned it, I was powering the Arduino together with the 12V power from the relay board (that board has a +5V connected to the Arduino).

I also tried to get the Arduino connected with USB (same problem), and also another independent 5V power supply. Same issue.

Here're some pictures of the Arduino with both USB and the 5V power supply.



I'm really wondering what's going on and I think you might be on the right track. What could cause the MUX to behave erratically when multiple output pins are toggled on?

Probably not worth mentioning but just in case: I sometimes get the following error when uploading code to the board:

Code: [Select]
avrdude: stk500_paged_load(): (a) protocol error, expect=0x14, resp=0x05
avrdude: stk500_cmd(): programmer is out of sync
Problem uploading to board.  See http://www.arduino.cc/en/Guide/Troubleshooting#upload for suggestions.


Again, I'm very certain this is not a software issue because I carefully debugged the code last night.

But what could it be????


Super_Genius_Brad

Maybe something to help...

In my experience with the MUX Shield II, I found that you have to make sure not to use certain pins for anything but Mux shield functions.  These pins are Digital pins 2,4,6,7,8,10,11, and 12, and analog pins A0, A1, and A2.  Per the data sheet, you can make some modifications (cut traces and add solder bridges) to free up some of the pins, but you HAVE TO MODIFY THE LIBRARY FUNCTIONS TO STOP USING THE PINS.

The library is handy for taking care of maintaining an image of your outputs in memory, and transferring it to the output shift registers painlessly, but it hides the workings of the program.  If your code changes the data or pin modes on any of the aforementioned pins, it can cause the library to deliver unreliable results.

Also, putting a low impedance to ground or power on said Arduino pins can cause also the shift register logic to choke.

Hope this helps!

_Roms_

Thanks a lot for your insight. Yes, I can imagine how one would forget the pins are used by the MUX!
Unfortunately (or fortunately maybe) I'm not using the Arduino pins.

Can you elaborate on the low impedance to ground/power on Arduino? I have to investigate but it's possible the issue comes from the fact that I'm driving 2 relay boards from the MUX. Both relay boards are grounded to the Arduino, one is powered by an external 12V DC and the other by the 5V Arduino port.

I'm thinking (I need to verify) that maybe the MUX works when using 1 relay board but not when using the two of them.


_Roms_

#10
May 18, 2016, 08:13 am Last Edit: May 18, 2016, 08:23 am by _Roms_
I examined the MUX a bit and found something suspicious. Here's the picture. Could this be the source of my issues?

Paul, what do you think?


Paul__B

Looks like a track that did not etch properly and was repaired.

You need to get your multimeter out and check for continuity between the two ends of that track.

_Roms_

Hi all,

Problem solved!!! Finally!

I sent an email to Mark at Mayhem Labs (who's selling the MUX Shield). Mark was really helpful and shipped another MUX for free, which had the same issues.

Finally, Mark identified a problem in the MUX library (MUXShield.cpp) and fixed the code. Here is the updated version of the file and a video showing it's much better now!

Thanks for your help guys!


Code: [Select]
/*
 MuxShield.cpp - Library for using Mayhew Labs' Mux Shield.
 Created by Mark Mayhew, December 29, 2012.
 Updated by Mark Mayhew, May 22, 2016: Fixed digital output issue where erroneous data was being clocked into shift registers
 Released into the public domain.
 */

#include "Arduino.h"
#include "MuxShield.h"

int _shiftReg1[16]={0};
int _shiftReg2[16]={0};
int _shiftReg3[16]={0};

bool _IO1IsOutput = 0;
bool _IO2IsOutput = 0;
bool _IO3IsOutput = 0;

MuxShield::MuxShield(int S0, int S1, int S2, int S3, int OUTMD,int IOS1, int IOS2, int IOS3, int IO1, int IO2, int IO3)
{
    _S0 = S0;
    _S1 = S1;
    _S2 = S2;
    _S3 = S3;
    _OUTMD = OUTMD;
    _IOS1 = IOS1;
    _IOS2 = IOS2;
    _IOS3 = IOS3;
    _IO1 = IO1;
    _IO2 = IO2;
    _IO3 = IO3;
   
    pinMode(_S0,OUTPUT);
    pinMode(_S1,OUTPUT);
    pinMode(_S2,OUTPUT);
    pinMode(_S3,OUTPUT);
    pinMode(_OUTMD,OUTPUT);
    digitalWrite(_OUTMD,LOW);
    pinMode(_IOS1,OUTPUT);
    pinMode(_IOS2,OUTPUT);
    pinMode(_IOS3,OUTPUT);
}

MuxShield::MuxShield()
{
    _S0 = 2;
    _S1 = 4;
    _S2 = 6;
    _S3 = 7;
    _OUTMD = 8;
    _IOS1 = 10;
    _IOS2 = 11;
    _IOS3 = 12;
    _IO1 = A0;
    _IO2 = A1;
    _IO3 = A2;
       
    pinMode(_S0,OUTPUT);
    pinMode(_S1,OUTPUT);
    pinMode(_S2,OUTPUT);
    pinMode(_S3,OUTPUT);
    pinMode(_OUTMD,OUTPUT);
    digitalWrite(_OUTMD,LOW);
    pinMode(_IOS1,OUTPUT);
    pinMode(_IOS2,OUTPUT);
    pinMode(_IOS3,OUTPUT);
   
   
}

void MuxShield::setMode(int mux, int mode)
{
    switch (mux) {
        case 1:
            switch (mode) {
                case DIGITAL_IN:
                    pinMode(_IO1,INPUT);
                    digitalWrite(_IOS1,LOW);
_IO1IsOutput = 0;
                    break;
                case DIGITAL_IN_PULLUP:
                    pinMode(_IO1,INPUT_PULLUP);
                    digitalWrite(_IOS1,LOW);
_IO1IsOutput = 0;
                    break;
                case DIGITAL_OUT:
                    pinMode(_IO1,OUTPUT);
                    digitalWrite(_IOS1,HIGH);
_IO1IsOutput = 1;
                    break;
                case ANALOG_IN:
                    digitalWrite(_IOS1,LOW);
_IO1IsOutput = 0;
                    break;
                default:
                    break;
            }
            break;
        case 2:
            switch (mode) {
                case DIGITAL_IN:
                    pinMode(_IO2,INPUT);
                    digitalWrite(_IOS2,LOW);
_IO2IsOutput = 0;
                    break;
                case DIGITAL_IN_PULLUP:
                    pinMode(_IO2,INPUT_PULLUP);
                    digitalWrite(_IOS2,LOW);
_IO2IsOutput = 0;
                    break;
                case DIGITAL_OUT:
                    pinMode(_IO2,OUTPUT);
                    digitalWrite(_IOS2,HIGH);
_IO2IsOutput = 1;
                    break;
                case ANALOG_IN:
                    digitalWrite(_IOS2,LOW);
_IO2IsOutput = 0;
                    break;
                default:
                    break;
            }
            break;
        case 3:
            switch (mode) {
                case DIGITAL_IN:
                    pinMode(_IO3,INPUT);
                    digitalWrite(_IOS3,LOW);
_IO3IsOutput = 0;
                    break;
                case DIGITAL_IN_PULLUP:
                    pinMode(_IO3,INPUT_PULLUP);
                    digitalWrite(_IOS3,LOW);
_IO3IsOutput = 0;
                    break;
                case DIGITAL_OUT:
                    pinMode(_IO3,OUTPUT);
                    digitalWrite(_IOS3,HIGH);
_IO3IsOutput = 1;
                    break;
                case ANALOG_IN:
                    digitalWrite(_IOS3,LOW);
_IO3IsOutput = 0;
                    break;
                default:
                    break;
            }
            break;
        default:
            break;
    }

}

void MuxShield::digitalWriteMS(int mux, int chan, int val)
{
    int i;
   
    digitalWrite(_S3,LOW);                              //S3 here is LCLK
    digitalWrite(_OUTMD,HIGH);                          //set to output mode
    switch (mux) {
        case 1:
            _shiftReg1[chan] = val;                     //store value until updated again
break;
        case 2:
            _shiftReg2[chan] = val;                     //store value until updated again
break;
case 3:
            _shiftReg3[chan] = val;                     //store value until updated again
break;
default:
            break;
}

if (_IO1IsOutput) {
for (i=15; i>=0; i--) {
digitalWrite(_S0,LOW);                  //S0 here is i/o1 _sclk
digitalWrite(_IO1,_shiftReg1[i]);       //put value
digitalWrite(_S0,HIGH);                 //latch in value
}
}

if (_IO2IsOutput) {
for (i=15; i>=0; i--) {
digitalWrite(_S1,LOW);                  //S0 here is i/o2 _sclk
digitalWrite(_IO2,_shiftReg2[i]);       //put value
digitalWrite(_S1,HIGH);                 //latch in value
}
}

if (_IO3IsOutput) {
for (i=15; i>=0; i--) {
digitalWrite(_S2,LOW);                  //S2 here is i/o3 _sclk
digitalWrite(_IO3,_shiftReg3[i]);       //put value
digitalWrite(_S2,HIGH);                 //latch in value
}
}

    digitalWrite(_S3,HIGH);                     //latch in ALL values
    digitalWrite(_OUTMD,LOW);                   //Exit output mode
}

int MuxShield::digitalReadMS(int mux, int chan)
{
    digitalWrite(_OUTMD,LOW);   //Set outmode off (i.e. set as input mode)
    int val;
    switch (mux) {
        case 1:
            digitalWrite(_S0, (chan&1));   
            digitalWrite(_S1, (chan&3)>>1);
            digitalWrite(_S2, (chan&7)>>2);
            digitalWrite(_S3, (chan&15)>>3);

            val = digitalRead(_IO1);
            break;
        case 2:
            digitalWrite(_S0, (chan&1));   
            digitalWrite(_S1, (chan&3)>>1);
            digitalWrite(_S2, (chan&7)>>2);
            digitalWrite(_S3, (chan&15)>>3);
 
            val = digitalRead(_IO2);
            break;
        case 3:
            digitalWrite(_S0, (chan&1));   
            digitalWrite(_S1, (chan&3)>>1);
            digitalWrite(_S2, (chan&7)>>2);
            digitalWrite(_S3, (chan&15)>>3);

            val = digitalRead(_IO3);
            break;
        default:
            break;
    }
    return val;
}

int MuxShield::analogReadMS(int mux, int chan)
{
    digitalWrite(_OUTMD,LOW);
    int val;

    digitalWrite(_S0, (chan&1));   
    digitalWrite(_S1, (chan&3)>>1);
    digitalWrite(_S2, (chan&7)>>2);
    digitalWrite(_S3, (chan&15)>>3);
   
    switch (mux) {
        case 1:
            val = analogRead(_IO1);
            break;
        case 2:
            val = analogRead(_IO2);
            break;
        case 3:
            val = analogRead(_IO3);
            break;
        default:
            break;
    }
    return val;
}

Go Up