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
 *
682 eqlazer 4
 * Build for use at ETA, http://www.eta.chalmers.se/, controlling their 2 meter yagi antenna.
638 eqlazer 5
 *
682 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
21
#define APP_VERSION 0x0001
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
 
682 eqlazer 32
#define CALIBRATE_AZIMUTH 0 // EEPROM adress
33
 
638 eqlazer 34
// Make sure this is a power of 2
35
#define AVERAGE_SIZE 16
36
#define AVERAGE_SIZE_SHIFT 4
37
 
682 eqlazer 38
// Tillfälliga defines
39
#define MSG_CAL_SET 0x0100001UL
40
#define MSG_CAL_GET 0x0100002UL
41
#define MSG_ABS 0x01000031UL
42
#define MSG_REL 0x0100004UL
43
#define MSG_START 0x0100005UL
44
#define MSG_STOP 0x0100006UL
45
#define MSG_STATUS 0x0100007UL
46
 
47
 
48
// ----------
49
 
638 eqlazer 50
// Essential pins
51
// 0: PD2 azimuth plus
682 eqlazer 52
// 1: PD1 azimuth minus 
638 eqlazer 53
// 8: PC4 ADC4 azimuth feedback
54
 
55
 
56
 
57
// A simple message "queue", with space for one message only.
58
// These are declared volatile to tell the compiler not to optimize away accesses.
59
volatile Can_Message_t rxMsg; // Message storage
60
volatile uint8_t rxMsgFull;   // Synchronization flag
61
 
62
//uint16_t actualElevationValue;
63
//uint16_t desiredElevationValue;
64
//uint16_t actualAzimuthValue;
65
//uint16_t desiredAzimuthValue;
66
 
682 eqlazer 67
// For calculating average feedback measurement
638 eqlazer 68
uint16_t azimuthReadout[ AVERAGE_SIZE ];
682 eqlazer 69
//uint16_t elevationReadout[ AVERAGE_SIZE];
638 eqlazer 70
 
682 eqlazer 71
uint16_t azimuthCalibration;
72
 
638 eqlazer 73
// CAN message reception callback.
74
// This function runs with interrupts disabled, keep it as short as possible.
75
void can_receive( Can_Message_t *msg ) {
76
    if (!rxMsgFull) {
77
        memcpy((void*)&rxMsg, msg, sizeof(rxMsg));
78
        rxMsgFull = 1;
79
    }
80
}
81
 
82
// Calibration function
83
// mode: set / get
84
// value:
682 eqlazer 85
int16_t calibration( uint8_t mode, uint16_t value );
638 eqlazer 86
 
682 eqlazer 87
// Turn rotor
638 eqlazer 88
// position: 0-1024
682 eqlazer 89
uint8_t turn( uint16_t position );
638 eqlazer 90
 
91
// Get position
92
// Gets the average value for compensation of distorsions
682 eqlazer 93
uint16_t getPosition( void );
638 eqlazer 94
 
95
// Initiate ADC
96
void initAdcFeedback( void );
97
 
682 eqlazer 98
// Read antenna feedback from ADC
99
void readFeedback( void );
638 eqlazer 100
 
101
// Control rotation relays
682 eqlazer 102
void controlRelay( uint8_t direction );
638 eqlazer 103
 
682 eqlazer 104
// Sends antennas position on CAN
105
void sendStatus( void );
638 eqlazer 106
 
107
 
108
int main( void )
109
{
110
    // Enable interrupts as early as possible
111
    sei();
112
 
113
    Timer_Init();
114
 
682 eqlazer 115
    // Setup ADC
116
    initAdcFeedback();
638 eqlazer 117
 
118
    Can_Message_t txMsg;
119
    txMsg.Id = (CAN_NMT_APP_START << CAN_SHIFT_NMT_TYPE) | (NODE_ID << CAN_SHIFT_NMT_SID);
120
    txMsg.DataLength = 4;
121
    txMsg.RemoteFlag = 0;
122
    txMsg.ExtendedFlag = 1;
123
    txMsg.Data.words[0] = APP_TYPE;
124
    txMsg.Data.words[1] = APP_VERSION;
125
 
126
    // Set up callback for CAN reception, this is optional if only sending is required.
127
    BIOS_CanCallback = &can_receive;
128
    // Send CAN_NMT_APP_START
129
    BIOS_CanSend(&txMsg);
130
 
682 eqlazer 131
    // Read calibration value from eeprom
132
    azimuthCalibration = eeprom_read_word( CALIBRATE_AZIMUTH );
638 eqlazer 133
 
682 eqlazer 134
    // Timer for reading position feedback
135
    Timer_SetTimeout(0, 50, TimerTypeFreeRunning, 0);
638 eqlazer 136
 
137
 
138
    while (1) {
139
        if (Timer_Expired(0)) {
682 eqlazer 140
            // Periodicly read antennas position
141
            readFeedback();
638 eqlazer 142
        }
143
 
144
        if (rxMsgFull) {
682 eqlazer 145
 
146
            switch (rxMsg.Id){
147
                case MSG_CAL_SET: // Set calibration value
148
                    if( 2 == rxMsg.DataLength ){
149
                        calibration( SET, rxMsg.Data.words[0] );
150
                    }
151
                    break;
152
 
153
                case MSG_CAL_GET: // Get calibration value
154
                    if( 0 == rxMsg.DataLength ){
155
 
156
                    }
157
                    break;
158
 
159
                case MSG_ABS: // Start turning to absolute position
160
                    if( 2 == rxMsg.DataLength ){
161
 
162
                    }
163
                    break;
164
 
165
                case MSG_REL: // Start turning to relative position
166
                    if( 2 == rxMsg.DataLength ){
167
 
168
                    }
169
                    break;
170
 
171
                case MSG_START: // Start turning
172
                    if( 1 == rxMsg.DataLength ){
173
                        // First data byte decides direction
174
                        controlRelay( rxMsg.Data.bytes[0] );
175
                    }
176
                    break;
177
 
178
                case MSG_STOP: // Stop turning
179
                    if( 1 == rxMsg.DataLength ){
180
                        controlRelay( ROTATE_STOP );
181
                    }
182
                    break;
183
                case MSG_STATUS: // Get position
184
                    if( 0 == rxMsg.DataLength ){
185
                        sendStatus();
186
                    }
187
                    break;
188
 
189
                default:
190
                    break;
191
            }
192
 
638 eqlazer 193
            rxMsgFull = 0; //  
194
        }
195
    }
196
 
197
    return 0;
198
}
199
 
