Subversion Repositories HomeAutomation

Rev

Rev 744 | Details | Compare with Previous | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
682 eqlazer 1
/**
638 eqlazer 2
 * AntennaControl
3
 *
744 eqlazer 4
 * Build for use at ETA, http://www.eta.chalmers.se/, controlling their 2 meter yagi antenna.
638 eqlazer 5
 *
744 eqlazer 6
 * @date 2007-10-28
638 eqlazer 7
 * @author Erik Larsson
8
 *
9
 */
10
 
11
#include <inttypes.h>
12
#include <avr/interrupt.h>
13
#include <stdio.h>
14
#include <string.h>
15
#include <avr/eeprom.h>
16
#include <config.h> // All configuration parameters
17
#include <bios.h>   // BIOS interface declarations, including CAN structure and ID defines.
18
#include <drivers/timer/timer.h>
19
 
20
#define APP_TYPE    0xf0a0
744 eqlazer 21
#define APP_VERSION 0x0001
638 eqlazer 22
 
23
#define AZIMUTH 0
24
 
25
#define ROTATE_STOP 0
26
#define ROTATE_PLUS 1
27
#define ROTATE_MINUS 2
28
 
29
#define SET 0
30
#define GET 1
31
 
744 eqlazer 32
#define STATUS 0
33
 
682 eqlazer 34
#define CALIBRATE_AZIMUTH 0 // EEPROM adress
35
 
638 eqlazer 36
// Make sure this is a power of 2
37
#define AVERAGE_SIZE 16
38
#define AVERAGE_SIZE_SHIFT 4
39
 
744 eqlazer 40
// Tillfälliga defines
731 eqlazer 41
#define MSG_CAL_SET 0x11100001UL
42
#define MSG_CAL_GET 0x11100002UL
43
#define MSG_ABS 0x111000031UL
44
#define MSG_REL 0x11100004UL
45
#define MSG_START 0x11100005UL
46
#define MSG_STOP 0x11100006UL
47
#define MSG_STATUS 0x11100007UL
744 eqlazer 48
 
731 eqlazer 49
#define MSG_CAL_RET 0x111000f2UL
682 eqlazer 50
 
51
 
744 eqlazer 52
// ----------
53
 
54
// Essential pins
55
// 0: PD2 azimuth plus
56
// 1: PD1 azimuth minus 
57
// 8: PC4 ADC4 azimuth feedback
58
 
59
 
60
 
638 eqlazer 61
// A simple message "queue", with space for one message only.
62
// These are declared volatile to tell the compiler not to optimize away accesses.
63
volatile Can_Message_t rxMsg; // Message storage
64
volatile uint8_t rxMsgFull;   // Synchronization flag
65
 
744 eqlazer 66
//uint16_t actualElevationValue;
67
//uint16_t desiredElevationValue;
68
//uint16_t actualAzimuthValue;
69
//uint16_t desiredAzimuthValue;
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
 
744 eqlazer 76
// CAN message reception callback.
77
// This function runs with interrupts disabled, keep it as short as possible.
78
void can_receive( Can_Message_t *msg ) {
79
    if (!rxMsgFull) {
80
        memcpy((void*)&rxMsg, msg, sizeof(rxMsg));
81
        rxMsgFull = 1;
82
    }
83
}
84
 
85
// Calibration function
86
// mode: set / get
87
// value:
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
682 eqlazer 92
uint8_t turn( uint16_t position );
638 eqlazer 93
 
744 eqlazer 94
// Get position
95
// Gets the average value for compensation of distorsions
682 eqlazer 96
uint16_t getPosition( void );
638 eqlazer 97
 
744 eqlazer 98
// Initiate ADC
638 eqlazer 99
void initAdcFeedback( void );
100
 
744 eqlazer 101
// Read antenna feedback from ADC
682 eqlazer 102
void readFeedback( void );
638 eqlazer 103
 
