PlatformIO Community

Software Serial problem ATtiny85

Hello!, this is my first post!, so I hope I wasn’t wrong in choosing the right category.
I state that I am a bit inexperienced with PlatformIO and this is one of my first projects with this software.


Come to the point.
I have problems with the developement of a temperature controller based on Attiny85 MCU, precisely I am unable to get a serial communication via the MCU itself and the PC via a separate UART-> USB converter.

I specify that due to the need of the code I have changed the prescaler of Timer1 to generate a 30kHz PWM on digital pin 1 (D1).
But I don’t think it is very important because from what I have seen even removing the prescaler settings I always get the same problems.

My setup consists of

  • Arduino UNO (as ISP)
  • Self Made shield for ATtiny85 programming
  • VSCode + PlatformIO extension
  • ATtiny85 with Arduino bootloader

From what I understand the SoftwareSerial can only be established if the frequency of the cpu is set to 8MHz, but since with the prescaler of 1 I can only get 18kHz on D1 it makes me think that the ATtiny85 is not running at 8MHz and all this would explain why in the serial monitor I get only random characters.

I tried to load the code with the Arduino IDE but I get the same result.

However I attach the platformio.ini file and the string I use for the prescaler.
(to set the platfromio.ini config file I followed the official PlatformIO wiki)

platformio.ini

[env:attiny85]
platform = atmelavr
board = attiny85
board_hardware.oscillator = internal
board_build.f_cpu = 8000000L ; MCU frequency
framework = arduino
upload_protocol = custom
upload_port = COM4 
upload_speed = 19200
upload_flags =
    -C
   
    $PROJECT_PACKAGES_DIR/tool-avrdude/avrdude.conf
    -p
    $BOARD_MCU
    -P
    $UPLOAD_PORT
    -b
    $UPLOAD_SPEED
    -c
    stk500v1
upload_command = avrdude $UPLOAD_FLAGS -U flash:w:$SOURCE:i

Timer/ Prescaler settings

TCCR1 = TCCR1 & 0b11110000 | 0b0001;

Thanks to everyone for the help given to me in advance
Kindly regards

Note: As per docs this option is only valid for MiniCore, MegaCore, MightyCore, MajorCore and MicroCore . Your ATTiny85 is using "core": "tiny" meaning the framework-arduino-avr-attiny package is used which is https://github.com/SpenceKonde/ATTinyCore, which is not one of the cores in which that setting is respected.

The first thing you should check / make sure of are the fuses of the ATTiny85. Using AVR® Fuse Calculator – The Engbedded Blog with part = ATTiny85, features = Int. RC Osc. 8MHz, unchecked divide clock by 8, I get L=0xE2, H=0xDF, EXT=0xFF.

So per docs you should add

board_fuses.lfuse = 0xE2
board_fuses.hfuse = 0xDF
board_fuses.efuse = 0xFF

and use the project task Platform → Set Fuses to burn them.

If that still doesn’t solve your problem, other things must be at play.

1 Like

If you don’t wan’t to mess around with checking the fuses as per @maxgerhardt’s explanation, upload the blink program with the default 1 second delay. You can check if the internal fuse to divide clock by 8 is set, because you’ll get an 8 second delay instead of 1 second.

Then you will have to set the fuses as per @maxgerhardt .

Have fun.

Cheers,
Norm.

1 Like

Hi, first of all thank you for answering me in such a short time.


So back to the topic, thanks to your suggestions I did some additional tests and now I would like to evaluate what I have achieved with you.

As suggested by @maxgerhardt I added the settings calculated by the Fuse Calculator in the file platformio.ini.
But I did not get any desired result, in fact from the serial monitor I receive only noise.
In addition I wanted to see which Fuse were previously set. So from the terminal output during the upload I got these values ​​which are the same as I confirmed in the configuration file …

avrdude: verifying ...
avrdude: 4452 bytes of flash verified

avrdude: safemode: Fuses OK (E:FF, H:DF, L:E2)

avrdude done.  Thank you.

============= [SUCCESS] Took 13.10 seconds =============

This makes me wonder if the CPU wasn’t already running at its set frequency.


So in spite of this I looked for the cause of the problem elsewhere. I threw away my code and uploaded this very simple ping

#include <Arduino.h>
#include <SoftwareSerial.h>


SoftwareSerial SWSERIAL(8, 0);  // RX, TX


void setup() {

  SWSERIAL.begin(4800);
  }

void loop() {
	
  SWSERIAL.println("Ping");
  delay(1000);
  }

