Using Servo8Bit library causes ATTiny85 to hang

Hi All,

I’m actually working on a solution to forward servo signals but under special circumstances the forwarding must be stopped and manual generated servo commands must be send to the servo.

I’m using a ATTiny85 working on 8MHz connected via ArduinpISP using an Arduino UNO R3.

For testing I wrote the following code:

//#include "Servo8Bit.h"
//Servo8Bit  Servo1;

int led = 3;

volatile  int       nDelay = 1000;
volatile  uint8_t  LastInterruptState	= PINB;  //  ATTiny84 : PINA;
volatile uint32_t nLastSpeedPositionChange  = micros();

// the setup routine runs once when you press reset:
void setup() 
{    
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);     
  pinMode(1, OUTPUT);

  digitalWrite( led, HIGH);
  delay(2000);
  digitalWrite(led, LOW);
/* ATTiny84
     PCMSK0 |= ( 1<<PCINT4);
      GIMSK |= (1 << PCIE0);
*/
//  ATTiny85
     PCMSK |= ( 1<<PCINT0);
      GIMSK |= (1 << PCIE);
 interrupts();

}

// the loop routine runs over and over again forever:
void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(nDelay);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(nDelay);               // wait for a second
}

void SpeedPositionInterrupt() 
{
  unsigned long  nMicros  = micros();
  
  unsigned long nDifference  = nMicros - nLastSpeedPositionChange;
  
  if ( (nDifference > 2000 ) || ( nDifference < 900))
  {
    //Hier passiert nix, denn es handelt sich um den "Leerlauf (LOW)
    
  }
  else

  {
    if ( nDifference < 1300 )
    nDelay = 500;
    else
    {
      if ( nDifference < 1600 )
      nDelay = 1000;
      else
      nDelay = 2000;
    }

//Servo1.writeMicroseconds( nDifference );
  }   
  nLastSpeedPositionChange = nMicros;
}

ISR( PCINT0_vect )
{
	uint8_t	PinState	= PINB;  //  ATTiny84  PINA;
	uint8_t	PinChanges	= PinState ^ LastInterruptState;

digitalWrite(1, digitalRead(0));
	if (PinChanges & (1<<PCINT0))
		SpeedPositionInterrupt();

	LastInterruptState	= PinState;
}

The servo signal coming from the RC sender is read by a pin change interrupt on pin 0 and on each signal change the corresponding signal on the outgoing pin 1 is switched. To get a control if it’s working, a LED is attached to pin3 if the servo is in the middle, the LED blinks in a 1 second interval. If I set the servo to “up” on teh sender, the LED blinks in 2 second intervals, if I put it down, the LED blinks in 0.5 seconds interval.

Listening to the servo signal and forwarding it works perfect.

Now I want to activate the manual servo commands… and the problems are coming up.

If I insert the

#include "Servo8Bit.h"

The uploaded code hangs immediatly. I added a LED ON/OFF in the setup() to see if the setup is started, but the LED stays dark. If I comment out the include statement, it’s working again.

It’s strange, because at that moment no Servo8Bit object is defined nor attached. Only the #include directive is set.

Than I suggested it might have to do with the timer handling, so I commented the complete timer handling code out in the libryry, but it’s still hanging.

I already searched here in the forum and I tested with Timer0 and Timer1, I tested with the alternative delay functions, the “avr/power.h” include, etc. but it never worked.

The used servo has an own power supply with the ground connected to the chip circuit.

Do you have any hints what might be the reason for this ?

Many thanx in advance for your comments and thoughts.

Greetinx
gismow

How does this behave…

#include <Servo8Bit.h>

const uint8_t MyTestLEDPin = 4;  // Change this to the pin number with the test LED

void setup( void )
{
  pinMode( MyTestLEDPin, OUTPUT );
}

void loop( void )
{
  digitalWrite( MyTestLEDPin, ! digitalRead( MyTestLEDPin ) );
  delay( 100 );
}

Same behaviour. Using your code with include directive is hangs, LED is dark. If I remove the include directive, the LED blinks.

Do the servo's draw too much current? or are they not connected?

please post a link to the Servo8Bit.h library?

The servos are powered via an external battery. But at the moment, no servo is connected. I only have setup the LED on pin 3.

