root / scout_avr / src / Atmega128rfa1.cpp @ ca9f6bd5
History | View | Annotate | Download (2.25 KB)
1 |
#include "Atmega128rfa1.h" |
---|---|
2 |
#include "bom.h" |
3 |
|
4 |
extern "C" |
5 |
{ |
6 |
#include <avr/io.h> |
7 |
#include <avr/interrupt.h> |
8 |
void __cxa_pure_virtual(void) {} |
9 |
} |
10 |
|
11 |
#define T0_KHZ 76 |
12 |
#define T0_OCR (F_CPU / 1000 / T0_KHZ) // 210 ticks |
13 |
#define T0_ERROR (F_CPU / 1000 - T0_OCR*T0_KHZ) // 40 ticks/ms |
14 |
|
15 |
unsigned char t0_count, t0_error; |
16 |
unsigned long millis; |
17 |
|
18 |
int rx_start, rx_end;
|
19 |
char rx_buffer[RX_BUFFER_SIZE];
|
20 |
|
21 |
Atmega128rfa1::Atmega128rfa1() |
22 |
{ |
23 |
} |
24 |
|
25 |
ISR(TIMER0_COMPA_vect) |
26 |
{ |
27 |
bom_isr(); |
28 |
|
29 |
// F_CPU = T0_OCR * T0_KHZ + T0_ERROR
|
30 |
// every millisecond, accumulate T0_ERROR, and when it reaches T0_OCR skip
|
31 |
// one iteration
|
32 |
t0_count++; |
33 |
if (t0_count >= T0_KHZ) {
|
34 |
t0_error += T0_ERROR; |
35 |
if (t0_error < T0_OCR) {
|
36 |
t0_count = 0;
|
37 |
} else {
|
38 |
t0_count = -1;
|
39 |
t0_error -= T0_OCR; |
40 |
} |
41 |
millis++; |
42 |
} |
43 |
} |
44 |
|
45 |
ISR(USART0_RX_vect) |
46 |
{ |
47 |
char data = UDR0;
|
48 |
int new_end = rx_end+1; |
49 |
if (new_end == RX_BUFFER_SIZE) {
|
50 |
new_end = 0;
|
51 |
} |
52 |
if (new_end == rx_start)
|
53 |
{ |
54 |
// TODO warn of buffer overflow?
|
55 |
} |
56 |
else
|
57 |
{ |
58 |
rx_buffer[rx_end] = data; |
59 |
rx_end = new_end; |
60 |
} |
61 |
} |
62 |
|
63 |
void Atmega128rfa1::init()
|
64 |
{ |
65 |
// === init serial ===
|
66 |
// baud = F_CPU / (16 (UBRR + 1))
|
67 |
uint16_t ubrr = F_CPU / 16 / BAUD_RATE - 1; |
68 |
UBRR0H = ubrr >> 8;
|
69 |
UBRR0L = ubrr; |
70 |
// UMSEL0 = 0, asynchronous usart
|
71 |
// UPM0 = 0, parity check disabled
|
72 |
// USBS0 = 0, 1 stop bit
|
73 |
// UCSZ0 = 3, 8-bit
|
74 |
UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0); |
75 |
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); |
76 |
|
77 |
// === init time ===
|
78 |
// COM0x = 0, pin OC0x not used
|
79 |
// WGM0 = 2, clear timer on compare match, TOP = OCRA
|
80 |
// CS0 = 1, no prescaler
|
81 |
TCCR0A = _BV(WGM01); |
82 |
TCCR0B = _BV(CS00); |
83 |
// enable interrupt on compare match A
|
84 |
TIMSK0 = _BV(OCIE0A); |
85 |
OCR0A = T0_OCR; |
86 |
millis = 0;
|
87 |
|
88 |
sei(); |
89 |
} |
90 |
|
91 |
int Atmega128rfa1::read()
|
92 |
{ |
93 |
int ret;
|
94 |
cli(); |
95 |
if (rx_start == rx_end)
|
96 |
ret = -1;
|
97 |
else
|
98 |
{ |
99 |
ret = rx_buffer[rx_start]; |
100 |
rx_start++; |
101 |
if (rx_start == RX_BUFFER_SIZE)
|
102 |
rx_start = 0;
|
103 |
} |
104 |
sei(); |
105 |
return ret;
|
106 |
} |
107 |
|
108 |
void Atmega128rfa1::write(uint8_t* data, int length) |
109 |
{ |
110 |
// TODO make this non-blocking with a tx buffer
|
111 |
int i;
|
112 |
for (i = 0; i < length; i++) |
113 |
{ |
114 |
while (!(UCSR0A & _BV(UDRE0)));
|
115 |
UDR0 = data[i]; |
116 |
} |
117 |
} |
118 |
|
119 |
unsigned long Atmega128rfa1::time() |
120 |
{ |
121 |
unsigned long ret; |
122 |
cli(); |
123 |
ret = millis; |
124 |
sei(); |
125 |
return ret;
|
126 |
} |