[SOLVED] Low-speed serial: How is it possible?

Hi all, A little technical question that came up while I was reading Arduino's Serial source code.

I can write, for example, Serial.begin(110) and get an appropriate signal from Serial.write(...).

In the HardwareSerial::begin method, the code goes like this:

[...] baud_setting = (F_CPU / 8 / baud - 1) / 2;

For 110, on a 16MHz Arduino, the result should be 9090. This goes into the UBRRn register pair:

 *_ubrrh = baud_setting >> 8;
  *_ubrrl = baud_setting;

So far so good. However, in the ATmega328 datasheet, it states that UBRRn is only 12 usable bits, i.e. up to 4095. The rest of the bits are "reserved for future use [...] these bit [sic] must be written to zero when UBRRnH is written." (page 205).

So, how does 9090 fit into 4095? :)

Thanks!

There are two possibilities: lower the CPU oscillator frequency or use "bit banged" (UART emulator) code to read/write at that baud rate.

jremington: There are two possibilities: lower the CPU oscillator frequency or use "bit banged" (UART emulator) code to read/write at that baud rate.

But the regular Arduino, with the regular Serial, manages to do it without changing the CPU clock and without bitbanging...

I don't see how that could work - if you think you're getting correct output, I believe you're mistaken - it's got to be going at a different speed than you think it is.

If you've done that on both sides with an Arduino at 16mhz, it would appear to be working, but would be running at... whatever baud rate you'd get if you only looked at the lowest 12 bits, I think.

igendel:
I can write, for example, Serial.begin(110) and get an appropriate signal from Serial.write(…).

So far so good. However, in the ATmega328 datasheet, it states that UBRRn is only 12 usable bits, i.e. up to 4095.

So, how does 9090 fit into 4095? :slight_smile:

When you say your getting an appropriate signal what do you mean and how are you testing it to confirm the correct baud rate. Maybe it truncating the 9090 to 12 bits (898) and setting an approx 2400/1200 baud rate (depending on U2Xn value.

Riva: When you say your getting an appropriate signal what do you mean and how are you testing it to confirm the correct baud rate.

Two tests, actually. First, I sent strings successfully to a terminal on the PC where I can set the baud rate to 110. Second, I sent various byte values using Serial.write, and got a rather clear signal on a scope with ~1.8ms per "bit", as expected for 110 bps.

Do your math

igendel: and got a rather clear signal on a scope with ~1.8ms per "bit", as expected for 110 bps.

1000 ms/second, divided by 110 bits/second does NOT equal 1.8 ms. I get 9.1ms expected bit length...

Also - many serial adapters have restrictions on what baud rates they support... What were you using as the terminal on the PC? What are you using as the serial adapter?

1.8 ms/bit is 555 baud.

I’ll bet he’s measuring a “bit” as what appears to be a high/low period instead of just a high or a low. The 9090 value, when truncated, calculates to 1112 baud, twice what he measured.

jremington: 1.8 ms/bit is 555 baud.

Yes, I screwed up the calculation somewhere along the way... better try to find the logic analyzer to see the signal for what it really is.

On the PC (Windows) I have my own software (http://www.idogendel.com/en/products/serial-monitor-deluxe) that's using some standard COM port library. I read somewhere that 110 baud is the minimum supported by Windows, hence this specific value.

jboyton: I'll bet he's measuring a "bit" as what appears to be a high/low period instead of just a high or a low. The 9090 value, when truncated, calculates to 1112 baud, twice what he measured.

"He"? I'm right here man... :) I did not measure high+low, but my old scope is not a perfect tool for such measurements anyway. I'll try to get better information later today.

better try to find the logic analyzer to see the signal for what it really is.

Who cares what it really is? It is straightforward to generate 110 baud in software.

jremington:
Who cares what it really is? It is straightforward to generate 110 baud in software.

Again, my goal here is NOT to generate 110 baud, but to understand how the ATMega328 does it at 16MHz - assuming it’s not just a misunderstanding on my part.

Ok... indeed, a logic analyzer is far better for these things than a CRT scope :-)

  1. The Arduino can't in fact go below 245 baud (as expected according to the datasheet). Sending lower values to Serial.begin just makes a mess and causes data to be sent at higher rates.

  2. Amazingly though, Windows terminal programs such as my own or RealTerm play along with this! If I tell them the incoming data is 110 baud, they display it correctly!

Thanks to all who helped me with this.

What hardware are you using as the serial adapter? If is the soak on an uno, with the 16u2 it has an Atmel uart too with the same limitation, and probably a naive enough implementation of usb-serial on the chip that it could be doing the same thing

DrAzzy: What hardware are you using as the serial adapter? If is the soak on an uno, with the 16u2 it has an Atmel uart too with the same limitation, and probably a naive enough implementation of usb-serial on the chip that it could be doing the same thing

That makes sense. I only tried this with an Uno R3; If Windows simply trusts the adapter for correct timing, this explains the terminal softwares' behavior as well.

igendel: "He"? I'm right here man... :)

Sorry about the third person reference, I didn't mean anything by it. I'm still learning how to behave properly on the internet.

igendel: 1. The Arduino can't in fact go below 245 baud (as expected according to the datasheet). Sending lower values to Serial.begin just makes a mess and causes data to be sent at higher rates.

Not that you'd want to do it this way, but you could change the system clock prescaler rate in your sketch and achieve 110 baud.

jboyton:
Sorry about the third person reference, I didn’t mean anything by it. I’m still learning how to behave properly on the internet.

Don’t worry about it.

jboyton:
Not that you’d want to do it this way, but you could change the system clock prescaler rate in your sketch and achieve 110 baud.

It all began because I simply got curious, what’s the lowest baud rate the Arduino could handle without tricks (the Serial documentation is silent on this). I have yet to find an actual use for such low rates.

I did wonder once, what would happen if I clocked an MCU using an LDR on the roof as an external clock source. Could it provide a day-scale clock? And if I wrote a loop that’s exactly 7 instruction cycles long, can I make the setup light an LED every Sunday? :smiley:

I think you could. According to the datasheet the minimum external clock frequency is zero.

Well, you'd need to write it in pure C, as digitalWrite() would take over a month to run, not to mention setup() and init()... and an LDR isn't a very clean clock source.... You'd need some external parts to get something close enough to a clock signal out of it I think...

Re: forum conventions

I've seen and used "he" (or she, if girls ever posted - they must all be great at electronics, I hardly ever see any asking for help here) to refer to another poster in a thread, even if said poster is still active. In fact, he's you're the first person I've seen take issue with that construction. It's most commonly used when commenting on a question raised by another poster in response to the "he"-person, where one is providing an answer to that other comment, but which is expected to be of little value to the "he"-person (maybe because others have already covered what he needs to know), hence I'm addressing the other posters rather than the "he"-person.