Sunday, November 24, 2013

Virtual USB port for AVR Microcontrollers

V-USB (formerly known as AVR-USB) is a software-only implementation of a low-speed USB device for Atmel’s AVR® microcontrollers, making it possible to build USB hardware with almost any AVR® microcontroller, not requiring any additional chip.

V-USB can be licensed freely under the GNU General Public License or alternatively under a commercial license. A comprehensive set of example projects demonstrates the wide range of possible applications.

Features of V-USB:
  • Fully USB 1.1 compliant low-speed device, except handling of communication errors and electrical specifications.
  • Example projects demonstrate device and host driver implementations on Linux, Mac OS X and Windows.
  • Supports multiple endpoints: one control endpoint, two interrupt/bulk-in endpoints and up to 7 interrupt/bulk-out endpoints. (Note that the USB specification forbids bulk endpoints for low speed devices, but V-USB supports them to some degree.)
  • Transfer sizes up to 254 bytes by default, more as configuration option.
  • Comes with freely usable USB identifiers (Vendor-ID and Product-ID pairs).
  • Runs on any AVR microcontroller with at least 2 kB of Flash memory, 128 bytes RAM and a clock rate of at least 12 MHz.
  • No UART, timer, input capture unit or other special hardware is required (except one edge triggered interrupt).
  • Can be clocked with 12 MHz, 15 MHz, 16 MHz or 20 MHz crystal or from a 12.8 MHz or 16.5 MHz internal RC oscillator.
  • High level functionality is written in C and is well commented.
  • Only about 1150 to 1400 bytes code size.
  • Choice of licensing type: Open Source or commercial.
This diagram shows a typical circuit for a bus powered device using Atmel ATtiny2313 MCU...
D1 and D2 are a low cost replacement for a low drop 3.3 V regulator chip, such as the LE33. Operating the AVR at higher voltages exceeds the common mode range of many USB chips. If you need to run the AVR at 5 V, add 3.6 V zener diodes at D+ and D- to limit the voltage.
Download the V-USB package containing a short description and several simple code examples.

Tuesday, November 12, 2013

Arduino UNO USART

Arduino Uno utilizing ATmega328P for it's main controller. Usually we use Hardware Serial library provided by Arduino. It's great library, except for three factors:
  1. 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
  2. It's bloated in size, consuming a lot of unoptimized code
  3. 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 ATmega328

The Universal Synchronous and Asynchronous serial Receiver and Transmitter (USART) is a highly-flexible serial communication device. The main features are:
  • Full Duplex Operation (Independent Serial Receiveand Transmit Registers)
  • Asynchronous or Synchronous Operation
  • Master or Slave Clocked Synchronous Operation
  • High Resolution Baud Rate Generator
  • Supports Serial Frames with 5, 6, 7, 8, or 9 Databits and 1 or 2 Stop Bits
  • Odd or Even Parity Generation and Parity Check Supported by Hardware
  • Data OverRun Detection
  • Framing Error Detection
  • Noise Filtering Includes False Start Bit Detection and Digital Low Pass Filter
  • Three Separate Interrupts on TX Complete, TX Data Register Empty and RX Complete
  • Multi-processor Communication Mode
  • Double Speed Asynchronous Communication Mode

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.

ATmega328 USART Block Diagram

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 select Asynchronous mode, clear UMSEL bit in UCSRC (USART Control and Status Register C). In other hand, set UMSEL bit to select 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:

USART Clock Generator Block Diagram

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
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):

Baud Rate24004800960014.4K19.2K28.8K38.4K57.6K115.2K250K
UBBR Value832416207138103685134167
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 ]

Monday, October 21, 2013

Fastest digitalRead / digitalWrite Alternative

Arduino's standard digitalRead/digitalWrite is well known for two reasons: it's simplicity / ease to use, and... it's extraordinary slow speed.

Fastest alternative is by using direct port manipulation. For example, alternative to digitalWrite( 13, HIGH ) is PORTB |= (1 << 5). Compiler will translated that code into 2-cycle instruction using sbi opCode. In 16 MHz, it will be executed in about 130 nano-seconds.

However it's not equivalent of digitalWrite. Beside of setting corresponding pin with specified value, digitalWrite also check and turn PWM output off for corresponding pin with PWM capability. If you've previously use PWM on corresponding pin (i.e., by invoking analogWrite function), this method won't work.

