USI Serial, Hardware Serial for ATtiny

Download from my github: GitHub - frank26080115/Arduino-UsiSerial-Library: Arduino library to implement hardware serial using USI

UsiSerial is a simple wrapper around the code from AVR307 so that Arduino can use USI to implement a hardware serial port

The USI class works almost exactly like HardwareSerial
So you can use print and println and other functions like that

PORTB0 is DI, thus it is RX
PORTB1 is DO, thus it is TX
default baud rate is 19200, which can only be changed in USI_UART_config.h
only some baud rates will work, depending on CPU frequency
buffers are small to save memory, since this library is designed for ATtiny
testing was done using a 16 MHz Trinket

I don't know if this has been done before but I needed it and wrote it just a few minutes ago

Thanks for sharing,

From a quick look at the usi-uart-config.h I can't immediately see how to know if it would work on an Attiny45 at 1MHz?


From a quick look at the usi-uart-config.h I can't immediately see how to know if it would work on an Attiny45 at 1MHz?


Right, this is a complicated calculation, you can't see it immediately. So if you really want to know, you need to go through the #define preprocessor calculations by hand.

If the final calculated timer value is too low, then the ISR may not execute fast enough

If the timer value is large enough, then the second problem is accuracy. There are two values, one for half of a bit and one for one full bit width. You need to compare what the full bit width should be with the one calculated by the preprocessor.

To be fair, 1 MHz is not exactly a UART friendly clock speed to begin with, and it is already super slow. On an ATmega (I know we are using ATtiny), you can probably achieve 2400, 4800, and 9600 baud (I'm looking at the table inside the datasheet for an ATmega328P, 9600 requires the 2X speed bit to be set as well). I'm not exactly hopeful.

Going through step by step for 9600 baud (I'm kind of interested myself so I'll go through it with you)

#define TIMERn_SEED               (256 - ( (SYSTEM_CLOCK / BAUDRATE) / TIMER_PRESCALER ))
#define TIMERn_SEED               (256 - ( (1000000/ 9600) / 1))

This calculates to 152

#define TIMER_PRESCALER           1
#if ( (( (1000000 / 9600) / 1) * 3/2) > (256 - 0x11) )
#if ((156) > (239))

This is false, so we go to the #else

    #define INITIAL_TIMERn_SEED       ( 256 - (( (SYSTEM_CLOCK / BAUDRATE) / TIMER_PRESCALER ) * 3/2) )
    #define INITIAL_TIMERn_SEED       ( 256 - (( (1000000/ 9600) / 1) * 3/2) )
    #define USI_COUNTER_SEED_RECEIVE  (16 - 8)

INITIAL_TIMERn_SEED calculates to 100

Both of these should be large enough for the ISR to execute completely before the next ISR

Now to calculate the accuracy

9600 baud means a bit width of 104.17us, while TIMERn_SEED is 152 which is 152us, which is way too bad.

sidenote: how do I know my calculations match what the compiler is actually doing? I'm using C code - 19 lines - codepad

#define SYSTEM_CLOCK 1000000UL
#define BAUDRATE 9600
#define DATA_BITS 8
#define TIMERn_SEED               (256 - ( (SYSTEM_CLOCK / BAUDRATE) / TIMER_PRESCALER ))
    #define INITIAL_TIMERn_SEED       ( 256 - (( (SYSTEM_CLOCK / BAUDRATE) / TIMER_PRESCALER ) * 1/2) )
    #define INITIAL_TIMERn_SEED       ( 256 - (( (SYSTEM_CLOCK / BAUDRATE) / TIMER_PRESCALER ) * 3/2) )

int main(void)
    return 0;

Thanks for that - I was hoping it might be simpler than my own solution SmallSerial. No Magic Numbers. Works on Uno 16Mhz and Attiny 1Mhz - Libraries - Arduino Forum - but appears not to be.


I tried writing a simple code which prints "hello world". I connected the tx of the tiny to the tx of the arduino and guessed that it would show me the same message on the serial monitor. But unfortunately it didn't. The baud rates were same but the monitor just kept on scrolling horizontally without actually showing any text.

I am trying to use this on attiny85 and programming it using the usbtinyisp, and the tiny core at Google Code Archive - Long-term storage for Google Code Project Hosting.. Tried using the 8Mhz and 16MHz(using PLL) versions of the board. Also tried different baud rates besides the default 19.2k @ 16Mhz, by changing the config file, taking help from AVR307.
For example,
57.6k @ 8Mhz by setting SYSTEM_CLOCK 8000000 and BAUDRATE 57600
19.2k@16Mhz by setting SYSTEM_CLOCK 8000000, TIMER_PRESCALER 8 and BAUDRATE 19200
115.2k@16Mhz by setting SYSTEM_CLOCK 16000000 and BAUDRATE 115200 etc.

But all this didn't change anything in the output. What am I doing wrong ?