SoftwareSerial Not Reliable?

Frankly, neither would I if:

  1. I had more experiences with Strings vs strings
  2. I had known that the Ram usage message generated by the compiler is far from sufficient.
  3. I didn't think that using a String is sullying a program. It looked like an attractive data type to me.

Sometimes it's harder to de-sully a program than start from scratch.

Can you please explain? Thanks.

Your experiences have highlighted one of the nastiest issues with Strings: It's hard to know when you're done testing. I expect that after twenty four hours of running successfully, you were convinced that you had cracked it, only to be dismayed by the Sudden Impact of a crash another day later.

It might indeed be better to bite the bullet and start again - then you can keep an eye on memory pressure as you add features. See if you can make use of progmem at all to preserve RAM.

Do you mean freeMemory()?

No. There is a directive called progmem that lets you tell the compiler not to bring something into RAM at startup. It's useful if you have a lot of constant data e.g. strings that you won't need all at the same time.

Similarly, if you're printing some text there is the F macro that essentially does the same thing:

Serial.println(F("Two Mules for Sister Sara"));

You don’t limit any String.
Reserve just sets the min memory allocated. It can grow. But all the + thingy you do are creating tons of intermediary substrings and copies that you don’t see

On AVR the String class won’t allocate memory if the operation would result in less than 128 bytes free. That’s how it’s coded.

I'm so used to allocating (malloc()) all the global variables like char and then passing pointers to the functions. I usually used minimal additional space in my functions. Maybe I'll be limited by the minimal RAM space in the ATmega328 in doing that if I decide to make a new Stringless program. I'll see what my latest last resort modification does to those crashes before a restart a new program from scratch.

If you're used to using malloc, you can avoid The Dead Pool of leakage that the String copy constructor can cause you. It's still risky though because the Nano has so little memory. With a PC, you can get away with assuming that a malloc will succeed (although of course you shouldn't) but a micro controller is a very different beast.

And as for variables that are only needed during part of the execution & not all the fuctions , I used allocated shared scratch memory.

I’m not so interested to test this myself (I’m not well at the moment), but I see a lot of to-ing and fro-ing on the merits and failings of Strings w.r.t. memory use and code size.

I’d be really interested to see a comparison of Strings vs c-strings in code that is mixed process / String handling - when compared for execution speed.

The moving and reprocessing of String buffers must eat into COU time to some degree.
This rarely comes into the conversation, and in many cases is not important, but there are definitely cases where wasted CPU cycles would be a real issue.

Examples that come to mind would be reading fast quad-encoders, or real-time FFT, and similar algorithms.

There are certainly low performance applications where String memory and execution speed make no difference, or well placed String usage makes no difference, but a 1:1 face-off would interesting to see. (aka Py vs C :scream:)

If you use reserve() so that the Strings to not call malloc( ) then not a lot of difference since String use c-string methods underneath. There are extra method calls to check input args and available space to prevent null pointer and buffer overflow crashes, but that is about it.
If the method calls are 'wasting' too much CPU, then look at ASM to avoid the unnecessary push/pops of all the registers that are generated by the compiler.
(well were generated last time I tried to use C on an Attiny85)

Code size Strings definitely use more, but you get the protection you pay for.

I "de-sullied", rather rewrote my program. 0 String Objects, only global characters. I also removed a coupla bells and whistles. I re-used the SoftwareSerial at 9600 Bauds though to find out what the Hell is going on via the serial monitor (if needed).

Program Memory usage: 45%, RAM 74%(526 bytes free), freeMemory() shows 451 bytes.

Code has been running without a hiccup for a good spell now.

My conclusions (for myself at least):

  1. Avoid Strings like the Covid19. Don't let your software control your memory allocations and de-allocations.
  2. Don't be too ambitious to do a load of tasks with the memory-poor ATmega 328P. Leave sufficient memory margin to avoid spurious bugs that bite you in the ass a few hours/days later.
  3. Use a more powerful processor for the big jobs. I uploaded my original hungry-for-memory program on a Mega 2560 Pro. Needless to say, it works fine at the expense of the added price tag and its larger footprint (5.5x4cm) compared to a Nano.

The Rookie uses Strings because they seem easy, helpful and harmless. Now you know better - glad you got it working.

1 Like

With that level of free RAM Strings can be problematic without careful usage (but still safe against sketch crashes).

I would recommend my SafeString library as a replacement.
It provides the safety and convenience of String type methods and buffer overflow protection while working on fix sized char[ ]s and providing detailed error messages so you can refine you char[ ]s down to the minimum size needed so saving precious RAM

You can also just 'wrap' a char[ ] in a SafeString for a few operations as needed.

If it runs and OP has been careful there is no need to wrap in anything :slight_smile:

If he is unsure that would give him Warning messages to help identify issues but the memory footprint will increase due to your library so challenges might appear just due to this (may be not with that much free SRAM)

Thanx but I've changed religion. I don't believe in Strings anymore. Ah, but maybe I'll look into it for some of my previous Stringy sketches if it's easier to switch to SafeString rather than rewrite the code. Good idea!

Well, I have comptely solved my memory problem, and hence, intermettint crashes after delayed intervals thanks to removal of all Strings and using fixed allocations for all the character arrays that replace them. Things have been running for over a month for both of my modules which were crashing using Strings. I have 2 addirional sensor modules connected to these 2 modules via internet and Lora modulation radio transmission. The sensors measure outside temperature and humidity, and swimming pool water temperature and level. My next problem is the reliability of my HC-SR04 ultrasonic distance measurement device to monitor water level. After a few months, the device is damaged and rusted due to the proximity of the water (10cm). I would like to replace it by a sealed utrasonic device but have only succeded in finding one that works with distances>25cm. 5V Module de Capteur Ultrasonique Etanche pour Mesure Difficile et Humide : Amazon.fr: Bricolage. Anybody have an idea where I can find one that can mesure 7cm<distances<15cm? Thanks!!!!

good job getting rid of the instability

you might want to look at ToF sensors like the VL53L0X

(Assuming you read French since your Amazon link is in French) if you dig into the French section of the forum there were a few post discussing techniques for measuring water level.

thanx but tried it. laser will reflect on the bottom of the swimming pool, not on the surface. ideal for me is ultrason but sealed and minimum distance of about 7 cm. my sonde is installed 10 cm above the average distance of the water surface