- It can NOT achieve highest speed actually possible by hardware UART underlying in it's core processor due to overhead in it's library implementation
- It's bloated in size, consuming a lot of unoptimized code
- It's hide powerful options which can be actually utilized to maximize performance
These conditions are actually derived from necessity (for Arduino broad range of user level) because Arduino library were intended to transparently support broad range of MCUs (resulting in unoptimized code) and to cover unexperienced programmer by rechecking every possible conditions which may lead to program malfunction. Take example the digitalRead example which checks PWM state every time it's being invoked.
Now, since we're trying to boost up Arduino to it's maximum potential, we need to understand the background process, sometimes in it's lowest level. Once we understand them, we can write efficient code which execute faster and consuming less resource than those consumed by the standard library.
The most source of information is certainly from Atmel's own-released datasheet. If you haven't had one, take a time to download it: [ ATmega328P Datasheet Complete Edition ]
USART is described in detail on it's own section, please refer to page 127-156 on the datasheet. For your convenience, some parts are copy-pasted on this article (marked with yellowish background).
USART Features on ATmega328The Universal Synchronous and Asynchronous serial Receiver and Transmitter (USART) is a highly-flexible serial communication device. The main features are:
|
A simplified block diagram of the USART Transmitter is shown in following figure. CPU accessible I/O
Registers are shown with green boxes, and I/O pins are shown in blue boxes. The USART Data Register UDR is shown in yellow boxes. Please note that altough shown as two boxes in diagram below, there is only one UDR register which functioned as register for holding either received byte / byte to be transmitted.
On diagram above, you'll notice on the top block is Clock Generator section. This section conduct the whole orchestra of USART operations. It generates the base clock for the Transmitter and Receiver.
There are four modes of clock operations:
To activate Double Speed Asynchronous mode, after clearing the UMSEL bit (to set USART into Async mode), set the U2X bit of UCSRA register. Clearing the U2X bit bring back USART to normal Async mode. For synchronous mode, this bit has no effect and should be cleared.
For Synchronous mode (UMSEL=1), data is clocked in sync with
Except for Synchronous Slave Mode, all other modes requires the MCU to generate clock signal. This is done internally by Clock Generator section (refer back to block diagram above).
As shown in the diagram, register related to this section is
Following is detailed block diagram of Clock Generator section:
The UBRR and the down-counter connected to it function as a programmable prescaler or baud rate generator. The down-counter, running at system clock (fosc), is loaded with the UBRR value each time the counter has counted down to zero or when the lower byte (UBRRL) Register is written. A clock is generated each time the counter reaches zero. This clock is the baud rate generator clock output, equal to fosc / (UBRR+1).
The Transmitter divides the baud rate generator clock output by 2, 8, or 16 depending on mode being selected. The baud rate generator output is used directly by the Receiver's clock and data recovery units. However, the recovery units use a state machine that uses 2, 8, or 16 states depending on mode set by the state of the UMSEL, U2X and DDR_XCK bits (examine flow logic shown by arrow lines on the diagram).
Following table constains equations for calculating the baud rate (in bits per second) and for calculating the UBRR value for each mode of operation using an internally generated clock source:
BAUD = Baud rate (in bits per second, bps)
fosc = System Oscillator clock frequency
UBRR = Contents of UBRRH and UBRRL Registers (12 bits, 0-4095)
Thus for fosc = 16 MHz (frequency of oscillator used in Arduino Uno), we can calculate the value of UBRR on Async Double Speed Mode (U2X=1) by formula:
= ( 2,000,000 / BAUD ) - 1
According to this equation, following is the value for common baud rates (Error Margin on the third row is rounding error caused by rounding a float number into it's corresponding integer value):
Registers are shown with green boxes, and I/O pins are shown in blue boxes. The USART Data Register UDR is shown in yellow boxes. Please note that altough shown as two boxes in diagram below, there is only one UDR register which functioned as register for holding either received byte / byte to be transmitted.
On diagram above, you'll notice on the top block is Clock Generator section. This section conduct the whole orchestra of USART operations. It generates the base clock for the Transmitter and Receiver.
There are four modes of clock operations:
- Normal Asynchronous mode
- Double Speed Asynchronous mode
- Master Synchronous mode
- Slave Synchronous mode
To activate Double Speed Asynchronous mode, after clearing the UMSEL bit (to set USART into Async mode), set the U2X bit of UCSRA register. Clearing the U2X bit bring back USART to normal Async mode. For synchronous mode, this bit has no effect and should be cleared.
For Synchronous mode (UMSEL=1), data is clocked in sync with
XCK
pin (PD.4, pin#6 of ATmega328). In this case, value of DDR_XCK (Data Direction Register for XCK Pin) determine whether the clock source is internal (Master mode, MCU is the one who generate clock signal into XCK
pin) or external (Slave mode, MCU is following clock signaled on XCK
pin from other party). The XCK
in is only active when using Synchronous mode. Please note that while in Sync mode, since PD.4
is shared the same physical pin as XCK
(pin#6), it's no longer functioned as General I/O pin.Except for Synchronous Slave Mode, all other modes requires the MCU to generate clock signal. This is done internally by Clock Generator section (refer back to block diagram above).
As shown in the diagram, register related to this section is
UBRR
, acronym for USART Bit Rate Register. It's actually a 12-bit register, thus it's divided into two byte: UBRRH register for the high-byte (note that only lower nibble of this register is being used) and UBRRL register for the low-byte.Following is detailed block diagram of Clock Generator section:
The UBRR and the down-counter connected to it function as a programmable prescaler or baud rate generator. The down-counter, running at system clock (fosc), is loaded with the UBRR value each time the counter has counted down to zero or when the lower byte (UBRRL) Register is written. A clock is generated each time the counter reaches zero. This clock is the baud rate generator clock output, equal to fosc / (UBRR+1).
The Transmitter divides the baud rate generator clock output by 2, 8, or 16 depending on mode being selected. The baud rate generator output is used directly by the Receiver's clock and data recovery units. However, the recovery units use a state machine that uses 2, 8, or 16 states depending on mode set by the state of the UMSEL, U2X and DDR_XCK bits (examine flow logic shown by arrow lines on the diagram).
Following table constains equations for calculating the baud rate (in bits per second) and for calculating the UBRR value for each mode of operation using an internally generated clock source:
BAUD = Baud rate (in bits per second, bps)
fosc = System Oscillator clock frequency
UBRR = Contents of UBRRH and UBRRL Registers (12 bits, 0-4095)
Thus for fosc = 16 MHz (frequency of oscillator used in Arduino Uno), we can calculate the value of UBRR on Async Double Speed Mode (U2X=1) by formula:
UBRR
= ( 16,000,000 / 8*BAUD ) - 1= ( 2,000,000 / BAUD ) - 1
Baud Rate | 2400 | 4800 | 9600 | 14.4K | 19.2K | 28.8K | 38.4K | 57.6K | 115.2K | 250K |
---|---|---|---|---|---|---|---|---|---|---|
UBBR Value | 832 | 416 | 207 | 138 | 103 | 68 | 51 | 34 | 16 | 7 |
Error Margin | — | -0.1% | 0.2% | -0.1% | 0.2% | -0.6% | 0.2% | -0.8% | 2.1% | — |
Note that in Double Speed mode, although for Transmitter it has no down-effect, the Receiver will only use half the number of samples (reduced from 16 to 8) for data sampling and clock recovery (it's the cost we paid for doubling the speed). Thus in this mode a more accurate baud rate setting and system clock are required. Avoid using baud rate with high error margin (such 28.8K, 57.6K, and especially 115.2K with 2.1% error margin). If you need to use 115.2K, better use Normal Async mode (with double speed turned off, U2X=0) and set UBRR value to 8 (although it's error margin will be increased to -3.5%, but with double sample the USART can compensate better and less prone from error).
[ to be continued ]
No comments:
Post a Comment