Problem with softwareserial on ATTint84

137 views
Skip to first unread message

Dave

unread,
Sep 28, 2021, 10:52:27 AM9/28/21
to devel...@arduino.cc

Hi, I'm hoping that one of you gurus can help me with this ...

I have an ATTiny84 that is controlling a 9g servo and a small stepper
motor - the ATTiny84 is receiving commands via "SoftwareSerial.h" at
9600 baud and is "receive ONLY", nothing is ever sent.

The servo is using hardware PWM on pin 8 using "Servo.h"
The stepper uses my code in "loop" as its not a standard stepper.

What I find is that the servo jumps around when the serial link is
active, it seems unaffected if the stepper is running as long as the
serial link is idle.

Any idea of the cause ???

Is there a better alternative than SoftwareSerial ??

Regards,
Dave


Bob McHugh

unread,
Sep 28, 2021, 4:08:28 PM9/28/21
to devel...@arduino.cc
Maybe interrupt issues when the serial port is running? I mean softserial
uses the hardware port and remaps it, right?

I had similar issues with running WIFI and trying to use the FastLED
library, I couldn't ever get the first LED section correct because an
interrupt would happen from the WIFI serial and screw up the timing on the
LED strip.

This group should be able to tell you right off if there is an easier way to
control the PWM than in the loop() section. I'm assuming you need pretty
specific timing values, right?

They are going to want to see your code by the way.



BobbyMac
--
You received this message because you are subscribed to the Google Groups
"Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to developers+...@arduino.cc.
To view this discussion on the web visit
https://groups.google.com/a/arduino.cc/d/msgid/developers/DB7PR07MB47488C4DA
80DE4D3524E1501D3A89%40DB7PR07MB4748.eurprd07.prod.outlook.com.

Dave

unread,
Sep 28, 2021, 7:31:53 PM9/28/21
to devel...@arduino.cc
I am trying to come up with a simple case that shows the problem.

Servo.h uses the hardware PWM AFAIK so interrupts shouldnt affect it ?

Unless SoftwareSerial stamps on the PWM register ...

Dave

Hart, Mikal N

unread,
Sep 28, 2021, 7:56:45 PM9/28/21
to devel...@arduino.cc

Dave,

 

The original Arduino Servo library used PWM on AVR devices to drive the servos, but it was replaced (2012?) with the modern library, which uses timers.  The new library provides the advantage of allowing any pin to control a servo—the old one was limited, I think, to only pins 8 and 9—but introduced the sort of jitter I think you're seeing, because Servo and SoftwareSerial have competing interrupt/timer needs.

 

There's a library floating around called PWMServo that’s basically just a repackaging of the old library.  I don’t know whether it would even work with ATTiny, but it might provide some reference for you.

 

Mikal Hart

--

You received this message because you are subscribed to the Google Groups "Developers" group.

To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.

Ken Perry

unread,
Sep 28, 2021, 8:43:07 PM9/28/21
to devel...@arduino.cc
You might want to look at this page. It might have a method for you.

https://tutorial.cytron.io/2015/09/04/softwareserial-conflicting-servo-interrupt/

-----Original Message-----
From: devel...@arduino.cc <devel...@arduino.cc> On Behalf Of Dave
Sent: Tuesday, September 28, 2021 7:32 PM
To: devel...@arduino.cc
--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.
To view this discussion on the web visit https://groups.google.com/a/arduino.cc/d/msgid/developers/DB7PR07MB47484F1DAE53005F90A6B50BD3A89%40DB7PR07MB4748.eurprd07.prod.outlook.com.

Bob McHugh

unread,
Sep 28, 2021, 9:33:06 PM9/28/21
to devel...@arduino.cc
You could also look at the data sheet, the External interrupt (EXT_INT0) is
handled differently I believe.

I also know that on many processors I have worked on they sometimes have a
interrupt priority setup, a sort of cascading master-slave assignment.

Also, a low level interrupt on INT0 is detected asynchronously on the Tiny84
which allows you to use it to wake-from-sleep conditions. That may give
some insight into a priority as compared to the software serial timing
issues.

The datasheet has some interesting information on interrupt handling if that
is the guess made to this point. So it's worth reading in any case.

http://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny24A-44A-84A-DataSheet-
DS40002269A.pdf


Or, I could just be full of shit, it's hard to know at this point in life...
https://groups.google.com/a/arduino.cc/d/msgid/developers/008301d7b4ca%24f64
43e60%24e2ccbb20%24%40blinksoft.com.

