├── ReadMe.txt
└── UsiSerial
├── USI_UART.c
├── USI_UART_config.h
├── UsiSerial.cpp
├── UsiSerial.h
└── examples
└── UsiSerialEchoExample
└── UsiSerialEchoExample.ino
/ReadMe.txt:
--------------------------------------------------------------------------------
1 | /* UsiSerial by me@frank-zhao.com
2 | *
3 | * UsiSerial is a simple wrapper around the code from AVR307 so that Arduino can use USI to implement a hardware serial port
4 | *
5 | * The USI class works almost exactly like HardwareSerial
6 | * So you can use print and println and other functions like that
7 | *
8 | * PORTB0 is DI, thus it is RX
9 | * PORTB1 is DO, thus it is TX
10 | * default baud rate is 19200, which can only be changed in USI_UART_config.h
11 | * only some baud rates will work, depending on CPU frequency
12 | * buffers are small to save memory, since this library is designed for ATtiny
13 | * testing was done using a 16 MHz Trinket
14 | *
15 | * Important note: requires Timer1 and PCINT to be occupied
16 | *
17 | Copyright (c) 2013 Frank Zhao
18 | All rights reserved.
19 |
20 | UsiSerial is free software: you can redistribute it and/or modify
21 | it under the terms of the GNU Lesser General Public License as
22 | published by the Free Software Foundation, either version 3 of
23 | the License, or (at your option) any later version.
24 |
25 | UsiSerial is distributed in the hope that it will be useful,
26 | but WITHOUT ANY WARRANTY; without even the implied warranty of
27 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 | GNU Lesser General Public License for more details.
29 |
30 | You should have received a copy of the GNU Lesser General Public
31 | License along with UsiSerial. If not, see
32 | .
33 | */
--------------------------------------------------------------------------------
/UsiSerial/USI_UART.c:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 | *
3 | * Copyright (C) 2003 Atmel Corporation
4 | *
5 | * File : USI_UART.c
6 | * Created : 18.07.2002 by JLL
7 | * Modified : 02-10-2003 by LTA
8 | *
9 | * Support mail : avr@atmel.com
10 | *
11 | * Supported devices : ATtiny26
12 | *
13 | * Application Note : AVR307 - Half duplex UART using the USI Interface
14 | *
15 | * Description : Functions for USI_UART_receiver and USI_UART_transmitter.
16 | * Uses Pin Change Interrupt to detect incomming signals.
17 | *
18 | * Modified by Frank Zhao to work with Arduino
19 | ****************************************************************************/
20 |
21 | #include
22 | #include
23 | #include "USI_UART_config.h"
24 |
25 |
26 | //********** USI UART Defines **********//
27 |
28 | #define DATA_BITS 8
29 | #define START_BIT 1
30 | #define STOP_BIT 1
31 | #define HALF_FRAME 5
32 |
33 | #define USI_COUNTER_MAX_COUNT 16
34 | #define USI_COUNTER_SEED_TRANSMIT (USI_COUNTER_MAX_COUNT - HALF_FRAME)
35 | #define INTERRUPT_STARTUP_DELAY (0x11 / TIMER_PRESCALER)
36 | #define TIMERn_SEED (256 - ( (SYSTEM_CLOCK / BAUDRATE) / TIMER_PRESCALER ))
37 |
38 | #if ( (( (SYSTEM_CLOCK / BAUDRATE) / TIMER_PRESCALER ) * 3/2) > (256 - INTERRUPT_STARTUP_DELAY) )
39 | #define INITIAL_TIMERn_SEED ( 256 - (( (SYSTEM_CLOCK / BAUDRATE) / TIMER_PRESCALER ) * 1/2) )
40 | #define USI_COUNTER_SEED_RECEIVE ( USI_COUNTER_MAX_COUNT - (START_BIT + DATA_BITS) )
41 | #else
42 | #define INITIAL_TIMERn_SEED ( 256 - (( (SYSTEM_CLOCK / BAUDRATE) / TIMER_PRESCALER ) * 3/2) )
43 | #define USI_COUNTER_SEED_RECEIVE (USI_COUNTER_MAX_COUNT - DATA_BITS)
44 | #endif
45 |
46 | #define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1 )
47 | #if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK )
48 | #error RX buffer size is not a power of 2
49 | #endif
50 |
51 | #define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1 )
52 | #if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK )
53 | #error TX buffer size is not a power of 2
54 | #endif
55 |
56 | /* General defines */
57 | #ifndef TRUE
58 | #define TRUE 1
59 | #endif
60 | #ifndef FALSE
61 | #define FALSE 0
62 | #endif
63 |
64 | // Frank: original AVR307 used timer0 but timer0 is used by Arduino's core, so these defines use timer1
65 | #define USI_UART_TCNTn TCNT1
66 | #define USI_UART_TCCRn TCCR1
67 | #define USI_UART_TOVn TOV1
68 | #define USI_UART_TOIEn TOIE1
69 |
70 | //********** Static Variables **********//
71 |
72 | static unsigned char USI_UART_TxData;
73 |
74 | unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE]; // UART buffers. Size is definable in the header file.
75 | volatile unsigned char UART_RxHead;
76 | volatile unsigned char UART_RxTail;
77 | static unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];
78 | static volatile unsigned char UART_TxHead;
79 | static volatile unsigned char UART_TxTail;
80 |
81 | static volatile union USI_UART_status // Status byte holding flags.
82 | {
83 | unsigned char status;
84 | struct
85 | {
86 | unsigned char ongoing_Transmission_From_Buffer:1;
87 | unsigned char ongoing_Transmission_Of_Package:1;
88 | unsigned char ongoing_Reception_Of_Package:1;
89 | unsigned char reception_Buffer_Overflow:1;
90 | unsigned char flag4:1;
91 | unsigned char flag5:1;
92 | unsigned char flag6:1;
93 | unsigned char flag7:1;
94 | };
95 | } USI_UART_status = {0};
96 |
97 |
98 | //********** USI_UART functions **********//
99 |
100 | // Reverses the order of bits in a byte.
101 | // I.e. MSB is swapped with LSB, etc.
102 | static inline unsigned char Bit_Reverse( unsigned char x )
103 | {
104 | x = ((x >> 1) & 0x55) | ((x << 1) & 0xaa);
105 | x = ((x >> 2) & 0x33) | ((x << 2) & 0xcc);
106 | x = ((x >> 4) & 0x0f) | ((x << 4) & 0xf0);
107 | return x;
108 | }
109 |
110 | // Flush the UART buffers.
111 | void USI_UART_Flush_Buffers( void )
112 | {
113 | UART_RxTail = 0;
114 | UART_RxHead = 0;
115 | UART_TxTail = 0;
116 | UART_TxHead = 0;
117 | }
118 |
119 | // Initialise USI for UART transmission.
120 | void USI_UART_Initialise_Transmitter( void )
121 | {
122 | cli();
123 | USI_UART_TCNTn = 0x00;
124 | USI_UART_TCCRn = (1<> 2) | 0x80; // Copy (initial high state,) start-bit and 6 LSB of original data (6 MSB
250 | // of bit of bit reversed data).
251 | }
252 | // Else enter receive mode.
253 | else
254 | {
255 | USI_UART_status.ongoing_Transmission_From_Buffer = FALSE;
256 |
257 | USI_UART_TCCRn = (0<.
21 | */
22 |
23 | #include "UsiSerial.h"
24 | #include "USI_UART_config.h"
25 |
26 | USISerial::USISerial()
27 | {
28 | // do nothing in initializer
29 | }
30 |
31 | // AVR307 does not calculate baudrate at runtime, set the baudrate in USI_UART_config.h
32 | void USISerial::begin()
33 | {
34 | USI_UART_Initialise_Receiver();
35 | USI_UART_Initialise_Transmitter();
36 | }
37 |
38 | void USISerial::end()
39 | {
40 | flush();
41 | TCCR1 = 0;
42 | TCNT1 = 0;
43 | TIFR |= _BV(TOV1);
44 | TIMSK &= ~_BV(TOIE1);
45 | USICR = 0;
46 | USISR = 0;
47 | GIFR |= _BV(PCIF);
48 | GIMSK &= ~_BV(PCIE);
49 | PCMSK &= ~(_BV(0) | _BV(1));
50 | DDRB &= ~(_BV(0) | _BV(1));
51 | PORTB &= ~(_BV(0) | _BV(1));
52 | }
53 |
54 | int USISerial::available(void)
55 | {
56 | return (unsigned int)(UART_RX_BUFFER_SIZE + UART_RxHead - UART_RxTail) % UART_RX_BUFFER_SIZE;
57 | }
58 |
59 | int USISerial::peek(void)
60 | {
61 | if (UART_RxHead == UART_RxTail) {
62 | return -1;
63 | } else {
64 | return UART_RxBuf[UART_RxTail];
65 | }
66 | }
67 |
68 | int USISerial::read(void)
69 | {
70 | USI_UART_Receive_Byte();
71 | }
72 |
73 | void USISerial::flush()
74 | {
75 | USI_UART_Flush_Buffers();
76 | }
77 |
78 | size_t USISerial::write(uint8_t c)
79 | {
80 | USI_UART_Transmit_Byte(c);
81 | return 1;
82 | }
83 |
84 | USISerial::operator bool() {
85 | return true;
86 | }
87 |
88 | USISerial UsiSerial; // user accessible instance
--------------------------------------------------------------------------------
/UsiSerial/UsiSerial.h:
--------------------------------------------------------------------------------
1 | /* UsiSerial by me@frank-zhao.com
2 | *
3 | * UsiSerial is a simple wrapper around the code from AVR307 so that Arduino can use USI to implement a hardware serial port
4 | *
5 | Copyright (c) 2013 Frank Zhao
6 | All rights reserved.
7 |
8 | UsiSerial is free software: you can redistribute it and/or modify
9 | it under the terms of the GNU Lesser General Public License as
10 | published by the Free Software Foundation, either version 3 of
11 | the License, or (at your option) any later version.
12 |
13 | UsiSerial is distributed in the hope that it will be useful,
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | GNU Lesser General Public License for more details.
17 |
18 | You should have received a copy of the GNU Lesser General Public
19 | License along with UsiSerial. If not, see
20 | .
21 | */
22 |
23 | #ifndef USISERIAL_H_
24 | #define USISERIAL_H_
25 |
26 | #include
27 | #include
28 |
29 |
30 | class USISerial : public Stream
31 | {
32 | private:
33 | public:
34 | USISerial();
35 | void begin(); // AVR307 does not calculate baudrate at runtime, set the baudrate in USI_UART_config.h
36 | void end();
37 | virtual int available(void);
38 | virtual int peek(void);
39 | virtual int read(void);
40 | virtual void flush(void);
41 | virtual size_t write(uint8_t);
42 | inline size_t write(unsigned long n) { return write((uint8_t)n); }
43 | inline size_t write(long n) { return write((uint8_t)n); }
44 | inline size_t write(unsigned int n) { return write((uint8_t)n); }
45 | inline size_t write(int n) { return write((uint8_t)n); }
46 | using Print::write; // pull in write(str) and write(buf, size) from Print
47 | operator bool();
48 | };
49 |
50 | extern USISerial UsiSerial; // user accessible instance
51 |
52 | #endif
--------------------------------------------------------------------------------
/UsiSerial/examples/UsiSerialEchoExample/UsiSerialEchoExample.ino:
--------------------------------------------------------------------------------
1 | /* UsiSerial by me@frank-zhao.com
2 | *
3 | * UsiSerial is a simple wrapper around the code from AVR307 so that Arduino can use USI to implement a hardware serial port
4 | *
5 | * This is a simple echo example.
6 | *
7 | * The USI class works almost exactly like HardwareSerial
8 | * So you can use print and println and other functions like that
9 | *
10 | * PORTB0 is DI, thus it is RX
11 | * PORTB1 is DO, thus it is TX
12 | * default baud rate is 19200, which can only be changed in USI_UART_config.h
13 | * only some baud rates will work, depending on CPU frequency
14 | * buffers are small to save memory, since this library is designed for ATtiny
15 | * testing was done using a 16 MHz Trinket
16 | *
17 | * Important note: requires Timer1 and PCINT to be occupied
18 |
19 | Copyright (c) 2013 Frank Zhao
20 | All rights reserved.
21 |
22 | UsiSerial is free software: you can redistribute it and/or modify
23 | it under the terms of the GNU Lesser General Public License as
24 | published by the Free Software Foundation, either version 3 of
25 | the License, or (at your option) any later version.
26 |
27 | UsiSerial is distributed in the hope that it will be useful,
28 | but WITHOUT ANY WARRANTY; without even the implied warranty of
29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 | GNU Lesser General Public License for more details.
31 |
32 | You should have received a copy of the GNU Lesser General Public
33 | License along with UsiSerial. If not, see
34 | .
35 | */
36 |
37 | #include
38 |
39 | void setup()
40 | {
41 | UsiSerial.begin();
42 | }
43 |
44 | void loop()
45 | {
46 | if (UsiSerial.available() > 0) {
47 | UsiSerial.write(UsiSerial.read());
48 | }
49 | }
--------------------------------------------------------------------------------