TPIC6B595 and 3.3v Logic for Midi button light indication

Status
Not open for further replies.

Dylpickle

Active member
Hi Everyone,

First post here so sorry if this is a simple answer :)

I am currently playing with a Teensy 4.0 and im looking to drive the LED's on a tactile button (Omron B3W-9000 Series). Looking at the specs they want about 15-20ma per LED and my project will at max possibly have 8 running concurrently, meaning using a 75HC595 wont be possible with it max 75ma output.

My current thoughts are to use a TPIC6B595 over SPI which will allow me to sink much more current per pin (Overkill but whatever), my only concern is that i've seen conflicting reports on this chip working with 3.3v logic.

Reading the data sheet it would look fine to me to use aslong as the chip is powered from the VIN (5V) pin. Is this correct or would i need a level converter between the Teensy SPI pins and the 595 IC?

I dont have a schematic with me atm but i've got one at home if you need more detail.
 
I understand your concern for the 75HC595's potential maximum current limit. However, in my recently completed TeensyMIDIPolySynth project (https://forum.pjrc.com/threads/60690-queued-TeensyMIDIPolySynth?p=237404&viewfull=1#post237404), I am using seven 74HC595s to drive 40 LEDs & 2 x 7-segment displays. I designed for 15ma current per LED (using 220 ohm resisters for each LED & segment). As it turned out, all of the indicators were WAY TOO BRIGHT, so I ended up driving the output enable (OE) pin on the 74HC595s with a PWM signal whose duty cycle was set by reading a pot (rather than changing out 56 resistors & being stuck with a single brightness level). I have full control from super bright (for use in full daylight) to very dim (for use in a low-light stage setting). I found the 74HC595 to be very easy to use, & it consumes, at a minimum, only two pins (data & clock), or three pins with addition of the the output enable if desired.

In general, most LEDs won't tolerate more than about 20mA, & most of the time even less current results in sufficient brightness, with the added benefit of extending the LED's life. I would suggest that you try hooking up at least one of your LEDs to a 74HC595 (with an appropriate current limiting resistor, of course) & see what it looks like. If it turns out that your particular LEDs are just not bright enough, then you could consider using each of the outputs from the 74HC595 to drive a transistor per LED, which could then (with the transistor wired in a voltage follower configuration, plus an appropriate series resistor) supply the needed extra current via the transistor.

I'll try to help with any other questions that you may have.

Good luck & have fun !!

Mark J Culross
KD5RXT
 
thanks alot for your help. I think its an avenue worth exploring, so ive just purchased a couple of 74hc595 and a bunch of resistors and LED's at the same current rating as the buttons. (Yet to buy them, In the planning stage).

At least this way i'll be able to test out the upper limits and see how it reacts.

I'll post my findings :)
 
thanks alot for your help. I think its an avenue worth exploring, so ive just purchased a couple of 74hc595 and a bunch of resistors and LED's at the same current rating as the buttons. (Yet to buy them, In the planning stage).

At least this way i'll be able to test out the upper limits and see how it reacts.

I'll post my findings :)

As a quick & dirty example (abbreviated to showing only the first 10 LEDs to shorten the code listing), this is the approach I used to update my 40 LEDs + 16 segments:

Code:
// variables for each LED
bool lfo_mod_active_state;
bool lfo_mod_single_state;
bool lfo_mod_sine_state;
bool lfo_mod_square_state;
bool lfo_mod_pulse_state;
bool lfo_mod_pulse_duty_state;
bool lfo_mod_triangle_state;
bool lfo_mod_saw_state;
bool lfo_mod_samphold_state;
bool vfoA_single_state;

bool *shiftreg_output_led_ref[] =
{
   &lfo_mod_active_state,
   &lfo_mod_single_state,
   &lfo_mod_sine_state,
   &lfo_mod_square_state,
   &lfo_mod_pulse_state,
   &lfo_mod_pulse_duty_state,
   &lfo_mod_triangle_state,
   &lfo_mod_saw_state,
   &lfo_mod_samphold_state,
   &vfoA_single_state,
};

#define NUM_LEDS 10

// how long to let shift register signals settle when clocking data bits in
#define SHIFTREG_DELAY_MICROSECONDS 5

#define LED_PIN                             13  // teensy 13
#define SHIFTREG_CLOCK_PIN             LED_PIN  // teensy 13