I made a change to the Timer function, because in on thread I've read that someone found out that the timer(s) are active before the first servo was attached.

//=============================================================================
// FUNCTION:    void timerCompareMatchISR()
//
// DESCRIPTION: Interrupt service routine for timer0 compare A match.
//              This is where the magic happens.
//
// INPUT:       Nothing
//
// RETURNS:     Nothing
//=============================================================================
void ServoSequencer::timerCompareMatchISR()
{
    if ( ( servoArrayIsInited == false ) || ( timerIsSetup == false ))
        return; //  The servoRegistry structures are not yet initialized

The variables of the servoSequencer class were all set to 'volatile', because some of them are used in the timer method

The library is downloaded form https://github.com/fri000/Servo8Bit

The core and board informations were downloaded from https://arduino-tiny.googlecode.com/files/arduino-tiny-0100-0017.zip I'm working wth the ATTiny 8MHz. The bootloader is installed without any issues.

These are the used board settings:

attiny85at8.name=ATtiny85 @ 8 MHz (internal oscillator; BOD disabled)

The following do NOT work...

attiny85at8.upload.using=avrispv2

attiny85at8.upload.using=Pololu USB AVR Programmer

The following DO work (pick one)...

attiny85at8.upload.using=arduino:arduinoisp

attiny85at8.upload.protocol=avrispv2

attiny85at8.upload.using=pololu

attiny85at8.upload.maximum_size=8192

Default clock (slowly rising power; long delay to clock; 8 MHz internal)

Int. RC Osc. 8 MHz; Start-up time PWRDWN/RESET: 6 CK/14 CK + 64 ms; [CKSEL=0010 SUT=10]; default value

Brown-out detection disabled; [BODLEVEL=111]

Preserve EEPROM memory through the Chip Erase cycle; [EESAVE=0]

attiny85at8.bootloader.low_fuses=0xE2 attiny85at8.bootloader.high_fuses=0xD7 attiny85at8.bootloader.extended_fuses=0xFF attiny85at8.bootloader.path=empty attiny85at8.bootloader.file=empty85at8.hex

attiny85at8.build.mcu=attiny85 attiny85at8.build.f_cpu=8000000L attiny85at8.build.core=tiny

Does that help ?

I got that damned beast !!!

It seems that the design of the library causes the hang. The ServoSequencer and several variables are implemented as static structures and variables.

Now I modified the library to use standard classes (no static stuff) and … uppppsssssss … it worked on the first test.

Please find attached my modified code for the library, I renamed it to “Servo8Bit2” so that tests with both libryries are still possible.

May be you can have a look at my code, I couldn’t find a reason why static is not working but my solution does.

Your comments and thoughts are much appreciated.

Servo8Bit2.zip (9.55 KB)

A quick look at the lib:

  • a lot of unneeded comments // those that explain nothing, or tell the obvious should be removed. (the less a programmer must read the easier a lib gets)
    // obvious comments take time and must be kept in sync with the code etc…

  • a lot of empty else cases // OK compiler will fix this

  • private(?) helper function to simplify the code in quite some functions. This test is done 5 times, think it even may have its value as public function.

bool ServoSequencer::valid(uint8_t servoNumber)
{
  return (servoNumber < kMaxNumberOfServosSupported) && servoRegistry[servoNumber].slotOccupied;
}

There is a bug here (I think)

int8_t Servo8Bit2::attach(uint8_t pin)
{	
	//Do we need to register with the servo sequencer?
    if (myServoNumber == invalidServoNumber)
	{
		//Yep, we do, so register and save our servo number.
		myServoNumber = this->pServoSequencer->registerServo();
		if (myServoNumber == invalidServoNumber)
		{
			//We got an invalid servo number. That means the servo sequencer is full and can't handle any more servos.
			return 0; <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 0 seems to me a valid servoNumber!
		}
	}
...
  • lots of magic numbers in the code esp those referring to timeticks etc ==> #defines

A good refactor can easily bring the .cpp file down 10-20% without loosing any quality. Binary size will not shrink as much as most things to remove is “air”.

The .h file looks better.

  • should include a version number e.g. #define SERVO_LIB “V0.3”

All that said, the base of the lib looks quite good and well worked out.

sofar my 2 cents