SlashDevin / NeoSWSerial

Efficient alternative to SoftwareSerial with attachInterrupt for RX chars, simultaneous RX & TX
173 stars 42 forks source link

Add Baudrate 4800 #32

Open Markus1995 opened 5 years ago

Markus1995 commented 5 years ago

Hello, Can you please implent also 4800 as Baudrate? Thank You

thielj commented 5 years ago

+1 - 4800 is commonly used for NMEA and GPS receivers

SRGDamia1 commented 5 years ago

4800 is too slow to use without requiring the use of an additional timer. It could be supported, but it wouldn't meet the goal of having no requirements.

thielj commented 5 years ago

Hi @SRGDamia1, wouldn't this just be the following or am I missing something?

      case 4800:
        txBitWidth      = TICKS_PER_BIT_9600 << 1;
        bitsPerTick_Q10 = BITS_PER_TICK_38400_Q10 >> 3;
SRGDamia1 commented 5 years ago

No, just doing that won't work. The timer that we need the ticks from is only 8-bit and with the "Arduino standard" pre-scaler set, each tick is 4µs. So the timer will roll over after 2564µs = 1.024ms. At 4800 baud you have (1+8+1)bits / 1character 1sec / 4800bits = 2.083ms. So you'd have no way of knowing how many ticks actually happened between bits because the timer might have rolled over (twice) in the middle.

You could get around this by summoning up another timer with a different pre-scaler (like Timer2, which the 8MHz boards already need). But I think one of @SlashDevin 's goals for this library is to have no extra requirements when being used on a "standard" board like an Uno.

thielj commented 5 years ago

Why not use micros() instead of accessing TCNT0 directly? It keeps track of timer overflows and should be safe to use at the beginning of the interrupt handler.

SRGDamia1 commented 5 years ago

I tried using micros at 1200 baud, and it didn't work. I think the extra overhead of calling micros() is too much: https://github.com/SlashDevin/NeoSWSerial/issues/23

thielj commented 5 years ago

Even if you simplify micros and eliminate all costly math?

// to be called once at start of interrupt handler
inline uint16_t ticks() {
    uint8_t m = (uint8_t) timer0_overflow_count;
    uint8_t t = TCNT0;
    if ((TIFR0 & _BV(TOV0)) && (t < 255))
        ++m;
    return ((uint16_t)m << 8) | t;
}
SRGDamia1 commented 5 years ago

I didn't try that.