FreeEMS  0.2.0-SNAPSHOT-285-g028e24c
init.c
Go to the documentation of this file.
1 /* FreeEMS - the open source engine management system
2  *
3  * Copyright 2008-2013 Fred Cooke
4  *
5  * This file is part of the FreeEMS project.
6  *
7  * FreeEMS software is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * FreeEMS software is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with any FreeEMS software. If not, see http://www.gnu.org/licenses/
19  *
20  * We ask that if you make any changes to this file you email them upstream to
21  * us at admin(at)diyefi(dot)org or, even better, fork the code on github.com!
22  *
23  * Thank you for choosing FreeEMS to run your engine!
24  */
25 
26 
27 /** @file
28  *
29  * @brief Initialise the devices state
30  *
31  * Setup, configure and initialise all aspects of the devices state including
32  * but not limited to:
33  *
34  * - Setup the bus clock speed
35  * - Configuration based variable initialisation
36  * - I/O register behaviour and initial state
37  * - Configure and enable interrupts
38  * - Copy tunable data up to RAM from flash
39  * - Configure peripheral module behaviour
40  */
41 
42 
43 #define INIT_C
44 #include "inc/freeEMS.h"
45 #include "inc/interrupts.h"
46 #include "inc/utils.h"
47 #include "inc/commsISRs.h"
49 #include "inc/init.h"
50 #include "inc/decoderInterface.h"
51 #include "inc/xgateVectors.h"
52 #include <string.h>
53 
54 
55 /** @brief The main top level init
56  *
57  * The main init function to be called from main.c before entering the main
58  * loop. This function is simply a delegator to the finer grained special
59  * purpose init functions.
60  */
61 void init(){
62  ATOMIC_START(); /* Disable ALL interrupts while we configure the board ready for use */
63  initPLL(); /* Set up the PLL and use it */
64  initGPIO();
65  initPWM();
66  initADC();
67  initAllPagedRAM(); /* Copy table and config blocks of data from flash to the paged RAM blocks for fast data lookup */
68  initVariables(); /* Initialise the rest of the running variables etc */
69  initFlash(); /* TODO, finalise this */
70  initECTTimer(); /* TODO move this to inside config in an organised way. Set up the timer module and its various aspects */
71 // initPITTimer(); /* TODO ditto... */
72  initSCIStuff(); /* Setup the sci module(s) that we will use. */
73  initConfiguration(); /* TODO Set user/feature/config up here! */
74 #ifdef XGATE
75  initXgate(); /* Fred is a legend, for good reason as of now */
76 #endif
77  initInterrupts(); /* still last, reset timers, enable interrupts here TODO move this to inside config in an organised way. Set up the rest of the individual interrupts */
78  ATOMIC_END(); /* Re-enable any configured interrupts */
79 }
80 
81 
82 #ifdef XGATE
83 #include "xgateInit.c"
84 #endif
85 
86 
87 /** @brief Set the PLL clock frequency
88  *
89  * Set the Phase Locked Loop to our desired frequency (80MHz) and enable PLL.
90  */
91 void initPLL(){
92  CLKSEL &= PLLSELOFF; /* Switches to base external OSCCLK to ensure PLL is not being used (off out of reset, but not sure if the monitor turns it on before passing control or not) */
93  PLLCTL &= PLLOFF; /* Turn the PLL device off to adjust its speed (on by default out of reset) */
94  REFDV = PLLDIVISOR; /* 16MHz / (3 + 1) = 4MHz Bus frequency */
95  SYNR = PLLMULTIPLIER; /* 4MHz * (9 + 1) = 40MHz Bus frequency */
96  PLLCTL |= PLLON; /* Turn the PLL device back on again at 80MHz */
97  enablePLL();
98 }
99 
100 /** @brief Switch to using PLL
101  *
102  * Switch to using PLL for clock (40MHz bus speed). Interrupt is enabled elsewhere.
103  *
104  * Note: Requires busy wait loop, only for init and emergency use.
105  *
106  * @todo Should be limited, and have break out with error code and fall back mechanism.
107  */
108 void enablePLL(){
109  while (!(CRGFLG & PLLLOCK)){
110  /* Do nothing while we wait till the PLL loop locks onto the target frequency. */
111  /* Target frequency is given by (2 * (crystal frequency / (REFDV + 1)) * (SYNR + 1)) */
112  /* Bus frequency is half PLL frequency and given by ((crystal frequency / (REFDV + 1)) * (SYNR + 1)) */
113  }
114 
115  CLKSEL = PLLSEL; /* Switches to PLL clock for internal bus frequency */
116  /* from MC9S12XDP512V2.pdf Section 2.4.1.1.2 page 101 Third paragraph */
117  /* "This takes a MAXIMUM of 4 OSCCLK clock cylces PLUS 4 PLL clock cycles" */
118  /* "During this time ALL clocks freeze, and CPU activity ceases" */
119  /* Therefore there is no point waiting for this to occur, we already are... */
120 }
121 
122 
123 /// Set up the analogue inputs
124 void initADC(){
125  // Currently not true, and may never be: TODO When the port something uses
126  // is changed via the tuning interface, the configuration will be done on
127  // the fly, and the value burned to flash such that next boot happens
128  // correctly and current running devices are used in that way.
129 
130  /* Digital input buffers on the ATD channels are off by default, leave them this way! */
131  //ATD0DIEN = ZEROS; /* You are out of your mind if you waste this on digital Inputs */
132  //ATD1DIEN0 = ZEROS; /* You are out of your mind if you waste this on digital Inputs (NOT-bonded, can't use) */
133  //ATD1DIEN1 = ZEROS; /* You are out of your mind if you waste this on digital Inputs */
134 
135  /* And configure them all for analog input */
136  //ATD0CTL0 = 0x07/* With mult turned on this is required to be set to cause wrap around, but is correct out of reset */
137  //ATD0CTL1 = 0x07/* Trigger and interrupt configuration, unused for now. */
138  ATD0CTL2 = 0xC0; /* Turns on the ADC block and sets auto flag clear */
139  ATD0CTL3 = 0x40; /* Set sequence length = 8 */
140  ATD0CTL4 = 0x73; /* Set the ADC clock and sample period for best accuracy */
141  ATD0CTL5 = 0xB0; /* Sets justification to right, multiplex and scan all channels. Writing to this causes conversions to begin */
142 
143  /* And configure them all for analog input */
144  ATD1CTL0 = 0x07; /* TODO bring this out of config based on chip variant variable. Sets wrap on 8th ADC because we can't use the other 8 on 112 pin version */
145  //ATD0CTL1 = 0x07/* Trigger and interrupt configuration, unused for now. */
146  ATD1CTL2 = 0xC0; /* Turns on the ADC block and sets auto flag clear */
147  ATD1CTL3 = 0x40; /* Set sequence length = 8 */
148  ATD1CTL4 = 0x73; /* Set the ADC clock and sample period for best accuracy */
149  ATD1CTL5 = 0xB0; /* Sets justification to right, multiplex and scan all channels. Writing to this causes conversions to begin */
150 }
151 
152 
153 /// Set up the PWM module from configuration
154 void initPWM(){
155  /* TODO PWM channel concatenation for high resolution */
156  // join channel pairs together here (needs 16 bit regs enabled too)
157  /* TODO Initialise pwm channels with frequency, and initial duty for real use */
158  // initial PWM settings for testing
159 
168 
177 
184  PWMCTL = fixedConfigs2.inputOutputSettings.PWMControl & 0xF0; // Disallow access to power saving and reserved bits
185  PWME = fixedConfigs2.inputOutputSettings.PWMEnable; // MUST be done after concatenation with PWMCTL
186 }
187 
188 
189 /// Set up all the pin states as per configuration, but protect key states.
190 void initGPIO(){
191  // Set the initial pin state of pins configured as output
192  PORTA = fixedConfigs2.inputOutputSettings.PortInitialValueA | BIT6 | BIT7; // Mask the fuel pump relay and CEL pins on
196  PORTE = (fixedConfigs2.inputOutputSettings.PortInitialValueE | BIT7) & (NBIT5 & NBIT6); // 7 should be high, and 5 and 6 low, to reduce current draw. The rest don't matter. 0 and 1 are not outputs.
202  PORTS = fixedConfigs2.inputOutputSettings.PortInitialValueS | 0x02; // Mask the SCI0 TX pin to high between transmissions!
203  PORTT = 0x00; // Set all ECT pins to off state, only matters for 2-7, and only if being used. TODO mask this dynamically based on decoder type and configured channels.
204  /* AD0PT1 You are out of your mind if you waste this on digital Inputs */
205  /* AD1PT1 You are out of your mind if you waste this on digital Inputs */
206 
207  // Initialise the Data Direction Registers
208  DDRA = fixedConfigs2.inputOutputSettings.PortDirectionA | BIT6 | BIT7; // Mask the fuel pump relay and CEL pins as outputs
212  DDRE = fixedConfigs2.inputOutputSettings.PortDirectionE; // No need to mask off bits 0 and 1, they have no effect and are always inputs.
218  DDRS = fixedConfigs2.inputOutputSettings.PortDirectionS & 0xFE; // Mask the SCI0 RX pin as input between receiving
219  DDRT = 0xFC; // Set ECT pins 0,1 to IC and 2:7 to OC (8) TODO mask this dynamically based on decoder type and configured channels.
220  /* AD0DDR1 You are out of your mind if you waste this on digital Inputs */
221  /* AD1DDR1 You are out of your mind if you waste this on digital Inputs */
222 }
223 
224 
225 /** @brief Buffer lookup tables addresses
226  *
227  * Save pointers to the lookup tables which live in paged flash.
228  */
234 }
235 
236 
237 /** @brief Buffer fuel tables addresses
238  *
239  * Save pointers to the fuel tables which live in paged flash.
240  */
242  /* Setup addresses within the page to avoid warnings */
251 }
252 
253 
254 /** @brief Copy fuel tables to RAM
255  *
256  * Initialises the fuel tables in RAM by copying them up from flash.
257  */
258 void initPagedRAMFuel(void){
259  /* Copy the tables from flash to RAM */
261  memcpy((void*)&TablesA, VETableMainFlashLocation, sizeof(mainTable));
262  memcpy((void*)&TablesB, VETableSecondaryFlashLocation, sizeof(mainTable));
263  memcpy((void*)&TablesC, AirflowTableFlashLocation, sizeof(mainTable));
264  memcpy((void*)&TablesD, LambdaTableFlashLocation, sizeof(mainTable));
266  memcpy((void*)&TablesA, VETableMainFlash2Location, sizeof(mainTable));
267  memcpy((void*)&TablesB, VETableSecondaryFlash2Location, sizeof(mainTable));
268  memcpy((void*)&TablesC, AirflowTableFlash2Location, sizeof(mainTable));
269  memcpy((void*)&TablesD, LambdaTableFlash2Location, sizeof(mainTable));
270 }
271 
272 
273 /** @brief Buffer timing tables addresses
274  *
275  * Save pointers to the timing tables which live in paged flash.
276  */
278  /* Setup addresses within the page to avoid warnings */
287 }
288 
289 
290 /** @brief Copy timing tables to RAM
291  *
292  * Initialises the timing tables in RAM by copying them up from flash.
293  */
295  /* Copy the tables from flash to RAM */
297  memcpy((void*)&TablesA, IgnitionAdvanceTableMainFlashLocation, sizeof(mainTable));
298  memcpy((void*)&TablesB, IgnitionAdvanceTableSecondaryFlashLocation, sizeof(mainTable));
299  memcpy((void*)&TablesC, InjectionAdvanceTableMainFlashLocation, sizeof(mainTable));
300  memcpy((void*)&TablesD, InjectionAdvanceTableSecondaryFlashLocation, sizeof(mainTable));
302  memcpy((void*)&TablesA, IgnitionAdvanceTableMainFlash2Location, sizeof(mainTable));
303  memcpy((void*)&TablesB, IgnitionAdvanceTableSecondaryFlash2Location, sizeof(mainTable));
304  memcpy((void*)&TablesC, InjectionAdvanceTableMainFlash2Location, sizeof(mainTable));
305  memcpy((void*)&TablesD, InjectionAdvanceTableSecondaryFlash2Location, sizeof(mainTable));
306 }
307 
308 
309 /** @brief Buffer tunable tables addresses
310  *
311  * Save pointers to the tunable tables which live in paged flash and their
312  * sub-sections too.
313  */
315  /* Setup addresses within the page to avoid warnings */
324 
325  /* TablesA */
342 
343  /* TablesB */
348 
349  /* TablesC */
350  // TODO
351 
352  /* TablesD */
353  // TODO
354 
355  /* filler defs */
364 }
365 
366 
367 /**
368  *
369  */
371  /* Copy the tables from flash to RAM */
373  memcpy((void*)&TablesA, SmallTablesAFlashLocation, sizeof(mainTable));
374  memcpy((void*)&TablesB, SmallTablesBFlashLocation, sizeof(mainTable));
375  memcpy((void*)&TablesC, SmallTablesCFlashLocation, sizeof(mainTable));
376  memcpy((void*)&TablesD, SmallTablesDFlashLocation, sizeof(mainTable));
378  // &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& WARNING &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //
379  // You will get garbage if you use table switching at this time!!! //
380  // XGATE code being run from this region temporarily!!! //
381  // Writing to these tables WILL corrupt XGATE code/kill your engine! //
382  // &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& WARNING &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //
383  //memcpy(xgateSchedRAMAddress, xgateSchedFlashAddress, (xgateSchedEnd - xgateSched));
384  //memcpy(xgateInjectorsOnRAMAddress, xgateInjectorsOnFlashAddress, (xgateInjectorsOnEnd - xgateInjectorsOn));
385  //memcpy(xgateInjectorsOffRAMAddress, xgateInjectorsOffFlashAddress, (xgateInjectorsOffEnd - xgateInjectorsOff));
386 // memcpy((void*)&TablesA, SmallTablesAFlash2Location, sizeof(mainTable));
387 // memcpy((void*)&TablesB, SmallTablesBFlash2Location, sizeof(mainTable));
388 // memcpy((void*)&TablesC, SmallTablesCFlash2Location, sizeof(mainTable));
389 // memcpy((void*)&TablesD, SmallTablesDFlash2Location, sizeof(mainTable));
390 }
391 
392 
393 /** @brief Buffer addresses of paged data
394  *
395  * Save the paged memory addresses to variables such that we can access them
396  * from another paged block with no warnings.
397  *
398  * If you try to access paged data from the wrong place you get nasty warnings.
399  * These calls to functions that live in the same page that they are addressing
400  * prevent those warnings.
401  *
402  * @note Many thanks to Jean BĂ©langer for the inspiration/idea to do this!
403  */
405  /* Setup pointers to lookup tables */
407  /* Setup pointers to the main tables */
411 }
412 
413 
414 /** @brief Copies paged flash to RAM
415  *
416  * Take the tables and config from flash up to RAM to allow live tuning.
417  *
418  * For the main tables and other paged config we need to adjust
419  * the RPAGE value to the appropriate one before copying up.
420  *
421  * This function is simply a delegator to the ones for each flash page. Each
422  * one lives in the same paged space as the data it is copying up.
423  */
425  /* Setup the flash block pointers before copying flash to RAM using them */
427 
428  /* Copy the tables up to their paged RAM blocks through the window from flash */
432 
433  /* Default to page one for now, perhaps read the configured port straight out of reset in future? TODO */
434  setupPagedRAM(TRUE); // probably something like (PORTA & TableSwitchingMask)
435 }
436 
437 
438 /* Initialise and set up all running variables that require a non-zero start value here */
439 /* All other variables are initialised to zero by the premain built in code */
441  /* And the opposite for the other halves */
442  CoreVars = &CoreVars0;
446 
447  ticksPerDegree = &ticksPerDegree0; // TODO temp, remove, maybe
448  ticksPerDegreeRecord = &ticksPerDegree1; // TODO temp, remove, maybe
449 
450  /* Setup the pointers to the registers for fueling use, this does NOT work if done in global.c, I still don't know why. */
463 
465 
466  // Preset all schedules to be disabled. Can be configured by scheduler if required.
467  descheduleAll();
468 
469  // TODO perhaps read from the ds1302 once at start up and init the values or different ones with the actual time and date then update them in RTI
470 }
471 
472 
473 /** @brief Flash module setup
474  *
475  * Initialise configuration registers for the flash module to allow burning of
476  * non-volatile flash memory from within the firmware.
477  *
478  * The FCLKDIV register can be written once only after reset, thus the lower
479  * seven bits and the PRDIV8 bit must be set at the same time.
480  *
481  * We want to put the flash clock as high as possible between 150kHz and 200kHz
482  *
483  * The oscillator clock is 16MHz and because that is above 12.8MHz we will set
484  * the PRDIV8 bit to further divide by 8 bits as per the manual.
485  *
486  * 16MHz = 16000KHz which pre-divided by 8 is 2000kHz
487  *
488  * 2000kHz / 200kHz = 10 thus we want to set the divide register to 10 or 0x0A
489  *
490  * Combining 0x0A with PRDIV8 gives us 0x4A (0x0A | 0x40 = 0x4A) so we use that
491  *
492  * @author Sean Keys
493  *
494  * @note If you use a different crystal lower than 12.8MHz PRDIV8 should not be set.
495  *
496  * @warning If the frequency you end up with is outside 150kHz - 200kHz you may
497  * damage your flash module or get corrupt data written to it.
498  */
499 void initFlash(){
500  FCLKDIV = 0x4A; /* Set the flash clock frequency */
501  FPROT = 0xFF; /* Disable all flash protection */
502  FSTAT = FSTAT | (PVIOL | ACCERR); /* Clear any errors */
503 }
504 
505 
506 /* Set up the timer module and its various interrupts */
508  /** @todo TODO Take the configuration from the decoder (as is) and mask it such that it does not affect the 6 other channels.
509  * Take the the number of output channels required from configuration and configure that many as outputs
510  * Configure the balance in whatever way is specified in the GPIO configuration - allow second input to be reused as GPI only.
511  *
512  * This stuff affects:
513  * - TIE = 0x01 or 0x03, only. OC channels enabled as required and IC only for RPM/position.
514  * - TIOS = nope, always 0xFC for 2 IC and 6 OC
515  * - TCTL (1,2,3,4) 4 = 0x0? mask off high 4 bits and allow low 4 to come from decoder config/init
516  * - PORTT = zeros, with balance from config
517  * - DDRT = 0,1 inputs, or if unused by decoder, from config
518  */
519 
520 
521 
522  // TODO rearrange the order of this stuff and pull enable and interrupt enable out to the last function call of init.
523 
524 
525  /* Timer channel interrupts */
526  TIE = 0x03; /* 0,1 IC interrupts enabled for reading engine position and RPM, 6 OC channels disabled such that no injector switching happens till scheduled */
527  TFLG = ONES; /* Clear all the flags such that we are up and running before they first occur */
528  TFLGOF = ONES; /* Clear all the flags such that we are up and running before they first occur */
529 
530  /* TODO Turn the timer on and set the rate and overflow interrupt */
531 // DLYCT = 0xFF; /* max noise filtering as experiment for volvo this will come from flash config */ // just hiding a wiring/circuit issue...
532  TSCR1 = 0x88; /* 0b_1000_1000 Timer enabled, and precision timer turned on */
533  TSCR2 = 0x87; /* 0b_1000_0111 Overflow interrupt enable, divide by 256 if precision turned off */
534 // PTPSR = 0x03; /* 4 prescaler gives .1uS resolution and max period of 7ms measured */
535  PTPSR = 0x1F; /* 32 prescaler gives 0.8uS resolution and max period of 52.4288ms measured */
536 // PTPSR = 0x3F; /* 64 prescaler gives 1.6uS resolution and max period of 105ms measured */
537 // PTPSR = 0xFF; /* 256 prescaler gives 6.4uS resolution and max period of 400ms measured */
538 // PTPSR = 0x7F; /* 128 prescaler gives 3.2uS resolution and max period of 200ms measured */
539  /* http://duckduckgo.com/?q=1+%2F+%2840MHz+%2F+32+%29 */
540  /* http://duckduckgo.com/?q=%281+%2F+%2840MHz+%2F+32+%29%29+*+2^16 */
541  /* www.mecheng.adelaide.edu.au/robotics_novell/WWW_Devs/Dragon12/LM4_Timer.pdf */
542 
543  /* Initial actions */
544  TIOS = 0xFC; /* 0b_1111_1100 0 and 1 are input capture, 2 through 7 are output compare */
545  TCTL1 = ZEROS; /* Set disabled at startup time, use these and other flags to switch fueling on and off inside the decoder */
546  TCTL2 = ZEROS; /* 0,1 have compare turned off regardless as they are in IC mode. */
547  TCTL3 = ZEROS; /* Capture off for 4 - 7 */
548  TCTL4 = 0x0F; /* Capture on both edges of two pins for IC (0,1), capture off for 2,3 */
549 
550  // TODO setup delay counters on 0 and 1 to filter noise (nice feature!)
551  //DLYCT = ??; built in noise filter
552 
553 // PTMCPSR = 0xFF // Precision prescaler - fastest is 1 represented by 0, slowest/longest possible is 256 represented by 255 or 0xFF
554 // MCCNT = ONES16; // init to slowest possible, first
555 // MCCTL = 0xC4; // turn on and setup the mod down counter
556 // MCFLG = 0x80; // clear the flag up front
557 
559 }
560 
561 
562 /* Configure the PIT timers for their various uses. */
564 // // set micro periods
565 // PITMTLD0 = 0x1F; /* 32 prescaler gives 0.8uS resolution and max period of 52.4288ms measured */
566 // PITMTLD1 = 0x1F; /* ditto */
567 // /* http://duckduckgo.com/?q=1+%2F+%2840MHz+%2F+32+%29 Exactly the same as for ECT */
568 //
569 // // set timers running
570 // PITLD0 = dwellPeriod;
571 // // enable module
572 // PITCFLMT = 0x80;
573 // // enable channels
574 // //PITCE = 0x03;
575 // // enable interrupt
576 // PITINTE = 0x01;
577 // // clear flags
578 // //PITFLT = ONES;
579 }
580 
581 /* Setup the sci module(s) that we need to use. */
583  /* The alternative register set selector defaults to zero */
584 
585  // set the baud/data speed
587 
588  // etc
589 
590  /* Switch to alternative register set? */
591 
592  // etc
593 
594  /* Switch back again? */
595 
596  /*
597  * 0 = LOOPS (normal two wire operation)
598  * 0 = SCISWAI (Wait mode on)
599  * 0 = RSRC (if loops=1, int/ext wiring)
600  * 1 = M MODE (9 bit operation)
601  * 0 = WAKE (idle line wakeup)
602  * 0 = ILT (idle line type count start pos)
603  * 1 = PE (parity on)
604  * 1 = PT (odd parity)
605  *
606  * 0x13 = ODD (default)
607  * 0x12 = EVEN
608  * 0x00 = NONE
609  */
610  SCI0CR1 = 0x13;
611 
612  /*
613  * 0 = TIE (tx data empty isr disabled)
614  * 0 = TCIE (tx complete isr disabled)
615  * 1 = RIE (rx full isr enabled)
616  * 0 = ILIE (idle line isr disabled)
617  * 0 = TE (transmit disabled)
618  * 1 = RE (receive enabled)
619  * 0 = RWU (rx wake up normal)
620  * 0 = SBK (send break off)
621  */
622  SCI0CR2 = 0x24;
623 }
624 
625 /* TODO Load and calculate all configuration data required to run */
627 // // TODO Calc TPS ADC range on startup or every time? this depends on whether we ensure that things work without a re init or reset or not.
628 
629 
630  /* Add in tunable physical parameters at boot time TODO move to init.c TODO duplicate for secondary fuel? or split somehow?
631  *nstant = ((masterConst * perCylinderVolume) / (stoichiometricAFR * injectorFlow));
632  *nstant = ((139371764 * 16384) / (15053 * 4096));
633  * OR
634  *nstant = ((masterConst / injectorFlow) * perCylinderVolume) / stoichiometricAFR;
635  *nstant = ((139371764 / 4096) * 16384) / 15053;
636  * http://duckduckgo.com/?q=%28%28139371764++%2F+4096%29+*+16384%29+%2F+15053 */
638 
639  /* The ADC range used to generate TPS percentage */
642  }else{
644  }
645 }
646 
647 
648 /* Set up all the remaining interrupts */
650  /* IMPORTANT : Set the s12x vector base register (Thanks Karsten!!) */
651  IVBR = 0xF7; /* Without this the interrupts will never find your code! */
652 
653  /* Set up the Real Time Interrupt */
654  RTICTL = 0x81; /* 0b_1000_0001 0.125ms/125us period http://duckduckgo.com/?q=1+%2F+%2816MHz+%2F+%282+*+10^3%29+%29 */
655 // RTICTL = 0xF9; /* 0b_1111_1001 0.125s/125ms period http://duckduckgo.com/?q=1+%2F+%2816MHz+%2F+%282*10^6%29+%29 */
656  CRGINT |= (RTIE | PLLLOCKIE | SCMIE); /* Enable the Real Time Interrupt, PLL Lock Interrupt, and Self Clock Mode Interrupt */
657  CRGFLG = (RTIF | PLLLOCKIF | SCMIF); /* Clear the RTI, LOCKI, and SCMI flags */
658  RAMWPC |= AVIE; // Enable the access protection interrupt for XGATE RAM
659 
660  // set up port H for testing
661  PPSH = ZEROS; // falling edge/pull up for all
662  PIEH = ONES; // enable all pins interrupts
663  PIFH = ONES; // clear all port H interrupt flags
664 
665  // TODO set up irq and xirq for testing
666  // IRQCR for IRQ
667 
668  /* VReg API setup (only for wait mode? i think so) */
669 // VREGAPIR = 0x09C3; /* For 500ms period : (500ms - 0.2ms) / 0.2ms = 0b100111000011 = 2499 */
670 // VREGAPICL = 0x02; /* Enable the interrupt */
671 // VREGAPICL = 0x04; /* Start the counter running */
672  /* Writing a one to the flag will set it if it is unset, so best not to mess with it here as it probably starts off unset */
673 
674  /* LVI Low Voltage Interrupt enable */
675  VREGCTRL = 0x02; // Counts bad power events for diagnosis reasons
676 }