Mcp23017 and Tlc5940 pin conflict

Status
Not open for further replies.

spoof

New member
Hi all,

I'm building a midi controller using a Teensy++ 2.0, for which I'd like to use several daisy-chained Mcp23017s i2c chips to extend my number of digital inputs and a bunch of Tlc5940s to drive a matrix of RGB leds. However, both IC's use the 1 pin on the Teensy, the Mcp23017 as SDA line for the i2c bus and the Tlc5940 for the GSCLK connection in the Tlc5940 Library. I tried assigning the GSCLK to another PWM-enabled pin (15) in the Tlc5940 library but that didn't seem to work :(

Can the Tlc5940 only work from pin 1? If so, would it be feasible to use two Teensy's? Probably not, as uI would also need the i2c bus to connect/sync them, right? Any thoughts?

Thanks!
 
Hi all,

I'm building a midi controller using a Teensy++ 2.0, for which I'd like to use several daisy-chained Mcp23017s i2c chips to extend my number of digital inputs and a bunch of Tlc5940s to drive a matrix of RGB leds. However, both IC's use the 1 pin on the Teensy, the Mcp23017 as SDA line for the i2c bus and the Tlc5940 for the GSCLK connection in the Tlc5940 Library. I tried assigning the GSCLK to another PWM-enabled pin (15) in the Tlc5940 library but that didn't seem to work :(

Can the Tlc5940 only work from pin 1? If so, would it be feasible to use two Teensy's? Probably not, as uI would also need the i2c bus to connect/sync them, right? Any thoughts?

Thanks!

I just bought TLC5940 driver and I'm facing same issue as you. Any answers to this?
 
I just bought TLC5940 driver and I'm facing same issue as you. Any answers to this?

nope, not possible i guess since the i2c bus is already in use... i ended up using bit shifters and software pwm which worked fine eventually...
 
http://ww1.microchip.com/downloads/en/DeviceDoc/21952b.pdf said:
• Three hardware address pins to allow up to eight
devices on the bus
The first datasheet I found indicates you can have eight on the one I2C bus without much fuss - are you guys trying to have more than 8? Is there another datasheet for the 'S' suffix I should have tried harder to find?

Edit: Hmmm, OK, sorry, posted in haste there; a longer look at the datasheet for TLC5940 isn't as helpful as the quick look at the other datasheet - I haven't spent long enough to confirm but perhaps the 'SOUT' signal is what 'SIN' was 16 shifts ago meaning that they should daisy chain, I turn busy in a moment but if you challenge me to I will spend more time with this datasheet later to confirm or deny that that is what 'SOUT' is for.
 
Last edited:
The first datasheet I found indicates you can have eight on the one I2C bus without much fuss - are you guys trying to have more than 8? Is there another datasheet for the 'S' suffix I should have tried harder to find?

Edit: Hmmm, OK, sorry, posted in haste there; a longer look at the datasheet for TLC5940 isn't as helpful as the quick look at the other datasheet - I haven't spent long enough to confirm but perhaps the 'SOUT' signal is what 'SIN' was 16 shifts ago meaning that they should daisy chain, I turn busy in a moment but if you challenge me to I will spend more time with this datasheet later to confirm or deny that that is what 'SOUT' is for.

Think I'll resort to using Software I2C library for Arduino - I guess it's Teensy compatible (haven't found anything in the code that would suggest otherwise).
 
maybe try to edit Teensypp_xx6.h, the last section on GSCLK, change it to

Code:
// OC3A (Teensy pin 16) -> GSCLK (TLC pin 18)
#define GSCLK_PIN	16
#define GSCLK_PORT	PORTC
#define GSCLK_DDR	DDRC
#define TLC_TIMER3_GSCLK 1

This will move it to pin16.
 
maybe try to edit Teensypp_xx6.h, the last section on GSCLK, change it to

Code:
// OC3A (Teensy pin 16) -> GSCLK (TLC pin 18)
#define GSCLK_PIN	16
#define GSCLK_PORT	PORTC
#define GSCLK_DDR	DDRC
#define TLC_TIMER3_GSCLK 1

This will move it to pin16.

It didn't work.
 
Last edited:
you are using teensy 2++ right?
do you have oscilloscope or logic analyzer to see if pin16 has clock output?

I do not own a teensy 2++, but I do not see any reason why the above code change will not move GSCLK to pin 16 if the file Teensypp_xxx6.h is edited correctly as I described.

replace
Code:
// OC2B (Teensy++ pin 1) -> GSCLK (TLC pin 18)
#define GSCLK_PIN	1
#define GSCLK_PORT	PORTD
#define GSCLK_DDR	DDRD

with
Code:
// OC3A (Teensy pin 16) -> GSCLK (TLC pin 18)
#define GSCLK_PIN	16
#define GSCLK_PORT	PORTC
#define GSCLK_DDR	DDRC
#define TLC_TIMER3_GSCLK 1
 
you are using teensy 2++ right?
do you have oscilloscope or logic analyzer to see if pin16 has clock output?

I do not own a teensy 2++, but I do not see any reason why the above code change will not move GSCLK to pin 16 if the file Teensypp_xxx6.h is edited correctly as I described.

replace
Code:
// OC2B (Teensy++ pin 1) -> GSCLK (TLC pin 18)
#define GSCLK_PIN	1
#define GSCLK_PORT	PORTD
#define GSCLK_DDR	DDRD

with
Code:
// OC3A (Teensy pin 16) -> GSCLK (TLC pin 18)
#define GSCLK_PIN	16
#define GSCLK_PORT	PORTC
#define GSCLK_DDR	DDRC
#define TLC_TIMER3_GSCLK 1

I spent almost entire night examining entire TLC library and reading AT90USB1286 datasheet, and I also don't get it. It should work, but what happens is this:

1) I upload the code (after rebuilding everything) - nothing happens
2) I restart Teensy (disconnect/connect USB) - now all LEDs are on, but only for a short period of time - 10-12 seconds, and during that time they flicker a bit
3) After that they turn off and that's it

