Subversion Repositories HomeAutomation

Rev

Go to most recent revision | Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
682 eqlazer 1
/**
638 eqlazer 2
 * AntennaControl
3
 *
731 eqlazer 4
 * Build for use at ETA, http://www.eta.chalmers.se/
5
 * controlling their 2 meter yagi antenna.
6
 * For the moment only support for azimuth,
7
 * elevation is yet to be implemented.
638 eqlazer 8
 *
731 eqlazer 9
 * @date 2007-12-10
638 eqlazer 10
 * @author Erik Larsson
11
 *
12
 */
13
 
731 eqlazer 14
/*
15
 * This version uses a NodeEssential
16
 * and the pins used are:
17
 * 0: PD2 azimuth plus
18
 * 1: PD1 azimuth minus
19
 * 8: PC4 ADC4 azimuth feedback
20
 */
21
 
22
/*-----------------------------------------------------------------------------
23
 * Includes
24
 *---------------------------------------------------------------------------*/
638 eqlazer 25
#include <inttypes.h>
26
#include <avr/interrupt.h>
27
#include <stdio.h>
28
#include <string.h>
29
#include <avr/eeprom.h>
30
#include <config.h> // All configuration parameters
31
#include <bios.h>   // BIOS interface declarations, including CAN structure and ID defines.
32
#include <drivers/timer/timer.h>
33
 
731 eqlazer 34
/*-----------------------------------------------------------------------------
35
 * Defines
36
 *---------------------------------------------------------------------------*/
638 eqlazer 37
#define APP_TYPE    0xf0a0
731 eqlazer 38
#define APP_VERSION 0x0002
638 eqlazer 39
 
40
#define AZIMUTH 0
41
 
42
#define ROTATE_STOP 0
43
#define ROTATE_PLUS 1
44
#define ROTATE_MINUS 2
45
 
46
#define SET 0
47
#define GET 1
48
 
682 eqlazer 49
#define CALIBRATE_AZIMUTH 0 // EEPROM adress
50
 
638 eqlazer 51
// Make sure this is a power of 2
52
#define AVERAGE_SIZE 16
53
#define AVERAGE_SIZE_SHIFT 4
54
 
731 eqlazer 55
//FIXME move these message id defines
56
#define MSG_CAL_SET 0x11100001UL
57
#define MSG_CAL_GET 0x11100002UL
58
#define MSG_ABS 0x111000031UL
59
#define MSG_REL 0x11100004UL
60
#define MSG_START 0x11100005UL
61
#define MSG_STOP 0x11100006UL
62
#define MSG_STATUS 0x11100007UL
63
#define MSG_CAL_RET 0x111000f2UL
682 eqlazer 64
 
65
 
638 eqlazer 66
// A simple message "queue", with space for one message only.
67
// These are declared volatile to tell the compiler not to optimize away accesses.
68
volatile Can_Message_t rxMsg; // Message storage
69
volatile uint8_t rxMsgFull;   // Synchronization flag
70
 
682 eqlazer 71
// For calculating average feedback measurement
638 eqlazer 72
uint16_t azimuthReadout[ AVERAGE_SIZE ];
73
 
682 eqlazer 74
uint16_t azimuthCalibration;
75
 
731 eqlazer 76
/*-----------------------------------------------------------------------------
77
 * Declarations
78
 *---------------------------------------------------------------------------*/
79
 
80
/**
81
 * calibration
82
 * Sets and gets calibration data from EEPROM
83
 *
84
 * @param mode: set /get
85
 * @param value
86
 * @return value
87
 */
682 eqlazer 88
int16_t calibration( uint8_t mode, uint16_t value );
638 eqlazer 89
 
682 eqlazer 90
// Turn rotor
638 eqlazer 91
// position: 0-1024
731 eqlazer 92
/**
93
 * turn
94
 * Turns rotor to given position
95
 * FIXME implement this function
96
 *
97
 * @param position
98
 * @return
99
 */
682 eqlazer 100
uint8_t turn( uint16_t position );
638 eqlazer 101
 