to check 2 things:

  • if the “divided by 8” has been set as suggested by @NormanDunbar with the delay (1000);
  • if other functions within my original code could interfere with the SoftwareSerial.h

The result, however, has always been the same and a delay (1000) is exactly 1s long.
For documentation this is what I get from the serial monitor

▒▒▒~f▒▒▒f▒▒▒~f▒▒▒f▒▒▒~n▒▒▒f▒▒▒~f▒▒▒f▒▒▒~N▒▒▒f▒▒▒~f▒▒▒f▒▒▒~f▒▒▒f▒▒▒

As a last resort I changed the UART-> USB converter with an arduino UNO (what I had at the time) which repeat the data from the SoftwareSerial to the USB itself.
But unfortunately, without having any success, I therefore had to give up.

Thank you for the help given
Cheers

With the pin reference for ATTinyX5 devices (your ATTiny85 is one of them)

there is no “Digital pin 8” that’s used for RX here, it only goes up to 5. So try e.g.“1” as the RX pin.

Also, do other baud rates, e.g. 9600, 19200, 57600, make a difference? Does the output maybe appear correctly if you set the serial monitor to half or double the intended baud rate?

1 Like

Good evening, so I made the latest changes recommended by you.
And that’s what I got


Yes, I’m sorry but I forgot to mention this in my previous messages, since I don’t need to send data to the MCU I have defined a pin that doesn’t exist in the Attiny85. To be precise, however, now I have assigned D1 as RX but it did not lead me to anything. :cry:


So, under your advice I changed the speed in the serial monitor to half the defined speed (9600/2 = 4800bps), I admit I was a little bit skeptical of this change, however I tried it anyway and to my surprise it worked! :partying_face: :partying_face:

Now how I could solve this strange behavior? I never seen anything like this in my (short) experience, I always assumed that once 9600bps is defined those remained constant everywhere.
Could be the wires? The distance of my cables is about 30cm


But at least now it WORKS!! :star_struck:

Thanks for your help
Cheers

No that can’t be the case, the length of the wire can’t just double the frequency of the signal. It’s the microcontroller producing the wrong signal in the first place. I’ll check this out on an ATTiny85 I have to verify this or try to make sense of it – either there are somehow wrong fuse settings (although off by a factor of 2 is weird, I’d more expect like by 8 since that’s a fuse setting) or the used Arduino core simply has a bug there or PlatformIO is not building the firmware correctly (e.g. by omitting critical information regarding the clock source or frequency).

1 Like

Greetings ,

But in this case, the frequency of the resulting signal is not the half?
Because I set 9600bps in the code and I get only 4800bps on the PC.

Maybe should change the Attiny85 chip?
Could it be defective?


I could change a fuse on purpose?
Let me explain better, as I need an extra pin for my project I could change the fuse which disables the RESET and enables pin D5 as an i / o pin.
(as explained from the Fuse Calculator that you kindly provided to me)
The resulting fuses would be the following ones, maybe it could work, but I’m not too sure …

    board_fuses.lfuse = 0xE2
    * board_fuses.hfuse = 0x5F *
    board_fuses.efuse = 0xFF

Before changing anything else I would like to have other opinions on this.


A bug? But if that were the case, wouldn’t there be many more problems of this kind?
Or this behavior would also extend to other boards/MCUs such as the UNO for example .


I also tried to add this in the code

#define F_CPU 8000000UL

hoping that something would change :grinning_face_with_smiling_eyes:, but nothing.

Cheers

DO NOT UNDER ANY CIRCUMSTANCES, SET THE FUSE TO USE THE RST PIN AS A GPIO.

Sorry for shouting, but if you do set that fuse, you will be unable to program the ATtiny unless you have a High Voltage Programmer.

I have a bricked ATtiny85 for exactly this reason.

:cry:

Cheers,
Norm.

From the ATtiny85 data sheet, section 6.1.5:

The internal PLL in ATtiny25/45/85 generates a clock frequency that is 8x multiplied from a source input. By default, the PLL uses the output of the internal, 8.0 MHz RC oscillator as source. Alternatively, if bit LSM of PLLCSR is set the PLL will use the output of the RC oscillator divided by two.

The internal PLL is enabled when:

  • The PLLE bit in the register PLLCSR is set.
  • The CKSEL fuse is programmed to ‘0001’.
  • The CKSEL fuse is programmed to ‘0011’.

Might be a clue?

Cheers,
Norm.