Dave

unread,
Sep 29, 2021, 12:15:10 AM9/29/21
to devel...@arduino.cc
Many thanks guys

Dave

Jon Perryman

unread,
Sep 29, 2021, 2:46:19 AM9/29/21
to devel...@arduino.cc
Try using a high baud rate like 115200 that is supported by your chipset. It's been a very long time but I seem to recall a blocking problem in software serial. By using high baud rates, you greatly reduce the time delay. Both PWM and serial can be sensitive to delays or blocking depending on your needs. 

--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.

Michael Miller

unread,
Sep 29, 2021, 5:20:55 AM9/29/21
to devel...@arduino.cc
GitHub. Makuna/PwmServo, but it was written for 16mhz only, and I haven't touched in 7 years.

Dave

unread,
Sep 29, 2021, 11:17:52 AM9/29/21
to devel...@arduino.cc

Sadly PWMServo doesn't support the ATTiny series and converting it to do so is way beyond my abilities :-(

I'm sure that using the hardware PWM ability of the ATTiny84 would solve my problem.

Dave.

Paul Stoffregen

unread,
Sep 29, 2021, 11:30:31 AM9/29/21
to devel...@arduino.cc
On 9/29/21 8:17 AM, Dave wrote:
>
> Sadly PWMServo doesn't support the ATTiny series and converting it to
> do so is way beyond my abilities :-(
>

Have you even tried?

I glanced quickly at the ATtiny84 and ATmega328P datasheet Register
Summary tables.  Both chips appear to have exactly the same timer1
registers.  Odds are very good the code will just work if you get it to
compile.

A first extremely obvious attempt would involve just add another #elif
defined() in PWMServo.h for the chip you're using and whatever pin
numbers its 2 PWM pins are for the 16 bit timer.

#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) // Arduino
  #define SERVO_PIN_A 9
  #define SERVO_PIN_B 10
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //
Arduino Mega
  #define SERVO_PIN_A 11
  #define SERVO_PIN_B 12
  #define SERVO_PIN_C 13




Dave

unread,
Sep 29, 2021, 1:28:34 PM9/29/21
to devel...@arduino.cc
I wanted to try the "NeoSWSerial" library but although it says that it
supports ATTinyx4 (in the Readme file) it fails with :-

C:\Users\Bob\Documents\Arduino\libraries\NeoSWSerial\src\NeoSWSerial.cpp:
In member function 'void NeoSWSerial::listen()':
C:\Users\Bob\Documents\Arduino\libraries\NeoSWSerial\src\NeoSWSerial.cpp:155:7:
error: 'TCCR2A' was not declared in this scope
       TCCR2A = 0x00;
       ^~~~~~

I think I'll call it a day for now.

Dave

Bob McHugh

unread,
Sep 29, 2021, 5:47:09 PM9/29/21
to devel...@arduino.cc
Dave,

Don't give up on yourself, sometimes it's best to walk away from it for a
short time. You may find the answer pops into your head or you find another
alternate you hadn't thought of.

You might also consider bread boarding another AVR to see if the twitching
is duplicated or minimized and compare the results.

BobbyMac


-----Original Message-----
From: devel...@arduino.cc [mailto:devel...@arduino.cc] On Behalf Of Dave
Sent: Wednesday, September 29, 2021 1:28 PM
To: devel...@arduino.cc
Subject: Re: [Developers] Problem with softwareserial on ATTint84

--
You received this message because you are subscribed to the Google Groups
"Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to developers+...@arduino.cc.
To view this discussion on the web visit
https://groups.google.com/a/arduino.cc/d/msgid/developers/DB7PR07MB4748EE2C0
C5A8FA8DED33E11D3A99%40DB7PR07MB4748.eurprd07.prod.outlook.com.

Bryan White

unread,
Sep 30, 2021, 2:49:48 AM9/30/21
to Developers
Something that helped me hack Arduino compiles that were missing defines ...
Let's say that TCCR2A needs to be defined as 0xFORTY_TWO (actually some real other hex number, but anyway ...)
And your using a board type of MY_BOARD_TYPE (I'm making sure someone doesn't copy-n-paste and say "it didn't work")
Then find MY_BOARD_TYPE in boards.txt (NB there can be several of them),
Under that find a line something like say
nano.menu.cpu.atmegaXXXXold.bootloader.low_fuses=0xFF
Note the dotted name up to 'bootloader'; that's what we need
Then at the bottom of that family insert a new line (probably only one of its type, and maybe add a # comment too) NB note the leading 'D'
nano.menu.cpu.atmegaXXXold.build.extra_flags=-DTCCR2A=0xFORTY_TWO

Then, wherever TCCR2A is mentioned, it gets replaces with 0xFORTY_TWO, just like the other register name.

HTH

Brewmanz

Mail Lists

unread,
Sep 30, 2021, 2:49:49 AM9/30/21
to devel...@arduino.cc
Hi Dave,

I don’t see any mention of which Arduino Core that you’re using.

Are you using the SoftSerial and Servo libraries bundled with this core: https://github.com/SpenceKonde/ATTinyCore

Alex

--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.

Dave

unread,
Sep 30, 2021, 8:25:04 AM9/30/21
to devel...@arduino.cc

Yes, it's the ATTinyCore ... I wasn't aware there was an alternative ;-)

Regards,
Dave

Dave

unread,
Sep 30, 2021, 1:11:17 PM9/30/21
to devel...@arduino.cc

Hmmm, interesting may give a clue as to what is going on but it's not
really a "fix" as it imposes a long delay between when servo moves can
be done.

It is clear to me that the problem is down to how the timer is uses when
receiving characters (I never send anything from the arduino).

I may look at moving the serial code to use timer1 ...

Dave


On 29/09/2021 01:43, Ken Perry wrote:

Jon Perryman

unread,
Sep 30, 2021, 2:31:34 PM9/30/21
to devel...@arduino.cc
Dave has a 9g servo that is twitching so it's unlikely to be related to power starvation unless your stepper motors are using lots of power. From what Dave doesn't believe the twitching is the servo itself and the twitching only occurs with softwareserial.

We assume that Dave is trying to slow down the movement of the servo by slicing the move into multiple smaller delayed moves. E.g. Instead of moving from 0 to 90 degrees, Dave is increasing the position by adding 1 degree at a specific interval such as 5 milliseconds.

If this is a software issue, then it's most likely a blocking issue. The twitching is caused by inconsistent times between all the slices. In my example above, each time slice needs to be close to 5 milliseconds otherwise your eye will detect the differences as twitching.

The obvious thing to look for are the DELAY's. If softwareserial is causing this, then look for a buffer full.

Less obvious will be your code. Things like writing non-blocking code and prioritizing work such as the servo. This can be tricky and cause side effects if you are not careful. There are multiple techniques. 

The most obvious is placing servo in an interrupt routine because interrupt routines pause LOOP. 

Another technique is to code LOOP so that each pass is short, quick, prioritized and Delay's eliminated. Most programmers code LOOP to perform A, B, C and DELAY. A simple replacement technique for LOOP is: if A-ready() then A() else if B-ready() then B() else if C-ready() then C(). The ready routines would check for the appropriate time delay and verify delay not excessive. Ensure some sort of delay is in every ready routine so that it does not monopolize the processor.

William Westfield

unread,
Oct 1, 2021, 12:22:44 AM10/1/21
to 'Owen Lyke' via Developers

Servo.h uses the hardware PWM AFAIK so interrupts shouldnt affect it ?

It looks to me like the servo library(s) use the HW compare register to time a Servo interval, but in the interest of supporting more than one servo, it has the timer generate an interrupt, and then the timer ISR does the actual pin manipulation and “step to next servo.”

Meanwhile, the softwareSerial library uses the pin Change interrupt to detect the start bit associated with a serial character, but then reads that entire character in the Pin change ISR.  At 9600bps, the character reception will take about a millisecond.

If the timer interrupt occurs while the pin change ISR is processing an incoming character, the PWM output could be delayed by up to a full character time (1ms), which is quite a bit compared to the 1.5 to 2.5ms typical of servo pulses.  Which would explain some jitter.

If you only have one servo, and have freedom to pick which pin is used, I think I agree with the suggestions to hunt up an older servo library that drives one of the pins directly from hardware.

BillW/WestfW

Dave

unread,
Oct 1, 2021, 9:24:22 PM10/1/21
to devel...@arduino.cc


Problem solved !!  :-)

