Project

General

Profile

Statistics
| Revision:

root / trunk / code / lib / src / libdragonfly / analog.c @ 351

History | View | Annotate | Download (7.34 KB)

1
/**
2
 * Copyright (c) 2007 Colony Project
3
 * 
4
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use,
8
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the
10
 * Software is furnished to do so, subject to the following
11
 * conditions:
12
 * 
13
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15
 * 
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 **/
25

    
26
/**
27
 * @file analog.c
28
 * @brief Analog input and output
29
 *
30
 * Contains functions for manipulating the ADC on the Dragonfly board.
31
 * 
32
 * @author Colony Project, CMU Robotics Club
33
 * code mostly taken from fwr analog file (author: Tom Lauwers)
34
 **/
35

    
36
#include <util/delay.h>
37
#include <avr/interrupt.h>
38
#include "analog.h"
39
#include "serial.h"
40
// Internal Function Prototypes
41
//TODO: if this function is only used in this file, make it static
42
void set_adc_mux(int which);
43

    
44
/**
45
 * @defgroup analog Analog
46
 * Functions for manipulation the ADC on the dragonfly board.
47
 * All definitions may be found in analog.h.
48
 *
49
 * @{
50
 **/
51

    
52
//TODO: if these variables are only used in this file, make them static
53
int adc_loop_running = 0;
54
int adc_current_port = 0;
55
adc_t an_val[11];
56

    
57
/**
58
 * Initializes the ADC.
59
 * Call analog_init before reading from the analog ports.
60
 *
61
 * @see analog8, analog10
62
 **/
63
void analog_init(int start_conversion) {
64
        for (int i = 0; i < 11; i++) {
65
                an_val[i].adc10 = 0;
66
                an_val[i].adc8 = 0;
67
        }
68

    
69
        //cli();
70
        // ADMUX register
71
        // Bit 7,6 - Set voltage reference to AVcc (0b01)
72
        // Bit 5 - ADLAR set to simplify moving from register
73
        // Bit 4 - X
74
        // Bit 3:0 - Sets the current channel
75
        // Initializes to read from AN1 first (AN0 is reservered for the BOM)
76
        ADMUX = 0;
77
        ADMUX |= ADMUX_OPT | _BV(MUX0);
78

    
79

    
80
        // ADC Status Register A
81
        // Bit 7 - ADEN is set (enables analog)
82
        // Bit 6 - Start conversion bit is set (must be done once for free-running mode)
83
        // Bit 5 - Enable Auto Trigger (for free running mode) NOT DOING THIS RIGHT NOW
84
        // Bit 4 - ADC interrupt flag, 0
85
        // Bit 3 - Enable ADC Interrupt (required to run free-running mode)
86
        // Bits 2-0 - Set to create a clock divisor of 128, to make ADC clock = 8,000,000/64 = 125kHz
87
        ADCSRA = 0;
88
        ADCSRA |= _BV(ADEN) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);
89
        
90
        // Set external mux lines to outputs
91
        DDRG |= 0x1C;
92
        
93
        // Set up first port for conversions
94
        set_adc_mux(0x00);
95
        adc_current_port = AN1;
96

    
97
        //Start the conversion if requested
98
        if (start_conversion)
99
                analog_start_loop();
100
        else
101
                analog_stop_loop();
102
        //sei();
103
        
104
}        
105

    
106
unsigned int analog8(int which) {
107
        if (which == BOM_PORT) {
108
                return 0;
109
        } else {
110
                return an_val[which - 1].adc8;
111
        }
112
}
113

    
114
unsigned int analog10(int which) {
115
        if (which == BOM_PORT) {
116
                return 0;
117
        } else {
118
                return an_val[which - 1].adc10;
119
        }
120
}
121

    
122
void analog_start_loop(void) {
123
        //Start the conversion
124
        ADCSRA |= _BV(ADSC);
125
        adc_loop_running = 0x1;
126
}
127

    
128
//will stop after current conversion finishes
129
void analog_stop_loop(void) {
130
        //Stop the conversion
131
        adc_loop_running = 0x0;
132
}
133
/**
134
 * Reads an eight bit number from an analog port.
135
 * analog_init must be called before using this function.
136
 * 
137
 * @param which the analog port to read from. One of
138
 * the constants AN0 - AN7.
139
 *
140
 * @return the eight bit input to the specified port
141
 *
142
 * @see analog_init, analog10
143
 **/
144
unsigned int analog_get8(int which)
145
{        
146
        // Let any previous conversion finish
147
        while (ADCSRA & _BV(ADSC));
148
        
149
        if(which < EXT_MUX) {
150
                ADMUX = ADMUX_OPT + which;
151
        } else {
152
                ADMUX = ADMUX_OPT + EXT_MUX;
153
                set_adc_mux(which - 8);
154
        }
155
        
156
        // Start the conversion
157
        ADCSRA |= _BV(ADSC);
158

    
159
        // Wait for the conversion to finish
160
        while (ADCSRA & _BV(ADSC));
161

    
162
        return ADCH; //since we left aligned the data, ADCH is the 8 MSB.
163
}
164

    
165
/**
166
 * Reads a ten bit number from the specified port.
167
 * analog_init must be called before using this function.
168
 * 
169
 *
170
 * @param which the analog port to read from. Typically
171
 * a constant, one of AN0 - AN7.
172
 *
173
 * @return the ten bit number input to the specified port
174
 * 
175
 * @see analog_init, analog8
176
 **/
