ATtiny85 with IRremote and Adafruit Dotstar

Hey everyone!

I’m trying to use an ATtiny85 to build an LED controller for the Adafruit Dotstar LED strips. I plan on using an IR remote to control the colour and animation of the LEDs.

So far I’ve been able to control the LEDs with a sketch using the Adafruit_Dotstar.h library and have also been able to correctly receive IR codes using the IRremote library in a seperate sketch. However, putting these two together into one sketch does not seem to work.

If I comment out all the IR code, the LEDs function as expected. Anyone know what needs to be done to get them to work together?

I’ve also tried using software serial to receive the IR code information from a seperate ATtiny85 and I can confirm that the code is received correctly, however the LEDs do not function.

Any suggestions are appreciated.

Cheers

//#include <IRremote.h>
#include <Adafruit_DotStar.h>
#include <avr/power.h>

#define F_CPU 8000000
#define __AVR_ATtiny85__ 

#define RED     0xFF0000
#define RED2    0xFF4000
#define ORANGE  0xFF8000
#define GOLD    0xFFC000
#define YELLOW  0xFFFF00

#define GREEN   0x00FF00
#define GREEN2  0x00FF80
#define CYAN    0x00FFFF
#define BLGR    0x00C0C0
#define BLGR2   0x008080

#define BLUE    0x0000FF
#define BLUE2   0x4000FF
#define PURPLE  0x8000FF
#define MAGENTA 0xC000FF
#define PINK    0xFF00FF

#define WHITE   0x808080

#define NUMPIXELS   72

#define DATAPIN     0
#define CLOCKPIN    2
#define RX          3
#define TX          4

//IRrecv irrecv(RECV_PIN);
//decode_results results;
Adafruit_DotStar strip(NUMPIXELS, DATAPIN, CLOCKPIN, DOTSTAR_BGR);

uint16_t hue = 0;
uint8_t sat = 255;
uint8_t val = 255;
uint32_t rgbcolour = WHITE;
uint8_t MODE = 1;

void setup() {
  #if defined(__AVR_ATtiny85__) && (F_CPU == 8000000L)
  clock_prescale_set(clock_div_1); // Enable 8 MHz on ATtiny85
  #endif

  pinMode(CLOCKPIN, OUTPUT);
  pinMode(DATAPIN, OUTPUT);

  strip.begin();
  strip.show();

  MODE = 5;
}

void loop() {
  /*
  if (irrecv.decode(&results))  {
    if ((MODE == 0) && (results.value == 0xF7C03F))  {
      MODE = 1;
    } else if (MODE > 0)  {
      switch(results.value)  {
        case 0xF700FF:
          // brightness up
          break;
        case 0xF7807F:
          // brightness down
          break;
        case 0xF740BF:
          MODE = 0;           // Turn off LED strip
          break;
        case 0xF720Df:
          MODE = 1;
          rgbcolour = RED;
          break;
        case 0xF7A05F:
          MODE = 1;
          rgbcolour = GREEN;
          break;
        case 0xF7609F:
          MODE = 1;
          rgbcolour = BLUE;
          break;
        case 0xF7E01F:
          MODE = 1;
          rgbcolour = WHITE;
          break;
        case 0xF710EF:
          MODE = 1;
          rgbcolour = RED2;
          break;
        case 0xF7906F:
          MODE = 1;
          rgbcolour = GREEN2;
          break;
        case 0xF750AF:
          MODE = 1;
          rgbcolour = BLUE2;
          break;
        case 0xF7D02F:
          MODE = 2;           // Swtich to FLASH
          break;
        case 0xF730CF:
          MODE = 1;
          rgbcolour = ORANGE;
          break;
        case 0xF7B04F:
          MODE = 1;
          rgbcolour = CYAN;
          break;
        case 0xF7708F:
          MODE = 1;
          rgbcolour = PURPLE;
          break;
        case 0xF7F00F:
          MODE = 3;           // Switch to STROBE
          break;
        case 0xF708F7:
          MODE = 1;
          rgbcolour = GOLD;
          break;
        case 0xF78877:
          MODE = 1;
          rgbcolour = BLGR;
          break;
        case 0xF748B7:
          MODE = 1;
          rgbcolour = MAGENTA;
          break;
        case 0xF7C837:
          MODE = 4;           // Switch to FADE
          break;
        case 0xF728D7:
          MODE = 1;
          rgbcolour = YELLOW;
          break;
        case 0xF7A857:
          MODE = 1;
          rgbcolour = BLGR2;
          break;
        case 0xF76897:
          MODE = 1;
          rgbcolour = PINK;
        case 0xF7E817:
          MODE = 5;           // Switch to SMOOTH
          break;
        default:
          break;
      }
    }
  }*/
  
  switch(MODE)  {
    case 0:
      strip.clear();
      strip.show();
      break;
    case 1:
      strip.fill(strip.gamma32(WHITE));
      strip.show();
      break;
    case 2:
      strip.clear();
      strip.show();
      delay(500);

      strip.fill(strip.gamma32(rgbcolour));
      strip.show();
      delay(500);
      break;
    case 3:
      strip.clear();
      strip.show();
      delay(50);

      strip.fill(strip.gamma32(rgbcolour));
      strip.show();
      delay(50);
      break;
    case 4:
      rgbcolour = strip.gamma32(strip.ColorHSV(hue, sat, val));
      strip.fill(rgbcolour);
      strip.show();

      hue += 128;
      break;
    case 5:
    // rememeber to set hue to 0
      for(uint8_t i = 1; i < NUMPIXELS; i++)  {
        strip.setPixelColor((NUMPIXELS-i), strip.getPixelColor(NUMPIXELS-i-1));
        rgbcolour = strip.gamma32(strip.ColorHSV(hue, sat, val));
        strip.setPixelColor(0, rgbcolour);
        
        hue += 910;
        if (hue == 65520)  {
          hue = 0;
        }
      }

      strip.show();
      break;
    default:
      strip.clear();
      strip.fill(strip.gamma32(WHITE));
      strip.show();
      break;
  }
  
}

