Go Down

Topic: ATtiny85 with SoftwareSerial and PinChange interrupts (Read 398 times) previous topic - next topic

sancho_sk

Hi all.
I am working on a project with ATtiny85.
The chip is checking multiple pins for pin change.
Within the code for ISR(PCINT0_vect) I am reading the port status and finding out what to do based on which pin actually changed.
This works OK.
Now I need to add debug function with SoftwareSerial.
The problem here is that it uses its own handler for ISR(PCINT0_vect).
As the tiny has no other interrupts, I have a problem.
What I did is I edited the library (renamed it to SoftwareSerialInt.h+cpp) and removed the actual code that sets the interrupt.
The idea here is to add additional if-then statement to my original handler and in case the pin for SoftwareSerial changed, call it's handle_interrupt() function.
And this is the problem.
I made a code like this:
Code: [Select]

SoftwareSerialInt SerialI(M1, M2);
...
#if defined(PCINT0_vect)
ISR(PCINT0_vect)
{
  if (SerialI.isListening())
  {
    SerialI.handle_interrupt();
  } else {
    // my own interrupt here
  }
}
#endif

But the compiler complains
Code: [Select]
attiny85.ino:121: undefined reference to `SoftwareSerialInt::handle_interrupt()'
collect2: error: ld returned 1 exit status
Error compiling.

This clearly states that the class did not publicly announced the handle_interrupt function.
However, when reading the .h file, I can see:
Code: [Select]
class SoftwareSeriapInt : public Stream
...
public:
...
// public only for easy access by interrupt handlers
  static inline void handle_interrupt();

I have no idea what am I doing wrong. Can someone, please, point me out to some information how can I actually do the decision before calling the library?
Thanks!

DrAzzy

Here's another approach:

Use my ATTiny core. It has a built-in software serial named Serial (like the real serial on boards that have hardware serial) that uses the analog comparator interrupt, not a PCINT). TX is AIN0 (pin 0), RX is AIN1 (pin 1). Then use "Serial" instead of creating a software serial instance, and you can use PCINT''s freely.

https://github.com/SpenceKonde/ATTinyCore (can be installed manually, or using the board manager json url in my sig)
ATtiny core for 841+1634+828 and x313/x4/x5/x61/x7/x8 series Board Manager:
http://drazzy.com/package_drazzy.com_index.json
ATtiny breakouts (some assembled), mosfets and awesome prototyping board in my store http://tindie.com/stores/DrAzzy

sancho_sk

Cool idea. However the pins 0 and 1 are also the only ones I can use for PWM :(
Have to read if I can use other pins for PWM, too...

DrAzzy

Cool idea. However the pins 0 and 1 are also the only ones I can use for PWM :(
Have to read if I can use other pins for PWM, too...
My core gives you one more PWM pin, on pin 3 I think (unfortunately, those are the only three pins we can get PWM out of :-/ ). ATTiny85 cores that only have two PWM outputs are pretty widespread - timer1 on the '85 *is* kinda strange.
ATtiny core for 841+1634+828 and x313/x4/x5/x61/x7/x8 series Board Manager:
http://drazzy.com/package_drazzy.com_index.json
ATtiny breakouts (some assembled), mosfets and awesome prototyping board in my store http://tindie.com/stores/DrAzzy

sancho_sk

Perhaps I can live with 1 PWM only for driving the motor correctly - I have to test it using 328 and then get back to Tiny85...

sancho_sk

YES!
It works with single PWM!!!

I just had to slightly modify the original dual-PWM code from
Code: [Select]
void pwmOut(int out) {
  if (out < 0) {
    analogWrite(M1, 0);
    analogWrite(M2, abs(out));
  }
  else {
    analogWrite(M1, abs(out));
    analogWrite(M2, 0);
  }
}

to
Code: [Select]
void pwmOut(int out) {
  out = out * moveCoef;
  if (out < 0) {
    digitalWrite(M1, 0);
    analogWrite(M2, abs(out));
  }
  else {
    digitalWrite(M1, 1);
    analogWrite(M2, 255 - abs(out));
  }
}

So, now I have to learn how to use the PWM on PB4 correctly and set the maximum frequency and I am good to go :)
Thanks for now - seems like I'll have a long night ahead of me :)

DrAzzy

Nice! Glad it's working - yeah, timer1's a little weird, doesn't work quite like other timers. You can, for example, change the prescaler to any factor of two instead of every-few-powers-of-2 like most AVR timers, and you can clock it off the PLL if you need it running at higher speed.
ATtiny core for 841+1634+828 and x313/x4/x5/x61/x7/x8 series Board Manager:
http://drazzy.com/package_drazzy.com_index.json
ATtiny breakouts (some assembled), mosfets and awesome prototyping board in my store http://tindie.com/stores/DrAzzy

sancho_sk

Nice! Glad it's working - yeah, timer1's a little weird, doesn't work quite like other timers.
Well, I have another problem.
After days of trial-and-error, I'm stuck.
I made a simple code like this:
Code: [Select]
/*
 * Goal: Have DC motor with encoder
 * driven by ATtiny85 and Step and Direction
 * from RAMPS
 * However, when starting, I want to determine a "DEBUG"
 * condition and wnable serial port to set PID and parameters
 * like enable (minimum and maximum search.
 *
 * Tiny setup:
 * 1 - PB5 - Encoder A
 * 2 - PB3 - Encoder B
 * 3 - PB4 - DC PWM
 * 4 - GND
 * 5 - PB0 - Step / Serial RX
 * 6 - PB1 - Direction / Serial TX
 * 7 - PB2 - DC direction
 * 8 - VCC
 */

// first - test the PB4 PWM direction pins
#define M1  4
#define M2  2

void setup() {
  // PWM setup according
  // http://matt16060936.blogspot.ch/2012/04/attiny-pwm.html
  DDRB |= 1<<DDB4;  // set the PB4 as output
  DDRB |= 1<<DDB2;  // set the PB2 as output (direction pin)
  TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
          // set the timers COM0A0 for enabling
          // timers and the rest for timer B
          // without COM0A0 the Timer1 will not work
  TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
          // this tells not to use pins OC0B and OC1A
          // and use no prescaler
  GTCCR = 1<<PWM1B | 2<<COM1B0;
          // enable OC1B (PB4)
          // and clears it to bottom
  // I'll use OCR1B = x to set the PWM value

  Serial.begin(115200);
  Serial.println("Setup is over");
}

void loop() {
  for (int i = 0; i < 256; i++) {
    OCR1B = i;
    delay(10);
    }
  Serial.println("Loop over, restarting");
}

The problem here is - if I don't setup the PWM for PB4, the serial works OK.
If I do set it up, the PWM works OK, but the serial does not :(
I suspect that by messing with the PWM I've set something wrong for the analogue comparator, I just have no idea what :(
Can someone, please, assist?

sancho_sk

Stupid me - simple typo :(
Instead of setting the COM0A0 I've erased it :(
By changing the line from
Code: [Select]
 TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
to
Code: [Select]
 TCCR0A = 1<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
It works.
I've spent 3 nights on this :(

sancho_sk

Well, thanks for the suggestion, but this finally does not work.
The problem here is the codespace - when I include the serial processing routines, I run out of the 8kB available.
:(

Go Up