744 eqlazer 104
// Control rotation relays
682 eqlazer 105
void controlRelay( uint8_t direction );
638 eqlazer 106
 
744 eqlazer 107
// Sends antennas position on CAN
108
void sendStatus( uint8_t type );
638 eqlazer 109
 
110
 
111
int main( void )
112
{
113
    // Enable interrupts as early as possible
114
    sei();
115
 
116
    Timer_Init();
731 eqlazer 117
 
744 eqlazer 118
    // Set as outputs and stop rotor
119
    DDRD |= (1 << PD1)|(1 << PD2);
120
    PORTD &= ~((1 << PD1)|(1 << PD2));
121
 
682 eqlazer 122
    // Setup ADC
123
    initAdcFeedback();
638 eqlazer 124
 
125
    Can_Message_t txMsg;
126
    txMsg.Id = (CAN_NMT_APP_START << CAN_SHIFT_NMT_TYPE) | (NODE_ID << CAN_SHIFT_NMT_SID);
127
    txMsg.DataLength = 4;
128
    txMsg.RemoteFlag = 0;
129
    txMsg.ExtendedFlag = 1;
130
    txMsg.Data.words[0] = APP_TYPE;
131
    txMsg.Data.words[1] = APP_VERSION;
132
 
744 eqlazer 133
    // Set up callback for CAN reception
638 eqlazer 134
    BIOS_CanCallback = &can_receive;
135
    // Send CAN_NMT_APP_START
136
    BIOS_CanSend(&txMsg);
137
 
682 eqlazer 138
    // Read calibration value from eeprom
139
    azimuthCalibration = eeprom_read_word( CALIBRATE_AZIMUTH );
638 eqlazer 140
 
682 eqlazer 141
    // Timer for reading position feedback
744 eqlazer 142
    Timer_SetTimeout(0, 100, TimerTypeFreeRunning, 0);
731 eqlazer 143
    Timer_SetTimeout(1, 1000, TimerTypeFreeRunning, 0);
638 eqlazer 144
 
744 eqlazer 145
    sendStatus( STATUS );
731 eqlazer 146
 
638 eqlazer 147
    while (1) {
148
        if (Timer_Expired(0)) {
682 eqlazer 149
            // Periodicly read antennas position
150
            readFeedback();
638 eqlazer 151
        }
731 eqlazer 152
        if (Timer_Expired(1)) {
744 eqlazer 153
            sendStatus(STATUS);
731 eqlazer 154
        }
638 eqlazer 155
 
156
        if (rxMsgFull) {
744 eqlazer 157
            switch (rxMsg.Id){
158
                case MSG_CAL_SET: // Set calibration value
682 eqlazer 159
                    if( 2 == rxMsg.DataLength ){
160
                        calibration( SET, rxMsg.Data.words[0] );
161
                    }
162
                    break;
163
 
744 eqlazer 164
                case MSG_CAL_GET: // Get calibration value
682 eqlazer 165
                    if( 0 == rxMsg.DataLength ){
731 eqlazer 166
                        txMsg.Id = MSG_CAL_RET;
167
                        txMsg.DataLength = 2;
168
                        txMsg.Data.words[0] = calibration( GET, 0 );
169
                        BIOS_CanSend(&txMsg);
682 eqlazer 170
                    }
171
                    break;
172
 
744 eqlazer 173
                case MSG_ABS: // Start turning to absolute position
682 eqlazer 174
                    if( 2 == rxMsg.DataLength ){
744 eqlazer 175
 
682 eqlazer 176
                    }
177
                    break;
178
 
744 eqlazer 179
                case MSG_REL: // Start turning to relative position
682 eqlazer 180
                    if( 2 == rxMsg.DataLength ){
744 eqlazer 181
 
682 eqlazer 182
                    }
183
                    break;
184
 
744 eqlazer 185
                case MSG_START: // Start turning
682 eqlazer 186
                    if( 1 == rxMsg.DataLength ){
187
                        // First data byte decides direction
188
                        controlRelay( rxMsg.Data.bytes[0] );
189
                    }
190
                    break;
191
 
744 eqlazer 192
                case MSG_STOP: // Stop turning
193
                    //if( 1 == rxMsg.DataLength ){
194
                        controlRelay( ROTATE_STOP );
195
                    //}
682 eqlazer 196
                    break;
744 eqlazer 197
                case MSG_STATUS: // Get position
682 eqlazer 198
                    if( 0 == rxMsg.DataLength ){
744 eqlazer 199
                        sendStatus(STATUS);
682 eqlazer 200
                    }
201
                    break;
202
 
203
                default:
204
                    break;
205
            }
206
 
744 eqlazer 207
                rxMsgFull = 0; //  
638 eqlazer 208
        }
209
    }
210
 
211
    return 0;
212
}
213
 
