Help with SPI and Adafruit TLC59711 RGB LED board with Teensy Audio

Status
Not open for further replies.

Tenumen

Member
Hi

I am trying to run my Teensy 3.6 using both the Teensy Audio board and an Adafruit TLC59711 12 channel SPI RGB LED board. I want to be able to easily pulse the LEDs in sync with the music using the features of the Teensy's great audio system design tool. However I am struggling to get the Adafruit TLC59711 to work properly.

Since I am using the teensy audio shield I cannot use the SPI0 pins or the default SPI1 pins. So I have tried to use the alternative SPI1 pins (eventually I'll use the SPI2 pins on the back) -but it won't work using those pins.

I can get it to work using software SPI -using pins 36 (data) and 35 (clock) but I can't using pins 20 & 21. Here is the code -it's basically the adafruit example but with the pins changed. View attachment RGB.h.

I think part of my problem is that I don't really know how to 'begin' SPI1 or SPI2, also I'm wondering if the Adafruit_TLC59711 library hardcodes for use of SPI0 or software SPI -but I can't check as my coding skills are way too limited.

I have seen that you can use commands such as ' SPI.setMOSI(pin)' to change the default pin to an alternative, and I'm guessing I can use 'SPI1.begin' to start the SPI1 channel. However I don't know where to add them into the code -as I don't understand why the example code doesn't include an SPI.begin line at all? Does the library kick off it's own software SPI channel using the pins that are defined in my code? So it works when I define generic pins (35, 36) but conflicts with the hardware SPI1 when I set it to use those pins?

Also, one further observation -when I upload this code it disables the USB serial. Why would it do that? How do I stop it doing that?

Can anyone point me in the right direction?
 
I have seen that you can use commands such as ' SPI.setMOSI(pin)' to change the default pin to an alternative,

This is probably the right path.

Look at the audio library WavFilePlayer example. It uses a SD card over SPI (in 2 of the 3 ways to configure). Using Adafruit's library should be similar. Configure the pins before you begin their lib, and then it should do the SPI access on those pins. Simple, right?


and I'm guessing I can use 'SPI1.begin' to start the SPI1 channel.

This is probably *NOT* the best way.


However I don't know where to add them into the code

Unless Adafruit designed their library to allow selecting a different SPI port, this would be a difficult path. You'd have to dig deep into Adafruit's library. Not simple or easy.

Lately Adafruit has been designing many of their libs to use different I2C ports. But with SPI, normally they give you the choice between the main SPI port or slower software bitband on any pins, but not SPI1, SPI2, etc. Maybe they will someday start designing for different hardware SPI ports, but as things are now, using SPI1 with their libs is a painful path.


-as I don't understand why the example code doesn't include an SPI.begin line at all?

Generally, most libraries which use SPI tend to do a SPI.begin() for you within their code.

But this is only a general rule which can have exceptions. It all depends on the specific design of whatever lib you're using. Most of Adafruit's libs have a similar design... but keep in mind you are asking questions about a specific library that we don't necessarily know (and I don't see any links to the code in these messages)


Also, one further observation -when I upload this code it disables the USB serial. Why would it do that?

Anything that interferes with the USB port can prevent Teensy from responding to the automatic reboot request. Every Teensy has the program pushbutton so you can recover from that situation, of course with the slight inconvenience of having to press the button.