Greetings,


So I was right to be cautious about modifying that fuse, I admit that I was very tempted to do so.
Also because I had thought about my project with a led connected to the RST pin. But I think I’ll omit it.

Thank you so much for letting me know, I don’t even know what an HV Programmer is :rofl: :rofl:, but I’m calmly making progress.


I have read the Attiny85 datasheet several times and I admit that it has always scared me a little :rofl: , but it could be something like that, also because I have set the Timer1 prescaler its minimum value and I can only get to 18kHz on the PWM.
So there is definitely some problems in the clock generation, or something else related to it.


Or I could be satisfied with all this, knowing that the serial works at half speed.

[as indeed the PWM,36kHz expected - 18kHz obtained (which not surprisingly is half of 36)].
Aspect that I will not have to underestimate and I will try to fix it.

Cheers

I know what you mean. I’m reading the data sheet at the moment as I want to play a bit with my collection of ATtiny85s in AVR C++, rather than using the Arduino Language. It’s quite surprising how different these guys are, compared to the Uno’s ATmega328P for example.

If I get a chance, I’ll see if mine suffer the same problem as yours. Would you mind posting your plarfomio.ini file here, the one you used for your minimal “ping” sketch please? Thanks.

A high voltage programmer needs to use 12v to program the device, rather than 5v as we normally use. It’s mandatory if you have set that fuse to disable the reset pin. You can read all about it at High-Voltage Serial Programmer - Rescue AVR Chips and even build your own with a spare ATtiny85.

Cheers,
Norm.

Cheers,
Norm.

Cool! :smiley:
Anyway for me I’m more comfortable with the Arduino anguage, for my specific needs Arduino is the best, so I don’t think that I should switch to another bootloader and/or language.


Absolutely, I think it is much more complex especially for a beginner.

However I really like these Attiny85 chips because for certain applications such as mine (a small temperature controller) an Arduino UNO/NANO would be too bulky and overkill to just measure a temperature and generate a PWM signal.


Yes sure, The platformio.ini file is the same one I posted in my first post with just the addition of the fuses.
In addition, I specify that the platformio.ini file of the Ping sketch and that one from my temperature controller are the same, as I don’t want to mess with the code that I have already written.
Anyway, in any case, here it is:

platformio.ini

[env:attiny85]
platform = atmelavr
board = attiny85
board_build.f_cpu = 8000000L ; MCU frequency
framework = arduino
upload_protocol = custom
upload_port = COM4
upload_speed = 19200
board_fuses.lfuse = 0xE2
board_fuses.hfuse = 0xDF
board_fuses.efuse = 0xFF
upload_flags =
    -C
    ; use "tool-avrdude-megaavr" for the atmelmegaavr platform
    $PROJECT_PACKAGES_DIR/tool-avrdude/avrdude.conf
    -p
    $BOARD_MCU
    -P
    $UPLOAD_PORT
    -b
    $UPLOAD_SPEED
    -c
    stk500v1
upload_command = avrdude $UPLOAD_FLAGS -U flash:w:$SOURCE:i

Yes i had already read some readings about the high voltage programming, it seems a very complex circuit.
In conclusion, better not to change that bit :joy: :joy:

Thanks to everyone for the availability and for the help given.
Cheers

Morning.
The puppy got me up early today, so I’ve had a bash at your problem.

Using your source file as src/main.cpp and the following platformio.ini:

[env:attiny85]
platform = atmelavr
board = attiny85
board_build.f_cpu = 8000000L ; MCU frequency
framework = arduino
upload_protocol = usbtiny
board_fuses.lfuse = 0xE2
board_fuses.hfuse = 0xDF
board_fuses.efuse = 0xFF

I see the exact same problem. I set the baud rate to 4800 and get nothing if my CoolTerm is set to that. Set CoolTerm to 2400 and I see PING…

Same, obviously in the Arduino IDE’s Serial Monitor. It works at 2400. The question is why…

Cheers,
Norm.

PS. I did of course set the fuses to those in the ini file and checked same on upload. All correct.

Cheers,
Norm.

This gets even weirder!

While attempting to find the SoftwareSerial source, I found a separate file named TinySoftwareSerial.h and .cpp, so I tried to use your code, modified to suit TinySoftwareSerial, and came up with this:

#include <Arduino.h>
//#include <SoftwareSerial.h>
#include <TinySoftwareSerial.h>

#define RX_PIN 8
#define TX_PIN 0

struct soft_ring_buffer rxBuff;

