├── 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 | } --------------------------------------------------------------------------------