200
 
682 eqlazer 201
int16_t calibration( uint8_t mode, uint16_t value )
638 eqlazer 202
{
203
    // set / get calibration value
204
    if( SET == mode ){
682 eqlazer 205
        eeprom_write_word( CALIBRATE_AZIMUTH, value );
206
        azimuthCalibration = value;
207
 
638 eqlazer 208
    }else if( GET == mode ){
682 eqlazer 209
        return azimuthCalibration;
638 eqlazer 210
    }
211
    return 0;
212
}
213
 
682 eqlazer 214
uint8_t turn( uint16_t position )
638 eqlazer 215
{
216
    // start relay
217
    // read feedback
218
    // callibrate measurement
219
 
220
    while(0){
221
 
222
    }
223
    return 0;
224
}
225
 
682 eqlazer 226
uint16_t getPosition( void )
638 eqlazer 227
{
682 eqlazer 228
    uint16_t position = 0;
638 eqlazer 229
 
230
    // Get average value of position
682 eqlazer 231
    for( uint8_t i=0; i < AVERAGE_SIZE; i++ ){
232
        position += azimuthReadout[i];
638 eqlazer 233
    }
234
 
682 eqlazer 235
    position = position >> AVERAGE_SIZE_SHIFT;
236
    position += azimuthCalibration;
638 eqlazer 237
 
238
    return position;
239
}
240
 
241
void initAdcFeedback( void )
242
{
243
    // ADC4: Azimuth feedback
244
 
245
    // Enable ADC4
246
    ADMUX |= ( 1 << MUX2 );
247
    ADMUX &= ~(( 1 << MUX0 )|( 1 << MUX1 )|( 1 << MUX3 ));
248
 
249
    // Prescaler /128
250
    ADCSRA |= ( 1 << ADPS2)|( 1 << ADPS1)|( 1 << ADPS0);
251
 
252
    // Enable AVcc as Voltage Reference
253
    ADMUX |= ( 1 << REFS0 );
254
    ADMUX &= ~( 1 << REFS1 );
255
 
256
    // Right adjust the result
257
    ADMUX &= ~( 1 << ADLAR );
258
 
682 eqlazer 259
//  // Auto Trigger
638 eqlazer 260
//  ADCSRA |= ( 1 << ADATE );
261
 
262
    // Disable digital input
263
    DIDR0 |= ( 1 << ADC5D )|( 1 << ADC4D );
264
 
682 eqlazer 265
    // Wake up ADC and enable it
638 eqlazer 266
    PRR &= ~( 1 << PRADC );
267
    ADCSRA |= ( 1 << ADEN );
682 eqlazer 268
 
269
    // Start first conversion
270
    ADCSRA |= ( 1 << ADSC );
638 eqlazer 271
}
272
 
682 eqlazer 273
void controlRelay( uint8_t direction )
638 eqlazer 274
{
682 eqlazer 275
    if( ROTATE_PLUS == direction ){ // Turn clockwise
276
        PORTD &= ~(1 << PD2);
277
        PORTD |= (1 << PD1);
278
    }else if ( ROTATE_MINUS == direction ){ // Turn counter clockwise
279
        PORTD &= ~(1 << PD1);
280
        PORTD |= (1 << PD2);
638 eqlazer 281
    }else{
682 eqlazer 282
        // Stop azimuth rotor
638 eqlazer 283
        PORTD |= (1 << PD1);
284
        PORTD |= (1 << PD2);
285
    }
286
}
287
 
682 eqlazer 288
void readFeedback( void )
638 eqlazer 289
{
290
    static uint8_t azimuthArrayPosition = 0;
682 eqlazer 291
 
292
    while( ADCSRA & ( 1 << ADSC )){} // Wait for conversion to complete
638 eqlazer 293
 
682 eqlazer 294
    azimuthReadout[ azimuthArrayPosition ] = ADCW;
295
    azimuthArrayPosition++;
296
    if( AVERAGE_SIZE <= azimuthArrayPosition ){
297
        azimuthArrayPosition = 0;
638 eqlazer 298
    }
299
 
682 eqlazer 300
    // Start next conversion
301
    ADCSRA |= ( 1 << ADSC );
302
}
303
 
304
void sendStatus( void )
305
{
306
    Can_Message_t txMsg;
638 eqlazer 307
 
682 eqlazer 308
    txMsg.Id = 0x01fff00UL; //(( 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 );
309
 
310
    txMsg.DataLength = 2;
311
    txMsg.RemoteFlag = 0;
312
    txMsg.ExtendedFlag = 1;
313
 
314
    txMsg.Data.words[ 0 ] = getPosition();
315
 
316
    BIOS_CanSend( &txMsg );
317
 
638 eqlazer 318
}