I tried a few of the suggestions made here with varying degrees of success, none of them 100%, sadly.

However, since I am already "bit banging" the stepper motor  and it occurred to me to try that approach on the servo.

I tried the following :-

void moveServo(int posn) {        // posn is angle in degrees 0-120
  int pulse = map(posn,0,120,1000,2000);    // calc required pulse width
  int loops = (abs(posn) * 10) + 1;  // Always need at least 1
  for (int i=0;i<loops;i++)
  {
    digitalWrite(8, 1);                    // start pulse
    delayMicroseconds(pulse);
    digitalWrite(8, 0);                    // end of pulse
    delayMicroseconds(10000);     // Split because it is limited to 16383 uSec as per Arduino ref
    delayMicroseconds(10000 - pulse);
  }
}

Originally I thought that I'd need a chain of pulses to get the servo to the target position - however, I discovered that the 9G servos (well the ones I have, at least) only need a single pulse of the appropriate width !! which made the code a lot faster and smaller ending up as :-

void moveServo(int posn) {        // posn is angle in degrees
  int pulse = map(posn,0,120,1000,2000);    // calc required pulse width
  digitalWrite(8, 1);                    // start pulse
  delayMicroseconds(pulse);
  digitalWrite(8, 0);                    // end of pulse
  delayMicroseconds(10000);     // Split because it is limited to 16284 uSec
  delayMicroseconds(10000 - pulse);
}