TinySoftwareSerial SWSERIAL(&rxBuff, TX_PIN, RX_PIN);  


void setup() {
  SWSERIAL.begin(4800);
}

void loop() {
  SWSERIAL.write("Ping\n");
  delay(1000);
}

It compiled and ran, but this time, instead of the output being legible at 2400 baud, I had to go down to 1200 baud. This from PlatformIO’s device monitor:

norman@hubble:~/temp/attiny85$ pio device monitor -b 1200
--- Available filters and text transformations: colorize, debug, default, direct, hexlify, log2file, nocontrol, printable, send_on_enter, time
--- More details at http://bit.ly/pio-monitor-filters
--- Miniterm on /dev/ttyUSB0  1200,8,N,1 ---
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
Ping
Ping
Ping
Ping

--- exit ---

Interestingly, when I run it in the Arduino IDE’s Serial Monitor, I get an update roughly every 2 seconds, not every second:

12:03:19.013 -> Ping
12:03:21.110 -> Ping
12:03:23.210 -> Ping
12:03:25.276 -> Ping
12:03:27.373 -> Ping
12:03:29.469 -> Ping
12:03:31.567 -> Ping
12:03:33.660 -> Ping
12:03:35.755 -> Ping
12:03:37.848 -> Ping

Mind you, with SoftwareSerial, I get this:

12:07:07.760 -> Ping
12:07:09.861 -> Ping
12:07:11.923 -> Ping
12:07:14.019 -> Ping
12:07:16.087 -> Ping
12:07:18.149 -> Ping
12:07:20.245 -> Ping
12:07:22.307 -> Ping
12:07:24.400 -> Ping

Which is about the same, just over two seconds per update, rather than a single second. Weird!

I’ll have a look at the code in the library and see if I can match it up to the ATtiny85 registers and see what’s happening. If my brain works that is!

Cheers,
Norm.

1 Like

Ok, I think the problem is in PlatformIO.

I started with a brand new ATtiny85 and I uploaded up the standard blink program, with PB0 as the LED pin:

#include <Arduino.h>


#define LED_PIN 0

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

void loop() {
  digitalWrite(LED_PIN, HIGH);
  delay(1000);
  digitalWrite(LED_PIN, LOW);
  delay(1000);
}

And this platformio.ini:

[env:attiny85]
platform = atmelavr
board = attiny85
framework = arduino
upload_protocol = usbtiny

board_fuses.lfuse = 0xE2
board_fuses.hfuse = 0xDF
board_fuses.efuse = 0xFF

I set the fuses first: pio run -t fuses and confirmed the fuses were set correctly as per the ini file. after uploading, pio run -t upload, I see this for the fuses:

avrdude: safemode: Fuses OK (E:FF, H:DF, L:E2)

So the fuses are indeed correct, however, on connecting a scope (Espotek Labrador – I can afford a proper scope!) to pin PB0, I see a period of 4 seconds and a frequency of 245 MHz mHz. (Edited, milliHertz not MegaHertz!) This is obviously wrong as the LED is off for 2 seconds and on for 2. The result is the same if I specify the board_build.f_cpu or leave it to default.

If I upload the same sketch, from the Arduino IDE, I get the period to correctly be 2 seconds and the frequency is 498 MHz mHz. (Edited, milliHertz not MegaHertz!) Checking the fuses with avrdude I see they are still the same as set by PlatformIO. Just to be doubly sure, I “burned a bootloader” with the Arduino IDE set to 8MHz internal oscillator, and the fuses burned were exactly as per PlatformIO.

I therefore suspect something is amiss in the PlatformIO framework for the ATTiny85.

Cheers,
Norm.

1 Like

There is an off-by-factor-2 somewhere. It must be somewhere in the build settings.

I noticed that the platform-atmelavr has had a recent update with regards to ATTiny85. Maybe the bug is already resolved? What happens you do

platform = https://github.com/platformio/platform-atmelavr.git

instead of of platform = atmelavr in the platformio.ini?

1 Like

Hi @maxgerhardt

yes, using platform = https://github.com/platformio/platform-atmelavr.git works fine for SoftwareSerial, whatever baud rate is defined in the begin() call is correct now in the device monitor/Arduino IDE/CoolTerm. Thanks.

USing TinySoftwareSerial no longer works at all. None of the baud rates seem to match up.

Cheers,
Norm.

Digging further, it seems this was known about, https://github.com/platformio/platform-atmelavr/issues/264 already!

Cheers,
Norm.