214
 
682 eqlazer 215
int16_t calibration( uint8_t mode, uint16_t value )
638 eqlazer 216
{
217
    // set / get calibration value
218
    if( SET == mode ){
682 eqlazer 219
        eeprom_write_word( CALIBRATE_AZIMUTH, value );
220
        azimuthCalibration = value;
221
 
638 eqlazer 222
    }else if( GET == mode ){
682 eqlazer 223
        return azimuthCalibration;
638 eqlazer 224
    }
225
    return 0;
226
}
227
 
682 eqlazer 228
uint8_t turn( uint16_t position )
638 eqlazer 229
{
230
    // start relay
231
    // read feedback
232
    // callibrate measurement
233
 
234
    while(0){
235
 
236
    }
237
    return 0;
238
}
239
 
682 eqlazer 240
uint16_t getPosition( void )
638 eqlazer 241
{
682 eqlazer 242
    uint16_t position = 0;
744 eqlazer 243
 
638 eqlazer 244
    // Get average value of position
682 eqlazer 245
    for( uint8_t i=0; i < AVERAGE_SIZE; i++ ){
246
        position += azimuthReadout[i];
638 eqlazer 247
    }
248
 
731 eqlazer 249
    // Calculate average
682 eqlazer 250
    position = position >> AVERAGE_SIZE_SHIFT;
731 eqlazer 251
 
744 eqlazer 252
    // Convert to degrees, gives about 361 degrees
253
    // start 508, stop 1023 => 516 bits per rotation
254
    // 516 * 7 / 10 = 361
731 eqlazer 255
 
744 eqlazer 256
    // Antennen rör sig inom 180 -> 360 (=0) -> 180
257
    // Norr = mittläget = 0 / 360 grader = 766 decimalt innan omräkning
258
    // Söder = ändlägena = 180 grader = 508 och 1023 innan omräkning
259
 
260
 
261
    // Make it between 508 and 1023
262
    if( position < 508 ){
263
        position = 0;
264
    }else{
265
        position -= 508;
266
    }
267
 
268
//  if( 0x8000&position ){
269
//      position = -position;
270
//      position *= 7;
271
//      position /= 10;
272
//      //position = -position;
273
//  }else{
274
 
275
        // Make it between 0 and 360
276
        position *= 7;
277
        position /= 10;
278
//  }
279
 
280
    // Move it to 180 and 540
281
    position += 180;
282
 
731 eqlazer 283
    // Calibrate
284
    position += (int16_t)azimuthCalibration;
638 eqlazer 285
 
744 eqlazer 286
    // North is now at 360
287
    if( position > 360 ){
288
        // Antenna is between 0 and 180
289
        position -= 360;
290
    }
291
 
638 eqlazer 292
    return position;
293
}
294
 