My code is literally two lines only:

Code:
void setup()
{
  Tlc.init(4095);
  Tlc.update();
}

EDIT:

I tried adding this to setup:

pinMode(16, OUTPUT);

...and now it suddenly works. What the hell? There is also same function inside library which does exactly the same thing, but only after I add pinMode in setup it works. Any explanations?
 
Last edited:
Here is my explanation.

Ok, AVR requires pin to be in output mode for PWM to work.
If you look at Tlc init function around line 108 is this

output_pin(GSCLK_DDR, GSCLK_PIN);

where GSCLK_PIN is 16. GSCLK_DDR is actually irrelevant, if you look at output_pin macro maps to pinMode(pin, OUTPUT), hence only value of parameter PIN is used and it simply sets the mode to output.

I think you found a bug in pin_function.h
it looks like it did not use the macro defined for teensyduino, but for __AVR__ ( line 4 of pin_function.h)
It will execute ddr |= _BV(pin)
where DDR we defined as DDRC, but pin will be 16, which is incorrect, it should have been remapped to 6 (or PC6 will work, as it gets mapped to 6) since OC3A is PC6.
on the case where it was on pin1, it, by coincidence worked because pin 1 is PD1, so teensy pin 1 maps to bit 1 of port D, by coincidence it worked.

The fix in pin_function.h should be to move #if defined(TEENSYDUINO) up before #if defined(__AVR___), as teensy 2++ is an avr cpu.

You should work with maintainer of this library for teensy to get this fixed.
and I highly recommend to move the GSCLK to pin 16. I think it was a very bad idea/design to use I2C SDA pin for it to begin with.
 
Last edited:
Here is my explanation.

Ok, AVR requires pin to be in output mode for PWM to work.
If you look at Tlc init function around line 108 is this

