1 /********************************************************/
2 /* Data Acqusition software for the DAM module */
3 /* RAMA UAV control system */
7 /* (c) 2006-2009 Ondrej Spinka, DCE FEE CTU Prague */
9 /* no animals were harmed during development/testing */
10 /* of this software product, except the author himself */
11 /********************************************************/
18 #include <periph/can.h>
19 #include <periph/uart_zen.h>
22 /*! @defgroup defines Constants Definitions
26 /*! @defgroup VERSION Program Version
28 * These constants define the program version.
31 #define MAIN_VERSION 5
35 /*! @defgroup CLK Clock settings
37 * These constants define the crystal frequency, core clock and peripheral clock.
40 #define OSC_FREQ 10000000
46 * Formal definition of logical "TRUE" value.
50 /*!\def SAMPLING_FREQ_PRESCALER
51 * Sampling frequency prescaler - 64Hz / ( SAMPLING_FREQ_PRESCALER + 1 ), that means that 0 - 64Hz, 1 - 32Hz etc.
54 #define SAMPLING_FREQ_PRESCALER 0
57 * Watchdog counter initialization/reset value.
59 /* 0x0003D090 corresponds to 100ms reset timeout */
60 #define WATCHDOG_INIT 0x0003D090
62 /*! @defgroup led_defines Status LEDs Definitions
64 * These constants define the IO ports and specific bits to manipulate respective status LEDs.
67 #define LED_IMU_PINSEL PINSEL2
68 #define LED_IMU_PINSEL_VAL 0xFFFFFFF3
69 #define LED_IMU_IODIR IODIR1
70 #define LED_IMU_IOSET IOSET1
71 #define LED_IMU_IOCLR IOCLR1
72 #define LED_IMU_IOBIT 0x00080000
74 #define LED_GPS_PINSEL PINSEL1
75 #define LED_GPS_PINSEL_VAL 0xFFFFCFFF
76 #define LED_GPS_IODIR IODIR0
77 #define LED_GPS_IOSET IOSET0
78 #define LED_GPS_IOCLR IOCLR0
79 #define LED_GPS_IOBIT 0x00400000
81 #define LED_MSH_PINSEL PINSEL1
82 #define LED_MSH_PINSEL_VAL 0xFFF3FFFF;
83 #define LED_MSH_IODIR IODIR0
84 #define LED_MSH_IOSET IOSET0
85 #define LED_MSH_IOCLR IOCLR0
86 #define LED_MSH_IOBIT 0x00800000
88 #define LED_ERR_PINSEL PINSEL1
89 #define LED_ERR_PINSEL_VAL 0xFFFCFFFF;
90 #define LED_ERR_IODIR IODIR0
91 #define LED_ERR_IOSET IOSET0
92 #define LED_ERR_IOCLR IOCLR0
93 #define LED_ERR_IOBIT 0x01000000
96 /*! @defgroup msh_degauss_defines Magnetic Sensor Hybrid Degauss Pin Definitions
98 * These constants define the IO port and specific bit to drive the MSH degauss pin.
101 #define PAL_PINSEL PINSEL1
102 #define PAL_PINSEL_VAL 0xFFFCFFFF
103 #define PAL_IODIR IODIR0
104 #define PAL_IOSET IOSET0
105 #define PAL_IOCLR IOCLR0
106 #define PAL_IOBIT 0x00200000
109 /*! @defgroup error_tresholds Error Treshold Constants
111 * These constants define the tresholds of number of errors to generate an CAN error message.
114 #define IMU_ERROR_TRESHOLD 3072
115 #define GPS_ERROR_TRESHOLD_RUN 6144
116 #define GPS_ERROR_TRESHOLD_INIT 65534
119 /*! @defgroup error_codes Error Codes
121 * Following constants define the error codes.
125 #define GENERAL_ERR 0x01
126 #define PARITY_ERR 0x02
127 #define RANGE_ERR 0x03
128 #define FRAME_ERR 0x04
129 #define FRAME_ETX_ERR 0x05
130 #define UART_ROUND_BUFFER_OVERRUN_ERR 0x06
131 #define UART_RX_BUFFER_OVERRUN_ERR 0x07
132 #define UART_PARITY_ERR 0x08
133 #define UART_FRAME_ERR 0x09
134 #define UART_BREAK_IRQ_ERR 0x0A
137 /*! @defgroup can_id CAN Message IDs
139 * The constants below define respective IDs for the CAN messages.
140 * Standard 11-bit IDs are used.
143 #define RQ_CAN_ID 0x0014
145 #define DAM_RESET_ID 0x0064
146 #define RESET_REQUEST_ID 0x006E
147 #define RUN_REQUEST_ID 0x006F
149 #define FILTER_ROLL_A_ID 0x0070
150 #define FILTER_ROLL_B_ID 0x0071
151 #define FILTER_PITCH_A_ID 0x0072
152 #define FILTER_PITCH_B_ID 0x0073
153 #define FILTER_YAW_A_ID 0x0074
154 #define FILTER_YAW_B_ID 0x0075
155 #define FILTER_ACCEL_X_A_ID 0x0076
156 #define FILTER_ACCEL_X_B_ID 0x0077
157 #define FILTER_ACCEL_Y_A_ID 0x0078
158 #define FILTER_ACCEL_Y_B_ID 0x0079
159 #define FILTER_ACCEL_Z_A_ID 0x007A
160 #define FILTER_ACCEL_Z_B_ID 0x007B
161 #define FILTER_MSH_X_A_ID 0x007C
162 #define FILTER_MSH_X_B_ID 0x007D
163 #define FILTER_MSH_Y_A_ID 0x007E
164 #define FILTER_MSH_Y_B_ID 0x007F
165 #define FILTER_MSH_Z_A_ID 0x0080
166 #define FILTER_MSH_Z_B_ID 0x0081
167 #define MSH_OFFSET_X_ID 0x0082
168 #define MSH_OFFSET_Y_ID 0x0083
169 #define MSH_OFFSET_Z_ID 0x0084
170 #define CAL_SAMPLE_NUM_ID 0x0059
172 #define IMU_ERR_CAN_ID 0x0002
173 #define AR_CAN_ID_ROLL 0x00C4
174 #define AR_CAN_ID_PITCH 0x01C4
175 #define AR_CAN_ID_YAW 0x03C4
176 #define AC_CAN_ID_X 0x0056
177 #define AC_CAN_ID_Y 0x0057
178 #define AC_CAN_ID_Z 0x0058
180 #define GPS_ERR_CAN_ID 0x0004
181 #define GPS_ID1 0x0400
182 #define GPS_ID2 0x0200
183 #define GPS_ID3 0x0180
184 #define GPS_ID4 0x0100
185 #define GPS_ID5 0x0300
186 #define GPS_ID6 0x0500
187 #define GPS_ID7 0x0700
188 #define GPS_ID8 0x0090
190 #define MSH_ID_X 0x0020
191 #define MSH_ID_Y 0x0040
192 #define MSH_ID_Z 0x0060
195 /*! @defgroup timer_settings Timer Settings
197 * The constants below define the timer settings (timer frequency and interrupt number).
201 #define TIMER_PRESCALER 1
202 #define TIMER_PERIOD ( PCLK / 1536 )
203 #define ISR_INT_VEC_TIMER 10
206 /*!\def ADC_PRESCALER
207 * The constant below defines the AD converter clock prescaler.
209 #define ADC_PRESCALER 14
211 /*! @defgroup can_settings CAN Settings
213 * The constants below define the CAN settings (baud rate and interrupt number).
216 #define CAN_BTR ( 0x00250000 + ( PCLK / 10000000 ) - 1 )
217 #define ISR_INT_VEC_CAN 11
220 /*! @defgroup imu_constants IMU Communication Constants
222 * The constants below define important IMU communication constants,
223 * such as message delimiter bytes and out-of-range bit mask.
226 #define IMU_MES_DELIMITER_1 0x78
227 #define IMU_MES_DELIMITER_2 0x87
228 #define IMU_RANGE_MASK 0x3F
231 /*! @defgroup gps_constants GPS Communication Constants
233 * The constants below define important GPS communication constants,
234 * such as message header and delimiter bytes and length.
237 #define DLE_BYTE 0x10
238 #define ETX_BYTE 0x03
240 #define GPS_DATA_LENGTH 0x40
243 /*! @defgroup uart_settings UART Settings
245 * The constants below define the UART settings, such as baud rates, interrupt numbers and buffer lengths.
248 #define BAUD_RATE0 38400
249 #define BAUD_RATE1 9600
251 #define ISR_INT_VEC_U0 12
252 #define ISR_INT_VEC_U1 13
254 #define BUFF_IMU_LEN 6
255 #define BUFF_GPS_LEN 64
258 /*! @defgroup angular_rates_conversion Angular Rates Conversion Constant
263 * The constant below defines the angular rates conversion constant for 64Hz sampling rate.
265 #define ANGULAR_CONV 0.000976563
267 /*!\def GYRO_OFFSET_FILTERING_TRESHOLD
268 * This constant defines the filter initialization treshold.
270 #define GYRO_OFFSET_FILTERING_TRESHOLD 10
273 /*! @defgroup accel_conversion Accelerations Conversion Constant
275 * Accelerations conversion constants
279 * This constant is used to convert accelerations suppoted by the IMU from m/s2 into miligs for 64Hz sampling rate.
281 /* ( 1/9.80665 ) * 64 */
282 #define ACCEL_CONV 6.5261838
285 /*! @defgroup msh_conversion Magnetic Field Intensity Constants
289 /*! @defgroup MSH_CONV AD value-to-mgauss conversion constants
290 * @ingroup msh_conversion
293 #define MSH_X_CONV 1.14
294 #define MSH_Y_CONV 1.05
295 #define MSH_Z_CONV 1.05
298 /*! @defgroup PWM_PARAMS PWM parameters (PWM is used for Villard charging)
299 * @ingroup msh_conversion
302 /* 1KHz, 1/2 pulse ratio */
303 #define PWM_PERIOD 60000
304 #define PWM_PULSE_LENGTH 30000
307 /*!\def VILLARD_CHARGE_WAIT
308 * Wait constant for initial Villard charge, used for magnetometer degaussing
310 #define VILLARD_CHARGE_WAIT 6000000
313 /*! @defgroup filter_settings Filter Settings
315 * The constants below define the polynomial filter coefficients for the roll, pitch and yaw angular rate filters.
318 #define MAX_FILTER_LEN 6
320 #define FILTER_ROLL_A_NUM_FLAG 0x00000001
321 #define FILTER_ROLL_B_NUM_FLAG 0x00000002
322 #define FILTER_PITCH_A_NUM_FLAG 0x00000004
323 #define FILTER_PITCH_B_NUM_FLAG 0x00000008
324 #define FILTER_YAW_A_NUM_FLAG 0x00000010
325 #define FILTER_YAW_B_NUM_FLAG 0x00000020
326 #define FILTER_ACCEL_X_A_NUM_FLAG 0x00000040
327 #define FILTER_ACCEL_X_B_NUM_FLAG 0x00000080
328 #define FILTER_ACCEL_Y_A_NUM_FLAG 0x00000100
329 #define FILTER_ACCEL_Y_B_NUM_FLAG 0x00000200
330 #define FILTER_ACCEL_Z_A_NUM_FLAG 0x00000400
331 #define FILTER_ACCEL_Z_B_NUM_FLAG 0x00000800
332 #define FILTER_MSH_X_A_NUM_FLAG 0x00001000
333 #define FILTER_MSH_X_B_NUM_FLAG 0x00002000
334 #define FILTER_MSH_Y_A_NUM_FLAG 0x00004000
335 #define FILTER_MSH_Y_B_NUM_FLAG 0x00008000
336 #define FILTER_MSH_Z_A_NUM_FLAG 0x00010000
337 #define FILTER_MSH_Z_B_NUM_FLAG 0x00020000
340 /*! @defgroup run_time_flags Run-Time Flags
342 * The constants below define the run-time flags (used to skip the calibration sequence, initial degaussing and filter coeffitients reception or to signal reset request).
345 #define COEF_RECEPTION_FINISH_FLAG 0x01
346 #define RUN_TIME_FLAG 0x02
347 #define RESET_REQUEST_FLAG 0x04
351 volatile uint8_t run
= 0x00; //!< run-time flag variable (used to skip the calibration sequence, initial degaussing and filter coeffitients reception or to signal reset request)
353 uint16_t gps_err_treshold
= GPS_ERROR_TRESHOLD_INIT
; //!< GPS error treshold value (when surpassed, error message is generated)
354 volatile uint16_t imu_timeout_count
= 0; //!< IMU timeout counter
355 volatile uint16_t gps_timeout_count
= 0; //!< GPS timeout counter
356 volatile uint8_t imu_err_state
= 0; //!< IMU error status flag
357 volatile uint8_t gps_err_state
= 0; //!< GPS error status flag
359 uint8_t filter_roll_a_num
= 0; //!< roll filter number of a coefficients
360 uint8_t filter_roll_b_num
= 0; //!< roll filter number of b coefficients
361 uint8_t filter_pitch_a_num
= 0; //!< pitch filter number of a coefficients
362 uint8_t filter_pitch_b_num
= 0; //!< pitch filter number of b coefficients
363 uint8_t filter_yaw_a_num
= 0; //!< yaw filter number of a coefficients
364 uint8_t filter_yaw_b_num
= 0; //!< yaw filter number of b coefficients
365 uint8_t filter_accel_x_a_num
= 0; //!< x-axis acceleration filter number of a coefficients
366 uint8_t filter_accel_x_b_num
= 0; //!< x-axis acceleration filter number of b coefficients
367 uint8_t filter_accel_y_a_num
= 0; //!< y-axis acceleration filter number of a coefficients
368 uint8_t filter_accel_y_b_num
= 0; //!< y-axis acceleration filter number of b coefficients
369 uint8_t filter_accel_z_a_num
= 0; //!< z-axis acceleration filter number of a coefficients
370 uint8_t filter_accel_z_b_num
= 0; //!< z-axis acceleration filter number of b coefficients
371 uint8_t filter_msh_x_a_num
= 0; //!< x-axis magnetometer filter number of a coefficients
372 uint8_t filter_msh_x_b_num
= 0; //!< x-axis magnetometer filter number of b coefficients
373 uint8_t filter_msh_y_a_num
= 0; //!< y-axis magnetometer filter number of a coefficients
374 uint8_t filter_msh_y_b_num
= 0; //!< y-axis magnetometer filter number of b coefficients
375 uint8_t filter_msh_z_a_num
= 0; //!< z-axis magnetometer filter number of a coefficients
376 uint8_t filter_msh_z_b_num
= 0; //!< z-axis magnetometer filter number of b coefficients
378 float msh_val
[3]; //!< computed magnetic field intensities in x, y and z axes
379 volatile uint8_t msh_sent_flag
= 0;
381 uint16_t cal_sample_num
= 0; //!< number of IMU calibration samples
383 float msh_offset
[3] = {0.0, 0.0, 0.0}; // MSH offsets
385 float a_roll
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, b_roll
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; //!< roll filter coeffitients
386 float a_pitch
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, b_pitch
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; //!< pitch filter coeffitients
387 float a_yaw
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, b_yaw
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; //!< yaw filter coeffitients
388 float a_accel_x
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, b_accel_x
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; //!< x-axis acceleration filter coeffitients
389 float a_accel_y
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, b_accel_y
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; //!< y-axis acceleration filter coeffitients
390 float a_accel_z
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, b_accel_z
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; //!< z-axis acceleration filter coeffitients
391 float a_msh_x
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, b_msh_x
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; //!< x-axis magnetometer filter coeffitients
392 float a_msh_y
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, b_msh_y
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; //!< y-axis magnetometer filter coeffitients
393 float a_msh_z
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, b_msh_z
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; //!< z-axis magnetometer filter coeffitients
395 can_msg_t imu_msg_err
= {.id
= IMU_ERR_CAN_ID
, .dlc
= 1}; //!< IMU CAN error message
396 can_msg_t gps_msg_err
= {.id
= GPS_ERR_CAN_ID
, .dlc
= 1}; //!< GPS CAN error message
398 /*! Timer 0 interrupt handler prototype. */
399 void timer_irq_handler ( void ) __attribute__ ( ( interrupt
) );
401 /*! Timer 0 initialization routine.
402 * Takes three arguments:
403 * \param prescale unsigned 32-bit int timer prescaler value
404 * \param period unsigned 32-bit int timer period value (counter reset occurs on match)
405 * \param irq_vect unsigned int timer interrupt number
407 inline void timer_init ( uint32_t prescale
, uint32_t period
, unsigned irq_vect
) {
408 T0PR
= prescale
- 1; // set prescaler
409 T0MR1
= period
- 1; // set period
410 T0MCR
= 0x0003 << 0x0003; // interrupt and counter reset on match1
411 T0EMR
= 0x0001 << 0x0006 | 0x0002; // set MAT0.1 low on match and high now
412 T0CCR
= 0x0000; // no capture
413 T0TCR
|= 0x0001; // go!
415 ( (uint32_t*) &VICVectAddr0
)[irq_vect
] = (uint32_t) timer_irq_handler
; // set the interrupt vector
416 ( (uint32_t*) &VICVectCntl0
)[irq_vect
] = 0x20 | 0x04;
417 VICIntEnable
= 0x00000010; // enable the timer 0 interrupt
420 /*! AD converter initialization function.
421 * Takes one argument:
422 * \param clk_div unsigned 32-bit int timer prescaler value. Resulting clock speed should be less then or equal to 4.5MHz
424 inline void adc_init ( uint32_t clk_div
) {
425 ADCR
= 0x00000004 | ( ( ( clk_div
- 1 ) & 0x000000FF ) << 8 ) | 0x00200000; // set the clock prescaler and switch the AD converter on
426 ADCR
|= 0x04000000; // conversion started on falling edge of MAT0.1
429 /*! Watchdog initialization function.
430 * Takes one argument:
431 * \param init_val unsigned 32-bit int timer initial value.
433 inline void watchdog_init ( uint32_t init_val
) {
434 WDTC
= init_val
; // timer counter start value
435 WDMOD
|= 0x03; // enable watchdog and reset capability
437 WDFEED
= 0x55; // feed sequence
440 /*! Watchdog reset function.
441 * Takes no arguments.
443 inline void watchdog_reset ( void ) {
445 WDFEED
= 0x55; // feed sequence
448 /*! Buttleworth filter algorithm.
449 * Takes seven arguments:
450 * \param sample float new sample
451 * \param x_array float pointer to the filter denominator array
452 * \param y_array float pointer to the filter nominator array
453 * \param a_coef float pointer to the filter denominator coefficients array
454 * \param b_coef float pointer to the filter nominator coefficients array
455 * \param a_num unsigned 8-bit integer number of a coefficients
456 * \param b_num unsigned 8-bit integer number of b coefficients
458 void filter ( float sample
, float *x_array
, float *y_array
, float *a_coef
, float *b_coef
, uint8_t a_num
, uint8_t b_num
) {
461 for ( i
= 0; i
< ( b_num
- 1 ); i
++ ) x_array
[i
] = x_array
[i
+ 1]; // input data buffer shifting
462 x_array
[b_num
- 1] = sample
; // store new samle into the buffer
464 for ( i
= 0; i
< ( a_num
- 1 ); i
++ ) y_array
[i
] = y_array
[i
+ 1]; // output data buffer shifting
465 y_array
[a_num
- 1] = 0.0; // store 0 at the end
467 for ( i
= 0; i
< b_num
; i
++ ) y_array
[a_num
- 1] += b_coef
[i
] * x_array
[b_num
- i
- 1]; // input polynom computation
469 for ( i
= 1; i
< a_num
; i
++ ) y_array
[a_num
- 1] -= a_coef
[i
] * y_array
[a_num
- i
- 1]; // input polynom computation
472 /*! Function sending a float number via CAN.
473 * Takes two arguments:
474 * \param id unsigned 32-bit integer message ID
475 * \param num1 float pointer to number 1 to be sent (must not be NULL - no error checking for simplicity)
476 * \param num2 float pointer to number 2 to be sent (may be NULL)
478 void send_float_can ( uint32_t id
, float *num1
, float *num2
) {
479 can_msg_t msg
= {.dlc
= 4}; // CAN message
481 /* decompose float into bytes */
482 memcpy ( msg
.data
, num1
, sizeof ( float ) );
484 if ( num2
!= NULL
) {
485 memcpy ( &msg
.data
[4], num2
, sizeof ( float ) );
486 msg
.dlc
+= sizeof ( float );
489 msg
.id
= id
; // set the message ID
490 while ( can_tx_msg ( &msg
) ); // send the CAN message
493 /*! Function initializing AD conversion and sampling the data.
494 * Takes one argument:
495 * \param channel AD channel to sample
496 * \return Returns sampled value.
498 int32_t read_AD ( int32_t channel
) {
499 int32_t read
= 0; // AD read value
501 while ( !( read
& 0x80000000 ) ) read
= ADDR
; // wait for sample acquisition
503 T0EMR
|= 0x00000002; // set MAT0.1 high again
504 read
= ( read
>> 6 ) & 0x000003FF; // read and preprocess sample
505 ADCR
= ( ADCR
& 0xFFFFFF00 ) | channel
; // select next AD channel to sample
510 /*! Timer 0 interrupt handler.
511 * Serves to handle response timeouts of IMU and GPS.
513 void timer_irq_handler ( void ) {
514 uint32_t count
; // cycle index
515 static uint16_t blinki
= 0; // counter for LED blinking
516 static uint8_t msh_channel_count
= 0; // msh channel counter (selecting AD channels for x, y and z magnetometers)
517 static uint8_t msh_meas_count
= 0; // MSH sample counter
518 static int32_t msh_meas
[3]; // x, y and z axes magnetic field intensity sample sum buffer
519 static uint16_t msh_degauss_count
= 0; // MSH degauss (timer) counter
520 const float msh_conv
[3] = {MSH_Y_CONV
, MSH_Z_CONV
, MSH_X_CONV
}; // MSH conversion constants
522 if ( !( run
& RESET_REQUEST_FLAG
) ) watchdog_reset ( ); // watchdog reset
524 if ( msh_degauss_count
++ > 12288 ) { // if the MSH sensor was not degaussed for approx. 8s
525 PAL_IOSET
|= PAL_IOBIT
; // degauss pulse (-)
526 msh_degauss_count
= 0; // reset MSH degauss counter
529 if ( msh_degauss_count
== 7 ) PAL_IOCLR
|= PAL_IOBIT
; // degauss pulse (+) (approx. 4.5ms after the (-) pulse)
531 if ( msh_degauss_count
> 8 ) { // do not measure while degaussing
532 msh_meas
[msh_channel_count
] += read_AD ( 0x00000001 << msh_channel_count
); // store the result into respective buffer
534 if ( ++msh_channel_count
> 2 ) { // if msh channel counter exceeds the number of channels (starting from 0)
535 msh_channel_count
= 0; // reset the msh channel counter
536 msh_meas_count
++; // increment the MSH sample counter
538 for ( count
= 0; count
< 3; count
++ ) { // compute magnetic field intensities using sampled MSH values
539 msh_val
[count
] = ( ( ( float ) msh_meas
[count
] ) / ( ( float ) msh_meas_count
) ); // mean value computation
540 msh_val
[count
] -= msh_offset
[count
]; // offset correction
541 msh_val
[count
] *= msh_conv
[count
]; // conversion to mgauss
544 if ( msh_sent_flag
) { // if the MSH values had been sent
545 memset ( msh_meas
, 0, 12 ); // reset MSH buffers
546 msh_meas_count
= 0; // reset MSH sample counter
547 msh_sent_flag
= 0; // resent MSH values sent flag
552 if ( imu_timeout_count
++ > IMU_ERROR_TRESHOLD
) { // if IMU is not responding for the preset time
554 LED_IMU_IOCLR
|= LED_IMU_IOBIT
; // switch the IMU LED off
555 LED_ERR_IOSET
|= LED_ERR_IOBIT
; // switch the ERR LED on
556 imu_timeout_count
= 0; // reset the IMU time counter
557 imu_msg_err
.data
[0] = GENERAL_ERR
; // fill in the error code into the IMU error message structure
558 while ( can_tx_msg ( &imu_msg_err
) ); // send the error message
561 if ( gps_timeout_count
++ > gps_err_treshold
) { // if GPS is not responding for the preset time
563 LED_GPS_IOCLR
|= LED_GPS_IOBIT
; // switch the GPS LED off
564 LED_ERR_IOSET
|= LED_ERR_IOBIT
; // switch the ERR LED on
565 gps_timeout_count
= 0; // reset the GPS time counter
566 gps_msg_err
.data
[0] = GENERAL_ERR
; // fill in the error code into the IMU error message structure
567 while ( can_tx_msg ( &gps_msg_err
) ); // send the error message
570 if ( blinki
++ < 384 ) LED_MSH_IOSET
|= LED_MSH_IOBIT
; // switch the MSH LED on for 0.25s
571 else LED_MSH_IOCLR
|= LED_MSH_IOBIT
; // switch the MSH LED off for 0.25s
572 if ( blinki
> 768 ) blinki
= 0; // after 0.5s, reset the LED blinking counter
574 T0IR
= 0xFFFFFFFF; // clear the interrupt flag
575 VICVectAddr
= 0; // int acknowledge
578 /*! Function adding coeffitients into the filter coeffitients array.
579 * Takes five arguments:
580 * \param filter_coef_flag unsigned 32-bit integer pointer filter coeffitient flag
581 * \param current_coef_flag unsigned 32-bit integer flag of the filter coeffitient currently being processed
582 * \param coef_num unsigned 8-bit integer pointer number of current coeffitient
583 * \param filter_array float pointer filter coeffitient array to which the coeffitient will be added
584 * \param rx_msg can_msg_t CAN message structure containing the coeffitient
586 void filter_coef_add ( uint32_t *filter_coef_flag
, uint32_t current_coef_flag
, uint8_t *coef_num
, float *filter_array
, can_msg_t
*rx_msg
) {
587 if ( !( *filter_coef_flag
& current_coef_flag
) ) { // if first filter coeficient received
588 *filter_coef_flag
|= current_coef_flag
; // set the corresponding flag
589 *coef_num
= 0; // and null respective coeficient number
592 if ( *coef_num
< MAX_FILTER_LEN
) {
593 memcpy ( &filter_array
[( *coef_num
)++], rx_msg
->data
, sizeof ( float ) ); // compose float from 4 bytes, store new coeficient
597 /*! CAN Rx message process routine.
598 * Serves to handle an incoming CAN message.
600 void can_rx ( void ) {
601 typedef struct { // structure holding non-constant filter_coef_add function params
602 uint32_t current_coef_flag
;
605 } filter_param_struct
;
607 const filter_param_struct filter_param
[18] = { {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
}, {FILTER_MSH_X_A_NUM_FLAG
, &filter_msh_x_a_num
, a_msh_x
}, {FILTER_MSH_X_B_NUM_FLAG
, &filter_msh_x_b_num
, b_msh_x
}, {FILTER_MSH_Y_A_NUM_FLAG
, &filter_msh_y_a_num
, a_msh_y
}, {FILTER_MSH_Y_B_NUM_FLAG
, &filter_msh_y_b_num
, b_msh_y
}, {FILTER_MSH_Z_A_NUM_FLAG
, &filter_msh_z_a_num
, a_msh_z
}, {FILTER_MSH_Z_B_NUM_FLAG
, &filter_msh_z_b_num
, b_msh_z
} }; // array of structures holding filter_coef_add function params for various filters
609 static uint32_t filter_coef_flag
= 0; // filter coefitients reception flag
610 can_msg_t rx_msg
; // received message
612 memcpy ( &rx_msg
, ( void * ) &can_rx_msg
, sizeof ( can_msg_t
) ); // create a local copy of the received message
614 switch ( rx_msg
.id
) { // switch according CAN message ID
615 case RESET_REQUEST_ID
: // when reset request is received
616 run
|= RESET_REQUEST_FLAG
; // set the reset request flag
617 while ( TRUE
); // wait for watchdog reset
619 case MSH_OFFSET_X_ID
: // magnetometer x-axis offset
620 if ( !run
) memcpy ( &msh_offset
[2], rx_msg
.data
, sizeof ( float ) ); // compose float from 4 bytes, store x-axis offset
623 case MSH_OFFSET_Y_ID
: // magnetometer y-axis offset
624 if ( !run
) memcpy ( msh_offset
, rx_msg
.data
, sizeof ( float ) ); // compose float from 4 bytes, store y-axis offset
627 case MSH_OFFSET_Z_ID
: // magnetometer z-axis offset
628 if ( !run
) memcpy ( &msh_offset
[1], rx_msg
.data
, sizeof ( float ) ); // compose float from 4 bytes, store z-axis offset
631 case RUN_REQUEST_ID
: // request to skip calibration and initial degaussing and to prevent further filter coeffitients update
632 run
|= RUN_TIME_FLAG
; // set the run-time flag
635 case CAL_SAMPLE_NUM_ID
: // receive number of calibration samples
636 if ( !run
) { // if no run-time flag is set
637 memcpy ( &cal_sample_num
, rx_msg
.data
, sizeof ( uint16_t ) ); // compose uint16 from 2 bytes
638 run
|= COEF_RECEPTION_FINISH_FLAG
; // set the prevent further filter coeffitients reception flag
643 default: // receive filter coeficients
644 if ( !run
&& ( rx_msg
.id
>= FILTER_ROLL_A_ID
) && ( rx_msg
.id
<= FILTER_MSH_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 and no run-time flag is set, add it to the respective filter coeffitients array
647 can_msg_received
= 0; // reset the pending CAN message flag
650 /*! IMU service routine.
651 * Serves to receive and process the IMU datagrams.
652 * \param *step unsigned 8-bit int pointer referencing the message processing step.
654 void IMU_service ( uint8_t *step
) {
655 uint8_t uart_err
; // UART error code
657 static uint8_t check_imu
; // IMU datagram cross-parity computation variable
658 static uint8_t i
; // Auxiliary index variable
659 static uint8_t sample_count
= 0; // IMU sample counter
660 static uint8_t blinki
= 0; // counter variable driving the LED blinking
661 static uint8_t buffer_int16
[2]; // receive buffer for a 16-bit integer
663 static int16_t buffer_imu
[BUFF_IMU_LEN
] = {0, 0, 0, 0, 0, 0}; // IMU data buffers
665 static uint16_t cal_sample_count
= 0; // calibration sample counter
667 float roll
; // Computed roll rate [64 Hz]
668 float pitch
; // Computed pitch rate [64 Hz]
669 float yaw
; // Computed yaw rate [64 Hz]
671 float accel_x
; // Computed x-axis acceleration [64 Hz]
672 float accel_y
; // Computed y-axis acceleration [64 Hz]
673 float accel_z
; // Computed z-axis acceleration [64 Hz]
675 float roll_compensated
= 0.0; // Computed roll rate [64 Hz] with offset compensation
676 float pitch_compensated
= 0.0; // Computed pitch rate [64 Hz] with offset compensation
677 float yaw_compensated
= 0.0; // Computed yaw rate [64 Hz] with offset compensation
679 static float roll_offset
= 0.0; // roll gyro offset
680 static float pitch_offset
= 0.0; // pitch gyro offset
681 static float yaw_offset
= 0.0; // yaw gyro offset
683 static float x_roll
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, y_roll
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // roll rate filtering buffer
684 static float x_pitch
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, y_pitch
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // pitch rate filtering buffer
685 static float x_yaw
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, y_yaw
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // yaw rate filtering buffer
686 static float x_accel_x
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, y_accel_x
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // x-axis acceleration filtering buffer
687 static float x_accel_y
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, y_accel_y
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // y-axis acceleration filtering buffer
688 static float x_accel_z
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, y_accel_z
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // z-axis acceleration filtering buffer
689 static float x_msh_x
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, y_msh_x
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // x-axis magnetometer filtering buffer
690 static float x_msh_y
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, y_msh_y
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // y-axis magnetometer filtering buffer
691 static float x_msh_z
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, y_msh_z
[MAX_FILTER_LEN
] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // z-axis magnetometer filtering buffer
693 can_msg_t msg_rq
= {.dlc
= 0, .id
= RQ_CAN_ID
}; // time synchronization CAN message
695 /* check UART errors */
696 if ( ( uart_err
= UART_test_err ( UART0
) ) ) {
697 if ( uart_err
& ROUND_BUFFER_OVERRUN_ERR_MASK
) { // if round buffer overrun
698 imu_msg_err
.data
[0] = UART_ROUND_BUFFER_OVERRUN_ERR
; // fill error code into the IMU error message structure
699 while ( can_tx_msg ( &imu_msg_err
) ); // send the error message
702 if ( uart_err
& RX_BUFFER_OVERRUN_ERR_MASK
) { // if hardware Rx buffer overrun
703 imu_msg_err
.data
[0] = UART_RX_BUFFER_OVERRUN_ERR
; // fill error code into the IMU error message structure
704 while ( can_tx_msg ( &imu_msg_err
) ); // send the error message
707 if ( uart_err
& PARITY_ERR_MASK
) { // if parity error
708 imu_msg_err
.data
[0] = UART_PARITY_ERR
; // fill error code into the IMU error message structure
709 while ( can_tx_msg ( &imu_msg_err
) ); // send the error message
712 if ( uart_err
& FRAME_ERR_MASK
) { // if framing error
713 imu_msg_err
.data
[0] = UART_FRAME_ERR
; // fill error code into the IMU error message structure
714 while ( can_tx_msg ( &imu_msg_err
) ); // send the error message
717 if ( uart_err
& BREAK_IRQ_ERR_MASK
) { // if interrupt break
718 imu_msg_err
.data
[0] = UART_BREAK_IRQ_ERR
; // fill error code into the IMU error message structure
719 while ( can_tx_msg ( &imu_msg_err
) ); // send the error message
723 /* state automaton for IMU data reception and processing */
725 case 0: if ( read_UART_data ( UART0
) == IMU_MES_DELIMITER_1
) ( *step
)++; // wait for the first telegram start character
728 case 1: if ( read_UART_data ( UART0
) == IMU_MES_DELIMITER_2
) { // wait for the second telegram start character
729 ( *step
)++; // increment the IMU step counter
731 if ( ++sample_count
> SAMPLING_FREQ_PRESCALER
) while ( can_tx_msg ( &msg_rq
) ); // when the ( SAMPLING_FREQ_PRESCALER + 1 )-th teleram is being received, send the synchonisation message (IMU running at 64Hz, overall system sampling frequency is 64 / ( SAMPLING_FREQ_PRESCALER + 1 )Hz)
732 } else ( *step
) = 0; // should another character be received, return to the sequence beginning
736 case 2: i
= read_UART_data ( UART0
); // read the next telegram character
737 check_imu
= IMU_MES_DELIMITER_1
^ IMU_MES_DELIMITER_2
^ i
; // cross parity initialization
739 if ( i
& IMU_RANGE_MASK
) { // when IMU range error is detected, fill in respective error code
740 imu_msg_err
.data
[0] = RANGE_ERR
; // into the IMU error message structure
741 while ( can_tx_msg ( &imu_msg_err
) ); // send the error message
744 i
= 0; // reset i, as it will be used as a cycle counter in the next two steps
747 if ( blinki
++ < 32 ) LED_IMU_IOSET
|= LED_IMU_IOBIT
; // switch the IMU LED on for 0.5s
748 else LED_IMU_IOCLR
|= LED_IMU_IOBIT
; // switch the IMU LED off for 0.5s
749 if ( blinki
> 64 ) blinki
= 0; // after 1s, reset the LED blinking counter
753 /* read the accelerations and angular velocities */
754 case 3: buffer_int16
[0] = read_UART_data ( UART0
); // read the first part of a 16-bit integer
755 check_imu
^= buffer_int16
[0]; // cross parity computation
759 case 4: buffer_int16
[1] = read_UART_data ( UART0
); // read the second part of a 16-bit integer
760 check_imu
^= buffer_int16
[1]; // cross parity computation
761 memcpy ( &buffer_imu
[i
], buffer_int16
, sizeof ( int16_t ) ); // read the second part of a 16-bit integer
763 if ( ++i
< 6 ) ( *step
)--; else ( *step
)++; // when all 6 values are acquired go ahead, or return to the previous step
766 case 5: check_imu
^= read_UART_data ( UART0
); // read the cross parity - this final XOR should give a zero if the parity was right
768 if ( check_imu
) { // should the parity be wrong fill in the respective error code
769 imu_msg_err
.data
[0] = PARITY_ERR
; // into the IMU error message structure
770 while ( can_tx_msg ( &imu_msg_err
) ); // send the error message
773 /* angular rates computation */
774 roll
= ( (float) buffer_imu
[0] ) * -ANGULAR_CONV
; // convert yaw rate to rads/s (*(-1) due to the IMU orientation)
775 pitch
= ( (float) buffer_imu
[1] ) * ANGULAR_CONV
; // convert yaw rate to rads/s
776 yaw
= ( (float) buffer_imu
[2] ) * -ANGULAR_CONV
; // convert yaw rate to rads/s (*(-1) due to the IMU orientation)
778 /* x, y and z acceleration computation */
779 accel_x
= ( (float) buffer_imu
[4] ) * -ACCEL_CONV
; // convert x-axis acceleration into miligs (*(-1) due to the IMU orientation)
780 accel_y
= ( (float) buffer_imu
[3] ) * ACCEL_CONV
; // convert y-axis acceleration into miligs
781 accel_z
= ( (float) buffer_imu
[5] ) * ACCEL_CONV
; // convert z-axis acceleration into miligs
783 /* data filtering - roll, pitch and yaw angular rates, x, y and z accelerations and magnetic intensities */
784 filter ( roll
, x_roll
, y_roll
, a_roll
, b_roll
, filter_roll_a_num
, filter_roll_b_num
);
785 filter ( pitch
, x_pitch
, y_pitch
, a_pitch
, b_pitch
, filter_pitch_a_num
, filter_pitch_b_num
);
786 filter ( yaw
, x_yaw
, y_yaw
, a_yaw
, b_yaw
, filter_yaw_a_num
, filter_yaw_b_num
);
787 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
);
788 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
);
789 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
);
790 filter ( msh_val
[2], x_msh_x
, y_msh_x
, a_msh_x
, b_msh_x
, filter_msh_x_a_num
, filter_msh_x_b_num
);
791 filter ( msh_val
[0], x_msh_y
, y_msh_y
, a_msh_y
, b_msh_y
, filter_msh_y_a_num
, filter_msh_y_b_num
);
792 filter ( msh_val
[1], x_msh_z
, y_msh_z
, a_msh_z
, b_msh_z
, filter_msh_z_a_num
, filter_msh_z_b_num
);
794 /* gyros offset computation (calibration) */
795 if ( !( run
& RUN_TIME_FLAG
) && ( cal_sample_count
>= GYRO_OFFSET_FILTERING_TRESHOLD
) && ( cal_sample_count
< cal_sample_num
) ) { // summarize (cal_sample_num - GYRO_OFFSET_FILTERING_TRESHOLD) samples
796 roll_offset
+= y_roll
[filter_roll_a_num
- 1];
797 pitch_offset
+= y_pitch
[filter_pitch_a_num
- 1];
798 yaw_offset
+= y_yaw
[filter_yaw_a_num
- 1];
800 /* ERR LED blinking */
801 if ( blinki
< 32 ) LED_ERR_IOSET
|= LED_ERR_IOBIT
; // switch the ERR LED on for 0.5s
802 else LED_ERR_IOCLR
|= LED_ERR_IOBIT
; // switch the ERR LED off for 0.5s
803 } else if ( !( run
& RUN_TIME_FLAG
) && ( cal_sample_count
== cal_sample_num
) ) { // compute offset mean values
804 roll_offset
/= ( (float) ( cal_sample_num
- GYRO_OFFSET_FILTERING_TRESHOLD
) );
805 pitch_offset
/= ( (float) ( cal_sample_num
- GYRO_OFFSET_FILTERING_TRESHOLD
) );
806 yaw_offset
/= ( (float) ( cal_sample_num
- GYRO_OFFSET_FILTERING_TRESHOLD
) );
808 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
809 else LED_ERR_IOSET
|= LED_ERR_IOBIT
; // else if IMU or GPS (or both) are in the error state switch the ERR LED on
811 run
|= RUN_TIME_FLAG
; // set the run-time flag to prevent calibration
814 /* filtered roll, pitch and yaw offset compensation */
815 if ( ( run
& RUN_TIME_FLAG
) ) {
816 roll_compensated
= y_roll
[filter_roll_a_num
- 1] - roll_offset
;
817 pitch_compensated
= y_pitch
[filter_pitch_a_num
- 1] - pitch_offset
;
818 yaw_compensated
= y_yaw
[filter_yaw_a_num
- 1] - yaw_offset
;
821 if ( cal_sample_count
< 0xFFFF ) cal_sample_count
++; // increment calibration sample counter
823 if ( sample_count
> SAMPLING_FREQ_PRESCALER
) { // if the ( SAMPLING_FREQ_PRESCALER + 1 )-th telegram is received, process the data
824 send_float_can ( AR_CAN_ID_ROLL
, &roll
, &roll_compensated
); // send the CAN message containing roll angular rate
825 send_float_can ( AR_CAN_ID_PITCH
, &pitch
, &pitch_compensated
); // send the CAN message containing pitch angular rate
826 send_float_can ( AR_CAN_ID_YAW
, &yaw
, &yaw_compensated
); // send the CAN message containing yaw angular rate
827 send_float_can ( AC_CAN_ID_X
, &accel_x
, &y_accel_x
[filter_accel_x_a_num
- 1] ); // send the CAN message containing x-axis acceleration
828 send_float_can ( AC_CAN_ID_Y
, &accel_y
, &y_accel_y
[filter_accel_y_a_num
- 1] ); // send the CAN message containing y-axis acceleration
829 send_float_can ( AC_CAN_ID_Z
, &accel_z
, &y_accel_z
[filter_accel_z_a_num
- 1] ); // send the CAN message containing z-axis acceleration
832 send_float_can ( MSH_ID_X
, &msh_val
[2], &y_msh_x
[filter_msh_x_a_num
- 1] ); // send the CAN message (x magnetic field intensity)
833 send_float_can ( MSH_ID_Y
, msh_val
, &y_msh_y
[filter_msh_y_a_num
- 1] ); // send the CAN message (y magnetic field intensity)
834 send_float_can ( MSH_ID_Z
, &msh_val
[1], &y_msh_z
[filter_msh_z_a_num
- 1] ); // send the CAN message (z magnetic field intensity)
837 imu_timeout_count
= 0; // reset the IMU timeout counter
838 sample_count
= 0; // reset the sample counter
840 if ( imu_err_state
) { // if IMU was in error state
841 imu_msg_err
.data
[0] = NO_ERR
; // fill in the no error code into the IMU error message structure
842 while ( can_tx_msg ( &imu_msg_err
) ); // send the error message
843 LED_ERR_IOCLR
|= LED_ERR_IOBIT
; // switch the ERR LED off
844 imu_err_state
= 0; // turn off the GPS error flag
848 ( *step
) = 0; // repeat the cycle from the beginning
852 /*! GPS service routine
853 * Serves to receive and process the GPS datagrams.
854 * \param *step unsigned 8-bit int pointer referencing the message processing step.
856 void GPS_service ( uint8_t *step
) {
857 const 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
859 uint8_t i
; // cycle counter
860 uint8_t uart_err
; // UART error code
862 static uint8_t check_gps
; // GPS datagram cross-parity computation variable
863 static uint8_t gps_data_count
; // GPS datagram received byte counter
864 static uint8_t dle_data_flag
= 0; // Flag variable, signalizing that bit stuffing occured
865 static uint8_t blinki
= 0; // counter variable driving the LED blinking
866 static uint8_t buffer_gps
[BUFF_GPS_LEN
]; // GPS receive buffer
868 can_msg_t gps_msg
= {.dlc
= 8}; // GPS CAN data packet
870 /* check UART errors */
871 if ( ( uart_err
= UART_test_err ( UART1
) ) ) {
872 if ( uart_err
& ROUND_BUFFER_OVERRUN_ERR_MASK
) { // if round buffer overrun
873 gps_msg_err
.data
[0] = UART_ROUND_BUFFER_OVERRUN_ERR
; // fill error code into the GPS error message structure
874 while ( can_tx_msg ( &gps_msg_err
) ); // send the error message
877 if ( uart_err
& RX_BUFFER_OVERRUN_ERR_MASK
) { // if hardware Rx buffer overrun
878 gps_msg_err
.data
[0] = UART_RX_BUFFER_OVERRUN_ERR
; // fill error code into the GPS error message structure
879 while ( can_tx_msg ( &gps_msg_err
) ); // send the error message
882 if ( uart_err
& PARITY_ERR_MASK
) { // if parity error
883 gps_msg_err
.data
[0] = UART_PARITY_ERR
; // fill error code into the GPS error message structure
884 while ( can_tx_msg ( &gps_msg_err
) ); // send the error message
887 if ( uart_err
& FRAME_ERR_MASK
) { // if framing error
888 gps_msg_err
.data
[0] = UART_FRAME_ERR
; // fill error code into the GPS error message structure
889 while ( can_tx_msg ( &gps_msg_err
) ); // send the error message
892 if ( uart_err
& BREAK_IRQ_ERR_MASK
) { // if interrupt break
893 gps_msg_err
.data
[0] = UART_BREAK_IRQ_ERR
; // fill error code into the GPS error message structure
894 while ( can_tx_msg ( &gps_msg_err
) ); // send the error message
898 /* state automaton for GPS data reception and processing */
900 case 0: if ( read_UART_data ( UART1
) == DLE_BYTE
) ( *step
)++; // wait for the first telegram start character
903 case 1: if ( read_UART_data ( UART1
) == ID_POS
) { // check for the position telegram ID
904 check_gps
= ID_POS
; // cross parity computation (sum of all telegram characters should be 0)
905 ( *step
)++; // go to the next step
906 } else ( *step
) = 0; // if other then position telegram ID is detected, go to the beginning and wait for another telegram
910 case 2: if ( read_UART_data ( UART1
) == GPS_DATA_LENGTH
) { // check the data message length
911 check_gps
+= GPS_DATA_LENGTH
; // cross parity computation (sum of all telegram characters should be 0)
912 gps_data_count
= 0; // reset the GPS Rx data counter
913 ( *step
)++; // go to the next step
914 } else ( *step
) = 0; // if wrong data length is detected, go to the beginning and wait for another telegram
918 case 3: buffer_gps
[gps_data_count
++] = read_UART_data ( UART1
); // store new GPS data into the GPS data buffer
920 if ( ( buffer_gps
[gps_data_count
- 1] == DLE_BYTE
) && !dle_data_flag
) { // get rid of the DLE byte stuffing
921 gps_data_count
--; // shift the data counter back - the stuffed character should be omitted
922 dle_data_flag
= 1; // set the DLE stuffing flag
923 } else if ( dle_data_flag
) dle_data_flag
= 0; // in the next step, clear the DLE stuffing flag
925 if ( !dle_data_flag
) check_gps
+= buffer_gps
[gps_data_count
- 1]; // cross parity computation (sum of all telegram characters should be 0)
927 if ( gps_data_count
== GPS_DATA_LENGTH
) ( *step
)++; // if the whole message has been read go to the next step
930 case 4: dle_data_flag
= read_UART_data ( UART1
); // read the last parity byte
931 check_gps
+= dle_data_flag
; // cross parity computation
932 if ( check_gps
) { // if the parity is wrong fill in the respective error code
933 gps_msg_err
.data
[0] = PARITY_ERR
; // into the IMU error message structure
934 while ( can_tx_msg ( &gps_msg_err
) ); // send the error message
937 ( *step
)++; // follow to the next step
940 case 5: if ( read_UART_data ( UART1
) != DLE_BYTE
) { // read the second DLE byte (DLE stuffing). In case it is not received,
941 gps_msg_err
.data
[0] = FRAME_ERR
; // fill the respective error code into the IMU error message structure
942 while ( can_tx_msg ( &gps_msg_err
) ); // send the error message
945 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
948 case 6: if ( read_UART_data ( UART1
) != ETX_BYTE
) { // the ETX byte should follow...
949 gps_msg_err
.data
[0] = FRAME_ETX_ERR
; // in case it does not, fill in the respective error code into the IMU error message structure
950 while ( can_tx_msg ( &gps_msg_err
) ); // send the error message
953 /* compose and send the CAN messages containing the GPS data */
954 for ( i
= 0; i
< 8; i
++ ) {
955 memcpy ( gps_msg
.data
, &buffer_gps
[8 * i
], 8 ); // fill in the first data message
956 gps_msg
.id
= gps_can_msg_id
[i
]; // set the ID
957 while ( can_tx_msg ( &gps_msg
) ); // send the GPS data packet
960 if ( blinki
++ < 1 ) LED_GPS_IOSET
|= LED_GPS_IOBIT
; // switch the GPS LED on for 1s
961 else LED_GPS_IOCLR
|= LED_GPS_IOBIT
; // switch the GPS LED off for 1s
962 if ( blinki
> 1 ) blinki
= 0; // after 2s, reset the LED blinking counter
964 gps_timeout_count
= 0; // reset the GPS timeout counter
965 gps_err_treshold
= GPS_ERROR_TRESHOLD_RUN
;
966 ( *step
) = 0; // repeat the cycle from the beginning
968 if ( gps_err_state
) { // if GPS was in error state
969 gps_msg_err
.data
[0] = NO_ERR
; // fill in the no error code into the GPS error message structure
970 while ( can_tx_msg ( &gps_msg_err
) ); // send the error message
971 LED_ERR_IOCLR
|= LED_ERR_IOBIT
; // switch the ERR LED off
972 gps_err_state
= 0; // turn off the GPS error flag
977 /*! Application entry point.
978 * This is where the application starts. This routine consists of
979 * initialization and an infinite cycle, where pending data are detected and
980 * respective service routines called to process them.
981 * \return Returns nothing - the program is an infinite cycle.
984 uint8_t step_imu
= 0; // actual step number in the IMU datagram processing
985 uint8_t step_gps
= 0; // actual step number in the GPS datagram processing
986 uint32_t count
= 0; // auxiliary variables for wait cycle
988 can_msg_t reset_msg
= {.id
= DAM_RESET_ID
, .dlc
= 2, .data
= {MAIN_VERSION
, SUB_VERSION
}}; // GPS CAN data packet
990 sys_pll_init ( CCLK
, OSC_FREQ
); // set the core clock to 60MHz
992 VPBDIV
= 0x01; // peripheral clock = CPU clock (60MHz)
994 VICIntEnClr
= 0xFFFFFFFF; // init Vector Interrupt Controller
995 VICIntSelect
= 0x00000000;
997 PAL_PINSEL
&= PAL_PINSEL_VAL
;
998 PAL_IODIR
|= PAL_IOBIT
; // set the PAL pin as output and set PAL to 1 (inactive)
999 PAL_IOSET
|= PAL_IOBIT
;
1001 LED_IMU_PINSEL
&= LED_IMU_PINSEL_VAL
;
1002 LED_IMU_IODIR
|= LED_IMU_IOBIT
; // set the IMU LED pin as output and switch the IMU LED on
1003 LED_IMU_IOSET
|= LED_IMU_IOBIT
;
1005 LED_GPS_PINSEL
&= LED_GPS_PINSEL_VAL
;
1006 LED_GPS_IODIR
|= LED_GPS_IOBIT
; // set the GPS LED pin as output and switch the GPS LED on
1007 LED_GPS_IOSET
|= LED_GPS_IOBIT
;
1009 LED_MSH_PINSEL
&= LED_MSH_PINSEL_VAL
;
1010 LED_MSH_IODIR
|= LED_MSH_IOBIT
; // set the MSH LED pin as output and switch the MSH LED on
1011 LED_MSH_IOSET
|= LED_MSH_IOBIT
;
1013 LED_ERR_PINSEL
&= LED_ERR_PINSEL_VAL
;
1014 LED_ERR_IODIR
|= LED_ERR_IOBIT
; // set the ERR LED pin as output and switch the ERR LED on
1015 LED_ERR_IOSET
|= LED_ERR_IOBIT
;
1017 pwm_channel ( 2, 0 ); // select PWM channel to be used as clock source for Villard
1018 pwm_init ( 1, PWM_PERIOD
); // init PWM
1019 pwm_set ( 2, PWM_PULSE_LENGTH
); // switch on Villard
1021 can_init ( CAN_BTR
, ISR_INT_VEC_CAN
, NULL
); // init CAN
1022 watchdog_init ( WATCHDOG_INIT
); // watchdog initialization
1024 while ( can_tx_msg ( &reset_msg
) ); // send the DAM reset message
1026 while ( ( count
< VILLARD_CHARGE_WAIT
) || !( run
& COEF_RECEPTION_FINISH_FLAG
) ) { // wait for Villard to charge and filter coeffitients reception
1027 if ( can_msg_received
) can_rx ( ); // when CAN receives new data, call the service routine
1028 if ( !( run
& RESET_REQUEST_FLAG
) && ( WDTV
< ( WATCHDOG_INIT
/ 2 ) ) ) watchdog_reset ( ); // watchdog reset
1029 if ( ( run
& RUN_TIME_FLAG
) ) break; // if run-time flag is set, skip the waiting
1030 if ( count
< VILLARD_CHARGE_WAIT
) count
++;
1033 run
|= COEF_RECEPTION_FINISH_FLAG
; // set the prevent further filter coeffitients reception flag
1035 adc_init ( ADC_PRESCALER
); // init AD converter
1036 UART_init ( UART0
, BAUD_RATE0
, PCLK
, ISR_INT_VEC_U0
); // init UART0
1037 UART_init ( UART1
, BAUD_RATE1
, PCLK
, ISR_INT_VEC_U1
); // init UART1
1038 timer_init ( TIMER_PRESCALER
, TIMER_PERIOD
, ISR_INT_VEC_TIMER
); // init timer0
1040 LED_IMU_IOCLR
|= LED_IMU_IOBIT
; // switch the IMU LED off
1041 LED_GPS_IOCLR
|= LED_GPS_IOBIT
; // switch the GPS LED off
1042 LED_MSH_IOCLR
|= LED_MSH_IOBIT
; // switch the MSH LED off
1043 LED_ERR_IOCLR
|= LED_ERR_IOBIT
; // switch the ERR LED off
1045 /* main infinite cycle - look for new data at both UARTs and CAN */
1047 if ( UART_new_data ( UART0
) ) IMU_service ( &step_imu
); // when UART0 receives new data, service the IMU
1048 if ( UART_new_data ( UART1
) ) GPS_service ( &step_gps
); // when UART1 receives new data, service the GPS
1049 if ( can_msg_received
) can_rx ( ); // when CAN receives new data, call the service routine