root / scout_avr / src / bom.cpp @ 066b08bb
History | View | Annotate | Download (5.83 KB)
1 | f115416e | Tom Mullins | extern "C" { |
---|---|---|---|
2 | #include <avr/io.h> |
||
3 | #include <avr/interrupt.h> |
||
4 | #include <util/delay.h> |
||
5 | } |
||
6 | #include "bom.h" |
||
7 | |||
8 | /*
|
||
9 | * Sharp protocol:
|
||
10 | * Period modulation
|
||
11 | * 1: 2ms period
|
||
12 | * 0: 1ms period
|
||
13 | * Signal:
|
||
14 | * 38kHz pulse for 320us, then off for rest of time (680us or 1680us)
|
||
15 | 812788aa | Tom Mullins | * BOM uses timer 4 for period timing, and timer 0 for 38kHz signal
|
16 | f115416e | Tom Mullins | */
|
17 | |||
18 | 63e19141 | Tom Mullins | /*
|
19 | * Recently modified so that when BOM is sending, it stops listening. When
|
||
20 | * not sending, it keeps listening.
|
||
21 | */
|
||
22 | |||
23 | f115416e | Tom Mullins | #define TIME_MICROS(us, prescale) (F_CPU / 1000000 * (us) / (prescale)) |
24 | |||
25 | typedef uint16_t sharp_msg_t;
|
||
26 | |||
27 | static sharp_msg_t sharp_msg_make(char address, bom_msg_t bom_msg) { |
||
28 | return (((uint16_t)address & 0x3F) << 10) | ((uint16_t)bom_msg << 2) | 2; |
||
29 | } |
||
30 | |||
31 | static char robot_id; |
||
32 | |||
33 | // tx global vars
|
||
34 | static sharp_msg_t out_msg;
|
||
35 | static uint8_t out_pin_mask;
|
||
36 | static char out_high, out_counter; |
||
37 | static volatile char out_done; |
||
38 | |||
39 | // rx global vars
|
||
40 | static uint8_t prev_bom_sig;
|
||
41 | static struct bom_rx_t { |
||
42 | 31f4a032 | Tom Mullins | uint8_t count; |
43 | f115416e | Tom Mullins | uint16_t bits; |
44 | 31f4a032 | Tom Mullins | int last_time;
|
45 | f115416e | Tom Mullins | |
46 | uint8_t new_data; |
||
47 | uint8_t address; |
||
48 | uint8_t data; |
||
49 | } bom_rx[4];
|
||
50 | |||
51 | void set_robot_id(char id) { |
||
52 | robot_id = id; |
||
53 | } |
||
54 | |||
55 | char get_robot_id(void) { |
||
56 | return robot_id;
|
||
57 | } |
||
58 | |||
59 | 812788aa | Tom Mullins | void bom_isr() {
|
60 | f115416e | Tom Mullins | if (out_high) {
|
61 | cc9ca04e | Tom Mullins | PORT_BOM_EMIT ^= out_pin_mask; |
62 | f115416e | Tom Mullins | } |
63 | } |
||
64 | |||
65 | static void init_38kHz_signal() { |
||
66 | out_high = 0;
|
||
67 | out_pin_mask = 0;
|
||
68 | 63e19141 | Tom Mullins | |
69 | 812788aa | Tom Mullins | // timer configuration now done in Atmega128rfa1.cpp
|
70 | f115416e | Tom Mullins | } |
71 | |||
72 | static void start_38kHz_signal() { |
||
73 | TCNT3 = 0;
|
||
74 | cc9ca04e | Tom Mullins | PORT_BOM_EMIT |= out_pin_mask; |
75 | f115416e | Tom Mullins | out_high = 1;
|
76 | } |
||
77 | |||
78 | static void stop_38kHz_signal() { |
||
79 | 63e19141 | Tom Mullins | PORT_BOM_EMIT &= ~ out_pin_mask; // why not just do PORT_BOM_EMIT &= 0; ?
|
80 | f115416e | Tom Mullins | out_high = 0;
|
81 | } |
||
82 | |||
83 | static void init_data_signal() { |
||
84 | // timer 4 mode CTC (clear timer on compare), TOP = OCRA
|
||
85 | TCCR4A = 0;
|
||
86 | TCCR4B = _BV(WGM42); |
||
87 | 63e19141 | Tom Mullins | |
88 | f115416e | Tom Mullins | // run interrupt immediately when timer started
|
89 | OCR4A = 0;
|
||
90 | 63e19141 | Tom Mullins | |
91 | f115416e | Tom Mullins | // enable interrupt
|
92 | TIMSK4 = _BV(OCIE4A); |
||
93 | } |
||
94 | |||
95 | static void start_data_signal() { |
||
96 | TCNT4 = 0;
|
||
97 | 63e19141 | Tom Mullins | |
98 | f115416e | Tom Mullins | // start timer 4 at F_CPU/64 prescaling
|
99 | TCCR4B |= _BV(CS41) | _BV(CS40); |
||
100 | } |
||
101 | |||
102 | static void stop_data_signal() { |
||
103 | // stop timer 4
|
||
104 | TCCR4B &= ~ (_BV(CS42) | _BV(CS41) | _BV(CS40)); |
||
105 | } |
||
106 | |||
107 | ISR(TIMER4_COMPA_vect) { |
||
108 | 31f4a032 | Tom Mullins | if (out_high) {
|
109 | stop_38kHz_signal(); |
||
110 | if (out_counter) {
|
||
111 | out_counter--; |
||
112 | if ((out_msg >> out_counter) & 1) { |
||
113 | f115416e | Tom Mullins | OCR4A = TIME_MICROS(1680, 64); |
114 | } else {
|
||
115 | OCR4A = TIME_MICROS(680, 64); |
||
116 | } |
||
117 | } else {
|
||
118 | 31f4a032 | Tom Mullins | stop_data_signal(); |
119 | out_done = 1;
|
||
120 | f115416e | Tom Mullins | } |
121 | } else {
|
||
122 | 31f4a032 | Tom Mullins | start_38kHz_signal(); |
123 | OCR4A = TIME_MICROS(320, 64); |
||
124 | f115416e | Tom Mullins | } |
125 | } |
||
126 | |||
127 | void bom_init(void) { |
||
128 | // BOM_SIG as input, interrupts enabled
|
||
129 | DDRB &= ~ (_BV(DDB0) | _BV(DDB1) | _BV(DDB2) | _BV(DDB3)); |
||
130 | PCMSK0 |= _BV(PCINT0) | _BV(PCINT1) | _BV(PCINT2) | _BV(PCINT3); |
||
131 | PCICR |= _BV(PCIE0); |
||
132 | 63e19141 | Tom Mullins | |
133 | f115416e | Tom Mullins | // BOM_EMIT as output
|
134 | cc9ca04e | Tom Mullins | DDRF |= _BV(DDF4) | _BV(DDF5) | _BV(DDF6) | _BV(DDF7); |
135 | f115416e | Tom Mullins | |
136 | init_38kHz_signal(); |
||
137 | init_data_signal(); |
||
138 | } |
||
139 | |||
140 | 63e19141 | Tom Mullins | static void stop_receiving(char dir) { |
141 | switch (dir) {
|
||
142 | case BOM_FRONT: PCMSK0 &= ~_BV(PCINT0); break; |
||
143 | case BOM_LEFT : PCMSK0 &= ~_BV(PCINT1); break; |
||
144 | case BOM_RIGHT: PCMSK0 &= ~_BV(PCINT2); break; |
||
145 | case BOM_BACK : PCMSK0 &= ~_BV(PCINT3); break; |
||
146 | } |
||
147 | } |
||
148 | |||
149 | static void start_receiving(char dir) { |
||
150 | // flush rx buffer before turning on the receiver
|
||
151 | bom_rx[(int)dir].bits = 0; |
||
152 | bom_rx[(int)dir].count = 0; |
||
153 | |||
154 | switch (dir) {
|
||
155 | case BOM_FRONT: PCMSK0 |= _BV(PCINT0); break; |
||
156 | case BOM_LEFT : PCMSK0 |= _BV(PCINT1); break; |
||
157 | case BOM_RIGHT: PCMSK0 |= _BV(PCINT2); break; |
||
158 | case BOM_BACK : PCMSK0 |= _BV(PCINT3); break; |
||
159 | } |
||
160 | } |
||
161 | |||
162 | f115416e | Tom Mullins | void bom_send(char dir) { |
163 | switch (dir) {
|
||
164 | cc9ca04e | Tom Mullins | case BOM_FRONT: out_pin_mask = _BV(P_BOM_EMIT0); break; |
165 | case BOM_LEFT: out_pin_mask = _BV(P_BOM_EMIT1); break; |
||
166 | case BOM_RIGHT: out_pin_mask = _BV(P_BOM_EMIT2); break; |
||
167 | case BOM_BACK: out_pin_mask = _BV(P_BOM_EMIT3); break; |
||
168 | f115416e | Tom Mullins | } |
169 | 31f4a032 | Tom Mullins | out_counter = 16;
|
170 | f115416e | Tom Mullins | out_msg = sharp_msg_make(0x2A, bom_msg_make(robot_id, dir));
|
171 | out_done = 0;
|
||
172 | 63e19141 | Tom Mullins | |
173 | stop_receiving(dir); // disable receiver
|
||
174 | start_38kHz_signal(); // enable the transmitter
|
||
175 | f115416e | Tom Mullins | start_data_signal(); |
176 | while (!out_done) {
|
||
177 | _delay_ms(0.1); |
||
178 | } |
||
179 | 63e19141 | Tom Mullins | stop_data_signal(); // disable the transmitter
|
180 | stop_38kHz_signal(); |
||
181 | start_receiving(dir); // enable the receiver
|
||
182 | f115416e | Tom Mullins | } |
183 | |||
184 | static void recv_edge(char is_rising, struct bom_rx_t *rx) { |
||
185 | if (is_rising) {
|
||
186 | 31f4a032 | Tom Mullins | // TODO check 320us? or have 320us timeout on rising edge?
|
187 | } else {
|
||
188 | 399f7d1b | Tom Mullins | // uses timer 5, assuming prescale 1/64
|
189 | 812788aa | Tom Mullins | // timer 5 is set up by range_init()
|
190 | 399f7d1b | Tom Mullins | int now = TCNT5;
|
191 | int min_low = TIME_MICROS(MIN_LOW_PW, 64); |
||
192 | int max_low = TIME_MICROS(MAX_LOW_PW, 64); |
||
193 | int min_high = TIME_MICROS(MIN_HIGH_PW, 64); |
||
194 | int max_high = TIME_MICROS(MAX_HIGH_PW, 64); |
||
195 | 63e19141 | Tom Mullins | |
196 | 31f4a032 | Tom Mullins | if (rx->count) {
|
197 | 399f7d1b | Tom Mullins | int diff = (now - rx->last_time);
|
198 | 31f4a032 | Tom Mullins | rx->bits <<= 1;
|
199 | 399f7d1b | Tom Mullins | if (min_low < diff && diff < max_low) {
|
200 | 31f4a032 | Tom Mullins | // 0 already in bits
|
201 | 399f7d1b | Tom Mullins | } else if (min_high < diff && diff < max_high) { |
202 | 31f4a032 | Tom Mullins | // add 1 to bits
|
203 | rx->bits |= 1;
|
||
204 | } else {
|
||
205 | // error, start from beginning
|
||
206 | rx->count = 0;
|
||
207 | rx->bits = 0;
|
||
208 | } |
||
209 | if (rx->count == 16) { |
||
210 | // finished!
|
||
211 | 69c2203a | Tom Mullins | if ((rx->bits & 3) == 2) { // expansion and check bits |
212 | 31f4a032 | Tom Mullins | rx->data = (rx->bits >> 2) & 0xff; |
213 | rx->address = (rx->bits >> 10) & 0x1f; |
||
214 | rx->new_data = 1;
|
||
215 | 69c2203a | Tom Mullins | } |
216 | 31f4a032 | Tom Mullins | rx->count = 0;
|
217 | rx->bits = 0;
|
||
218 | f115416e | Tom Mullins | } |
219 | } |
||
220 | 63e19141 | Tom Mullins | |
221 | 31f4a032 | Tom Mullins | rx->count++; |
222 | rx->last_time = now; |
||
223 | f115416e | Tom Mullins | } |
224 | } |
||
225 | |||
226 | ISR(PCINT0_vect) { |
||
227 | cc9ca04e | Tom Mullins | uint8_t bom_sig = PIN_BOM_SIG; |
228 | f115416e | Tom Mullins | uint8_t changed = bom_sig ^ prev_bom_sig; |
229 | cc9ca04e | Tom Mullins | if (changed & _BV(P_BOM_SIG0)) recv_edge(bom_sig & _BV(P_BOM_SIG0), &bom_rx[0]); |
230 | if (changed & _BV(P_BOM_SIG1)) recv_edge(bom_sig & _BV(P_BOM_SIG1), &bom_rx[1]); |
||
231 | if (changed & _BV(P_BOM_SIG2)) recv_edge(bom_sig & _BV(P_BOM_SIG2), &bom_rx[2]); |
||
232 | if (changed & _BV(P_BOM_SIG3)) recv_edge(bom_sig & _BV(P_BOM_SIG3), &bom_rx[3]); |
||
233 | f115416e | Tom Mullins | prev_bom_sig = bom_sig; |
234 | } |
||
235 | |||
236 | int bom_get(char dir) { |
||
237 | bom_rx_t *rx = &bom_rx[(int)dir];
|
||
238 | int ret = BOM_NO_DATA;
|
||
239 | cli(); |
||
240 | if (rx->new_data) {
|
||
241 | rx->new_data = 0;
|
||
242 | ret = rx->data; |
||
243 | } |
||
244 | sei(); |
||
245 | return ret;
|
||
246 | } |