Adjusted status LED definitions
[LPC2xxx_and_RobotSpejbl.git] / app / rama_dam / rama_dam.c
blob6722a1c0c63174e556d4b45847bd66f1e89851f0
1 /********************************************************/
2 /* Data Acqusition software for the DAM module */
3 /* RAMA UAV control system */
4 /* */
5 /* ver. 5.6 beta */
6 /* */
7 /* (c) 2006-2009 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 <pll.h>
18 #include <periph/can.h>
19 #include <periph/uart_zen.h>
20 #include <pwm.h>
22 /*! @defgroup defines Constants Definitions
23 * @{
26 /*! @defgroup VERSION Program Version
27 * @ingroup defines
28 * These constants define the program version.
29 * @{
31 #define MAIN_VERSION 5
32 #define SUB_VERSION 6
33 /*! @} */
35 /*! @defgroup CLK Clock settings
36 * @ingroup defines
37 * These constants define the crystal frequency, core clock and peripheral clock.
38 * @{
40 #define OSC_FREQ 10000000
41 #define CCLK 60000000
42 #define PCLK 60000000
43 /*! @} */
45 /*!\def TRUE
46 * Formal definition of logical "TRUE" value.
48 #define TRUE 1
50 /*!\def SAMPLING_FREQ_PRESCALER
51 * Sampling frequency prescaler - 64Hz / ( SAMPLING_FREQ_PRESCALER + 1 ), that means that 0 - 64Hz, 1 - 32Hz etc.
53 /* 64Hz */
54 #define SAMPLING_FREQ_PRESCALER 0
56 /*!\def WATCHDOG_INIT
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
63 * @ingroup defines
64 * These constants define the IO ports and specific bits to manipulate respective status LEDs.
65 * @{
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
94 /*! @} */
96 /*! @defgroup msh_degauss_defines Magnetic Sensor Hybrid Degauss Pin Definitions
97 * @ingroup defines
98 * These constants define the IO port and specific bit to drive the MSH degauss pin.
99 * @{
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
107 /*! @} */
109 /*! @defgroup error_tresholds Error Treshold Constants
110 * @ingroup defines
111 * These constants define the tresholds of number of errors to generate an CAN error message.
112 * @{
114 #define IMU_ERROR_TRESHOLD 3072
115 #define GPS_ERROR_TRESHOLD_RUN 6144
116 #define GPS_ERROR_TRESHOLD_INIT 65534
117 /*! @} */
119 /*! @defgroup error_codes Error Codes
120 * @ingroup defines
121 * Following constants define the error codes.
122 * @{
124 #define NO_ERR 0x00
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
135 /*! @} */
137 /*! @defgroup can_id CAN Message IDs
138 * @ingroup defines
139 * The constants below define respective IDs for the CAN messages.
140 * Standard 11-bit IDs are used.
141 * @{
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
193 /*! @} */
195 /*! @defgroup timer_settings Timer Settings
196 * @ingroup defines
197 * The constants below define the timer settings (timer frequency and interrupt number).
198 * @{
200 /* 1536 Hz */
201 #define TIMER_PRESCALER 1
202 #define TIMER_PERIOD ( PCLK / 1536 )
203 #define ISR_INT_VEC_TIMER 10
204 /*! @} */
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
212 * @ingroup defines
213 * The constants below define the CAN settings (baud rate and interrupt number).
214 * @{
216 #define CAN_BTR ( 0x00250000 + ( PCLK / 10000000 ) - 1 )
217 #define ISR_INT_VEC_CAN 11
218 /*! @} */
220 /*! @defgroup imu_constants IMU Communication Constants
221 * @ingroup defines
222 * The constants below define important IMU communication constants,
223 * such as message delimiter bytes and out-of-range bit mask.
224 * @{
226 #define IMU_MES_DELIMITER_1 0x78
227 #define IMU_MES_DELIMITER_2 0x87
228 #define IMU_RANGE_MASK 0x3F
229 /*! @} */
231 /*! @defgroup gps_constants GPS Communication Constants
232 * @ingroup defines
233 * The constants below define important GPS communication constants,
234 * such as message header and delimiter bytes and length.
235 * @{
237 #define DLE_BYTE 0x10
238 #define ETX_BYTE 0x03
239 #define ID_POS 0x33
240 #define GPS_DATA_LENGTH 0x40
241 /*! @} */
243 /*! @defgroup uart_settings UART Settings
244 * @ingroup defines
245 * The constants below define the UART settings, such as baud rates, interrupt numbers and buffer lengths.
246 * @{
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
256 /*! @} */
258 /*! @defgroup angular_rates_conversion Angular Rates Conversion Constant
259 * @ingroup defines
260 * @{
262 /*!\def ANGULAR_CONV
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
271 /*! @} */
273 /*! @defgroup accel_conversion Accelerations Conversion Constant
274 * @ingroup defines
275 * Accelerations conversion constants
276 * @{
278 /*!\def ACCEL_CONV
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
283 /*! @} */
285 /*! @defgroup msh_conversion Magnetic Field Intensity Constants
286 * @ingroup defines
287 * @{
289 /*! @defgroup MSH_CONV AD value-to-mgauss conversion constants
290 * @ingroup msh_conversion
291 * @{
293 #define MSH_X_CONV 1.14
294 #define MSH_Y_CONV 1.05
295 #define MSH_Z_CONV 1.05
296 /*! @} */
298 /*! @defgroup PWM_PARAMS PWM parameters (PWM is used for Villard charging)
299 * @ingroup msh_conversion
300 * @{
302 /* 1KHz, 1/2 pulse ratio */
303 #define PWM_PERIOD 60000
304 #define PWM_PULSE_LENGTH 30000
305 /*! @} */
307 /*!\def VILLARD_CHARGE_WAIT
308 * Wait constant for initial Villard charge, used for magnetometer degaussing
310 #define VILLARD_CHARGE_WAIT 6000000
311 /*! @} */
313 /*! @defgroup filter_settings Filter Settings
314 * @ingroup defines
315 * The constants below define the polynomial filter coefficients for the roll, pitch and yaw angular rate filters.
316 * @{
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
338 /*! @} */
340 /*! @defgroup run_time_flags Run-Time Flags
341 * @ingroup defines
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).
343 * @{
345 #define COEF_RECEPTION_FINISH_FLAG 0x01
346 #define RUN_TIME_FLAG 0x02
347 #define RESET_REQUEST_FLAG 0x04
348 /*! @} */
349 /*! @} */
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
436 WDFEED = 0xAA;
437 WDFEED = 0x55; // feed sequence
440 /*! Watchdog reset function.
441 * Takes no arguments.
443 inline void watchdog_reset ( void ) {
444 WDFEED = 0xAA;
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 ) {
459 uint8_t i;
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
507 return read;
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
553 imu_err_state = 1;
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
562 gps_err_state = 1;
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;
603 uint8_t *coef_num;
604 float *filter_array;
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
621 break;
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
625 break;
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
629 break;
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
633 break;
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
641 break;
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 */
724 switch ( *step ) {
725 case 0: if ( read_UART_data ( UART0 ) == IMU_MES_DELIMITER_1 ) ( *step )++; // wait for the first telegram start character
726 break;
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
734 break;
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
745 ( *step )++;
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
751 break;
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
756 ( *step )++;
757 break;
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
764 break;
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
831 /* MSH messages */
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)
835 msh_sent_flag = 1;
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 */
899 switch ( *step ) {
900 case 0: if ( read_UART_data ( UART1 ) == DLE_BYTE ) ( *step )++; // wait for the first telegram start character
901 break;
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
908 break;
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
916 break;
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
928 break;
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
938 break;
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
946 break;
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.
983 int main ( void ) {
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 */
1046 while ( TRUE ) {
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