#define AUDIO_VOLUME_PIN                    A1  // teensy 15
#define SHIFTREG_DATA_PIN     AUDIO_VOLUME_PIN  // teensy 15

#define SHIFTREG_LOW_OUTPUT_ENABLE_PIN      22  // teensy 22



// display the current state of all LEDs
void write_leds_thru_shiftreg(void)
{
   AudioNoInterrupts();

   // constant enable the shift register output enable (turn off PWM while writing)
   analogWrite(SHIFTREG_LOW_OUTPUT_ENABLE_PIN, 0);

   // write each LED state sequentially into the shift register
   for (int led_index = 0; led_index < NUM_LEDS; led_index++)
   {
      // set the shift register data
      digitalWrite(SHIFTREG_DATA_PIN, *shiftreg_output_led_ref[led_index]);

      // delay long enough for the data to settle (spec says 125ns)
      //    (knowing that values less than delayMicroseconds(3) are not guaranteed to work consistently)
      delayMicroseconds(SHIFTREG_DELAY_MICROSECONDS);

      // activate the shift register clock (which will also temporarily light the on-board LED)
      digitalWrite(SHIFTREG_CLOCK_PIN, HIGH);

      // delay long enough for the data to be consistently clocked into the shift register (spec says 100ns)
      //    (knowing that values less than delayMicroseconds(3) are not guaranteed to work consistently)
      delayMicroseconds(SHIFTREG_DELAY_MICROSECONDS);

      // deactivate the shift register clock
      digitalWrite(SHIFTREG_CLOCK_PIN, LOW);

      // delay long enough for the data to be consistently clocked into the shift register (spec says 100ns)
      //    (knowing that values less than delayMicroseconds(3) are not guaranteed to work consistently)
      delayMicroseconds(SHIFTREG_DELAY_MICROSECONDS);

   }

   // need to toggle the shift register clock two extra times (once to account for the 1-bit delay induced by
   //    connecting the shift-clock & data-clock together, & a second time to bypass one unused output in the
   //    shift register chain - of course, Murphy would have it that the unused output is at the beginning of
   //    the chain, so it affects *every* update - if it were at the end of the chain, it could be ignored !!)

   // set the shift register data LOW for the extra bits & leave it inactive
   digitalWrite(SHIFTREG_DATA_PIN, LOW);

   // delay long enough for the data to settle (spec says 125nsec)
   //    (knowing that values less than delayMicroseconds(3) are not guaranteed to work consistently)
   delayMicroseconds(SHIFTREG_DELAY_MICROSECONDS);

   // activate the shift register clock (which will also temporarily light the on-board LED)
   digitalWrite(SHIFTREG_CLOCK_PIN, HIGH);

   // delay long enough for the data to be consistently clocked into the shift register (spec says 100ns)
   //    (knowing that values less than delayMicroseconds(3) are not guaranteed to work consistently)
   delayMicroseconds(SHIFTREG_DELAY_MICROSECONDS);

   // deactivate the shift register clock
   digitalWrite(SHIFTREG_CLOCK_PIN, LOW);

   // delay long enough for the data to be consistently clocked into the shift register (spec says 100ns)
   //    (knowing that values less than delayMicroseconds(3) are not guaranteed to work consistently)
   delayMicroseconds(SHIFTREG_DELAY_MICROSECONDS);

   // activate the shift register clock (which will also temporarily light the on-board LED)
   digitalWrite(SHIFTREG_CLOCK_PIN, HIGH);

   // delay long enough for the data to be consistently clocked into the shift register (spec says 100ns)
   //    (knowing that values less than delayMicroseconds(3) are not guaranteed to work consistently)
   delayMicroseconds(SHIFTREG_DELAY_MICROSECONDS);

   // deactivate the shift register clock
   digitalWrite(SHIFTREG_CLOCK_PIN, LOW);

   // re-activate the shift register output enable PWM
   analogWrite(SHIFTREG_LOW_OUTPUT_ENABLE_PIN, (255 - led_intensity));

   AudioInterrupts();
}  // write_leds_thru_shiftreg()

Good luck & have fun !!

Mark J Culross
KD5RXT
 
Thanks Mark,

This was powered via usb, so no external power source.