Anyway, this condition is rarely encountered. Usually once a pin assigned as PWM-driven pin, it will never reverted back to "normal" (non-PWM-driven) pin. So rather than wasting execution time on invoking unnecessary code, we should take a little bit control and explicitly turn PWM off only if it's really necessary.

To keep it simple and easy to use, we'll use following macros (note that this code only works with ATmega8/168/328-based board such Arduino Uno. Other MCU might have different pin numbering!):

#define portOfPin(P)\
  (((P)>=0&&(P)<8)?&PORTD:(((P)>7&&(P)<14)?&PORTB:&PORTC))
#define ddrOfPin(P)\
  (((P)>=0&&(P)<8)?&DDRD:(((P)>7&&(P)<14)?&DDRB:&DDRC))
#define pinOfPin(P)\
  (((P)>=0&&(P)<8)?&PIND:(((P)>7&&(P)<14)?&PINB:&PINC))
#define pinIndex(P)((uint8_t)(P>13?P-14:P&7))
#define pinMask(P)((uint8_t)(1<<pinIndex(P)))

#define pinAsInput(P) *(ddrOfPin(P))&=~pinMask(P)
#define pinAsInputPullUp(P) *(ddrOfPin(P))&=~pinMask(P);digitalHigh(P)
#define pinAsOutput(P) *(ddrOfPin(P))|=pinMask(P)
#define digitalLow(P) *(portOfPin(P))&=~pinMask(P)
#define digitalHigh(P) *(portOfPin(P))|=pinMask(P)
#define isHigh(P)((*(pinOfPin(P))& pinMask(P))>0)
#define isLow(P)((*(pinOfPin(P))& pinMask(P))==0)
#define digitalState(P)((uint8_t)isHigh(P))

Thus, you can save valuable code space and get dramatically faster execution by changing:
  • pinMode( pin, INPUT ); with pinAsInput( pin );
  • pinMode( pin, OUTPUT ); with pinAsOutput( pin );
  • pinMode( pin, INPUT_PULLUP); with pinAsInputPullUp( pin );
  • digitalWrite( pin, LOW ); with digitalLow( pin );
  • digitalWrite( pin, HIGH ); with digitalHigh( pin );
  • digitalRead( pin ) with digitalState( pin )

Additionally, rather than typing if( digitalState( pin ) == HIGH ) you can type if( isHigh( pin ) ) for clearer code clarity. Also use isLow( pin ) rather than digitalState( pin ) == LOW.

Now let's try it in action. Load the Blink.pde example sketch and try to compile. You'll get 1,084 bytes of compiled code. Now insert our new macros in the beginning of the file, and replace the code according to
changing guide above.

Your source code will be like this (comments removed, newly inserted macros are not shown):

int led = 13;

void setup() {              
  pinAsOutput(led);
}

void loop() {
  digitalHigh( led );
  delay( 1000 );
  digitalLow( led );
  delay( 1000 );
}

After compiling, we'll get size reduction to 956 bytes. Not much fat-loss, eh? Actually you can get much smaller code, by changing the way you define associated led symbol.

First, it's defined as int (with range from -32,768 to 32,767) which taken 2 bytes. A pin number in Arduino Uno is from 0 to 19, so it's a waste to declared it as int (2 bytes). If you really need to put it in variable, you should defined it with byte (uint8_t) type.

Second, and most importantly, since the LED won't changed it's pin attachment on middle of execution, you should define it as constant with const keyword. This way, compiler will evaluate associated macro condition in compile time (instead of making actual run-time code to evaluate variable arguments).

Take hard notice on this issue. Under any circumstances, use variable only if you need to change it's value (variable ⇒ able to vary) throughout execution. Otherwise, always use const (constant ⇒ always the same, never changed).  You'll save a lot of code space and execution time by follow this simple rule.

So, try changing the int led = 13; statement with const byte led = 13 (or simply #define led 13) and recompile you code. Now your slim program only takes 674 bytes, more than 30% size reduction!

How fast is digitalHigh / digitalLow versus digitalWrite in common 16 MHz clockrate? For digitalWrite  it depends on whether specified pin has PWM capabilities or not  (from about 3.6 µs to  4.8 µs). For digitalHigh / digitalLow, it is exactly 130 ns (2 cycles), so it's between 27-37 times faster).