1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
|
/*
* AE6HO EZ-Doppler firmware for onboard ATmega8 microcontroller
* Copyright 2006 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* GNU Radio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
/*
* ARCHITECTURE
*
* Timer0 is 8000 Hz time base
* PORTD.2 through PORTD.5 are doppler antenna array element enables.
* PORTB.0 is a diagnostic LED, set low to light up
* ADC7 is audio input
* ADC6 is RSSI input - not yet used
*
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <compat/deprecated.h> // for timer_enable_int
#include "dopctrl.h"
#define LED 0
#define turn_off_led() PORTB |= _BV(LED);
#define turn_on_led() PORTB &= ~_BV(LED);
#define ANT1 _BV(2)
#define ANT2 _BV(3)
#define ANT3 _BV(4)
#define ANT4 _BV(5)
#define ANTMASK ANT1|ANT2|ANT3|ANT4
#define ADCAIN 7
#define BAUDRATE 250000
/* Assume these are all set to zero in startup code */
uint8_t rotate; /* Flag to indicate antennas should rotate or not */
uint8_t streaming; /* Flag to indicate continuous sampling */
uint8_t antennas; /* Holds shadow copy of PORTD antennas */
uint8_t speed; /* Holds samples per phase increment */
uint8_t phase; /* Holds rotation phase (measured in samples */
uint8_t audio_hi; /* High byte of ADC sample of audio */
uint8_t audio_lo; /* Low byte of ADC sample of audio */
uint8_t rx; /* Temporary holds received byte from USART */
uint8_t command; /* Temporary to hold command when getting operand */
uint8_t cmdbyte; /* Tracks bytes received in multi-byte commands */
int main(void)
{
/* Diagnostic port setup */
DDRB = _BV(LED); /* PB0 is output */
turn_off_led();
/* Antenna control port setup */
speed = 4; /* Todo: read from EEPROM */
antennas = ANT1; /* Start with antenna #1 */
PORTD = antennas; /* Set port value */
DDRD = ANTMASK; /* Set antenna enables as PORTD outputs */
/* ADC port setup */
ADMUX = _BV(REFS0)|ADCAIN; /* AVCC is reference, use ADC for audio input (ADC7) */
ADCSRA = _BV(ADEN)|_BV(ADIE)|0x07; /* Enable converter, prescale by 128, enable ADC interrupt */
/* USART port setup*/
UCSRA = 0; /* Normal asynchronous mode */
UCSRB = _BV(TXEN)|_BV(RXEN)|_BV(RXCIE); /* Enable transmitter and receiver, and receiver interrupts */
UCSRC = _BV(URSEL)|_BV(UCSZ1)|_BV(UCSZ0); /* 8N1 format */
UBRRH = 0; /* Set baud rate prescaler to 3 */
UBRRL = 3; /* To get 250000 bps */
/* Set up 8000 Hz time base */
timer_enable_int(_BV(TOIE0)); /* Turn on Timer0 output overflow interrupt */
TCCR0 = _BV(CS01); /* Clock Timer0 from CLK/8 */
sei(); /* Let 'er rip! */
return 0;
}
/* Timer0 overflow interrupt handler
*
* Creates 8000 Hz time base, or 125us budget
*
*/
SIGNAL(SIG_OVERFLOW0)
{
/* Reload Timer0 samples to 8, results in 8000 Hz overflow interrupt */
TCNT0 = 0x08;
if (streaming) {
/* Kick-off an audio sample conversion, will interrupt 104us later */
ADCSRA |= _BV(ADSC);
/* Write the first byte of previous sample and enable UDRIE */
UDR = audio_lo;
UCSRB |= _BV(UDRIE);
}
if (!rotate) /* Skip rotating antenna if not started */
return;
/* Increment antenna phase and see if antenna need to be rotated */
if (++phase == speed) {
phase = 0;
/* Sequence antenna array elements */
antennas >>= 1;
antennas &= ANTMASK;
if (!antennas)
antennas = ANT4;
PORTD = antennas;
}
}
/* ADC conversion complete interrupt handler
*
* Read value and store. Assume prior sample has been handled.
*
*/
SIGNAL(SIG_ADC)
{
audio_lo = ADCL;
audio_hi = ADCH;
}
/* USART data transmit holding register empty interrupt handler
*
* First byte is always sent from timer interrupt
* So second byte gets sent here with UDRIE disabled
*
*/
SIGNAL(SIG_UART_DATA)
{
/* Write second byte of previous sample and disable UDRIE */
UDR = audio_hi | (antennas << 2);
UCSRB &= ~_BV(UDRIE);
}
/* USART receive complete interrupt handler
*
* Received bytes are commands, with one or two bytes of operands following
*
*/
SIGNAL(SIG_UART_RECV)
{
rx = UDR;
if (cmdbyte == 0) {
if (rx == EZDOP_CMD_ROTATE) /* Start rotation */
rotate = 1;
else if (rx == EZDOP_CMD_STOP) /* Stop rotation */
rotate = 0;
else if (rx == EZDOP_CMD_RATE) { /* Set rotation rate */
command = rx;
cmdbyte = 1;
}
else if (rx == EZDOP_CMD_STREAM) /* Stream audio samples */
streaming = 1;
else if (rx == EZDOP_CMD_STROFF) /* Stop streaming */
streaming = 0;
else
turn_on_led(); /* Unknown command */
}
else if (cmdbyte == 1) {
if (command == EZDOP_CMD_RATE) { /* Operand is number of samples per phase increment */
speed = rx;
cmdbyte = 0;
}
else
turn_on_led(); /* Bogus command state */
}
else
turn_on_led(); /* Bogus command state */
}
|