TLC5940: tlc_shifts.h question

I am using the arduino tlc5940 library, and have a question regarding the tlc_shifts function.
Is it possible to modify the tlc_shift_h to make it work with only some of the channels, for instance 12 instead of 16, 24 instead of 32?
Without understanding the code completely I suspect it might be difficult since it seems to be using bit-shifting, but if anyone has any insight on how to approach this I would be grateful.

hc

The relevant bit of the code is:-

// bit-bangs data out of SIN and SCLK
static void shiftData(uint8_t *data, uint8_t length)
{
      uint8_t *dpMax = data + length;
      for (uint8_t *dp = data; dp < dpMax; dp++) {
            shift8(*dp);
      }
}

static void shift8(uint8_t value)
{
      //                        128 = 1000 0000
      for (uint8_t bit = 128; bit; bit >>= 1) {
            if (value & bit) {
                  pin_high(SIN_PORT, SIN_PIN);
            } else {
                  pin_low(SIN_PORT, SIN_PIN);
            }
            pulse_pin(SCLK_PORT, SCLK_PIN);
      }
}

So you see it is based round multiples of 8 shifts. It uses a mask to isolate the appropriate bit in the byte. So if you want to change this then just change the mask. So the line:-
for (uint8_t bit = 128; bit; bit >>= 1)
becomes:-
for (uint8_t bit = 8; bit; bit >>= 1)
if you just want to transfer the 4 least significant bits.

However, I am not sure why you want to do this apart from saving a bit of time. Also I am not sure if the TLC chip would take kindly to only having part of it's data clocked in.

thanks for the input.
in a circular setup it becomes a quite clear break in the movement if there are four lights missing when using the shift routine as it is.

hc

Yes but isn't that just a matter of where you put the values in the buffer indicating where you want the lights on? Rather than the feeding of the TLC

maybe I don´t understand how the tlc_shifts.h routine works, but it seems to update all channels everytime the tlc_shift command is sent.

So in my ideal setup (using 4 leds here to keep it short) I would for instance want 1 led on and then move that around, and this would produce the following series
1 0 0 0, 0 1 0 0, 0 0 1 0, 0 0 0 1 and then around to 1 0 0 0 again.
However, if the shift function cycles through all channels I would get
1 0 0 0, 0 1 0 0, 0 0 1 0, 0 0 0 1,0 0 0 0,[10 more 0 0 0 0],0 0 0 0 where there would be no leds on for 12 of the steps.

hc

hc

but it seems to update all channels everytime the tlc_shift command is sent.

Indeed it is.

However, if the shift function cycles through all channels

What you are doing is mixing up the loading of the TLC with the manipulation of the memory to produce the bit pattern you want.
Look at the Set01.pde in the examples folder. That puts every LED on in turn.
Change that loop to:-

for (uint8_t channel = 1; channel <= 12; channel++) {

And it will only do it for the first 12 LEDs before repeating.

I don´t have a set01.pde in my examples folder, would you mind posting it?

hc

The examples folder inside the library folder.

#include <TLC5940LED.h>

#define NUM_TLCS      1

void setup()
{
  Tlc.init(NUM_TLCS);
  Tlc.resetTimers();
}

void loop()
{
  for (uint8_t channel = 1; channel <= NUM_TLCS * 16; channel++) {
    Tlc.clear(); // sets all the channels to zero, but doesn't update
//  Tlc.set(channel, value (0-4095))   this requires a Tlc.update() to set the values.
    Tlc.set(channel, 4095);
    Tlc.update();
    delay(100);
  }
}

ok, thanks, this example isn´t part of my tlc5940 library.

I think we are talking about different things, as I have been through the different examples (basic use, fade, fadescope, circular buffer,animation etc).
I should have explained my whole intention from the start:
I want to create a wave lookup table, then feed first number in the table into led0, shift the channels, feed next number into led, shift the channels, etc.
I am trying to achieve something I use quite often in max/msp, using a simple oscillator to output different waveforms.

hc

It is still the same idea just have a buffer in your sketch with the data in. Then transfer it to the TLC's buffer in what ever fashion you want.

Something like this:-

#include <TLC5940LED.h>
void setup()
{
  Tlc.init(1);
  Tlc.resetTimers();
}

int waveform[12] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} // what ever values you want
int progress = 0;
void loop()
{
  for (uint8_t channel = 1; channel <= 12; channel++) {
    Tlc.clear(); // sets all the channels to zero, but doesn't update
    if(channel > progress) Tlc.set(channel, waveform[channel]);
    Tlc.update();
    delay(100);
  }
  progress ++;
  if(progress > 11) progress = 0;

}

you seem to have a different version of the library than I do.
there is no TLC5940LED.h or TLC.resetTimers.
i have r014 which I think is the latest library.

This method seems to limit the length of the wavetable to the number of channels. What I am looking for is a wavetable which can describe a sine-, sawtooth-, triangle-, square-wave, and would need many more steps.
That is why I thought it would be possible to use the tlc_shifts routine: Read each element of the array into led0, then shift up.

This method seems to limit the length of the wavetable to the number of channels.

Yes that is what I thought you wanted.