and I suspect that the last two delays could be dropped but I'll probably leave them in as a safety measure to prevent the pulses getting too close.

Anyway, with SoftwareSerial sending and receiving data I see no "twitches" :-)

I suspect that the "1 pulse" feature is specific to the 9G servo so may not be suitable for other types.

Thanks for all the advice,
Dave

--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.

Ken Perry

unread,
Oct 1, 2021, 9:46:05 PM10/1/21
to devel...@arduino.cc

The good news is this is probably better than what you were doing to start with anyway.

 

From: devel...@arduino.cc <devel...@arduino.cc> On Behalf Of Dave
Sent: Friday, October 1, 2021 9:24 PM
To: devel...@arduino.cc
Subject: Re: [Developers] Problem with softwareserial on ATTint84

 

 

Problem solved !!  :-)

Jon Perryman

unread,
Oct 2, 2021, 2:07:23 AM10/2/21
to devel...@arduino.cc
Hardware and software PWM perform the same functionality. Both move the servo from the current position to the specified position. You won't see jitter with a single PWM unless there is a problem with the servo. Jitter will only occur when you send multiple PWM commands (hardware or software) which are needed when the servo moves too fast with a single PWM command.

--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.

Jon Perryman

unread,
Oct 2, 2021, 10:17:17 PM10/2/21
to devel...@arduino.cc
This is a terrible solution but if it works for you then great. It's far better than the first. Expect the servo to twitch.

void moveServo(int posn) {        // posn is angle in degrees
  int pulse = map(posn,0,120,1000,2000);    // calc required pulse width
  digitalWrite(8, 1);                    // start pulse
  delayMicroseconds(pulse);
  digitalWrite(8, 0);                    // end of pulse
  delayMicroseconds(10000);     // Split because it is limited to 16284 uSec
  delayMicroseconds(10000 - pulse);
}

Some comments:

1. You have a trailing edge after ending the pulse but you do not have a leading edge before the start of the pulse. Technically, the trailing delays will suffice but it's a bad habit.

2. The last 2 delays should be a single delay that is the length of the trailing edge for servos. I can't remember how long that is but it's only a few microseconds.

3. You mentioned that besides the servo, your program uses serial and stepper motors. They are all impacted by blocking. As coded above, your servo function wastes 20ms. That is 400,000 instructions wasted that could be used to service serial and stepper motor. By implementing leading and trailing edge, you reduce it to 2ms or 40,000 instructions. 

4. Do you experience buffer overruns on serial? At 9600 baud, the 64 byte buffer would be full in 100ms if you sent as much data as possible. 5 calls to your servo function is 100ms. If your commands are 5 bytes, the buffer would hold 12 commands at most.   

Ken Perry

unread,
Oct 2, 2021, 10:32:58 PM10/2/21
to devel...@arduino.cc

Maybe just remove the delays all together and write it to use a counter and if statements testing time elapsed. 

 

From: devel...@arduino.cc <devel...@arduino.cc> On Behalf Of Jon Perryman
Sent: Saturday, October 2, 2021 10:17 PM
To: devel...@arduino.cc
Subject: Re: [Developers] Problem with softwareserial on ATTint84

 

This is a terrible solution but if it works for you then great. It's far better than the first. Expect the servo to twitch.

Dave

unread,
Oct 3, 2021, 12:39:34 AM10/3/21
to devel...@arduino.cc

