1 /********************************************************/
2 /* Data Acqusition software for the DAM module */
3 /* RAMA UAV control system */
7 /* (c) 2006, 2007 Ondrej Spinka, DCE FEE CTU Prague */
9 /* no animals were harmed during development/testing */
10 /* of this software product, except the author himself */
11 /********************************************************/
17 #include <periph/can.h>
18 #include <periph/uart_zen.h>
21 /*! @defgroup defines Constants Definitions
26 * Formal definition of logical "TRUE" value.
31 * Watchdog counter initialization/reset value.
33 /* 0x0003D090 corresponds to 100ms reset timeout */
34 #define WATCHDOG_INIT 0x0003D090
36 /*! @defgroup MEMMAP_EXC Exception Mapping Definitions
38 * These constants serve to set the exception mapping either to FLASH (0x01) or RAM (0x02).
41 #define MEMMAP_EXC_FLASH 0x01
42 #define MEMMAP_EXC_RAM 0x02
46 * Defines that status LEDs exist on the target board.
50 /*! @defgroup led_defines Status LEDs Definitions
52 * These constants define the IO ports and specific bits to manipulate respective status LEDs.
57 #define LED_IMU_PINSEL PINSEL2
58 #define LED_IMU_PINSEL_VAL 0xFFFFFFF3
59 #define LED_IMU_IODIR IODIR1
60 #define LED_IMU_IOSET IOSET1
61 #define LED_IMU_IOCLR IOCLR1
62 #define LED_IMU_IOBIT 0x00080000
64 #define LED_GPS_PINSEL PINSEL1
65 #define LED_GPS_PINSEL_VAL 0xFFFFCFFF
66 #define LED_GPS_IODIR IODIR0
67 #define LED_GPS_IOSET IOSET0
68 #define LED_GPS_IOCLR IOCLR0
69 #define LED_GPS_IOBIT 0x00400000
71 #define LED_MSH_PINSEL PINSEL1
72 #define LED_MSH_PINSEL_VAL 0xFFF3FFFF;
73 #define LED_MSH_IODIR IODIR0
74 #define LED_MSH_IOSET IOSET0
75 #define LED_MSH_IOCLR IOCLR0
76 #define LED_MSH_IOBIT 0x00800000
78 #define LED_ERR_PINSEL PINSEL1
79 #define LED_ERR_PINSEL_VAL 0xFFFCFFFF;
80 #define LED_ERR_IODIR IODIR0
81 #define LED_ERR_IOSET IOSET0
82 #define LED_ERR_IOCLR IOCLR0
83 #define LED_ERR_IOBIT 0x01000000
88 /*! @defgroup msh_degauss_defines Magnetic Sensor Hybrid Degauss Pin Definitions
90 * These constants define the IO port and specific bit to drive the MSH degauss pin.
93 #define PAL_PINSEL PINSEL1
94 #define PAL_PINSEL_VAL 0xFFFCFFFF
95 #define PAL_IODIR IODIR0
96 #define PAL_IOSET IOSET0
97 #define PAL_IOCLR IOCLR0
98 #define PAL_IOBIT 0x00200000
101 /*! @defgroup error_tresholds Error Treshold Constants
103 * These constants define the tresholds of number of errors to generate an CAN error message.
106 #define IMU_ERROR_TRESHOLD 1024
107 #define GPS_ERROR_TRESHOLD_RUN 2048
108 #define GPS_ERROR_TRESHOLD_INIT 30720
111 /*! @defgroup error_codes Error Codes
113 * Following constants define the error codes.
117 #define GENERAL_ERR 0x01
118 #define PARITY_ERR 0x02
119 #define RANGE_ERR 0x03
120 #define FRAME_ERR 0x04
121 #define FRAME_ERR_ETX 0x05
124 /*! @defgroup can_id CAN Message IDs
126 * The constants below define respective IDs for the CAN messages.
127 * Standard 11-bit IDs are used.
130 #define RQ_CAN_ID 0x0014
132 #define RESET_REQUEST_ID 0x006E
134 #define FILTER_ROLL_A_ID 0x0070
135 #define FILTER_ROLL_B_ID 0x0071
136 #define FILTER_PITCH_A_ID 0x0072
137 #define FILTER_PITCH_B_ID 0x0073
138 #define FILTER_YAW_A_ID 0x0074
139 #define FILTER_YAW_B_ID 0x0075
140 #define FILTER_ACCEL_X_A_ID 0x0076
141 #define FILTER_ACCEL_X_B_ID 0x0077
142 #define FILTER_ACCEL_Y_A_ID 0x0078
143 #define FILTER_ACCEL_Y_B_ID 0x0079
144 #define FILTER_ACCEL_Z_A_ID 0x007A
145 #define FILTER_ACCEL_Z_B_ID 0x007B
146 #define CAL_SAMPLE_NUM_ID 0x0059
148 #define IMU_ERR_CAN_ID 0x0002
149 #define AR_CAN_ID_ROLL_FILTERED 0x0028
150 #define AR_CAN_ID_PITCH_FILTERED 0x0029
151 #define AR_CAN_ID_YAW_FILTERED 0x002A
152 #define AR_CAN_ID_ROLL 0x00C4
153 #define AR_CAN_ID_PITCH 0x01C4
154 #define AR_CAN_ID_YAW 0x03C4
155 #define AC_CAN_ID_X_FILTERED 0x0053
156 #define AC_CAN_ID_Y_FILTERED 0x0054
157 #define AC_CAN_ID_Z_FILTERED 0x0055
158 #define AC_CAN_ID_X 0x0056
159 #define AC_CAN_ID_Y 0x0057
160 #define AC_CAN_ID_Z 0x0058
162 #define GPS_ERR_CAN_ID 0x0004
163 #define GPS_ID1 0x0400
164 #define GPS_ID2 0x0200
165 #define GPS_ID3 0x0180
166 #define GPS_ID4 0x0100
167 #define GPS_ID5 0x0300
168 #define GPS_ID6 0x0500
169 #define GPS_ID7 0x0700
170 #define GPS_ID8 0x0080
172 #define MSH_ID_X 0x0020
173 #define MSH_ID_Y 0x0040
174 #define MSH_ID_Z 0x0060
177 /*! @defgroup timer_settings Timer Settings
179 * The constants below define the timer settings (timer frequency and interrupt number).
183 #define TIMER_PRESCALER 1
184 #define TIMER_PERIOD 19531
185 #define ISR_INT_VEC_TIMER 10
188 /*! @defgroup can_settings CAN Settings
190 * The constants below define the CAN settings (baud rate and interrupt number).
193 #define CAN_BTR 0x00250000
194 #define ISR_INT_VEC_CAN 11
197 /*! @defgroup imu_constants IMU Communication Constants
199 * The constants below define important IMU communication constants,
200 * such as message delimiter bytes and out-of-range bit mask.
203 #define IMU_MES_DELIMITER_1 0x78
204 #define IMU_MES_DELIMITER_2 0x87
205 #define IMU_RANGE_MASK 0x3F
208 /*! @defgroup gps_constants GPS Communication Constants
210 * The constants below define important GPS communication constants,
211 * such as message header and delimiter bytes and length.
214 #define DLE_BYTE 0x10
215 #define ETX_BYTE 0x03
217 #define GPS_DATA_LENGTH 0x40
220 /*! @defgroup uart_settings UART Settings
222 * The constants below define the UART settings, such as baud rates, interrupt numbers and buffer lengths.
225 #define BAUD_RATE0 38400
227 /* a bit of dirty work - should be 9600, but 9530 better suits with respect to clock speed */
228 #define BAUD_RATE1 9530
230 #define ISR_INT_VEC_U0 12
231 #define ISR_INT_VEC_U1 13
233 #define BUFF_IMU_LEN 6
234 #define BUFF_GPS_LEN 64
237 /*! @defgroup angular_rates_conversion Angular Rates Conversion Constant
241 /*!\def ANGULAR_CONV_64
242 * The constant below defines the angular rates conversion constant for 64Hz sampling rate.
244 #define ANGULAR_CONV_64 0.000976563
246 /*!\def GYRO_OFFSET_FILTERING_TRESHOLD
247 * This constant defines the filter initialization treshold.
249 #define GYRO_OFFSET_FILTERING_TRESHOLD 10
252 /*! @defgroup accel_conversion Accelerations Conversion Constant
254 * Accelerations conversion constants
257 /*!\def ACCEL_CONV_64
258 * This constant is used to convert accelerations suppoted by the IMU from m/s2 into miligs for 64Hz sampling rate.
260 /* ( 1/9.80665 ) * 64 */
261 #define ACCEL_CONV_64 6.5261838
264 /*! @defgroup msh_conversion Magnetic Field Intensity Constants
269 * AD value-to-mgauss conversion constant
271 #define MSH_CONV 0.91
276 #define MSH_OFFSET 430
281 #define BUFF_MSH_LEN 32
284 /*! @defgroup filter_settings Filter Settings
286 * The constants below define the polynomial filter coefficients for the roll, pitch and yaw angular rate filters.
289 #define MAX_FILTER_LEN 6
291 #define FILTER_ROLL_A_NUM_FLAG 0x0001
292 #define FILTER_ROLL_B_NUM_FLAG 0x0002
293 #define FILTER_PITCH_A_NUM_FLAG 0x0004
294 #define FILTER_PITCH_B_NUM_FLAG 0x0008
295 #define FILTER_YAW_A_NUM_FLAG 0x0010
296 #define FILTER_YAW_B_NUM_FLAG 0x0020
297 #define FILTER_ACCEL_X_A_NUM_FLAG 0x0040
298 #define FILTER_ACCEL_X_B_NUM_FLAG 0x0080
299 #define FILTER_ACCEL_Y_A_NUM_FLAG 0x0100
300 #define FILTER_ACCEL_Y_B_NUM_FLAG 0x0200
301 #define FILTER_ACCEL_Z_A_NUM_FLAG 0x0400
302 #define FILTER_ACCEL_Z_B_NUM_FLAG 0x0800
304 #define FILTER_A_NUM 3
305 #define FILTER_B_NUM 3
307 #define FILTER_COEF_A_1 1.0
308 #define FILTER_COEF_A_2 0.462938
309 #define FILTER_COEF_A_3 0.2097154
310 #define FILTER_COEF_B_1 0.4181633
311 #define FILTER_COEF_B_2 0.836327
312 #define FILTER_COEF_B_3 0.4181633
316 uint8_t reset_req
= 0; //!< reset request flag
318 uint16_t imu_timeout_count
= 0; //!< IMU timeout counter
319 uint16_t gps_timeout_count
= 0; //!< GPS timeout counter
320 uint16_t gps_err_treshold
= GPS_ERROR_TRESHOLD_INIT
; //!< GPS error treshold value (when surpassed, error message is generated)
321 uint8_t imu_err_state
= 0; //!< IMU error status flag
322 uint8_t gps_err_state
= 0; //!< GPS error status flag
324 uint8_t filter_roll_a_num
= FILTER_A_NUM
; //!< roll filter number of a coefficients
325 uint8_t filter_roll_b_num
= FILTER_B_NUM
; //!< roll filter number of b coefficients
326 uint8_t filter_pitch_a_num
= FILTER_A_NUM
; //!< pitch filter number of a coefficients
327 uint8_t filter_pitch_b_num
= FILTER_B_NUM
; //!< pitch filter number of b coefficients
328 uint8_t filter_yaw_a_num
= FILTER_A_NUM
; //!< yaw filter number of a coefficients
329 uint8_t filter_yaw_b_num
= FILTER_B_NUM
; //!< yaw filter number of b coefficients
330 uint8_t filter_accel_x_a_num
= FILTER_A_NUM
; //!< x-axis acceleration filter number of a coefficients
331 uint8_t filter_accel_x_b_num
= FILTER_B_NUM
; //!< x-axis acceleration filter number of b coefficients
332 uint8_t filter_accel_y_a_num
= FILTER_A_NUM
; //!< y-axis acceleration filter number of a coefficients
333 uint8_t filter_accel_y_b_num
= FILTER_B_NUM
; //!< y-axis acceleration filter number of b coefficients
334 uint8_t filter_accel_z_a_num
= FILTER_A_NUM
; //!< z-axis acceleration filter number of a coefficients
335 uint8_t filter_accel_z_b_num
= FILTER_B_NUM
; //!< z-axis acceleration filter number of b coefficients
337 uint8_t msh_meas_count
= 0; //!< MSH sample counter
338 uint8_t msh_degauss_count
= 0; //!< MSH degauss (time) counter
339 int32_t mg_meas_x
[BUFF_MSH_LEN
]; //!< x-axis magnetic field intensity sample buffer
340 int32_t mg_meas_y
[BUFF_MSH_LEN
]; //!< y-axis magnetic field intensity sample buffer
341 int32_t mg_meas_z
[BUFF_MSH_LEN
]; //!< z-axis magnetic field intensity sample buffer
343 uint16_t cal_sample_num
; //!< number of IMU calibration samples
345 double a_roll
[MAX_FILTER_LEN
] = {FILTER_COEF_A_1
, FILTER_COEF_A_2
, FILTER_COEF_A_3
, 0, 0, 0}, b_roll
[MAX_FILTER_LEN
] = {FILTER_COEF_B_1
, FILTER_COEF_B_2
, FILTER_COEF_B_3
, 0, 0, 0}; //!< roll filter coeffitients
346 double a_pitch
[MAX_FILTER_LEN
] = {FILTER_COEF_A_1
, FILTER_COEF_A_2
, FILTER_COEF_A_3
, 0, 0, 0}, b_pitch
[MAX_FILTER_LEN
] = {FILTER_COEF_B_1
, FILTER_COEF_B_2
, FILTER_COEF_B_3
, 0, 0, 0}; //!< pitch filter coeffitients
347 double a_yaw
[MAX_FILTER_LEN
] = {FILTER_COEF_A_1
, FILTER_COEF_A_2
, FILTER_COEF_A_3
, 0, 0, 0}, b_yaw
[MAX_FILTER_LEN
] = {FILTER_COEF_B_1
, FILTER_COEF_B_2
, FILTER_COEF_B_3
, 0, 0, 0}; //!< yaw filter coeffitients
348 double a_accel_x
[MAX_FILTER_LEN
] = {FILTER_COEF_A_1
, FILTER_COEF_A_2
, FILTER_COEF_A_3
, 0, 0, 0}, b_accel_x
[MAX_FILTER_LEN
] = {FILTER_COEF_B_1
, FILTER_COEF_B_2
, FILTER_COEF_B_3
, 0, 0, 0}; //!< x-axis acceleration filter coeffitients
349 double a_accel_y
[MAX_FILTER_LEN
] = {FILTER_COEF_A_1
, FILTER_COEF_A_2
, FILTER_COEF_A_3
, 0, 0, 0}, b_accel_y
[MAX_FILTER_LEN
] = {FILTER_COEF_B_1
, FILTER_COEF_B_2
, FILTER_COEF_B_3
, 0, 0, 0}; //!< y-axis acceleration filter coeffitients
350 double a_accel_z
[MAX_FILTER_LEN
] = {FILTER_COEF_A_1
, FILTER_COEF_A_2
, FILTER_COEF_A_3
, 0, 0, 0}, b_accel_z
[MAX_FILTER_LEN
] = {FILTER_COEF_B_1
, FILTER_COEF_B_2
, FILTER_COEF_B_3
, 0, 0, 0}; //!< z-axis acceleration filter coeffitients
352 can_msg_t imu_msg_err
= {.id
= IMU_ERR_CAN_ID
}; //!< IMU CAN error message
353 can_msg_t gps_msg_err
= {.id
= GPS_ERR_CAN_ID
}; //!< GPS CAN error message
355 /*! Timer 0 interrupt handler prototype. */
356 void timer_irq_handler ( void ) __attribute__ ( ( interrupt
) );
358 /*! Timer 0 initialization routine.
359 * Takes three arguments:
360 * \param prescale unsigned 32-bit int timer prescaler value
361 * \param period unsigned 32-bit int timer period value (counter reset occurs on match)
362 * \param irq_vect unsigned int timer interrupt number
364 inline void timer_init ( uint32_t prescale
, uint32_t period
, unsigned irq_vect
) {
365 T0PR
= prescale
- 1; // set prescaler
366 T0MR1
= period
- 1; // set period
367 T0MCR
= 0x0003 << 3; // interrupt and counter reset on match1
368 T0EMR
= 0x0001 << 6 | 0x2; // set MAT0.1 low on match and high now
369 T0CCR
= 0x0000; // no capture
370 T0TCR
|= 0x0001; // go!
372 ( (uint32_t*) &VICVectAddr0
)[irq_vect
] = (uint32_t) timer_irq_handler
; // set the interrupt vector
373 ( (uint32_t*) &VICVectCntl0
)[irq_vect
] = 0x20 | 4;
374 VICIntEnable
= 0x00000010; // enable the timer 0 interrupt
377 /*! AD convertor initialization function.
378 * Takes one argument:
379 * \param clk_div unsigned 32-bit int timer prescaler value. Resulting clock speed should be less then or equal to 4.5MHz
381 inline void adc_init ( uint32_t clk_div
) {
382 ADCR
= ( ( clk_div
& 0x000000FF ) << 8 ) | 0x00200000; // set the clock prescaler and switch the AD convertor on
385 /*! Watchdog initialization function.
386 * Takes one argument:
387 * \param init_val unsigned 32-bit int timer initial value.
389 inline void watchdog_init ( uint32_t init_val
) {
390 WDTC
= init_val
; // timer counter start value
391 WDMOD
|= 0x03; // enable watchdog and reset capability
393 WDFEED
= 0x55; // feed sequence
396 /*! Watchdog reset function.
397 * Takes no arguments.
399 inline void watchdog_reset ( void ) {
401 WDFEED
= 0x55; // feed sequence
404 /*! Buttleworth filter algorithm.
405 * Takes seven arguments:
406 * \param sample double new sample
407 * \param x_array double pointer to the filter denominator array
408 * \param y_array double pointer to the filter nominator array
409 * \param a_coef double pointer to the filter denominator coefficients array
410 * \param b_coef double pointer to the filter nominator coefficients array
411 * \param a_num unsigned 8-bit integer number of a coefficients
412 * \param b_num unsigned 8-bit integer number of b coefficients
414 void filter ( double sample
, double *x_array
, double *y_array
, double *a_coef
, double *b_coef
, uint8_t a_num
, uint8_t b_num
) {
417 for ( i
= 0; i
< ( b_num
- 1 ); i
++ ) x_array
[i
] = x_array
[i
+ 1]; // input data buffer shifting
418 x_array
[b_num
- 1] = sample
; // store new samle into the buffer
420 for ( i
= 0; i
< ( a_num
- 1 ); i
++ ) y_array
[i
] = y_array
[i
+ 1]; // output data buffer shifting
421 y_array
[a_num
- 1] = 0; // store 0 at the end
423 for ( i
= 0; i
< b_num
; i
++ ) y_array
[a_num
- 1] += b_coef
[i
] * x_array
[b_num
- i
- 1]; // input polynom computation
425 for ( i
= 1; i
< a_num
; i
++ ) y_array
[a_num
- 1] -= a_coef
[i
] * y_array
[a_num
- i
- 1]; // input polynom computation
428 /*! Function sending a double number via CAN.
429 * Takes two arguments:
430 * \param id unsigned 32-bit integer message ID
431 * \param num double number to be sent
433 void send_double_can ( uint32_t id
, double num
) {
434 can_msg_t msg
= {.dlc
= 8}; // CAN message
436 /* decompose double into 8-bit fields (quartet byte order change) */
437 memcpy ( &msg
.data
[4], &num
, 4 );
438 memcpy ( &msg
.data
[0], ( ( ( uint8_t * ) &num
) + 4 ), 4 );
440 msg
.id
= id
; // set the message ID
441 while ( can_tx_msg ( &msg
) ); // send the CAN message
444 /*! Function initializing AD conversion and sampling the data.
445 * Takes one argument:
446 * \param channel AD channel to sample
447 * \return Returns sampled value.
449 int32_t read_AD ( int32_t channel
) {
450 int32_t read
; // AD read value
453 ADCR
|= channel
; // initialize AD channel sample
455 while ( ! ( ( read
= ADDR
) & 0x80000000 ) ); // wait for sample acquisition
457 read
>>= 6; // read and preprocess sample
463 /*! Timer 0 interrupt handler.
464 * Serves to handle response timeouts of IMU and GPS.
466 void timer_irq_handler ( void ) {
467 static uint16_t blinki
= 0; // counter for LED blinking
469 if ( !reset_req
) watchdog_reset ( ); // watchdog reset
471 mg_meas_x
[msh_meas_count
] = read_AD ( 0x00000001 ); // store the result into respective buffer
472 mg_meas_y
[msh_meas_count
] = read_AD ( 0x00000002 ); // store the result into respective buffer
473 mg_meas_z
[msh_meas_count
] = read_AD ( 0x00000004 ); // store the result into respective buffer
475 if ( msh_meas_count
< BUFF_MSH_LEN
) msh_meas_count
++; // increment the MSH sample counter
477 if ( imu_timeout_count
++ > IMU_ERROR_TRESHOLD
) { // if IMU is not responding for the preset time
479 LED_IMU_IOCLR
|= LED_IMU_IOBIT
; // switch the IMU LED off
480 LED_ERR_IOSET
|= LED_ERR_IOBIT
; // switch the ERR LED on
481 imu_timeout_count
= 0; // reset the IMU time counter
482 imu_msg_err
.data
[imu_msg_err
.dlc
++] = GENERAL_ERR
; // fill in the error code into the IMU error message structure
483 while ( can_tx_msg ( &imu_msg_err
) ); // send the error message
484 imu_msg_err
.dlc
= 0; // null the error message
487 if ( gps_timeout_count
++ > gps_err_treshold
) { // if GPS is not responding for the preset time
489 LED_GPS_IOCLR
|= LED_GPS_IOBIT
; // switch the GPS LED off
490 LED_ERR_IOSET
|= LED_ERR_IOBIT
; // switch the ERR LED on
491 gps_timeout_count
= 0; // reset the GPS time counter
492 gps_msg_err
.data
[gps_msg_err
.dlc
++] = GENERAL_ERR
; // fill in the error code into the IMU error message structure
493 while ( can_tx_msg ( &gps_msg_err
) ); // send the error message
494 gps_msg_err
.dlc
= 0; // null the error message
497 if ( blinki
++ < 128 ) LED_MSH_IOSET
|= LED_MSH_IOBIT
; // switch the MSH LED on for 0.25s
498 else LED_MSH_IOCLR
|= LED_MSH_IOBIT
; // switch the MSH LED off for 0.25s
499 if ( blinki
> 256 ) blinki
= 0; // after 0.5s, reset the LED blinking counter
501 T0IR
= 0xFFFFFFFF; // clear the interrupt flag
502 VICVectAddr
= 0; // int acknowledge
505 /*! Function adding coeffitients into the filter coeffitients array.
506 * Takes five arguments:
507 * \param filter_coef_flag unsigned 16-bit integer pointer filter coeffitient flag
508 * \param current_coef_flag unsigned 16-bit integer flag of the filter coeffitient currently being processed
509 * \param coef_num unsigned 8-bit integer pointer number of current coeffitient
510 * \param filter_array double pointer filter coeffitient array to which the coeffitient will be added
511 * \param rx_msg can_msg_t CAN message structure containing the coeffitient
513 void filter_coef_add ( uint16_t *filter_coef_flag
, uint16_t current_coef_flag
, uint8_t *coef_num
, double *filter_array
, can_msg_t
*rx_msg
) {
514 if ( !( (*filter_coef_flag
) & current_coef_flag
) ) { // if first filter ceficient received
515 (*filter_coef_flag
) |= current_coef_flag
; // set the corresponding flag
516 *coef_num
= 0; // and null respective coeficient number
519 if ( *coef_num
< MAX_FILTER_LEN
) {
520 memcpy ( &filter_array
[*coef_num
], &(*rx_msg
).data
[4], 4 ); // compose double from 8-bit fields, store new coeficient
521 memcpy ( ( ( ( uint8_t * ) &filter_array
[(*coef_num
)++] ) + 4 ), &(*rx_msg
).data
[0], 4 ); // and increment the coeficients counter
525 /*! CAN Rx message process routine.
526 * Serves to handle an incoming CAN message.
528 void can_rx ( void ) {
529 typedef struct { // structure holding non-constant filter_coef_add function params
530 uint16_t current_coef_flag
;
532 double *filter_array
;
533 } filter_param_struct
;
535 filter_param_struct filter_param
[12] = { {FILTER_ROLL_A_NUM_FLAG
, &filter_roll_a_num
, a_roll
}, {FILTER_ROLL_B_NUM_FLAG
, &filter_roll_b_num
, b_roll
}, {FILTER_PITCH_A_NUM_FLAG
, &filter_pitch_a_num
, a_pitch
}, {FILTER_PITCH_B_NUM_FLAG
, &filter_pitch_b_num
, b_pitch
}, {FILTER_YAW_A_NUM_FLAG
, &filter_yaw_a_num
, a_yaw
}, {FILTER_YAW_B_NUM_FLAG
, &filter_yaw_b_num
, b_yaw
}, {FILTER_ACCEL_X_A_NUM_FLAG
, &filter_accel_x_a_num
, a_accel_x
}, {FILTER_ACCEL_X_B_NUM_FLAG
, &filter_accel_x_b_num
, b_accel_x
}, {FILTER_ACCEL_Y_A_NUM_FLAG
, &filter_accel_y_a_num
, a_accel_y
}, {FILTER_ACCEL_Y_B_NUM_FLAG
, &filter_accel_y_b_num
, b_accel_y
}, {FILTER_ACCEL_Z_A_NUM_FLAG
, &filter_accel_z_a_num
, a_accel_z
}, {FILTER_ACCEL_Z_B_NUM_FLAG
, &filter_accel_z_b_num
, b_accel_z
} }; // array of structures holding non-constant filter_coef_add function params for various filters
537 static uint16_t filter_coef_flag
= 0; // filter coefitients reception flag
538 can_msg_t rx_msg
; // received message
540 memcpy ( &rx_msg
, (void *) &can_rx_msg
, sizeof ( can_msg_t
) ); // create a local copy of the received message
542 switch ( rx_msg
.id
) { // switch according CAN message ID
543 case RESET_REQUEST_ID
: // when reset request is received
544 reset_req
= TRUE
; // set the reset request flag
545 while ( TRUE
); // wait for watchdog reset
548 case CAL_SAMPLE_NUM_ID
: // receive number of calibration samples
549 memcpy ( &cal_sample_num
, &rx_msg
.data
[0], sizeof ( uint16_t ) ); // compose uint16 from 8-bit fields
552 default: // receive filter coeficients
553 if ( ( rx_msg
.id
>= FILTER_ROLL_A_ID
) && ( rx_msg
.id
<= FILTER_ACCEL_Z_B_ID
) ) filter_coef_add ( &filter_coef_flag
, filter_param
[rx_msg
.id
- FILTER_ROLL_A_ID
].current_coef_flag
, filter_param
[rx_msg
.id
- FILTER_ROLL_A_ID
].coef_num
, filter_param
[rx_msg
.id
- FILTER_ROLL_A_ID
].filter_array
, &rx_msg
); // if filter coeffitient is received, add it to the respective filter coeffitients array
557 can_msg_received
= 0; // reset the pending CAN message flag
560 /*! IMU service routine.
561 * Serves to receive and process the IMU datagrams.
562 * \param *step unsigned 8-bit int pointer referencing the message processing step.
564 void IMU_service ( uint8_t *step
) {
565 uint8_t count
, temp
= 0; // auxiliary variables for wait cycle
566 static uint8_t check_imu
; // IMU datagram cross-parity computation variable
567 static uint8_t c
; // Auxiliary index variable
568 static uint8_t sample_count
= 0; // IMU sample counter
569 static uint8_t blinki
= 0; // counter variable driving the LED blinking
570 static uint8_t buffer_int16
[2]; // receive buffer for a 16-bit integer
572 static int16_t buffer_imu
[BUFF_IMU_LEN
] = {0, 0, 0, 0, 0, 0}; // IMU data buffers
574 static uint16_t cal_sample_count
= 0; // calibration sample counter
576 int32_t msh_read_x
; // MSH measurement sum x
577 int32_t msh_read_y
; // MSH measurement sum y
578 int32_t msh_read_z
; // MSH measurement sum z
579 uint8_t msh_meas_count_local
; // local copy of msh_meas_count
580 double msh_val
; // MSH sample
582 double roll_compensated
= 0; // Computed roll rate [64 Hz] with offset compensation
583 double pitch_compensated
= 0; // Computed pitch rate [64 Hz] with offset compensation
584 double yaw_compensated
= 0; // Computed yaw rate [64 Hz] with offset compensation
585 double accel_x
; // Computed x-axis acceleration
586 double accel_y
; // Computed y-axis acceleration
587 double accel_z
; // Computed z-axis acceleration
589 static double roll_offset
= 0; // roll gyro offset
590 static double pitch_offset
= 0; // pitch gyro offset
591 static double yaw_offset
= 0; // yaw gyro offset
593 static double x_roll
[MAX_FILTER_LEN
] = {0, 0, 0, 0, 0, 0}, y_roll
[MAX_FILTER_LEN
] = {0, 0, 0, 0, 0, 0}; // roll rate filtering buffer
594 static double x_pitch
[MAX_FILTER_LEN
] = {0, 0, 0, 0, 0, 0}, y_pitch
[MAX_FILTER_LEN
] = {0, 0, 0, 0, 0, 0}; // pitch rate filtering buffer
595 static double x_yaw
[MAX_FILTER_LEN
] = {0, 0, 0, 0, 0, 0}, y_yaw
[MAX_FILTER_LEN
] = {0, 0, 0, 0, 0, 0}; // yaw rate filtering buffer
596 static double x_accel_x
[MAX_FILTER_LEN
] = {0, 0, 0, 0, 0, 0}, y_accel_x
[MAX_FILTER_LEN
] = {0, 0, 0, 0, 0, 0}; // x-axis acceleration filtering buffer
597 static double x_accel_y
[MAX_FILTER_LEN
] = {0, 0, 0, 0, 0, 0}, y_accel_y
[MAX_FILTER_LEN
] = {0, 0, 0, 0, 0, 0}; // y-axis acceleration filtering buffer
598 static double x_accel_z
[MAX_FILTER_LEN
] = {0, 0, 0, 0, 0, 0}, y_accel_z
[MAX_FILTER_LEN
] = {0, 0, 0, 0, 0, 0}; // z-axis acceleration filtering buffer
600 can_msg_t msg_rq
= {.dlc
= 0, .id
= RQ_CAN_ID
}; // time synchronization CAN message
603 case 0: if ( read_UART_data ( UART0
) == IMU_MES_DELIMITER_1
) ( *step
)++; // wait for the first telegram start character
606 case 1: if ( read_UART_data ( UART0
) == IMU_MES_DELIMITER_2
) { // wait for the second telegram start character
607 ( *step
)++; // increment the IMU step counter
609 if ( ++sample_count
> 1 ) while (can_tx_msg(&msg_rq
)); // when the second teleram is being received, send the
610 // synchonisation message (IMU running at 64Hz, overall system sampling frequency is 32Hz)
611 } else ( *step
) = 0; // should another character be received, return to the sequence beginning
615 case 2: if ( blinki
++ < 32 ) LED_IMU_IOSET
|= LED_IMU_IOBIT
; // switch the IMU LED on for 0.5s
616 else LED_IMU_IOCLR
|= LED_IMU_IOBIT
; // switch the IMU LED off for 0.5s
617 if ( blinki
> 64 ) blinki
= 0; // after 1s, reset the LED blinking counter
619 check_imu
= IMU_MES_DELIMITER_1
; // cross parity initialization
620 check_imu
^= IMU_MES_DELIMITER_2
; // cross parity initialization
622 c
= read_UART_data ( UART0
); // read the next telegram character
623 check_imu
^= c
; // cross parity computation
625 if ( c
& IMU_RANGE_MASK
) { // when IMU range error is detected, fill in respective error code
626 imu_msg_err
.data
[imu_msg_err
.dlc
++] = RANGE_ERR
; // into the IMU error message structure
627 while ( can_tx_msg ( &imu_msg_err
) ); // send the error message
628 imu_msg_err
.dlc
= 0; // null the error message
631 c
= 0; // reset c, as it will be used as a cycle counter in the next two steps
635 /* read the accelerations and angular velocities */
636 case 3: buffer_int16
[0] = read_UART_data ( UART0
); // read the first part of a 16-bit integer
637 check_imu
^= buffer_int16
[0]; // cross parity computation
641 case 4: buffer_int16
[1] = read_UART_data ( UART0
); // read the second part of a 16-bit integer
642 check_imu
^= buffer_int16
[1]; // cross parity computation
643 memcpy ( &buffer_imu
[c
], buffer_int16
, sizeof ( int16_t ) ); // read the second part of a 16-bit integer
645 if ( ++c
< 6 ) ( *step
)--; else ( *step
)++; // when all 6 values are acquired go ahead, or return to the previous step
648 case 5: c
= read_UART_data ( UART0
); // read the cross parity
649 check_imu
^= c
; // this final XOR should give a zero if the parity was right
651 if ( check_imu
) { // should the parity be wrong fill in the respective error code
652 imu_msg_err
.data
[imu_msg_err
.dlc
++] = PARITY_ERR
; // into the IMU error message structure
653 while ( can_tx_msg ( &imu_msg_err
) ); // send the error message
654 imu_msg_err
.dlc
= 0; // null the error message
657 /* data filtering - roll, pitch and yaw angular rates */
658 filter ( ( ( (double) buffer_imu
[0] ) * -ANGULAR_CONV_64
), x_roll
, y_roll
, a_roll
, b_roll
, filter_roll_a_num
, filter_roll_b_num
);
659 filter ( ( ( (double) buffer_imu
[1] ) * -ANGULAR_CONV_64
), x_pitch
, y_pitch
, a_pitch
, b_pitch
, filter_pitch_a_num
, filter_pitch_b_num
);
660 filter ( ( ( (double) buffer_imu
[2] ) * ANGULAR_CONV_64
), x_yaw
, y_yaw
, a_yaw
, b_yaw
, filter_yaw_a_num
, filter_yaw_b_num
);
662 /* gyros offset computation (calibration) */
663 if ( ( cal_sample_count
>= GYRO_OFFSET_FILTERING_TRESHOLD
) && ( cal_sample_count
< cal_sample_num
) ) { // summarize (cal_sample_num - GYRO_OFFSET_FILTERING_TRESHOLD) samples
664 roll_offset
+= y_roll
[filter_roll_a_num
- 1];
665 pitch_offset
+= y_pitch
[filter_pitch_a_num
- 1];
666 yaw_offset
+= y_yaw
[filter_yaw_a_num
- 1];
668 /* ERR LED blinking */
669 if ( blinki
< 32 ) LED_ERR_IOSET
|= LED_ERR_IOBIT
; // switch the ERR LED on for 0.5s
670 else LED_ERR_IOCLR
|= LED_ERR_IOBIT
; // switch the ERR LED off for 0.5s
671 } else if ( cal_sample_count
== cal_sample_num
) { // compute offset mean values
672 roll_offset
/= ( (double) ( cal_sample_num
- GYRO_OFFSET_FILTERING_TRESHOLD
) );
673 pitch_offset
/= ( (double) ( cal_sample_num
- GYRO_OFFSET_FILTERING_TRESHOLD
) );
674 yaw_offset
/= ( (double) ( cal_sample_num
- GYRO_OFFSET_FILTERING_TRESHOLD
) );
676 if ( !imu_err_state
&& !gps_err_state
) LED_ERR_IOCLR
|= LED_ERR_IOBIT
; // if IMU and GPS are not in the error state switch the ERR LED off
677 else LED_ERR_IOSET
|= LED_ERR_IOBIT
; // else if IMU or GPS (or both) are in the error state switch the ERR LED on
680 /* filtered roll, pitch and yaw offset compensation */
681 if ( cal_sample_count
> cal_sample_num
) {
682 roll_compensated
= y_roll
[filter_roll_a_num
- 1] - roll_offset
;
683 pitch_compensated
= y_pitch
[filter_pitch_a_num
- 1] - pitch_offset
;
684 yaw_compensated
= y_yaw
[filter_yaw_a_num
- 1] - yaw_offset
;
687 if ( cal_sample_count
< 0xFFFF ) cal_sample_count
++; // increment calibration sample counter
689 /* x, y and z acceleration computation */
690 accel_x
= ( (double) buffer_imu
[4] ) * ACCEL_CONV_64
; // convert x-axis acceleration into miligs
691 accel_y
= ( (double) buffer_imu
[3] ) * ACCEL_CONV_64
; // convert y-axis acceleration into miligs
692 accel_z
= ( (double) buffer_imu
[5] ) * -ACCEL_CONV_64
; // convert z-axis acceleration into miligs (*(-1) due to the IMU orientation)
694 /* data filtering - x, y and z axes accelerations */
695 filter ( accel_x
, x_accel_x
, y_accel_x
, a_accel_x
, b_accel_x
, filter_accel_x_a_num
, filter_accel_x_b_num
);
696 filter ( accel_y
, x_accel_y
, y_accel_y
, a_accel_y
, b_accel_y
, filter_accel_y_a_num
, filter_accel_y_b_num
);
697 filter ( accel_z
, x_accel_z
, y_accel_z
, a_accel_z
, b_accel_z
, filter_accel_z_a_num
, filter_accel_z_b_num
);
699 if ( sample_count
> 1 ) { // if the second telegram is received, process the data
700 send_double_can ( AR_CAN_ID_ROLL_FILTERED
, roll_compensated
); // send the CAN message containing filtered roll angular velocity
701 send_double_can ( AR_CAN_ID_PITCH_FILTERED
, pitch_compensated
); // send the CAN message containing filtered pitch angular velocity
702 send_double_can ( AR_CAN_ID_YAW_FILTERED
, yaw_compensated
); // send the CAN message containing filtered yaw angular velocity
703 send_double_can ( AR_CAN_ID_ROLL
, ( ( (double) buffer_imu
[0] ) * -ANGULAR_CONV_64
) ); // send the CAN message containing roll angular velocity
704 send_double_can ( AR_CAN_ID_PITCH
, ( ( (double) buffer_imu
[1] ) * -ANGULAR_CONV_64
) ); // send the CAN message containing pitch angular velocity
705 send_double_can ( AR_CAN_ID_YAW
, ( ( (double) buffer_imu
[2] ) * ANGULAR_CONV_64
) ); // send the CAN message containing yaw angular velocity
706 send_double_can ( AC_CAN_ID_X_FILTERED
, y_accel_x
[filter_accel_x_a_num
- 1] ); // send the CAN message containing filtered x-axis acceleration
707 send_double_can ( AC_CAN_ID_Y_FILTERED
, y_accel_y
[filter_accel_y_a_num
- 1] ); // send the CAN message containing filtered y-axis acceleration
708 send_double_can ( AC_CAN_ID_Z_FILTERED
, y_accel_z
[filter_accel_z_a_num
- 1] ); // send the CAN message containing filtered z-axis acceleration
709 send_double_can ( AC_CAN_ID_X
, accel_x
); // send the CAN message containing x-axis acceleration
710 send_double_can ( AC_CAN_ID_Y
, accel_y
); // send the CAN message containing y-axis acceleration
711 send_double_can ( AC_CAN_ID_Z
, accel_z
); // send the CAN message containing z-axis acceleration
713 /* MSH messages composition */
714 msh_read_x
= 0; // clear the MSH measure sum x
715 msh_read_y
= 0; // clear the MSH measure sum y
716 msh_read_z
= 0; // clear the MSH measure sum z
717 msh_meas_count_local
= msh_meas_count
; // store msh measure counter into a local copy
718 for ( c
= 0; c
< msh_meas_count_local
; c
++ ) {
719 msh_read_x
+= mg_meas_x
[c
];
720 msh_read_y
+= mg_meas_y
[c
]; // compute the sums
721 msh_read_z
+= mg_meas_z
[c
];
724 msh_meas_count
= 0; // reset the MSH measure counter
726 if ( msh_degauss_count
++ > 127 ) { // generate the degauss pulse for MSH every 4s
727 PAL_IOCLR
|= PAL_IOBIT
; // degauss pulse (+)
728 for ( count
= 0; count
< 60; count
++ ) temp
++; // delay between pulses
729 PAL_IOSET
|= PAL_IOBIT
; // degauss pulse (-)
730 msh_degauss_count
= 0; // reset degauss timer counter
733 msh_val
= ( ( double ) msh_read_x
) / ( ( double ) msh_meas_count_local
); // mean value computation x
734 msh_val
/= MSH_CONV
; // conversion to mgauss
735 msh_val
-= MSH_OFFSET
; // offset correction
736 msh_val
= -msh_val
; // reverse direction to correspond with the vehicle axis orientation
738 send_double_can ( MSH_ID_X
, msh_val
); // send the CAN message (y magnetic field intensity)
740 msh_val
= ( ( double ) msh_read_y
) / ( ( double ) msh_meas_count_local
); // mean value computation y
741 msh_val
/= MSH_CONV
; // conversion to mgauss
742 msh_val
-= MSH_OFFSET
; // offset correction
744 send_double_can ( MSH_ID_Y
, msh_val
); // send the CAN message (y magnetic field intensity)
746 msh_val
= ( ( double ) msh_read_z
) / ( ( double ) msh_meas_count_local
); // mean value computation z
747 msh_val
/= MSH_CONV
; // conversion to mgauss
748 msh_val
-= MSH_OFFSET
; // offset correction
750 send_double_can ( MSH_ID_Z
, msh_val
); // send the CAN message (z magnetic field intensity)
752 imu_timeout_count
= 0; // reset the IMU timeout counter
753 sample_count
= 0; // reset the sample counter
755 if ( imu_err_state
) { // if IMU was in error state
756 imu_msg_err
.data
[imu_msg_err
.dlc
++] = NO_ERR
; // fill in the no error code into the IMU error message structure
757 while ( can_tx_msg ( &imu_msg_err
) ); // send the error message
758 imu_msg_err
.dlc
= 0; // null the error message
759 LED_ERR_IOCLR
|= LED_ERR_IOBIT
; // switch the ERR LED off
760 imu_err_state
= 0; // turn off the GPS error flag
764 ( *step
) = 0; // repeat the cycle from the beginning
769 /*! GPS service routine
770 * Serves to receive and process the GPS datagrams.
771 * \param *step unsigned 8-bit int pointer referencing the message processing step.
773 void GPS_service ( uint8_t *step
) {
774 uint32_t gps_can_msg_id
[8] = {GPS_ID1
, GPS_ID2
, GPS_ID3
, GPS_ID4
, GPS_ID5
, GPS_ID6
, GPS_ID7
, GPS_ID8
}; // GPS can messages ID array
775 uint8_t i
; // cycle counter
776 static uint8_t check_gps
; // GPS datagram cross-parity computation variable
777 static uint8_t gps_data_count
; // GPS datagram received byte counter
778 static uint8_t dle_data_flag
= 0; // Flag variable, signalizing that bit stuffing occured
779 static uint8_t blinki
= 0; // counter variable driving the LED blinking
780 static uint8_t buffer_gps
[BUFF_GPS_LEN
]; // GPS receive buffer
782 can_msg_t gps_msg
= {.dlc
= 8}; // GPS CAN data packet
785 case 0: if ( read_UART_data ( UART1
) == DLE_BYTE
) ( *step
)++; // wait for the first telegram start character
788 case 1: if ( read_UART_data ( UART1
) == ID_POS
) { // check for the position telegram ID
789 check_gps
= ID_POS
; // cross parity computation (sum of all telegram characters should be 0)
790 ( *step
)++; // go to the next step
791 } else ( *step
) = 0; // if other then position telegram ID is detected, go to the beginning and wait for another telegram
795 case 2: if ( read_UART_data ( UART1
) == GPS_DATA_LENGTH
) { // check the data message length
796 check_gps
+= GPS_DATA_LENGTH
; // cross parity computation (sum of all telegram characters should be 0)
798 if ( blinki
++ < 1 ) LED_GPS_IOSET
|= LED_GPS_IOBIT
; // switch the GPS LED on for 1s
799 else LED_GPS_IOCLR
|= LED_GPS_IOBIT
; // switch the GPS LED off for 1s
800 if ( blinki
> 1 ) blinki
= 0; // after 2s, reset the LED blinking counter
802 gps_data_count
= 0; // reset the GPS Rx data counter
803 ( *step
)++; // go to the next step
804 } else ( *step
) = 0; // if wrong data length is detected, go to the beginning and wait for another telegram
808 case 3: buffer_gps
[gps_data_count
++] = read_UART_data ( UART1
); // store new GPS data into the GPS data buffer
810 if ( ( buffer_gps
[gps_data_count
- 1] == DLE_BYTE
) && !dle_data_flag
) { // get rid of the DLE byte stuffing
811 gps_data_count
--; // shift the data counter back - the stuffed character should be omitted
812 dle_data_flag
= 1; // set the DLE stuffing flag
813 } else if ( dle_data_flag
) dle_data_flag
= 0; // in the next step, clear the DLE stuffing flag
815 if ( !dle_data_flag
) check_gps
+= buffer_gps
[gps_data_count
- 1]; // cross parity computation (sum of all telegram characters should be 0)
817 if ( gps_data_count
== GPS_DATA_LENGTH
) ( *step
)++; // if the whole message has been read go to the next step
820 case 4: dle_data_flag
= read_UART_data ( UART1
); // read the last parity byte
821 check_gps
+= dle_data_flag
; // cross parity computation
822 if ( check_gps
) { // if the parity is wrong fill in the respective error code
823 gps_msg_err
.data
[gps_msg_err
.dlc
++] = PARITY_ERR
; // into the IMU error message structure
824 while ( can_tx_msg ( &gps_msg_err
) ); // send the error message
825 gps_msg_err
.dlc
= 0; // null the error message
828 ( *step
)++; // follow to the next step
831 case 5: if ( read_UART_data ( UART1
) != DLE_BYTE
) { // read the second DLE byte (DLE stuffing). In case it is not received,
832 gps_msg_err
.data
[gps_msg_err
.dlc
++] = FRAME_ERR
; // fill the respective error code into the IMU error message structure
833 while ( can_tx_msg ( &gps_msg_err
) ); // send the error message
834 gps_msg_err
.dlc
= 0; // null the error message
837 if ( dle_data_flag
!= DLE_BYTE
) ( *step
)++; else dle_data_flag
= 0; // follow to the next step, if DLE stuffing occured repeat the step 5 once more
840 case 6: if ( read_UART_data ( UART1
) != ETX_BYTE
) { // the ETX byte should follow...
841 gps_msg_err
.data
[gps_msg_err
.dlc
++] = FRAME_ERR_ETX
; // in case it does not, fill in the respective error code into the IMU error message structure
842 while ( can_tx_msg ( &gps_msg_err
) ); // send the error message
843 gps_msg_err
.dlc
= 0; // null the error message
846 ( *step
)++; // follow to the next step
849 /* compose and send the CAN messages containing the GPS data */
850 case 7: for ( i
= 0; i
< 8; i
++ ) {
851 memcpy ( gps_msg
.data
, &buffer_gps
[8 * i
], 8 ); // fill in the first data message
852 gps_msg
.id
= gps_can_msg_id
[i
]; // set the ID
853 while ( can_tx_msg ( &gps_msg
) ); // send the GPS data packet
856 gps_timeout_count
= 0; // reset the GPS timeout counter
857 gps_err_treshold
= GPS_ERROR_TRESHOLD_RUN
;
858 ( *step
) = 0; // repeat the cycle from the beginning
860 if ( gps_err_state
) { // if GPS was in error state
861 gps_msg_err
.data
[gps_msg_err
.dlc
++] = NO_ERR
; // fill in the no error code into the GPS error message structure
862 while ( can_tx_msg ( &gps_msg_err
) ); // send the error message
863 gps_msg_err
.dlc
= 0; // null the error message
864 LED_ERR_IOCLR
|= LED_ERR_IOBIT
; // switch the ERR LED off
865 gps_err_state
= 0; // turn off the GPS error flag
872 /*! Application entry point.
873 * This is where the application starts. This routine consists of
874 * initialization and an infinite cycle, where pending data are detected and
875 * respective service routines called to process them.
876 * \return Returns nothing - the program is an infinite cycle.
879 uint8_t step_imu
= 0; // actual step number in the IMU datagram processing
880 uint8_t step_gps
= 0; // actual step number in the GPS datagram processing
881 int count
, temp
= 0; // auxiliary variables for wait cycle
883 VPBDIV
= 1; // peripheral clock = CPU clock (10MHz)
885 MEMMAP
= MEMMAP_EXC_RAM
; // map exception handling to RAM
887 VICIntEnClr
= 0xFFFFFFFF; // init Vector Interrupt Controller
888 VICIntSelect
= 0x00000000;
890 PAL_PINSEL
&= PAL_PINSEL_VAL
;
891 PAL_IODIR
|= PAL_IOBIT
; // set the PAL pin as output and set PAL to 1 (inactive)
892 PAL_IOSET
|= PAL_IOBIT
;
894 LED_IMU_PINSEL
&= LED_IMU_PINSEL_VAL
;
895 LED_IMU_IODIR
|= LED_IMU_IOBIT
; // set the IMU LED pin as output and switch the IMU LED off
896 LED_IMU_IOCLR
|= LED_IMU_IOBIT
;
898 LED_GPS_PINSEL
&= LED_GPS_PINSEL_VAL
;
899 LED_GPS_IODIR
|= LED_GPS_IOBIT
; // set the GPS LED pin as output and switch the GPS LED off
900 LED_GPS_IOCLR
|= LED_GPS_IOBIT
;
902 LED_MSH_PINSEL
&= LED_MSH_PINSEL_VAL
;
903 LED_MSH_IODIR
|= LED_MSH_IOBIT
; // set the MSH LED pin as output and switch the MSH LED off
904 LED_MSH_IOCLR
|= LED_MSH_IOBIT
;
906 LED_ERR_PINSEL
&= LED_ERR_PINSEL_VAL
;
907 LED_ERR_IODIR
|= LED_ERR_IOBIT
; // set the ERR LED pin as output and switch the ERR LED on
908 LED_ERR_IOSET
|= LED_ERR_IOBIT
;
910 pwm_channel ( 2, 0 ); // select PWM channel to be used as clock source for Villard
911 pwm_init ( 1, 2000 ); // init PWM
912 pwm_set ( 2, 1000 ); // switch on Villard 5kHz
914 can_init ( CAN_BTR
, ISR_INT_VEC_CAN
, NULL
); // init CAN
915 watchdog_init ( WATCHDOG_INIT
); // watchdog initialization
917 for ( count
= 0; count
< 2500000; count
++ ) { // wait for Villard to charge
918 if ( can_msg_received
) can_rx ( ); // when CAN receives new data, call the service routine
919 if ( WDTV
< ( WATCHDOG_INIT
/ 2 ) ) watchdog_reset ( ); // watchdog reset
922 PAL_IOCLR
|= PAL_IOBIT
; // degauss pulse (+)
923 for ( count
= 0; count
< 100; count
++ ) temp
++; // delay between pulses
924 PAL_IOSET
|= PAL_IOBIT
; // degauss pulse (-)
926 LED_ERR_IOCLR
|= LED_ERR_IOBIT
; // switch the ERR LED off
928 adc_init ( 3 ); // init AD convertor (AD clock prescaller 3)
929 UART_init ( UART0
, BAUD_RATE0
, ISR_INT_VEC_U0
); // init UART0
930 UART_init ( UART1
, BAUD_RATE1
, ISR_INT_VEC_U1
); // init UART1
931 timer_init ( TIMER_PRESCALER
, TIMER_PERIOD
, ISR_INT_VEC_TIMER
); // init timer 0 - interrupt frequency 1Hz
933 /* main infinite cycle - look for new data at both UARTs and CAN */
935 if ( UART_new_data ( UART0
) ) IMU_service ( &step_imu
); // when UART0 receives new data, service the IMU
936 if ( UART_new_data ( UART1
) ) GPS_service ( &step_gps
); // when UART1 receives new data, service the GPS
937 if ( can_msg_received
) can_rx ( ); // when CAN receives new data, call the service routine