"Serial" is cpu hungry (?) while "SoftwareSerial" is not.

Hi,

I would be greatful if someone could explain what is happening in this sketch :

void setup() {
  //Serial.begin(115200);
  DDRB = B11100000;   // pinMode(13, OUTPUT);
}

void loop() {
  PORTB = B11100000; // digitalWrite(13, 1);
  PORTB = B11000000; // digitalWrite(13, 0);
}

void test() {
  //Serial.print('A');
}

It is loaded on a DFRobot Bluno Nano, and I use Arduino IDE ver 1.8.2. I have connected an oscilloscope to pin 13, so I can see a repeating positive pulse (pulse duration ~100 ns). The complete cycle period (high to high) is what I do not understand. The above code, with two commented lines, gives 390 ns. But if I uncomment any of these (or both), I get ~1000 ns. What is happening during this extra time, and why ? Maybe I should upgrade to a more recent IDE, but I remember I had some problems with newer than 1.8.2 at the time of installation, so this would not be my first choice.

If I replace Serial with SoftwareSerial, there is no such behaviour (390 ns all the time) :

#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX

void setup() {
  mySerial.begin(115200);
  DDRB = B11100000;   // pinMode(13, OUTPUT);
}

void loop() {
  PORTB = B11100000; // digitalWrite(13, 1);
  PORTB = B11000000; // digitalWrite(13, 0);
}

void test() {
  mySerial.print('A');
}

/bb328

You could try masking the bits properly, so you're only really changing the bit that corresponds to pin 13. Just to be safe.

If you look at the main program the arduino runs, it is basically this

int main(void)
{
    init();

    setup();
    
    for (;;) {
        loop();
        if (serialEventRun) serialEventRun();
    }
        
    return 0;
}

which means once you define Serial, it checks at the end of every loop() for a serial event to process which does take time. If you never define it, it skips that section of code.

SoftwareSerial doesn't use the hardware so doesn't do that.

@aarg, I just tried what you proposed but no difference. @blh64, thank you for explaining this. Does this make SoftwareSerial a better choice if you mind about performance ? I guess it need some more memory, but besides that, is there any advantage with Serial vs SoftwareSerial ?

blh64: If you look at the main program the arduino runs, it is basically this

int main(void)
{
 init();

setup();     for (;;) { loop(); if (serialEventRun) serialEventRun(); }         return 0; }




which means once you define Serial, it checks at the end of every loop() for a serial event to process which does take time.

Wrong. It does not take any more time if you don't define serialEventRun().

If you need Serial communication then SoftwareSerial is NEVER a better choice than HardwareSerial. SoftwareSerial uses up a lot of CPU cycles.

...R

blh64: which means once you define Serial, it checks at the end of every loop() for a serial event to process which does take time. If you never define it, it skips that section of code.

Somewhat off-topic, but I had not thought of this and I never use SerialEvent so now I wonder should I make myself a copy of the IDE with main() modified so it does not waste time doing that check.

...R

Robin2: If you need Serial communication then SoftwareSerial is NEVER a better choice than HardwareSerial. SoftwareSerial uses up a lot of CPU cycles.

...R

I dont understand. Can you please explain how I could use Serial instead of SoftwareSerial without any performance penalty ? In my case, I need serial communication only occasionally (when performance does not matter) but when it is not in use I want the best performance. In my example above, SoftwareSerial has no performance impact, but Serial does.

@Robin That if will take a few cpu cycles; most code will not benefit from it. And there is a good chance that the compiler optimises it away.

bb328: I dont understand. Can you please explain how I could use Serial instead of SoftwareSerial without any performance penalty ? In my case, I need serial communication only occasionally (when performance does not matter) but when it is not in use I want the best performance. In my example above, SoftwareSerial has no performance impact, but Serial does.

I guess if you only need to send data occasionally the saving from not testing for Serial in every iteration of loop() might outweigh the CPU cycles needed to send the data using SoftwareSerial. If so I suspect yours is a very unusual case.

...R

Robin2: Somewhat off-topic, but I had not thought of this and I never use SerialEvent so now I wonder should I make myself a copy of the IDE with main() modified so it does not waste time doing that check.

...R

Or just leave loop() empty and make your own while(1) loop in setup()...

OP, I don't see how you expect to bit bang an output pin continuously, in some future sketch, and also use serial communications? The basic idea is a non-starter regardless of what kind of serial you use. In fact, I don't see how you could possible run ANY other code and still bit bang (without interruptions).

@aarg,

I am not planning to bit bang an output pin continuously. I just happened to find that mentioning "Serial" (like "Serial.begin") had a performance impact, so I minimized the sketch just to narrow things down and find what was causing it. Just because I want to know the rules, for future programming. Now I understand what is happening and why.

Thank you all.

At least in semi-recent versions of the board package, main is weakly defined, you can override it with your own main that doesnt have the serialevent stuff.

The big performance difference is when you actually send send or receive something. Serial does the (fairly slow) by putting the data into an output buffer, and sending through the hardware in the background, with a fast ISR every time a character sends to pass the next one to hardware. Software serial, on the other hand, takes 100% of the processors attention while data is coming out on serial (on hardware serial if output buffer is full, it will wait for it to empty enough to get the full string in there too, but if you hit this limit, you are trying to send too much data too fast (eg, printing every pass through loop). Software serial cannot send and receive at the same time, hardware serial can, and software serial also eats all the PCINT interrupts, while hardware serial does t touch them.

I avoid software serial whenever possible

oqibidipo: Wrong. It does not take any more time if you don't define serialEventRun().

Running another function vs. not running it certainly does take time. That is what the OP measured which began this topic