731 eqlazer 102
/**
103
 * getPosition
104
 * Calculates the antenna position
105
 * Uses a number of the latest adc readings
106
 * and gets the avarage value
107
 *
108
 * @param void
109
 * @return position
110
 */
682 eqlazer 111
uint16_t getPosition( void );
638 eqlazer 112
 
731 eqlazer 113
/**
114
 * initAdcFeedback
115
 * Starts the ADC
116
 *
117
 * @param void
118
 * @return void
119
 */
638 eqlazer 120
void initAdcFeedback( void );
121
 
731 eqlazer 122
/**
123
 * readFeedback
124
 * Gets antenna position from ADC and
125
 * puts in arrary for later calculations
126
 *
127
 * @param void
128
 * @return void
129
 */
682 eqlazer 130
void readFeedback( void );
638 eqlazer 131
 
731 eqlazer 132
/**
133
 * controlRelay
134
 * Control the relay that turns the rotor
135
 *
136
 * @param direction
137
 * @return void
138
 */
682 eqlazer 139
void controlRelay( uint8_t direction );
638 eqlazer 140
 
731 eqlazer 141
/**
142
 * sendStatus
143
 * Sends antennas position on CAN bus
144
 *
145
 * @param void
146
 * @return void
147
 */
682 eqlazer 148
void sendStatus( void );
638 eqlazer 149
 
731 eqlazer 150
// CAN message reception callback.
151
// This function runs with interrupts disabled, keep it as short as possible.
152
void can_receive( Can_Message_t *msg ) {
153
    if (!rxMsgFull) {
154
        memcpy((void*)&rxMsg, msg, sizeof(rxMsg));
155
        rxMsgFull = 1;
156
    }
157
}
638 eqlazer 158
 
731 eqlazer 159
/*-----------------------------------------------------------------------------
160
 * Main Program
161
 *---------------------------------------------------------------------------*/