I agree that it's not ideal, but it works and satisfies my requirements.

The serial I/O is trivial (1 byte received, 3 or 4 times per second and one byte sent (an acknowledgement) at the same rate - strictly 1/2 duplex), much more important is the consistency of the servo position.

Since there is no PWMServo that works for the ATTiny84 I have little or no choice unless I am able to spend a lot of time trying to get PWMServo working on the 8MHz ATTiny and dealing with the steep (for me) learning curve.

Those servos do NOT like a pulse repetition rate of more than 50Hz, I know, I tried so a delay is needed after the 1-2mS pulse. I may change it to use "millis()" to keep track of when the last pulse was issued and enforce a delay if its less than 20mS.

Dave

Ken Perry

unread,
Oct 3, 2021, 12:52:49 AM10/3/21
to devel...@arduino.cc

I guess what I was saying is you don’t need to do a delay if you keep track of current puls pseudo code is like

StartTime (starting time in milliseconds)

curTiome (current time in miliiseconds)

delayTime (time to delay in milliseconds)

 

loop{

currentTime set the current time

if ((currentTime – startTime) > delayTime){

do your servo stuff

}

 

}

 

This gets rid of the use of the delay function which is a good thing.

 

 

Sent: Sunday, October 3, 2021 12:39 AM


Subject: Re: [Developers] Problem with softwareserial on ATTint84

 

I agree that it's not ideal, but it works and satisfies my requirements.

William Westfield

unread,
Oct 3, 2021, 3:29:42 AM10/3/21
to devel...@arduino.cc

 unless I am able to spend a lot of time trying to get PWMServo working on the 8MHz ATTiny

It might not be as difficult as you think.  And educational.

Paul’s PWMServo library’s complexity looks like it is largely due to wanting to support as may timers on as many different types of chips as possible.  Cutting it down to support a single output should be relatively simple.
(and the tiny84 timer looks pretty compatible with the more commonly used chips.)

BillW/WestfW

Paul Stoffregen

unread,
Oct 3, 2021, 7:27:45 AM10/3/21
to devel...@arduino.cc
I'm pretty sure PWMServo can work by just adding 3 lines in PWMServo.h to define the 2 pin numbers for whatever pins are the PWM controlled by timer1.  The pin numbers don't even have to be correct, as they're only the numbers your code will use to tell the library to turn on timer hardware.  You could just put 1 & 2 into the code and then look at which pins actually start pulsing when your program uses myServo.attach(1) and myOtherServo.attach(2);

It's literally as easy as the 3 lines between
// Arduino and // Arduino Mega


#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) // Arduino
  #define SERVO_PIN_A 9
  #define SERVO_PIN_B 10
#elif defined(whatever name your ATTINY chip has)
  #define SERVO_PIN_A 1
  #define SERVO_PIN_B 2

#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // Arduino Mega
  #define SERVO_PIN_A 11
  #define SERVO_PIN_B 12
  #define SERVO_PIN_C 13

If you don't know "whatever name your ATTINY chip has" automatically defined by the compiler (odds are strong it follows the same naming convention as all the others...), you could just put "#if 1" on that line to force your 2 defines to be used for the sake of testing.

Of course there is a slim chance the library won't compile or actually work on that particular ATTINY chip.  But it appears to have the same timer1 registers, so odds are pretty good it will work.  You just need get past irrational fear of editing a library header file, and then you can have the hardware create pristine servo waveforms which aren't messed up by interrupts from SoftwareSerial.

Or you could put a *lot* more work into bitbanging servo waveforms and trying to make sure the interrupt don't happen at sensitive moments!
--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.

phillip torrone

unread,
Oct 5, 2021, 10:51:17 PM10/5/21
to Developers
this may be helpful for folks using the latest attiny and atmega chips that are programmed with "synch uart" UPDI rather than "SPI" AVR-ISP: we've updated our self-contained/standalone programming library to add UPDI support!

video
https://youtu.be/sXSll5yI22Q

the library is here:
https://github.com/adafruit/Adafruit_AVRProg

example here:
https://github.com/adafruit/Adafruit_AVRProg/tree/master/examples/attiny817_updiprog

we can erase-program-verify an 8KB flash chip in 2 seconds, super fast. great for loading firmware in production.

thanks to bradanlane's portaprog for much of the updi support implementation:
https://gitlab.com/bradanlane/portaprog/-/blob/master/src/avrupdi.cpp

cheers,
pt & limor
Reply all
Reply to author
Forward
0 new messages