295
void initAdcFeedback( void )
296
{
297
    // ADC4: Azimuth feedback
298
 
299
    // Enable ADC4
300
    ADMUX |= ( 1 << MUX2 );
301
    ADMUX &= ~(( 1 << MUX0 )|( 1 << MUX1 )|( 1 << MUX3 ));
302
 
303
    // Prescaler /128
304
    ADCSRA |= ( 1 << ADPS2)|( 1 << ADPS1)|( 1 << ADPS0);
305
 
306
    // Enable AVcc as Voltage Reference
307
    ADMUX |= ( 1 << REFS0 );
308
    ADMUX &= ~( 1 << REFS1 );
309
 
310
    // Right adjust the result
311
    ADMUX &= ~( 1 << ADLAR );
312
 
313
    // Disable digital input
314
    DIDR0 |= ( 1 << ADC5D )|( 1 << ADC4D );
315
 
682 eqlazer 316
    // Wake up ADC and enable it
638 eqlazer 317
    PRR &= ~( 1 << PRADC );
318
    ADCSRA |= ( 1 << ADEN );
682 eqlazer 319
 
320
    // Start first conversion
321
    ADCSRA |= ( 1 << ADSC );
638 eqlazer 322
}
323
 
682 eqlazer 324
void controlRelay( uint8_t direction )
638 eqlazer 325
{
744 eqlazer 326
    if( ROTATE_PLUS == direction ){ // Turn clockwise
327
        PORTD &= ~(1 << PD1);
328
        PORTD |= (1 << PD2);
329
    }else if ( ROTATE_MINUS == direction ){ // Turn counter clockwise
682 eqlazer 330
        PORTD &= ~(1 << PD2);
331
        PORTD |= (1 << PD1);
638 eqlazer 332
    }else{
682 eqlazer 333
        // Stop azimuth rotor
744 eqlazer 334
        PORTD &= ~(1 << PD1);
335
        PORTD &= ~(1 << PD2);
638 eqlazer 336
    }
337
}
338
 
682 eqlazer 339
void readFeedback( void )
638 eqlazer 340
{
341
    static uint8_t azimuthArrayPosition = 0;
682 eqlazer 342
 
744 eqlazer 343
    while( ADCSRA & ( 1 << ADSC )){} // Wait for conversion to complete
638 eqlazer 344
 
744 eqlazer 345
    azimuthReadout[ azimuthArrayPosition ] = ADCW; // Store result in ring buffer
682 eqlazer 346
    azimuthArrayPosition++;
347
    if( AVERAGE_SIZE <= azimuthArrayPosition ){
348
        azimuthArrayPosition = 0;
638 eqlazer 349
    }
744 eqlazer 350
 
682 eqlazer 351
    // Start next conversion
352
    ADCSRA |= ( 1 << ADSC );
353
}
354
 
744 eqlazer 355
void sendStatus( uint8_t type )
682 eqlazer 356
{
357
    Can_Message_t txMsg;
638 eqlazer 358
 
744 eqlazer 359
    //txMsg.Id = 0x1f8f0100UL; //(( CAN_SNS << CAN_SHIFT_CLASS )|( SNS_TYPE_STATUS << CAN_SHIFT_SNS_TYPE )|( SNS_ID_ANTENNA_STATUS << CAN_SHIFT_SNS_ID )|( NODE_ID << CAN_SHIFT_SNS_SID );
682 eqlazer 360
 
361
    txMsg.DataLength = 2;
362
    txMsg.RemoteFlag = 0;
363
    txMsg.ExtendedFlag = 1;
364
 
744 eqlazer 365
//  txMsg.Data.words[ 0 ] = getPosition();
366
 
367
    if(STATUS == type){
368
        txMsg.Id = 0x1f8f0100UL;
369
        txMsg.Data.words[ 0 ] = getPosition();
370
        txMsg.DataLength = 2;
371
    }else{
372
        txMsg.Id = 0x12020202UL;
373
        txMsg.Data.bytes[ 0 ] = type;
374
        txMsg.DataLength = 1;
375
    }
376
 
377
    // Try to resend up to four times
378
    for(int i=0; i<3;i++){
379
        if( CAN_OK == BIOS_CanSend( &txMsg )){
380
            return;
381
        }
382
    }      
682 eqlazer 383
 
638 eqlazer 384
}