# Weird behaviour of Attiny85 while producing RC servo output

#### sumeryamaner

Joined May 29, 2017
109
I am designing a small circuit for use in twin engine RC aircraft. Let me explain it a little bit first.
As you may already know, in twin engine RC aircraft we must use two separate receiver channels to be able to fine tune each engine and to prevent thrust difference during flight.
Sometimes we run out of available receiver channels and look for solutions to combine similar channels in one channel.
Now my module is a simple servo sync module. It gets the receiver signal from CH.3 (usually the throttle channel) and lets you adjust the high and low end positions of the throttle servo using two multiturn potentiometers. Every engine will have it's own controller and this way only one channel of the receiver will be occupied.
Now, this is the PCB (sorry, I do not have a schematic). The signal from the receiver (consisting of 1000 - 2000 microsecond pulses repeating every 20 mS) go to the base of a 2N2222 and the collector of the 2N2222 is connected to the Attiny85 input. The emitter is of course connected to ground and the internal pullup resistor of the Attiny85 will be activated by the code. This setup guarantees that even puses of 2.5V are recognized by the microcontroller (some modern RC receivers work on very low voltages). This setup also leads to an inverted signal at the microcontroller input.
The microcontroller reads the pulse lenght, reads the two potentiometers and computes the necessary output signal. It then outputs a PWM pulse to the servo.
Attiny85 has been programmed to work on the internal oscillator at 8MHz.

I have planned subroutines to do the individual tasks.

This is the beginning of the code and there is nothing special.

Code:
#define high_end_read A2
#define pwm_pin PB0
#define servo_pin PB1

int inpwm;
int outpwm;
int high_value;
int low_value;
int temp;
int tmph;
int tmpl;

void setup()
{
pinMode(pwm_pin, INPUT_PULLUP);
pinMode(servo_pin, OUTPUT);
}
Now the main loop...

Code:
void loop()
{
outpwm = calcPWM();
servoout(outpwm);
}
That means there are three subroutines...
The first is to read the incoming signal:

Code:
int readPWM(int q)
{
temp = pulseIn(q, LOW);
if(temp < 800) return 0;
if(temp > 2200) return 0;
return temp;
}
The second is to calculate the output signal according to the readings of the two potentiometers.

Code:
int calcPWM()
{
tmpl = map(low_value, 0, 1023, 1000, 1500);
tmph = map(high_value, 0, 1023, 1500, 2000);
int x = map(inpwm, 1000, 2000, tmpl, tmph);
return x;
}
And finally the third is to produce the servo signal

Code:
void servoout(int z)
{
cli();
digitalWrite(servo_pin, HIGH);
delayMicroseconds(z);
digitalWrite(servo_pin, LOW);
sei();
}
The cli() and sei() instruction are there to prevent servo jitter.

Now, this is a very straightforward code. Of course it can be optimized but I don't think that for such a simple task one should try to optimize it further.

Now my problem...
This code didn't work as expected. I have been getting only 160 microsecond pulses at the output.
Then I erased almost everything and tried to output the input signal without modification. That means I used;
"servoout(inpwm);" instead of "servoout(outpwm);". Interestingly I kept getting only about 160 microsecond pulses at the output.
Later I decided to cancel all subroutines and put everything into the "loop".

Code:
void loop()
{
cli();
inpwm = pulseIn(pwm_pin, LOW);
if (inpwm > 0)
{
tmpl = map(low_value, 0, 1023, 1000, 1500);
tmph = map(high_value, 0, 1023, 1500, 2000);
outpwm = map(inpwm, 1000, 2000, tmpl, tmph);
digitalWrite(servo_pin, HIGH);
delayMicroseconds(outpwm);
digitalWrite(servo_pin, LOW);
}
sei();
}
Now it works without any problems!

Summary:
If I put the servo signal output routine in a subroutine, there is a serious timing problem of the output signal. If I write the exact same code into the main loop, there are no problems.

Any idea about what I did wrong?