638 eqlazer 162
int main( void )
163
{
164
    // Enable interrupts as early as possible
165
    sei();
166
 
167
    Timer_Init();
731 eqlazer 168
 
169
    DDRD |= (1 << PD1)|(1 << PD2);
170
    PORTD |= (1 << PD1)|(1 << PD2);
171
 
682 eqlazer 172
    // Setup ADC
173
    initAdcFeedback();
638 eqlazer 174
 
175
    Can_Message_t txMsg;
176
    txMsg.Id = (CAN_NMT_APP_START << CAN_SHIFT_NMT_TYPE) | (NODE_ID << CAN_SHIFT_NMT_SID);
177
    txMsg.DataLength = 4;
178
    txMsg.RemoteFlag = 0;
179
    txMsg.ExtendedFlag = 1;
180
    txMsg.Data.words[0] = APP_TYPE;
181
    txMsg.Data.words[1] = APP_VERSION;
182
 
183
    // Set up callback for CAN reception, this is optional if only sending is required.
184
    BIOS_CanCallback = &can_receive;
185
    // Send CAN_NMT_APP_START
186
    BIOS_CanSend(&txMsg);
187
 
682 eqlazer 188
    // Read calibration value from eeprom
189
    azimuthCalibration = eeprom_read_word( CALIBRATE_AZIMUTH );
638 eqlazer 190
 
682 eqlazer 191
    // Timer for reading position feedback
192
    Timer_SetTimeout(0, 50, TimerTypeFreeRunning, 0);
731 eqlazer 193
    Timer_SetTimeout(1, 1000, TimerTypeFreeRunning, 0);
638 eqlazer 194
 
731 eqlazer 195
    sendStatus();
196
 
638 eqlazer 197
    while (1) {
198
        if (Timer_Expired(0)) {
682 eqlazer 199
            // Periodicly read antennas position
200
            readFeedback();
638 eqlazer 201
        }
731 eqlazer 202
        if (Timer_Expired(1)) {
203
            // Send antennas position
204
            sendStatus();
205
        }
638 eqlazer 206
 
731 eqlazer 207
        /* If any messages is received */
638 eqlazer 208
        if (rxMsgFull) {
682 eqlazer 209
 
731 eqlazer 210
            switch ( rxMsg.Id ){
211
                case MSG_CAL_SET:
212
                    // Set calibration value
682 eqlazer 213
                    if( 2 == rxMsg.DataLength ){
731 eqlazer 214
 
682 eqlazer 215
                        calibration( SET, rxMsg.Data.words[0] );
216
                    }
731 eqlazer 217
 
682 eqlazer 218
                    break;
219
 
731 eqlazer 220
                case MSG_CAL_GET:
221
                    // Get calibration value
682 eqlazer 222
                    if( 0 == rxMsg.DataLength ){
731 eqlazer 223
 
224
                        txMsg.Id = MSG_CAL_RET;
225
                        txMsg.DataLength = 2;
226
                        txMsg.Data.words[0] = calibration( GET, 0 );
227
 
228
                        BIOS_CanSend(&txMsg);
682 eqlazer 229
                    }
731 eqlazer 230
 
682 eqlazer 231
                    break;
232
 
731 eqlazer 233
                case MSG_ABS:
234
                    // Start turning to absolute position
682 eqlazer 235
                    if( 2 == rxMsg.DataLength ){
731 eqlazer 236
 
237
                        //FIXME implement this
682 eqlazer 238
                    }
731 eqlazer 239
 
682 eqlazer 240
                    break;
241
 
731 eqlazer 242
                case MSG_REL:
243
                    // Start turning to relative position
682 eqlazer 244
                    if( 2 == rxMsg.DataLength ){
731 eqlazer 245
 
246
                        //FIXME implement this
682 eqlazer 247
                    }
731 eqlazer 248
 
682 eqlazer 249
                    break;
250
 
731 eqlazer 251
                case MSG_START:
252
                    // Start turning rotor
682 eqlazer 253
                    if( 1 == rxMsg.DataLength ){
731 eqlazer 254
 
682 eqlazer 255
                        // First data byte decides direction
256
                        controlRelay( rxMsg.Data.bytes[0] );
257
                    }
731 eqlazer 258
 
682 eqlazer 259
                    break;
260
 
731 eqlazer 261
                case MSG_STOP:
262
                    // Stop turning rotor
263
 
264
                    controlRelay( ROTATE_STOP );
265
 
682 eqlazer 266
                    break;
731 eqlazer 267
 
268
                case MSG_STATUS:
269
                    // Get position
682 eqlazer 270
                    if( 0 == rxMsg.DataLength ){
271
                        sendStatus();
272
                    }
731 eqlazer 273
 
682 eqlazer 274
                    break;
275
 
276
                default:
277
                    break;
278
            }
279
 
731 eqlazer 280
            rxMsgFull = 0;
638 eqlazer 281
        }
282
    }
283
 
284
    return 0;
285
}
286
 
731 eqlazer 287
/*-----------------------------------------------------------------------------
288
 * Definitions
289
 *---------------------------------------------------------------------------*/
638 eqlazer 290
 
682 eqlazer 291
int16_t calibration( uint8_t mode, uint16_t value )
638 eqlazer 292
{
293
    // set / get calibration value
294
    if( SET == mode ){
682 eqlazer 295
        eeprom_write_word( CALIBRATE_AZIMUTH, value );
296
        azimuthCalibration = value;
297
 
638 eqlazer 298
    }else if( GET == mode ){
682 eqlazer 299
        return azimuthCalibration;
638 eqlazer 300
    }
301
    return 0;
302
}
303
 
682 eqlazer 304
uint8_t turn( uint16_t position )
638 eqlazer 305
{
731 eqlazer 306
    //FIXME implement this
638 eqlazer 307
    // start relay
308
    // read feedback
309
    // callibrate measurement
310
 
311
    while(0){
312
 
313
    }
314
    return 0;
315
}
316
 