While there are many ways to mess up the USB, the most most common are leaving interrupts disabled and buffer overflow mistakes in code your code (or the libraries - though that's not common) which overwrite memory needed for the USB packets or other USB details.



Can anyone point me in the right direction?

Hopefully the helped?

If you'd like us to look briefly at this Adafruit library, please give us a link directly to its github repository. Also tell us exactly which of its examples you're using, or show us your code... or better, a small version of your code that you've double-checked really does demonstrate the issue. Don't make us try to guess which code you're really using.
 
So, i've had a look in the adafruit library (github here https://github.com/adafruit/Adafruit_TLC59711) and I have found out where it starts SPI so I went through everywhere to change SPI to SPI1 -as follows:

Code:
/*************************************************** 
  This is a library for our Adafruit 24-channel PWM/LED driver

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/products/1455

  These drivers uses SPI to communicate, 3 pins are required to  
  interface: Data, Clock and Latch. The boards are chainable

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/


#include <Adafruit_TLC59711.h>
#include <SPI.h>

Adafruit_TLC59711::Adafruit_TLC59711(uint8_t n, uint8_t c, uint8_t d) {
  numdrivers = n;
  _clk = c;
  _dat = d;

  BCr = BCg = BCb = 0x7F;

  pwmbuffer = (uint16_t *)calloc(2, 12*n);
}

Adafruit_TLC59711::Adafruit_TLC59711(uint8_t n) {
  numdrivers = n;
  _clk = -1;
  _dat = -1;

  SPI1.setBitOrder(MSBFIRST);
#ifdef __arm__
  SPI1.setClockDivider(42);
#else
  SPI1.setClockDivider(SPI_CLOCK_DIV8);
#endif
  SPI1.setDataMode(SPI_MODE0);
  BCr = BCg = BCb = 0x7F;

  pwmbuffer = (uint16_t *)calloc(2, 12*n);
}

void  Adafruit_TLC59711::spiwriteMSB(uint32_t d) {

  if (_clk >= 0) {
    uint32_t b = 0x80;
    //  b <<= (bits-1);
    for (; b!=0; b>>=1) {
      digitalWrite(_clk, LOW);
      if (d & b)  
	digitalWrite(_dat, HIGH);
      else
	digitalWrite(_dat, LOW);
      digitalWrite(_clk, HIGH);
    }
  } else {
    SPI1.transfer(d);
  }
}

void Adafruit_TLC59711::write(void) {
  uint32_t command;

  // Magic word for write
  command = 0x25;

  command <<= 5;
  //OUTTMG = 1, EXTGCK = 0, TMGRST = 1, DSPRPT = 1, BLANK = 0 -> 0x16
  command |= 0x16;

  command <<= 7;
  command |= BCr;

  command <<= 7;
  command |= BCg;

  command <<= 7;
  command |= BCb;

  noInterrupts();
  for (uint8_t n=0; n<numdrivers; n++) {
    spiwriteMSB(command >> 24);
    spiwriteMSB(command >> 16);
    spiwriteMSB(command >> 8);
    spiwriteMSB(command);

    // 12 channels per TLC59711
    for (int8_t c=11; c >= 0 ; c--) {
      // 16 bits per channel, send MSB first
      spiwriteMSB(pwmbuffer[n*12+c]>>8);
      spiwriteMSB(pwmbuffer[n*12+c]);
    }
  }

  if (_clk >= 0)
    delayMicroseconds(200);
  else
    delayMicroseconds(2);
  interrupts();
}



void Adafruit_TLC59711::setPWM(uint8_t chan, uint16_t pwm) {
  if (chan > 12*numdrivers) return;
  pwmbuffer[chan] = pwm;  
}


void Adafruit_TLC59711::setLED(uint8_t lednum, uint16_t r, uint16_t g, uint16_t b) {
  setPWM(lednum*3, r);
  setPWM(lednum*3+1, g);
  setPWM(lednum*3+2, b);
}


boolean Adafruit_TLC59711::begin() {
  if (!pwmbuffer) return false;

  if (_clk >= 0) {
    pinMode(_clk, OUTPUT);
    pinMode(_dat, OUTPUT);
  } else {
    SPI1.begin();
  }
  return true;
}

I then call the library using this code:
Code:
#include "Adafruit_TLC59711.h"
#include <SPI.h>

// How many boards do you have chained?
#define NUM_TLC59711 1

#define data   21
#define clock  20

Adafruit_TLC59711 tlc = Adafruit_TLC59711(NUM_TLC59711, clock, data);

void setup() {
  SPI1.setMOSI(21);
  SPI1.setSCK(20);
  Serial.begin(9600);
  Serial.println("TLC59711 test");
  tlc.begin();
  tlc.write();
}

void loop() {
  colorWipe(65535, 0, 0, 100); // "Red" (depending on your LED wiring)
  delay(200);
  colorWipe(0, 65535, 0, 100); // "Green" (depending on your LED wiring)
  delay(200);
  colorWipe(0, 0, 65535, 100); // "Blue" (depending on your LED wiring)
  delay(200);
  Serial.println("colourwipe complete");
}

// Fill the dots one after the other with a color
void colorWipe(uint16_t r, uint16_t g, uint16_t b, uint8_t wait) {
  for(uint16_t i=0; i<8*NUM_TLC59711; i++) {
      tlc.setLED(i, r, g, b);
      tlc.write();
      delay(wait);
  }
}

Unfortunately this doesn't work. I get an error saying Error compiling for board Teensy 3.6.

I am a bit stumped.
 
Maybe the bottom console area of the Arduino window has more info about the error, like which file and the line number within that file where the error is?

By default that bottom section is small. You can drag the divider between the sections to make it bigger. You may need to scroll up to see the actual info about the error.
 
Well things are progressing. I think yesterday's issues were due to me messing up multiple instances of the libraries. A clean install has fixed the issues and the code now runs. LED lights won't work yet but the code runs -so I think I need to spend a bit more time to see whats happening.
Thanks for your help getting me this far.
 
Any progress on this issue yet? I'm running into a similar issue with the tlc59711 chip and teensy 3.6. I am able to run a successful code using pins 7(data) and 27(clock) with real time audio processing and 16-bit LED output at the same time, but I do this using two separate power supplies to run the teensy (5V) and LED strips and driver (12V). My issue is when trying to power both teensy and tlc59711 on one power supply (12v power supply EPS-65S-12 with a LM2576 5V regulator) I get really a bad flickering with any RGB values between 4000-4500 and no visible light below 4000. I haven't done any configuring to the pins other than assign them with Adafruit_TLC59711(NUM_TLC59711, TLC_CLOCK, TLC_DATA);.... perhaps more configuring is needed?



I also use the same 12v power supply EPS-65S-12 to test the Adafruit example code and I run into the same flickering issue (see below):




#include "Adafruit_TLC59711.h"
#include <SPI.h>
#include <Wire.h>

// How many boards do you have chained?
#define NUM_TLC59711 1

//#define data 17
//#define clock 16
#define data 7
#define clock 27

Adafruit_TLC59711 tlc = Adafruit_TLC59711(NUM_TLC59711, clock, data);
//Adafruit_TLC59711 tlc = Adafruit_TLC59711(NUM_TLC59711);

int ledNum = 5000;
int ledFadeAmount = 1;

void setup() {
Serial.begin(9600);

Serial.println("TLC59711 test");
pinMode(10, OUTPUT);
tlc.begin();
tlc.write();

}

void loop() {
tlc.setPWM(0, 0);
tlc.setPWM(1, 0);
tlc.setPWM(2, ledNum);

tlc.setPWM(3, 0);
tlc.setPWM(4, 0);
tlc.setPWM(5, ledNum);

tlc.write();

ledNum = ledNum + ledFadeAmount;

if (ledNum <= 0 || ledNum >= 5000)
{
ledFadeAmount = -ledFadeAmount;
}
Serial.println(ledNum);
delay(100);

}
 
Last edited:
Status
Not open for further replies.
Back
Top