ATtiny85 Template Code
Code snippets for the ATtiny85
 All Files Functions Variables Typedefs Enumerations Enumerator Macros
uart_recv.c
Go to the documentation of this file.
1 /*--------------------------------------------------------------------------*
2 * UART interface implementation for ATmega
3 *---------------------------------------------------------------------------*
4 * 01-Apr-2014 ShaneG
5 *
6 * Half-duplex 8N1 serial UART in software.
7 *
8 * 1%/2% Tx/Rx timing error for 115.2kbps@8Mhz
9 * 2%/1% Tx/Rx timing error for 230.4kbps@8Mhz
10 *
11 * Uses only one pin on the AVR for both Tx and Rx:
12 *
13 * D1
14 * AVR ----+--|>|-----+----- Tx
15 * | 10K $ R1
16 * +--------(/^\)--- Rx
17 * NPN E C
18 *--------------------------------------------------------------------------*/
19 #include <avr/io.h>
20 #include <avr/interrupt.h>
21 #include "../hardware.h"
22 #include "uart_defs.h"
23 #include "softuart.h"
24 
25 // Only if enabled
26 #ifdef UART_ENABLED
27 
28 //--- Set up input buffer if applicable
29 #ifdef UART_INTERRUPT
30 
35 static uint8_t g_buffer[UART_BUFFER];
36 
39 static volatile uint8_t g_index = 0;
40 #endif
41 
51 uint8_t uartAvail() {
52 #ifndef UART_INTERRUPT
53  return 0;
54 #else
55  return g_index;
56 #endif
57  }
58 
65 char uartRecv() {
66  char ch;
67 #ifdef UART_INTERRUPT
68  // Wait for a character
69  while(g_index==0);
70  cli();
71  // Return the first character in the buffer
72  ch = g_buffer[0];
73  g_index--;
74  // Move everything down
75  for(uint8_t index=0; index<g_index; g_buffer[index] = g_buffer[index + 1], index++);
76  // Done
77  sei();
78 #else
79  // Set as input and disable pullup
80  DDRB &= ~(1 << UART_RX);
81  PORTB &= ~(1 << UART_RX);
82  // Read the byte
83  cli();
84  asm volatile(
85  " ldi r18, %[rxdelay2] \n\t" // 1.5 bit delay
86  " ldi %0, 0x80 \n\t" // bit shift counter
87  "WaitStart: \n\t"
88  " sbic %[uart_port]-2, %[uart_pin] \n\t" // wait for start edge
89  " rjmp WaitStart \n\t"
90  "RxBit: \n\t"
91  // 6 cycle loop + delay - total = 5 + 3*r22
92  // delay (3 cycle * r18) -1 and clear carry with subi
93  " subi r18, 1 \n\t"
94  " brne RxBit \n\t"
95  " ldi r18, %[rxdelay] \n\t"
96  " sbic %[uart_port]-2, %[uart_pin] \n\t" // check UART PIN
97  " sec \n\t"
98  " ror %0 \n\t"
99  " brcc RxBit \n\t"
100  "StopBit: \n\t"
101  " dec r18 \n\t"
102  " brne StopBit \n\t"
103  : "=r" (ch)
104  : [uart_port] "I" (_SFR_IO_ADDR(PORTB)),
105  [uart_pin] "I" (UART_RX),
106  [rxdelay] "I" (RXDELAY),
107  [rxdelay2] "I" (RXDELAY2)
108  : "r0","r18","r19");
109  sei();
110 #endif
111  return ch;
112  }
113 
114 #ifdef UART_INTERRUPT
115 /* Interrupt handler for the pin change
116  */
117 ISR(PCINT0_vect) {
118  uint8_t ch;
119  // Make sure it is our pin and it is 0
120  if(!(PINB&(1<<UART_RX))) {
121  // Start the read (assuming we have the start bit)
122  asm volatile(
123  " ldi r18, %[rxdelay2] \n\t" // 1.5 bit delay
124  " ldi %0, 0x80 \n\t" // bit shift counter
125  "RxBit: \n\t"
126  // 6 cycle loop + delay - total = 5 + 3*r22
127  // delay (3 cycle * r18) -1 and clear carry with subi
128  " subi r18, 1 \n\t"
129  " brne RxBit \n\t"
130  " ldi r18, %[rxdelay] \n\t"
131  " sbic %[uart_port]-2, %[uart_pin] \n\t" // check UART PIN
132  " sec \n\t"
133  " ror %0 \n\t"
134  " brcc RxBit \n\t"
135  "StopBit: \n\t"
136  " dec r18 \n\t"
137  " brne StopBit \n\t"
138  : "=r" (ch)
139  : [uart_port] "I" (_SFR_IO_ADDR(PORTB)),
140  [uart_pin] "I" (UART_RX),
141  [rxdelay] "I" (RXDELAY),
142  [rxdelay2] "I" (RXDELAY2)
143  : "r0","r18","r19");
144  // Now put it in the buffer (if we have room)
145  if(g_index<UART_BUFFER)
146  g_buffer[g_index++] = ch;
147  }
148  // TODO: Chain on to the user interrupt handler if available.
149  }
150 #endif /* UART_INTERRUPT */
151 
152 #endif /* UART_ENABLED */
char uartRecv()
Definition: uart_recv.c:65
#define UART_BUFFER
Definition: hardware.h:80
uint8_t uartAvail()
Definition: uart_recv.c:51
#define UART_RX
Definition: hardware.h:65
ISR(TIMER1_OVF_vect)
Definition: systicks.c:170