682 eqlazer 317
uint16_t getPosition( void )
638 eqlazer 318
{
682 eqlazer 319
    uint16_t position = 0;
638 eqlazer 320
 
321
    // Get average value of position
682 eqlazer 322
    for( uint8_t i=0; i < AVERAGE_SIZE; i++ ){
323
        position += azimuthReadout[i];
638 eqlazer 324
    }
325
 
731 eqlazer 326
    // Calculate average
682 eqlazer 327
    position = position >> AVERAGE_SIZE_SHIFT;
731 eqlazer 328
 
329
    // Convert to degrees, gives about 379 degrees
330
    position /= 3;
331
 
332
    // Calibrate
333
    position += (int16_t)azimuthCalibration;
638 eqlazer 334
 
335
    return position;
336
}
337
 
338
void initAdcFeedback( void )
339
{
340
    // ADC4: Azimuth feedback
341
 
342
    // Enable ADC4
343
    ADMUX |= ( 1 << MUX2 );
344
    ADMUX &= ~(( 1 << MUX0 )|( 1 << MUX1 )|( 1 << MUX3 ));
345
 
346
    // Prescaler /128
347
    ADCSRA |= ( 1 << ADPS2)|( 1 << ADPS1)|( 1 << ADPS0);
348
 
349
    // Enable AVcc as Voltage Reference
350
    ADMUX |= ( 1 << REFS0 );
351
    ADMUX &= ~( 1 << REFS1 );
352
 
353
    // Right adjust the result
354
    ADMUX &= ~( 1 << ADLAR );
355
 
356
    // Disable digital input
357
    DIDR0 |= ( 1 << ADC5D )|( 1 << ADC4D );
358
 
682 eqlazer 359
    // Wake up ADC and enable it
638 eqlazer 360
    PRR &= ~( 1 << PRADC );
361
    ADCSRA |= ( 1 << ADEN );
682 eqlazer 362
 
363
    // Start first conversion
364
    ADCSRA |= ( 1 << ADSC );
638 eqlazer 365
}
366
 
682 eqlazer 367
void controlRelay( uint8_t direction )
638 eqlazer 368
{
731 eqlazer 369
    if( ROTATE_PLUS == direction ){
370
        // Turn CW
682 eqlazer 371
        PORTD &= ~(1 << PD2);
372
        PORTD |= (1 << PD1);
731 eqlazer 373
    }else if ( ROTATE_MINUS == direction ){
374
        // Turn CCW
682 eqlazer 375
        PORTD &= ~(1 << PD1);
376
        PORTD |= (1 << PD2);
638 eqlazer 377
    }else{
682 eqlazer 378
        // Stop azimuth rotor
638 eqlazer 379
        PORTD |= (1 << PD1);
380
        PORTD |= (1 << PD2);
381
    }
382
}
383
 
682 eqlazer 384
void readFeedback( void )
638 eqlazer 385
{
386
    static uint8_t azimuthArrayPosition = 0;
682 eqlazer 387
 
731 eqlazer 388
    // Wait for ADC conversion to complete
389
    while( ADCSRA & ( 1 << ADSC )){}
638 eqlazer 390
 
731 eqlazer 391
    // Put readout in ringbuffer
682 eqlazer 392
    azimuthReadout[ azimuthArrayPosition ] = ADCW;
393
    azimuthArrayPosition++;
731 eqlazer 394
 
682 eqlazer 395
    if( AVERAGE_SIZE <= azimuthArrayPosition ){
396
        azimuthArrayPosition = 0;
638 eqlazer 397
    }
398
 
682 eqlazer 399
    // Start next conversion
400
    ADCSRA |= ( 1 << ADSC );
401
}
402
 
403
void sendStatus( void )
404
{
731 eqlazer 405
    // Gets antennas position and sends on CAN bus
682 eqlazer 406
    Can_Message_t txMsg;
638 eqlazer 407
 
731 eqlazer 408
    txMsg.Id = 0x1f8f0100UL; //FIXME id should not be defined here
682 eqlazer 409
 
410
    txMsg.DataLength = 2;
411
    txMsg.RemoteFlag = 0;
412
    txMsg.ExtendedFlag = 1;
413
 
414
    txMsg.Data.words[ 0 ] = getPosition();
415
 
416
    BIOS_CanSend( &txMsg );
417
 
638 eqlazer 418
}
731 eqlazer 419