Soooooo I messed up when frustrated and accidentally shorted the a 5v pin to pin 13, so my CLK pin is cooked. I will use the other SPI bus (as this 4.0 is just for experimenting, I'll be designing around a 4.1).

I tried a few different bits of code and for some reason still couldn't get any action. I checked all the LED's were working without the 595, which they were and the 595 was getting the correct voltages on the pins but the outputs didn't seem to change.

I just put this together as this was what I was doing with the pinouts.

w3SYirE.png

I don't have the code to attach as i deleted it in frustration. my questions are...

1) Is there any code out there that will give me the basics of the LED blink sketch but through the 595?
2) Is there anything wrong with my pinout?

I'm thinking i might just try the one off using 1 LED to start and expand on that.

Sorry about the newbie questions =(

Sorry about the extreme newbie questions.
 
Last edited:
quick & dirty "blink" - midified for using 74HC595

It would probably be safest if you powered the 74HC595 from the 3.3VDC pin on the Teensy, rather than from 5VDC since the Teensy 4.x is not 5VDC tolerant.

I would suggest (for simplicity) that you drive the "RCLK" & "SRCLK" pins on the 74HC595 with a single Teensy pin (call it "TCLK" just to have something to refer to). The only thing to be aware of with the clocks wired this way is that it will take two full cycles on the "TCLK" pin (since both clock pins idle LOW, two full cycles would be LOW-HIGH-LOW-HIGH-LOW) before the first output on the 74HC595 will become active. You should be able to use any pin for "TCLK".

Here's a version of blink for you to try that has been modified for using the 74HC595 (with the common RCLK/SRCLK assumption above & setup for you to build upon & easily add more LEDs). . . you should modify the pin definitions to match how you have everything wired:

Code:
/*
  Blink
  Turns on an LED on for one second, then off for one second, repeatedly.

  This example code is in the public domain.
 */

#define NUM_LEDS 1

// variables for each LED
bool blink_led0_state = false;

// a pointer to each of the LED variables
bool *shiftreg_output_led_ref[] =
{
   &blink_led0_state,
};

// how long to let shift register signals settle when clocking data bits in
#define SHIFTREG_DELAY_MICROSECONDS 5

#define SHIFTREG_CLOCK_PIN             13  // teensy 13
#define SHIFTREG_DATA_PIN               A1  // teensy 15
#define SHIFTREG_LOW_OUTPUT_ENABLE_PIN      22  // teensy 22


// the setup routine runs once when you press reset:
void setup() {
  // initialize the shift register output enable pin as an output.
  pinMode(SHIFTREG_LOW_OUTPUT_ENABLE_PIN, OUTPUT);

  // constant enable the shift register output enable (active low)
  digitalWrite(SHIFTREG_LOW_OUTPUT_ENABLE_PIN, 0);

  // initialize the shift register clock pin as an output.
  pinMode(SHIFTREG_CLOCK_PIN, OUTPUT);

  // the shift register clock pin idles LOW (active high)
  digitalWrite(SHIFTREG_CLOCK_PIN, 0);

  // initialize the shift register data pin as an output.
  pinMode(SHIFTREG_DATA_PIN, OUTPUT);

  // the shift register data pin idles LOW
  digitalWrite(SHIFTREG_CLOCK_PIN, 0);
}

// the loop routine runs over and over again forever:
void loop() {
  // toggle the state of the led blink variable
  blink_led0_state = !blink_led0_state;

  // write the current state of the led blink variable thru the shift register
  write_leds_thru_shiftreg();

  // wait for a second
  delay(1000);
}


// display the current state of all LEDs
void write_leds_thru_shiftreg(void)
{
  // write each LED state sequentially into the shift register
  for (int led_index = 0; led_index < NUM_LEDS; led_index++)
  {
    // set the shift register data
    digitalWrite(SHIFTREG_DATA_PIN, *shiftreg_output_led_ref[led_index]);

    // delay long enough for the data to settle (spec says 125ns)
    //    (knowing that values less than delayMicroseconds(3) are not guaranteed to work consistently)
    delayMicroseconds(SHIFTREG_DELAY_MICROSECONDS);

    // activate the shift register clock (which will also temporarily light the on-board LED)
    digitalWrite(SHIFTREG_CLOCK_PIN, HIGH);

    // delay long enough for the data to be consistently clocked into the shift register (spec says 100ns)
    //    (knowing that values less than delayMicroseconds(3) are not guaranteed to work consistently)
    delayMicroseconds(SHIFTREG_DELAY_MICROSECONDS);

    // deactivate the shift register clock
    digitalWrite(SHIFTREG_CLOCK_PIN, LOW);

    // delay long enough for the data to be consistently clocked into the shift register (spec says 100ns)
    //    (knowing that values less than delayMicroseconds(3) are not guaranteed to work consistently)
    delayMicroseconds(SHIFTREG_DELAY_MICROSECONDS);
  }

  // need to toggle the shift register clock one extra time to account for the 1-bit delay induced by
  //    connecting RCLK & SRCLK together

  // set the shift register data LOW for the extra bit & leave it inactive
  digitalWrite(SHIFTREG_DATA_PIN, LOW);

  // delay long enough for the data to settle (spec says 125nsec)
  //    (knowing that values less than delayMicroseconds(3) are not guaranteed to work consistently)
  delayMicroseconds(SHIFTREG_DELAY_MICROSECONDS);

  // activate the shift register clock (which will also temporarily light the on-board LED)
  digitalWrite(SHIFTREG_CLOCK_PIN, HIGH);

  // delay long enough for the data to be consistently clocked into the shift register (spec says 100ns)
  //    (knowing that values less than delayMicroseconds(3) are not guaranteed to work consistently)
  delayMicroseconds(SHIFTREG_DELAY_MICROSECONDS);

  // deactivate the shift register clock
  digitalWrite(SHIFTREG_CLOCK_PIN, LOW);

  // delay long enough for the data to be consistently clocked into the shift register (spec says 100ns)
  //    (knowing that values less than delayMicroseconds(3) are not guaranteed to work consistently)
  delayMicroseconds(SHIFTREG_DELAY_MICROSECONDS);
}  // write_leds_thru_shiftreg()

Good luck & have fun !!

Mark J Culross
KD5RXT
 
oh man,

Im an idiot. I was using the 5v pin thinking id need more current for everything earlier on, now ive released id be using 150ma total. Scope creep got me.

I'll do it with the 3v to be safe next time :) I thought the CS/SS and CLK pins were specific to SPI and could only be used on certain pins? Is there further documentation i should be reading on this?

Thank you for your help so far :)
 