177
unsigned int analog_get10(int which)
178
{
179
        int adc_h;
180
        int adc_l;
181
        
182
        // Let any previous conversion finish
183
        while (ADCSRA & _BV(ADSC));
184

    
185
        if(which < EXT_MUX) {
186
                ADMUX = ADMUX_OPT + which;
187
        } else {
188
                ADMUX = ADMUX_OPT + EXT_MUX;
189
                set_adc_mux(which - 8);
190
        }
191
        
192
        // Start the conversion
193
        ADCSRA |= _BV(ADSC);
194

    
195
        // Wait for the conversion to finish
196
        while (ADCSRA & _BV(ADSC));
197
        
198
        adc_l = ADCL;
199
        adc_h = ADCH;
200

    
201
        return ((adc_h << 2) | (adc_l >> 6));
202
}
203

    
204
/**
205
 * Returns the current position of the wheel, as an integer
206
 * in the range 0 - 255.
207
 * analog_init must be called before using this function.
208
 *
209
 * @return the orientation of the wheel, as an integer in
210
 * the range 0 - 255.
211
 *
212
 * @see analog_init
213
 **/
214
int wheel(void)
215
{
216
        return analog8(WHEEL_PORT);
217
}
218

    
219

    
220
/**
221
 * Sets the value of the external analog mux. Values are read
222
 *         on AN7 physical port. (AN8 - AN15 are "virtual" ports).
223
 *
224
 * @param which which analog mux port (0-7) which corresponds
225
 *                   to AN8-AN15.
226
 *
227
 * @bug FIX THIS IN THE NEXT BOARD REVISION:
228
 *                ADDR2 ADDR1 ADDR0
229
 *                G2.G4.G3 set mux to port 0-7 via vinary selection
230
 *                math would be much cleaner if it was G4.G3.G2
231
 *
232
 * @see analog_init
233
 **/
234
void set_adc_mux(int which)
235
{  
236
  // mask so only proper bits are possible.  
237
  PORTG = (PORTG & 0xE3) | ((which & 0x03) << 3) | (which & 0x04);
238
}
239

    
240
/**@}**/ //end defgroup
241

    
242

    
243
ISR(ADC_vect) {
244
        static volatile int adc_prev_loop_running = 0;
245

    
246
        int adc_h = 0;
247
        int adc_l = 0;
248

    
249
        //usb_putc('p');
250
        //usb_puti(adc_current_port);
251
        //usb_putc('r');
252
        //usb_puti(adc_loop_running);
253
        //usb_puts("\n\r");
254

    
255
        //Store the value only if this read isn't for the BOM
256
        if (ADMUX != BOM_PORT) {
257
                adc_l = ADCL;
258
                adc_h = ADCH;
259
        
260
                an_val[adc_current_port - 1].adc10 = (adc_h << 2) | (adc_l >> 6);
261
                an_val[adc_current_port - 1].adc8 = adc_h;
262
                //usb_puti(an_val[adc_current_port - 1].adc10);
263
                //usb_puts("\n\r");
264
                //usb_puti(an_val[adc_current_port - 1].adc8);
265
                //usb_puti(ADCH);
266
                //usb_puts("\n\r");
267
        }
268
        
269
        //Save the result only if we just turned off the loop
270
        if (!adc_loop_running && !adc_prev_loop_running)
271
                return;
272
        
273
        adc_prev_loop_running = adc_loop_running;
274
        
275
        //Skip AN7 because it is not a real port
276
        if (adc_current_port == AN6) {
277
                ADMUX = ADMUX_OPT | EXT_MUX;
278
                set_adc_mux(AN8 - 8);
279
                adc_current_port = AN8;
280
        //Wrap around
281
        } else if (adc_current_port == AN11) {
282
                adc_current_port = AN1;
283
                ADMUX = ADMUX_OPT | adc_current_port;
284
        //Normal increment
285
        } else {
286
                adc_current_port++;
287
        
288
                if(adc_current_port < EXT_MUX) {
289
                        ADMUX = ADMUX_OPT | adc_current_port;
290
                } else {
291
                        ADMUX = ADMUX_OPT | EXT_MUX;
292
                        set_adc_mux(adc_current_port - 8);
293
                }
294
        }
295

    
296
        //Initiate next conversion only if we are running a loop
297
        if (!adc_loop_running)
298
                return;
299

    
300
        ADCSRA |= _BV(ADSC);
301
        
302
        //if (ADCSRA & _BV(ADSC))
303
        //        usb_putc('s');
304
                
305
        return;
306
}
307