Look into the source code for those libraries. Do they use the same timer?

Looking into the source code for the Adafruit_Dotstar.h library and cpp files, I’d expect clock/timer setups to be contained within serial setup functions. However these use the USI inbuilt counter according to the Datasheet and seen in the code segment below.

/*!
  @brief   Initialize 'soft' (bitbang) SPI. Data and clock pins are set
           to outputs.
*/
void Adafruit_DotStar::sw_spi_init(void) {
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
#ifdef __AVR__
  dataPort = portOutputRegister(digitalPinToPort(dataPin));
  clockPort = portOutputRegister(digitalPinToPort(clockPin));
  dataPinMask = digitalPinToBitMask(dataPin);
  clockPinMask = digitalPinToBitMask(clockPin);
  *dataPort &= ~dataPinMask;
  *clockPort &= ~clockPinMask;
#else
  digitalWrite(dataPin, LOW);
  digitalWrite(clockPin, LOW);
#endif
}

Also seen in the SPI end function.

/*!
  @brief   Stop 'soft' (bitbang) SPI. Data and clock pins are set to inputs.
*/
void Adafruit_DotStar::sw_spi_end() {
  pinMode(dataPin, INPUT);
  pinMode(clockPin, INPUT);
}

#ifdef __AVR_ATtiny85__

// Teensy/Gemma-specific stuff for hardware-half-assisted SPI

#define SPIBIT                                                                 \
  USICR = ((1 << USIWM0) | (1 << USITC));                                      \
  USICR =                                                                      \
      ((1 << USIWM0) | (1 << USITC) | (1 << USICLK)); // Clock bit tick, tock

Going through the source files for IRremote.h on the other hand, I’m confused as to which timer is actually being used as I can see segments of code defined for both timers, just a matter of which is actually being run. I know mills() and delay() run on TINY1 by default so that would lead me to believe that IRremote is using TINY0 (as delay() works fine in my code for LED flash and strobe animations). However, I’m not too sure if IRremote is changing their definitions and switching them over to a different timer. I’ve attached the source files for these, definitions for these are in the IRremoteBoardDefs.h file.

Regardless, there shouldn’t be a timer conflict as the Adafruit library doesn’t use timers. So I’m not too sure what’s wrong.

Adafruit_DotStar.h (9.99 KB)

Adafruit_DotStar.cpp (23.5 KB)

ir_NEC.cpp (6.52 KB)

irReceive.cpp (18 KB)

IRremote.cpp (8.4 KB)

IRremote.h (18.5 KB)

IRremoteBoardDefs.h (29.8 KB)

IRremoteInt.h (4.59 KB)