The 74HC595 does not use SPI. It can use any pin for its clock & any pin for its data. You are just "bit-banging" (as it's commonly called) the data to it, one bit at a time. Each time you clock it, it shifts each bit internally to its next neighbor register & loads the current bit into the first register. You can clock it as fast (up to its speed limit, which is pretty fast...see the data sheet) or slow as you want. Take a look at the data sheet here http://www.ti.com/general/docs/suppproductinfo.tsp?distId=10&gotoUrl=http%3A%2F%2Fwww.ti.com%2Flit%2Fgpn%2Fsn74hc595.

Glad to be able to help. As I tell my fellow radio club members "I wasn't born knowing this stuff...I had to learn it too !!" & "I get to enjoy this bit of knowledge twice...once when I learn it myself & a second time when I pass it along & help someone else to learn it !!"

Good luck & have fun !!

Mark J Culross
KD5RXT
 
No problem...Google is also my friend, especially when tackling something new. Sorry, I don't have any experience with using the 74HC595 via SPI. Because of the way I have used this shift register in my recent project, I am, of course, biased into thinking that using SPI is just adding unnecessary complexity. Did you get the expected behavior with the simple blink sketch that I posted earlier ??

Good luck & have fun !!

Mark J Culross
KD5RXT
 
Hi mate! yes thank you :) Ive managed to get it working as I wanted. TBH all 8 work at once but to allow a little more current i think i'll run them between 2 of them. It'll allow them to be a little bit brighter and i wont have to worry about getting close :)

Thanks so much for your help :)
 
oh and maybe one more question. If I were to daisychain the 595's is the max current still 75ma or is it per chip?
 
oh and maybe one more question. If I were to daisychain the 595's is the max current still 75ma or is it per chip?

That's probably a 75ma limit per chip. Glad to hear that things are working for you.

Good luck & have fun !!

Mark J Culross
KD5RXT
 
Status
Not open for further replies.
Back
Top