SoftwareSerial problem on the Attiny85

Hi Everyone,

I’ve been having issues using SoftwareSerial with this software pwm code (very slightly modified) on the attiny85. My circuit set up is as follows:

        |1 8| - 5V
   Tx - |2 7| - 
B LED - |3 6| - G LED
  GND - |4 5| - R LED

The micro is running at 8MHz internal, using this core. I’m using an Arduino UNO (Arduino ISP) to flash the chip, but once done, the UNO is no longer connected except for providing power and ground. I’m using a standard USB - serial device to receive the output from the micro.

My full code is:

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <SoftwareSerial.h>

#define CHMAX 3 // maximum number of PWM channels
#define PWMDEFAULT 0x00 // default PWM value at start up for all channels

#define RED_CLEAR (pinlevelB &= ~(1 << RED)) // map RED to PB0
#define GREEN_CLEAR (pinlevelB &= ~(1 << GREEN)) // map GREEN to PB1
#define BLUE_CLEAR (pinlevelB &= ~(1 << BLUE)) // map BLUE to PB4

//! Set bits corresponding to pin usage above
#define PORTB_MASK  (1 << PB0)|(1 << PB1)|(1 << PB4)

#define set(x) |= (1<<x) 
#define clr(x) &=~(1<<x) 
#define inv(x) ^=(1<<x)

#define RED PB0
#define GREEN PB1
#define BLUE PB4
#define LED_PORT PORTB
#define LED_DDR DDRB

void delay_ms(uint16_t ms);
void init();

unsigned char compare[CHMAX];
volatile unsigned char compbuff[CHMAX];

int r_val = 0x00;
int g_val = 0x55;
int b_val = 0xAA;
float dim = 1;

SoftwareSerial mySerial(-1, 3);

int main() {
  init();
  
  int r_dir = 1;
  int g_dir = 2;
  int b_dir = 4;

  mySerial.println("Testing");
  
  for(;;) {
    if (r_val > 254 - 1) {
      r_dir = -1;
    }
    if (r_val < 1 + 1) {
      r_dir = 1;
    }

    if (g_val > 254 - 3) {
      g_dir = -2;
    }
    if (g_val < 1 + 3) {
      g_dir = 2;
    }

    if (b_val > 254 - 4) {
      b_dir = -4;
    }
    if (b_val < 1 + 4) {
      b_dir = 4;
    }
    
    r_val += r_dir;
    g_val += g_dir;
    b_val += b_dir;

    compbuff[0] = r_val;
    compbuff[1] = g_val;
    compbuff[2] = b_val;

    delay_ms(50);
  }
}


void delay_ms(uint16_t ms) {
  while (ms) {
    _delay_ms(1);
    ms--;
  }
}

void init(void) {

  mySerial.begin(9600);
  
  // set the direction of the ports
  LED_DDR set(RED);
  LED_DDR set(GREEN);
  LED_DDR set(BLUE);
  
  unsigned char i, pwm;

  CLKPR = (1 << CLKPCE);        // enable clock prescaler update
  CLKPR = 0;                    // set clock to maximum (= crystal)

  pwm = PWMDEFAULT;

  // initialise all channels
  for(i=0 ; i<CHMAX ; i++) {
    compare[i] = pwm;           // set default PWM values
    compbuff[i] = pwm;          // set default PWM values
  }

  TIFR = (1 << TOV0);           // clear interrupt flag
  TIMSK = (1 << TOIE0);         // enable overflow interrupt
  TCCR0B = (10 << CS00);         // start timer, no prescale

  sei();
}


ISR (TIM0_OVF_vect) {
  static unsigned char pinlevelB=PORTB_MASK;
  static unsigned char softcount=0xFF;

  PORTB = pinlevelB;            // update outputs
  
  if(++softcount == 0){         // increment modulo 256 counter and update
                                // the compare values only when counter = 0.
    compare[0] = compbuff[0];   // verbose code for speed
    compare[1] = compbuff[1];
    compare[2] = compbuff[2];

    pinlevelB = PORTB_MASK;     // set all port pins high
  }
  // clear port pin on compare match (executed on next interrupt)
  if(compare[0] == softcount) RED_CLEAR;
  if(compare[1] == softcount) GREEN_CLEAR;
  if(compare[2] == softcount) BLUE_CLEAR;
}

If I run the code as above, the leds cycle through the colours as expected, but they also flash quickly on and off. The serial output is garbage.

If I disable the interrupt (comment out sei()) the leds no longer light (obviously) but the serial output works correctly.

If remove the SoftwareSerial stuff, the leds cycle through the colours as expected, and no longer flash.

What have I tried? Everything I can think of, but none of these have had any effect:

  • Using this core instead
  • The arduino provides power and ground to the micro. The USB-serial device shares the same ground and power, so no issues there
  • Changing the clock frequency to 1MHz
  • Calibrating the timing on the chip by using an oscilloscope and setting OSCCAL
  • Changing the pin assignments in many different ways
  • Removing the Tx connection, problem persists so must be in software
  • Changing the baud rate
  • Switching the timer over to use timer1 instead of timer0 - the flashing changed in frequency otherwise the situation is the same

What do I do now? Have I missed something obvious? On the plus side, I now know far more about how the timers and interrupts work on this micro!

Thank you.