rename*d*_include_HEADERS typo again in lpcanvca
[LPC2xxx_and_RobotSpejbl.git] / app / rama_dam / rama_dam.c
blob01450b624bf015bb02f34a83380efdce3957291c
1 /********************************************************/
2 /* Data Acqusition software for the DAM module */
3 /* RAMA UAV control system */
4 /* */
5 /* ver. 5.3 release */
6 /* */
7 /* (c) 2006, 2007 Ondrej Spinka, DCE FEE CTU Prague */
8 /* */
9 /* no animals were harmed during development/testing */
10 /* of this software product, except the author himself */
11 /********************************************************/
13 #include <cpu_def.h>
14 #include <types.h>
15 #include <lpc21xx.h>
16 #include <string.h>
17 #include <periph/can.h>
18 #include <periph/uart_zen.h>
19 #include "pwm.h"
21 /*! @defgroup defines Constants Definitions
22 * @{
25 /*!\def TRUE
26 * Formal definition of logical "TRUE" value.
28 #define TRUE 1
30 /*!\def WATCHDOG_INIT
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
37 * @ingroup defines
38 * These constants serve to set the exception mapping either to FLASH (0x01) or RAM (0x02).
39 * @{
41 #define MEMMAP_EXC_FLASH 0x01
42 #define MEMMAP_EXC_RAM 0x02
43 /*! @} */
45 /*!\def STATUS_LED
46 * Defines that status LEDs exist on the target board.
48 #define STATUS_LED
50 /*! @defgroup led_defines Status LEDs Definitions
51 * @ingroup defines
52 * These constants define the IO ports and specific bits to manipulate respective status LEDs.
53 * @{
55 #ifdef STATUS_LED
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
85 #endif
86 /*! @} */
88 /*! @defgroup msh_degauss_defines Magnetic Sensor Hybrid Degauss Pin Definitions
89 * @ingroup defines
90 * These constants define the IO port and specific bit to drive the MSH degauss pin.
91 * @{
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
99 /*! @} */
101 /*! @defgroup error_tresholds Error Treshold Constants
102 * @ingroup defines
103 * These constants define the tresholds of number of errors to generate an CAN error message.
104 * @{
106 #define IMU_ERROR_TRESHOLD 1024
107 #define GPS_ERROR_TRESHOLD_RUN 2048
108 #define GPS_ERROR_TRESHOLD_INIT 30720
109 /*! @} */
111 /*! @defgroup error_codes Error Codes
112 * @ingroup defines
113 * Following constants define the error codes.
114 * @{
116 #define NO_ERR 0x00
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
122 /*! @} */
124 /*! @defgroup can_id CAN Message IDs
125 * @ingroup defines
126 * The constants below define respective IDs for the CAN messages.
127 * Standard 11-bit IDs are used.
128 * @{
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
175 /*! @} */
177 /*! @defgroup timer_settings Timer Settings
178 * @ingroup defines
179 * The constants below define the timer settings (timer frequency and interrupt number).
180 * @{
182 /* 512 Hz */
183 #define TIMER_PRESCALER 1
184 #define TIMER_PERIOD 19531
185 #define ISR_INT_VEC_TIMER 10
186 /*! @} */
188 /*! @defgroup can_settings CAN Settings
189 * @ingroup defines
190 * The constants below define the CAN settings (baud rate and interrupt number).
191 * @{
193 #define CAN_BTR 0x00250000
194 #define ISR_INT_VEC_CAN 11
195 /*! @} */
197 /*! @defgroup imu_constants IMU Communication Constants
198 * @ingroup defines
199 * The constants below define important IMU communication constants,
200 * such as message delimiter bytes and out-of-range bit mask.
201 * @{
203 #define IMU_MES_DELIMITER_1 0x78
204 #define IMU_MES_DELIMITER_2 0x87
205 #define IMU_RANGE_MASK 0x3F
206 /*! @} */
208 /*! @defgroup gps_constants GPS Communication Constants
209 * @ingroup defines
210 * The constants below define important GPS communication constants,
211 * such as message header and delimiter bytes and length.
212 * @{
214 #define DLE_BYTE 0x10
215 #define ETX_BYTE 0x03
216 #define ID_POS 0x33
217 #define GPS_DATA_LENGTH 0x40
218 /*! @} */
220 /*! @defgroup uart_settings UART Settings
221 * @ingroup defines
222 * The constants below define the UART settings, such as baud rates, interrupt numbers and buffer lengths.
223 * @{
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
235 /*! @} */
237 /*! @defgroup angular_rates_conversion Angular Rates Conversion Constant
238 * @ingroup defines
239 * @{
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
250 /*! @} */
252 /*! @defgroup accel_conversion Accelerations Conversion Constant
253 * @ingroup defines
254 * Accelerations conversion constants
255 * @{
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
262 /*! @} */
264 /*! @defgroup msh_conversion Magnetic Field Intensity Constants
265 * @ingroup defines
266 * @{
268 /*!\def MSH_CONV
269 * AD value-to-mgauss conversion constant
271 #define MSH_CONV 0.91
273 /*!\def MSH_OFFSET
274 * offset constant
276 #define MSH_OFFSET 430
278 /*!\def BUFF_MSH_LEN
279 * Data buffer length
281 #define BUFF_MSH_LEN 32
282 /*! @} */
284 /*! @defgroup filter_settings Filter Settings
285 * @ingroup defines
286 * The constants below define the polynomial filter coefficients for the roll, pitch and yaw angular rate filters.
287 * @{
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
313 /*! @} */
314 /*! @} */
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
392 WDFEED = 0xAA;
393 WDFEED = 0x55; // feed sequence
396 /*! Watchdog reset function.
397 * Takes no arguments.
399 inline void watchdog_reset ( void ) {
400 WDFEED = 0xAA;
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 ) {
415 uint8_t i;
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
452 ADCR &= 0xFFFFFF00;
453 ADCR |= channel; // initialize AD channel sample
454 ADCR |= 0x01000000;
455 while ( ! ( ( read = ADDR ) & 0x80000000 ) ); // wait for sample acquisition
456 read &= 0x0000FFC0;
457 read >>= 6; // read and preprocess sample
459 return read;
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
478 imu_err_state = 1;
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
488 gps_err_state = 1;
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;
531 uint8_t *coef_num;
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
546 break;
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
550 break;
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
554 break;
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
602 switch ( *step ) {
603 case 0: if ( read_UART_data ( UART0 ) == IMU_MES_DELIMITER_1 ) ( *step )++; // wait for the first telegram start character
604 break;
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
613 break;
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
632 ( *step )++;
633 break;
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
638 ( *step )++;
639 break;
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
646 break;
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
765 break;
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
784 switch ( *step ) {
785 case 0: if ( read_UART_data ( UART1 ) == DLE_BYTE ) ( *step )++; // wait for the first telegram start character
786 break;
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
793 break;
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
806 break;
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
818 break;
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
829 break;
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
838 break;
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
847 break;
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
868 break;
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.
878 int main ( void ) {
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 */
934 while ( TRUE ) {
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