output_pin(GSCLK_DDR, GSCLK_PIN);

where GSCLK_PIN is 16. GSCLK_DDR is actually irrelevant, if you look at output_pin macro maps to pinMode(pin, OUTPUT), hence only value of parameter PIN is used and it simply sets the mode to output.

I think you found a bug in pin_function.h
it looks like it did not use the macro defined for teensyduino, but for __AVR__ ( line 4 of pin_function.h)
It will execute ddr |= _BV(pin)
where DDR we defined as DDRC, but pin will be 16, which is incorrect, it should have been remapped to 6 (or PC6 will work, as it gets mapped to 6) since OC3A is PC6.
on the case where it was on pin1, it, by coincidence worked because pin 1 is PD1, so teensy pin 1 maps to bit 1 of port D, by coincidence it worked.

The fix in pin_function.h should be to move #if defined(TEENSYDUINO) up before #if defined(__AVR___), as teensy 2++ is an avr cpu.

You should work with maintainer of this library for teensy to get this fixed.
and I highly recommend to move the GSCLK to pin 16. I think it was a very bad idea/design to use I2C SDA pin for it to begin with.

That's only part of a solution. I tried to do what you suggested - it didn't work (and also I couldn't get it to compile because it complained about how it can't find digitalWriteFast, so I renamed it to simply digitalWrite).

Then I removed both AVR and TEENSYDUINO sections and was left out with only this:

Code:
#define pulse_pin(port, pin)        digitalWrite(pin, HIGH); digitalWrite(pin, LOW)
#define set_pin(port, pin)          digitalWrite(pin, HIGH)
#define clear_pin(port, pin)        digitalWrite(pin, LOW)
#define output_pin(ddr, pin)        pinMode(pin, OUTPUT)
#define pullup_pin(ddr, port, pin)  pinMode(pin, INPUT_PULLUP)

Also didn't work. Then I left out only AVR section again, but started to replace one by one line with Arduino functions. So, this works (but I still need pinMode(16, OUTPUT) below Tlc.init(4095) line):

Code:
#define pulse_pin(port, pin)        digitalWrite(pin, HIGH); digitalWrite(pin, LOW)
#define set_pin(port, pin)          digitalWrite(pin, HIGH)
#define clear_pin(port, pin)        digitalWrite(pin, LOW)
#define output_pin(ddr, pin)        ddr |= _BV(pin)
#define pullup_pin(ddr, port, pin)  pinMode(pin, INPUT_PULLUP)

When I replace ddr |= _BV(pin) with pinMode(pin, OUTPUT) it doesn't work anymore. So, I finally got it. So, the first part of the fix is to replace pin_functions.h with this:

Code:
#ifndef TLC_pin_functions_h
#define TLC_pin_functions_h

#if defined(TEENSYDUINO)
  #if F_CPU > 48000000
  #define pulse_pin(port, pin)        digitalWrite(pin, HIGH); asm("nop"); digitalWrite(pin, LOW)
  #else
  #define pulse_pin(port, pin)        digitalWrite(pin, HIGH); digitalWrite(pin, LOW)
  #endif
  #define set_pin(port, pin)          digitalWrite(pin, HIGH)
  #define clear_pin(port, pin)        digitalWrite(pin, LOW)
  #define output_pin(ddr, pin)        pinMode(pin, OUTPUT)
  #define pullup_pin(ddr, port, pin)  pinMode(pin, INPUT_PULLUP)
  
#elif defined(__AVR__)
  #define pulse_pin(port, pin)        port |= _BV(pin); port &= ~_BV(pin)
  #define set_pin(port, pin)          port |= _BV(pin)
  #define clear_pin(port, pin)        port &= ~_BV(pin)
  #define output_pin(ddr, pin)        ddr |= _BV(pin)
  #define pullup_pin(ddr, port, pin)  ddr &= ~_BV(pin); port |= _BV(pin)