What I am looking for is a wavetable which can describe a sine-, sawtooth-, triangle-, square-wave, and would need many more steps.

Sorry I don't understand what you are trying to do. The TLC5940 has 16 channels corresponding to 16 LEDs. I thought you wanted to shift waveform data into only the first 12 in a recirculating pattern.

What do you want to do with this wave table of say 256 entries?

It would be good if you would say what you wanted to do and what it would look like.

If I want to have a certain resolution in the waveform, I would need more elements than the number of channels.
So let´s pretend that this is my wavetable.
{0 200 400 600 800 1000 1200 1400 1600 1800 1600 1400 1200 1000 800 600 400 200}
I am using 4 leds.
So I want the 4 channels to move through the table, as shown below:

This is what I want to be output:
1: 0 200 400 600
2: 200 400 600 800
3. 400 600 800 1000
4. 600 800 1000 1200
5. 800 1000 1200 1400
6. 1000 1200 1400 1600
7. 1200 1400 1600 1800
8. 1400 1600 1800 1600
9. 1600 1800 1600 1400
10. 1800 1600 1400 1200
11. 1600 1400 1200 1000
12. 1400 1200 1000 800
13. 1200 1000 800 600
14. 1000 800 600 400
15. 800 600 400 200
16. 600 400 200 0
17. 400 200 0 200
18. 200 0 200 400

Ok how about this:-

{
int sample = 0;
sample = progress;
for (uint8_t channel = 1; channel <= 12; channel++) {
if(sample => waveformSize) {
sample = 0; }
else
{ sample ++; }
Tlc.set(channel, waveform[sample]);
}
Tlc.update();
delay(100);

progress ++;
if(progress > waveformSize) progress = 0;

}

Not compiled it but it gives you the idea. Just put your waveform starting at some point in the 12 channels of the TLC buffer. Each time round the loop move the starting point on one sample. Handle wrap round when you run out of samples in your waveform.

Try something like this:

  1. put wavetable data into TLC buffer pos 0
  2. update TLC (display data currently in buffer);
  3. push TLC buffer data one step forward
  4. increment wavetable position and repeat from 1

or in

int waveform[12] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
int progress = 0;
void loop() {
  Tlc.set(0, waveform[progress];
  Tlc.update();
  tlc_shiftUp();
  if(++progress == 12)
      progress = 0;
  delay(100);
}

I've not used tlc_shift... but reading the library docs it should work.
The right-most (or top-most) buffer value will 'fall off', or overflow, which is just what we want since we're constantly feeding new data in at the front.
To move the other way just put data at the end of the TLC buffer and shiftDown().
This will work with any number of LEDs as long as they're connected in sequence, e.g. to channels 0-4, or 8-15.

hth,

/m

thank you for the input!

Since my setup is a circular one, I think there would be a rough edge between the first led and the last led using these methods, but that is partly because I am still having problems articulating what I am trying to achieve. I realize my wave-table example is incorrect in a circular setup at least.

I am trying to recreate something I do in max/msp which works very well:
Each channel has its own LFO but with the same waveshape (which can be changed dynamically). The phases of the LFOs are different, so led0 would be at the beginning of the waveform, with the other channels being evenly spaced out over the waveform (this can also easily be changed depending on the number of channels).
The wavetable is then continously scanned, so that each channel goes through the whole wave, but at different offsets. This produces quite nice fadepatterns.

So, trying again with a similar wave table as in my previous attempt:

{0 200 400 600 800 1000 1200 1400 1600 1800 2000 1800 1600 1400 1200 1000 800 600 400 200}

This table has 20 elements, and I want to use 4 channels.
So channel0 would start at wavetable[0], channel1 at wavetable[5], channel2 at wavetable[10],channel3 at wavetable[15].

Then the program would continuously scan through the wavetable, applying the offsets to each channel, producing a sequence of array positions following this pattern:
0 5 10 15
1 6 11 16
2 7 12 17
3 8 13 18
4 9 14 19
5 10 15 20
6 11 16 0
etc

Of course this would look rough with 20 elements, but when you get 100 elements it looks quite smooth.

An obvious problem with this method is that if I want to have many different waveshapes it quickly fills up the memory. I guess I could use the same array and fill it using different equations, but I have to see if this would cause a delay when changing between the wavetables.

A very optimistic/unrealistic alternative would be to store the wavetables in progmem on the tlc5940, and then recall them when needed, but as far as I have understood the progmem, when you recall something it is immediately output, so I wouldn´t be able to somehow copy it over to an array?

hc

Connect LED1 to TLC channel 0, LED2 to channel 4, LED3 to channel 9 and LED4 to channel 14, and use my code above - and change the wavetable data to what you want it to be (of any length).

You will then have exactly the result that you describe.

The TLC5940 has no progmem, but the ATmega does, and you can use it for wavetables if you want.

Simple waveforms such as pulse, triangle and saw could just as well be generated on the fly.

I think you misunderstand.
As I wrote earlier, 4 channels was for illustration purposes, I will more likely use 12 or 24 channels, so your suggestion would be very inefficient.

hc

With the TLC5940 which has 16 channels?
I think you've got some terminology mixed up, or is it me?

yes,
by connecting two tlc5940 together you get up to 32 channels.

hc