#else
  #define pulse_pin(port, pin)        digitalWrite(pin, HIGH); digitalWrite(pin, LOW)
  #define set_pin(port, pin)          digitalWrite(pin, HIGH)
  #define clear_pin(port, pin)        digitalWrite(pin, LOW)
  #define output_pin(ddr, pin)        pinMode(pin, OUTPUT)
  #define pullup_pin(ddr, port, pin)  pinMode(pin, INPUT_PULLUP)
#endif

#endif

Second part of the fix is to replace Teensypp_xxx6.h contents with this:

Code:
#ifndef TLC_Teensypp_xxx6_H
#define TLC_Teensypp_xxx6_H

#if DATA_TRANSFER_MODE == TLC_BITBANG
#error "If you want bitbang mode, insert pin defs here"
#endif

// MOSI (Teensy++ pin 22) -> SIN (TLC pin 26)
#define TLC_MOSI_PIN	22
#define TLC_MOSI_PORT	PORTB
#define TLC_MOSI_DDR	DDRB

// SCK (Teensy++ pin 21) -> SCLK (TLC pin 25)
#define TLC_SCK_PIN	21
#define TLC_SCK_PORT	PORTB
#define TLC_SCK_DDR	DDRB

// SS (Teensy++ pin 20)
#define TLC_SS_PIN	20
#define TLC_SS_DDR	DDRB

// OC1A (Teensy++ pin 25) -> XLAT (TLC pin 24)
#define XLAT_PIN	25
#define XLAT_PORT	PORTB
#define XLAT_DDR	DDRB

// OC1B (Teensy++ pin 26) -> BLANK (TLC pin 23)
#define BLANK_PIN	26
#define BLANK_PORT	PORTB
#define BLANK_DDR	DDRB

// OC3A (Teensy pin 16) -> GSCLK (TLC pin 18)
#define GSCLK_PIN	16
#define GSCLK_PORT	PORTC
#define GSCLK_DDR	DDRC
#define TLC_TIMER3_GSCLK 1

#endif

That Teensy file contained pins on port, not Arduino/Teensy pin numbering scheme. Since we fixed problem 1, and library now properly detects Teensy, called functions are actually digitalRead/digitalWrite/pinMode, and not direct port manipulation. Supplying Teensy pins instead of port pins in Teensypp_xxx6.h fixed everything, and TLC now happily works on Teensy using pin 16 for GLSCK. Thanks!
 
Last edited:
ok, I see.

In this case, the proper fix is to leave pin_functions.h alone.
then use this instead in Teensypp_xxx6.h

Code:
// OC3A (Teensy pin 16) -> GSCLK (TLC pin 18)
#define GSCLK_PIN	PC6
#define GSCLK_PORT	PORTC
#define GSCLK_DDR	DDRC
#define TLC_TIMER3_GSCLK 1

Please check this, If this works (I think it should), this is the simplest change to move the GSCLK from pin1 to pin16.

if PC6 results in compile error, just use 6 instead, since pin16 is bit 6 of port c.
 
Last edited:
you can suggest to TLC5490 maintainer to add a new tlc_config.h define

Code:
//uncomment the next line to use pin16 for GSCLK on Teensy++ 2.0
//#define TEENSYPPGSCLKPIN16

before the #include "pinouts/chip_includes.h" line

Then modify Teensypp_xxx6.h GSCLK section to

Code:
#ifdef TEENSYPPGSCLKPIN16
// OC3A (Teensy pin 16) -> GSCLK (TLC pin 18)
#define GSCLK_PIN	PC6
#define GSCLK_PORT	PORTC
#define GSCLK_DDR	DDRC
#define TLC_TIMER3_GSCLK 1
#else
// OC2B (Teensy++ pin 1) -> GSCLK (TLC pin 18)
#define GSCLK_PIN	1
#define GSCLK_PORT	PORTD
#define GSCLK_DDR	DDRD
#endif
 
Status
Not open for further replies.
Back
Top