Merge branch 'philsmaster'
[freeems-vanilla.git] / src / init.c
blobdb01b5b03d8f4106835677d5e22a6f287b0a323c
1 /* FreeEMS - the open source engine management system
3 Copyright 2008 Fred Cooke
5 This file is part of the FreeEMS project.
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.
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.
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/
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!
23 Thank you for choosing FreeEMS to run your engine! */
26 /** @file init.c
28 * @brief Initialise the devices state
30 * Setup, configure and initialise all aspects of the devices state including
31 * but not limited to:
33 * - Setup the bus clock speed
34 * - Configuration based variable initialisation
35 * - I/O register behaviour and initial state
36 * - Configure and enable interrupts
37 * - Copy tunable data up to RAM from flash
38 * - Configure peripheral module behaviour
40 * @author Fred Cooke
44 #define INIT_C
45 #include "inc/freeEMS.h"
46 #include "inc/interrupts.h"
47 #include "inc/utils.h"
48 #include "inc/commsISRs.h"
49 #include "inc/pagedLocationBuffers.h"
50 #include "inc/init.h"
51 #include <string.h>
54 /** @brief The main top level init
56 * The main init function to be called from main.c before entering the main
57 * loop. This function is simply a delegator to the finer grained special
58 * purpose init functions.
60 * @author Fred Cooke
62 void init(){
63 ATOMIC_START(); /* Disable ALL interrupts while we configure the board ready for use */
64 initPLL(); /* Set up the PLL and use it */
65 initIO(); /* TODO make this config dependent. Set up all the pins and modules to be in low power harmless states */
66 initAllPagedRAM(); /* Copy table and config blocks of data from flash to the paged ram blocks for fast data lookup */
67 initAllPagedAddresses(); /* Save the paged memory addresses to variables such that we can access them from another paged block with no warnings */
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 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 */
75 ATOMIC_END(); /* Re-enable any configured interrupts */
79 /* used to chop out all the init stuff at compile time for hardware testing. */
80 //#define NO_INIT
83 /** @brief Set the PLL clock frequency
85 * Set the Phase Locked Loop to our desired frequency (80MHz) and switch to
86 * using it for clock (40MHz bus speed).
88 * @author Fred Cooke
90 void initPLL(){
91 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) */
92 PLLCTL &= PLLOFF; /* Turn the PLL device off to adjust its speed (on by default out of reset) */
93 REFDV = PLLDIVISOR; /* 16MHz / (3 + 1) = 4MHz Bus frequency */
94 SYNR = PLLMULTIPLIER; /* 4MHz * (9 + 1) = 40MHz Bus frequency */
95 PLLCTL |= PLLON; /* Turn the PLL device back on again at 80MHz */
97 while (!(CRGFLG & PLLLOCK)){
98 /* Do nothing while we wait till the PLL loop locks onto the target frequency. */
99 /* Target frequency is given by (2 * (crystal frequency / (REFDV + 1)) * (SYNR + 1)) */
100 /* Bus frequency is half PLL frequency and given by ((crystal frequency / (REFDV + 1)) * (SYNR + 1)) */
103 CLKSEL = PLLSELON; /* Switches to PLL clock for internal bus frequency */
104 /* from MC9S12XDP512V2.pdf Section 2.4.1.1.2 page 101 Third paragraph */
105 /* "This takes a MAXIMUM of 4 OSCCLK clock cylces PLUS 4 PLL clock cycles" */
106 /* "During this time ALL clocks freeze, and CPU activity ceases" */
107 /* Therefore there is no point waiting for this to occur, we already are... */
111 /* Configure all the I/O to default values to keep power use down etc */
112 void initIO(){
113 /* for now, hard code all stuff to be outputs as per Freescale documentation, */
114 /* later what to do will be pulled from flash configuration such that all */
115 /* things are setup at once, and not messed with thereafter. when the port */
116 /* something uses is changed via the tuning interface, the confuration will be */
117 /* done on the fly, and the value burned to flash such that next boot happens */
118 /* correctly and current running devices are used in that way. */
120 /* Turn off and on and configure all the modules in an explicit way */
121 // TODO set up and turn off all modules (CAN,SCI,SPI,IIC,etc)
123 /* Turn off the digital input buffers on the ATD channels */
124 ATD0DIEN = ZEROS; /* You are out of your mind if you waste this on digital Inputs */
125 ATD1DIEN0 = ZEROS; /* You are out of your mind if you waste this on digital Inputs (NOT-bonded, can't use) */
126 ATD1DIEN1 = ZEROS; /* You are out of your mind if you waste this on digital Inputs */
127 /* TODO Second half of ATD1 - can we disable this somehow */
129 /* And configure them all for analog input */
130 ATD0CTL2 = 0x80; /* Turns on the ADC block. */
131 ATD0CTL3 = 0x40; /* Set sequence length = 8 */
132 ATD0CTL5 = 0xB0; /* Sets justification to right, multiplex and scan all channels. */
133 // TODO find out if this is the default (i suspect it is)
134 // TODO look into sampling techniques
136 /* And configure them all for analog input */
137 ATD1CTL0 = 0x07; /* Sets wrap on 8th ADC because we can't use the other 8 */
138 ATD1CTL2 = 0x80; /* Turns on the ADC block. */
139 ATD1CTL3 = 0x40; /* Set sequence length = 8 */
140 ATD1CTL5 = 0xB0; /* Sets justification to right, multiplex and scan all channels. */
141 // TODO find out if this is the default (i suspect it is)
142 // TODO look into sampling techniques
144 #ifndef NO_INIT
145 /* Set up the PWM component and initialise its values to off */
146 PWME = 0x7F; /* Turn on PWM 0 - 6 (7 is user LED on main board) */
147 PWMCLK = ZEROS; /* The fastest we can go for all channels */
148 PWMPRCLK = ZEROS; /* The fastest prescaler we can go for all channels */
149 PWMSCLA = ZEROS; /* The fastest we can go */
150 PWMSCLB = ZEROS; /* The fastest we can go */
151 /* TODO PWM channel concatenation for high resolution */
152 // join channel pairs together here (needs 16 bit regs enabled too)
153 /* TODO Initialise pwm channels with frequency, and initial duty for real use */
154 // initial PWM settings for testing
155 /* PWM periods */
156 PWMPER0 = 0xFF; // 255 for ADC0 testing
157 PWMPER1 = 0xFF; // 255 for ADC1 testing
158 PWMPER2 = 0xFF; // 255 for ADC1 testing
159 PWMPER3 = 0xFF; // 255 for ADC1 testing
160 PWMPER4 = 0xFF; // 255 for ADC1 testing
161 PWMPER5 = 0xFF; // 255 for ADC1 testing
162 PWMPER6 = 0xFF; // 255 for ADC1 testing
163 PWMPER7 = 0xFF; // 255 for ADC1 testing
164 /* PWM duties */
165 PWMDTY0 = 0;
166 PWMDTY1 = 0;
167 PWMDTY2 = 0;
168 PWMDTY3 = 0;
169 PWMDTY4 = 0;
170 PWMDTY5 = 0;
171 PWMDTY6 = 0;
172 PWMDTY7 = 0;
175 /* Initialise the state of pins configured as output */
176 /* Initialise to low such that transistor grounded things are all turned off by default. */
177 PORTA = ZEROS; /* The serial monitor pin is on 0x40, and could cause problems if capacitance at the output is large when a reset occurs. */
178 PORTB = ZEROS; /* Init the rest of the spark outputs as off */
179 PORTE = 0x1F; /* 0b_0001_1111 : when not in use 0b_1001_1111 PE7 should be high PE5 and PE6 should be low, the rest high */
180 PORTK = ZEROS;
181 PORTS = ZEROS;
182 PORTT = ZEROS; /* All pins in off state at boot up (only matters for 2 - 7) */
183 PORTM = ZEROS;
184 PORTP = ZEROS; // TODO hook these up to the adc channels such that you can vary the brightness of an led with a pot.
185 PORTH = ZEROS;
186 PORTJ = ZEROS;
187 /* AD0PT1 You are out of your mind if you waste this on digital Inputs */
188 /* AD1PT1 You are out of your mind if you waste this on digital Inputs */
190 /* Initialise the Data Direction Registers */
191 /* To outputs based on the note at the end of chapter 1.2.2 of MC9S12XDP512V2.pdf */
192 DDRA = ONES; /* GPIO (8) */
193 DDRB = ONES; /* GPIO (8) */
194 DDRE = 0xFC; /* 0b_1111_1100 : Clock and mode pins PE0,PE1 are input only pins, the rest are GPIO */
195 DDRK = ONES; /* Only 0,1,2,3,4,5,7, NOT 6 (7) */
196 DDRS = ONES; /* SCI0, SCI1, SPI0 (8) */
197 DDRT = 0xFC; /* 0b_1111_1100 set ECT pins 0,1 to IC and 2:7 to OC (8) */
198 DDRM = ONES; /* CAN 0 - 3 (8) */
199 DDRP = ONES; /* PWM pins (8) */
200 DDRH = ZEROS; /* All pins configured as input for misc isrs (SPI1, SPI2) (8) */
201 DDRJ = ONES; /* Only 0,1,6,7 are brought out on the 112 pin chip (4) */
202 /* Configure the non bonded pins to output to avoid current drain (112 pin package) */
203 DDRC = ONES; /* NON-bonded external data bus pins */
204 DDRD = ONES; /* NON-bonded external data bus pins */
205 /* AD0DDR1 You are out of your mind if you waste this on digital Inputs */
206 /* AD1DDR1 You are out of your mind if you waste this on digital Inputs */
207 #endif
211 /** @brief Buffer lookup tables addresses
213 * Save pointers to the lookup tables which live in paged flash.
215 * @note Many thanks to Jean Bélanger for the inspiration/idea to do this!
217 * @author Fred Cooke
219 void initLookupAddresses(){
220 IATTransferTableLocation = (void*)&IATTransferTable;
221 CHTTransferTableLocation = (void*)&CHTTransferTable;
222 MAFTransferTableLocation = (void*)&MAFTransferTable;
223 TestTransferTableLocation = (void*)&TestTransferTable;
227 /** @brief Buffer fuel tables addresses
229 * Save pointers to the fuel tables which live in paged flash.
231 * @note Many thanks to Jean Bélanger for the inspiration/idea to do this!
233 * @author Fred Cooke
235 void initFuelAddresses(){
236 /* Setup addresses within the page to avoid warnings */
237 VETableMainFlashLocation = (void*)&VETableMainFlash;
238 VETableSecondaryFlashLocation = (void*)&VETableSecondaryFlash;
239 VETableTertiaryFlashLocation = (void*)&VETableTertiaryFlash;
240 LambdaTableFlashLocation = (void*)&LambdaTableFlash;
241 VETableMainFlash2Location = (void*)&VETableMainFlash2;
242 VETableSecondaryFlash2Location = (void*)&VETableSecondaryFlash2;
243 VETableTertiaryFlash2Location = (void*)&VETableTertiaryFlash2;
244 LambdaTableFlash2Location = (void*)&LambdaTableFlash2;
248 /** @brief Copy fuel tables to RAM
250 * Initialises the fuel tables in RAM by copying them up from flash.
252 * @author Fred Cooke
254 void initPagedRAMFuel(void){
255 /* Copy the tables from flash to RAM */
256 RPAGE = RPAGE_FUEL_ONE;
257 memcpy((void*)&TablesA, VETableMainFlashLocation, MAINTABLE_SIZE);
258 memcpy((void*)&TablesB, (void*)&VETableSecondaryFlash, MAINTABLE_SIZE);
259 memcpy((void*)&TablesC, (void*)&VETableTertiaryFlash, MAINTABLE_SIZE);
260 memcpy((void*)&TablesD, (void*)&LambdaTableFlash, MAINTABLE_SIZE);
261 RPAGE = RPAGE_FUEL_TWO;
262 memcpy((void*)&TablesA, (void*)&VETableMainFlash2, MAINTABLE_SIZE);
263 memcpy((void*)&TablesB, (void*)&VETableSecondaryFlash2, MAINTABLE_SIZE);
264 memcpy((void*)&TablesC, (void*)&VETableTertiaryFlash2, MAINTABLE_SIZE);
265 memcpy((void*)&TablesD, (void*)&LambdaTableFlash2, MAINTABLE_SIZE);
269 /** @brief Buffer timing tables addresses
271 * Save pointers to the timing tables which live in paged flash.
273 * @note Many thanks to Jean Bélanger for the inspiration/idea to do this!
275 * @author Fred Cooke
277 void initTimingAddresses(){
278 /* Setup addresses within the page to avoid warnings */
279 IgnitionAdvanceTableMainFlashLocation = (void*)&IgnitionAdvanceTableMainFlash;
280 IgnitionAdvanceTableSecondaryFlashLocation = (void*)&IgnitionAdvanceTableSecondaryFlash;
281 InjectionAdvanceTableMainFlashLocation = (void*)&InjectionAdvanceTableMainFlash;
282 InjectionAdvanceTableSecondaryFlashLocation = (void*)&InjectionAdvanceTableSecondaryFlash;
283 IgnitionAdvanceTableMainFlash2Location = (void*)&IgnitionAdvanceTableMainFlash2;
284 IgnitionAdvanceTableSecondaryFlash2Location = (void*)&IgnitionAdvanceTableSecondaryFlash2;
285 InjectionAdvanceTableMainFlash2Location = (void*)&InjectionAdvanceTableMainFlash2;
286 InjectionAdvanceTableSecondaryFlash2Location = (void*)&InjectionAdvanceTableSecondaryFlash2;
290 /** @brief Copy timing tables to RAM
292 * Initialises the timing tables in RAM by copying them up from flash.
294 * @author Fred Cooke
296 void initPagedRAMTime(){
297 /* Copy the tables from flash to RAM */
298 RPAGE = RPAGE_TIME_ONE;
299 memcpy((void*)&TablesA, IgnitionAdvanceTableMainFlashLocation, MAINTABLE_SIZE);
300 memcpy((void*)&TablesB, IgnitionAdvanceTableSecondaryFlashLocation, MAINTABLE_SIZE);
301 memcpy((void*)&TablesC, InjectionAdvanceTableMainFlashLocation, MAINTABLE_SIZE);
302 memcpy((void*)&TablesD, InjectionAdvanceTableSecondaryFlashLocation, MAINTABLE_SIZE);
303 RPAGE = RPAGE_TIME_TWO;
304 memcpy((void*)&TablesA, IgnitionAdvanceTableMainFlash2Location, MAINTABLE_SIZE);
305 memcpy((void*)&TablesB, IgnitionAdvanceTableSecondaryFlash2Location, MAINTABLE_SIZE);
306 memcpy((void*)&TablesC, InjectionAdvanceTableMainFlash2Location, MAINTABLE_SIZE);
307 memcpy((void*)&TablesD, InjectionAdvanceTableSecondaryFlash2Location, MAINTABLE_SIZE);
311 /** @brief Buffer tunable tables addresses
313 * Save pointers to the tunable tables which live in paged flash and their
314 * sub-sections too.
316 * @note Many thanks to Jean Bélanger for the inspiration/idea to do this!
318 * @author Fred Cooke
320 void initTunableAddresses(){
321 /* Setup addresses within the page to avoid warnings */
322 SmallTablesAFlashLocation = (void*)&SmallTablesAFlash;
323 SmallTablesBFlashLocation = (void*)&SmallTablesBFlash;
324 SmallTablesCFlashLocation = (void*)&SmallTablesCFlash;
325 SmallTablesDFlashLocation = (void*)&SmallTablesDFlash;
326 SmallTablesAFlash2Location = (void*)&SmallTablesAFlash2;
327 SmallTablesBFlash2Location = (void*)&SmallTablesBFlash2;
328 SmallTablesCFlash2Location = (void*)&SmallTablesCFlash2;
329 SmallTablesDFlash2Location = (void*)&SmallTablesDFlash2;
331 /* TablesA */
332 dwellDesiredVersusVoltageTableLocation = (void*)&SmallTablesAFlash.dwellDesiredVersusVoltageTable;
333 dwellDesiredVersusVoltageTable2Location = (void*)&SmallTablesAFlash2.dwellDesiredVersusVoltageTable;
334 injectorDeadTimeTableLocation = (void*)&SmallTablesAFlash.injectorDeadTimeTable;
335 injectorDeadTimeTable2Location = (void*)&SmallTablesAFlash2.injectorDeadTimeTable;
336 postStartEnrichmentTableLocation = (void*)&SmallTablesAFlash.postStartEnrichmentTable;
337 postStartEnrichmentTable2Location = (void*)&SmallTablesAFlash2.postStartEnrichmentTable;
338 engineTempEnrichmentTableFixedLocation = (void*)&SmallTablesAFlash.engineTempEnrichmentTableFixed;
339 engineTempEnrichmentTableFixed2Location = (void*)&SmallTablesAFlash2.engineTempEnrichmentTableFixed;
340 primingVolumeTableLocation = (void*)&SmallTablesAFlash.primingVolumeTable;
341 primingVolumeTable2Location = (void*)&SmallTablesAFlash2.primingVolumeTable;
342 engineTempEnrichmentTablePercentLocation = (void*)&SmallTablesAFlash.engineTempEnrichmentTablePercent;
343 engineTempEnrichmentTablePercent2Location = (void*)&SmallTablesAFlash2.engineTempEnrichmentTablePercent;
344 dwellMaxVersusRPMTableLocation = (void*)&SmallTablesAFlash.dwellMaxVersusRPMTable;
345 dwellMaxVersusRPMTable2Location = (void*)&SmallTablesAFlash2.dwellMaxVersusRPMTable;
347 /* TablesB */
348 perCylinderFuelTrimsLocation = (void*)&SmallTablesBFlash.perCylinderFuelTrims;
349 perCylinderFuelTrims2Location = (void*)&SmallTablesBFlash2.perCylinderFuelTrims;
351 /* TablesC */
352 // TODO
354 /* TablesD */
355 // TODO
357 /* filler defs */
358 fillerALocation = (void*)&SmallTablesAFlash.filler;
359 fillerA2Location = (void*)&SmallTablesAFlash2.filler;
360 fillerBLocation = (void*)&SmallTablesBFlash.filler;
361 fillerB2Location = (void*)&SmallTablesBFlash2.filler;
362 fillerCLocation = (void*)&SmallTablesCFlash.filler;
363 fillerC2Location = (void*)&SmallTablesCFlash2.filler;
364 fillerDLocation = (void*)&SmallTablesDFlash.filler;
365 fillerD2Location = (void*)&SmallTablesDFlash2.filler;
372 void initPagedRAMTune(){
373 /* Copy the tables from flash to RAM */
374 RPAGE = RPAGE_TUNE_ONE;
375 memcpy((void*)&TablesA, SmallTablesAFlashLocation, MAINTABLE_SIZE);
376 memcpy((void*)&TablesB, SmallTablesBFlashLocation, MAINTABLE_SIZE);
377 memcpy((void*)&TablesC, SmallTablesCFlashLocation, MAINTABLE_SIZE);
378 memcpy((void*)&TablesD, SmallTablesDFlashLocation, MAINTABLE_SIZE);
379 RPAGE = RPAGE_TUNE_TWO;
380 memcpy((void*)&TablesA, SmallTablesAFlash2Location, MAINTABLE_SIZE);
381 memcpy((void*)&TablesB, SmallTablesBFlash2Location, MAINTABLE_SIZE);
382 memcpy((void*)&TablesC, SmallTablesCFlash2Location, MAINTABLE_SIZE);
383 memcpy((void*)&TablesD, SmallTablesDFlash2Location, MAINTABLE_SIZE);
387 /** @brief Buffer addresses of paged data
389 * If you try to access paged data from the wrong place you get nasty warnings.
390 * These calls to functions that live in the same page that they are addressing
391 * prevent those warnings.
393 * @note Many thanks to Jean Bélanger for the inspiration/idea to do this!
395 * @author Fred Cooke
397 void initAllPagedAddresses(){
398 /* Setup pointers to lookup tables */
399 initLookupAddresses();
400 /* Setup pointers to the main tables */
401 initFuelAddresses();
402 initTimingAddresses();
403 initTunableAddresses();
407 /** @brief Copies paged flash to RAM
409 * Take the tables and config from flash up to RAM to allow live tuning.
411 * For the main tables and other paged config we need to adjust
412 * the RPAGE value to the appropriate one before copying up.
414 * This function is simply a delegator to the ones for each flash page. Each
415 * one lives in the same paged space as the data it is copying up.
417 * @author Fred Cooke
419 void initAllPagedRAM(){
420 /* Copy the tables up to their paged ram blocks through the window from flash */
421 initPagedRAMFuel();
422 initPagedRAMTime();
423 initPagedRAMTune();
425 /* Default to page one for now, perhaps read the configured port straight out of reset in future? TODO */
426 setupPagedRAM(TRUE); // probably something like (PORTA & TableSwitchingMask)
430 /* Init all pointers to tunable items with direct addresses */
431 /* Pointers remain the same when switching pages so are initialised only once */
432 // VETableMain = &TablesA.VETableMain;
433 // VETableSecondary = &TablesB.VETableSecondary;
434 // VETableTertiary = &TablesC.VETableMainTertiary;
435 // LambdaTable = &TablesD.LambdaTable;
437 // IgnitionAdvanceTableMain = &TablesA.IgnitionAdvanceTableMain;
438 // IgnitionAdvanceTableSecondary = &TablesB.IgnitionAdvanceTableSecondary;
439 // InjectionAdvanceTableMain = &TablesC.InjectionAdvanceTableMain;
440 // InjectionAdvanceTableSecondary = &TablesD.InjectionAdvanceTableSecondary;
442 // dwellDesiredVersusVoltageTable = &TablesA.SmallTablesA.dwellDesiredVersusVoltageTable;
443 // injectorDeadTimeTable = &TablesA.SmallTablesA.injectorDeadTimeTable;
444 // postStartEnrichmentTable = &TablesA.SmallTablesA.postStartEnrichmentTable;
445 // engineTempEnrichmentTableFixed = &TablesA.SmallTablesA.engineTempEnrichmentTableFixed;
446 // primingVolumeTable = &TablesA.SmallTablesA.primingVolumeTable;
447 // engineTempEnrichmentTablePercent = &TablesA.SmallTablesA.engineTempEnrichmentTablePercent;
448 // dwellMaxVersusRPMTable = &TablesA.SmallTablesA.dwellMaxVersusRPMTable;
450 // perCylinderFuelTrims = TablesB.SmallTablesB.perCylinderFuelTrims;
453 /* Initialise and set up all running variables that require a non-zero start value here */
454 /* All other variables are initialised to zero by the premain built in code */
455 void initVariables(){
456 /* And the opposite for the other halves */
457 CoreVars = &CoreVars0;
458 DerivedVars = &DerivedVars0;
459 ADCArrays = &ADCArrays0;
460 ADCArraysRecord = &ADCArrays1;
461 asyncADCArrays = &asyncADCArrays0;
462 asyncADCArraysRecord = &asyncADCArrays1;
463 currentDwellMath = &currentDwell0;
464 currentDwellRealtime = &currentDwell1;
466 injectorMainPulseWidthsMath = injectorMainPulseWidths0;
467 injectorMainPulseWidthsRealtime = injectorMainPulseWidths1;
468 injectorStagedPulseWidthsMath = injectorStagedPulseWidths0;
469 injectorStagedPulseWidthsRealtime = injectorStagedPulseWidths1;
471 mathSampleTimeStamp = &ISRLatencyVars.mathSampleTimeStamp0; // TODO temp, remove
472 mathSampleTimeStampRecord = &ISRLatencyVars.mathSampleTimeStamp1; // TODO temp, remove
473 RPM = &RPM0; // TODO temp, remove
474 RPMRecord = &RPM1; // TODO temp, remove
476 /* Setup the pointers to the registers for fueling use, this does NOT work if done in global.c, I still don't know why. */
477 injectorMainTimeRegisters[0] = TC2_ADDR;
478 injectorMainTimeRegisters[1] = TC3_ADDR;
479 injectorMainTimeRegisters[2] = TC4_ADDR;
480 injectorMainTimeRegisters[3] = TC5_ADDR;
481 injectorMainTimeRegisters[4] = TC6_ADDR;
482 injectorMainTimeRegisters[5] = TC7_ADDR;
483 injectorMainControlRegisters[0] = TCTL2_ADDR;
484 injectorMainControlRegisters[1] = TCTL2_ADDR;
485 injectorMainControlRegisters[2] = TCTL1_ADDR;
486 injectorMainControlRegisters[3] = TCTL1_ADDR;
487 injectorMainControlRegisters[4] = TCTL1_ADDR;
488 injectorMainControlRegisters[5] = TCTL1_ADDR;
490 configuredBasicDatalogLength = maxBasicDatalogLength;
492 // 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
496 /** @brief Flash module setup
498 * Initialise configuration registers for the flash module to allow burning of
499 * non-volatile flash memory from within the firmware.
501 * The FCLKDIV register can be written once only after reset, thus the lower
502 * seven bits and the PRDIV8 bit must be set at the same time.
504 * We want to put the flash clock as high as possible between 150kHz and 200kHz
506 * The oscillator clock is 16MHz and because that is above 12.8MHz we will set
507 * the PRDIV8 bit to further divide by 8 bits as per the manual.
509 * 16MHz = 16000KHz which pre-divided by 8 is 2000kHz
511 * 2000kHz / 200kHz = 10 thus we want to set the divide register to 10 or 0x0A
513 * Combining 0x0A with PRDIV8 gives us 0x4A (0x0A | 0x40 = 0x4A) so we use that
515 * @author Sean Keys
517 * @note If you use a different crystal lower than 12.8MHz PRDIV8 should not be set.
519 * @warning If the frequency you end up with is outside 150kHz - 200kHz you may
520 * damage your flash module or get corrupt data written to it.
522 void initFlash(){
523 FCLKDIV = 0x4A; /* Set the flash clock frequency */
524 FPROT = 0xFF; /* Disable all flash protection */
525 FSTAT = FSTAT | (PVIOL | ACCERR); /* Clear any errors */
529 /* Set up the timer module and its various interrupts */
530 void initECTTimer(){
532 // TODO rearrange the order of this stuff and pull enable and interrupt enable out to the last function call of init.
535 #ifndef NO_INIT
536 /* Timer channel interrupts */
537 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 */
538 TFLG = ONES; /* Clear all the flags such that we are up and running before they first occur */
539 TFLGOF = ONES; /* Clear all the flags such that we are up and running before they first occur */
541 /* TODO Turn the timer on and set the rate and overflow interrupt */
542 TSCR1 = 0x88; /* 0b_1000_1000 Timer enabled, and precision timer turned on */
543 TSCR2 = 0x87; /* 0b_1000_0111 Overflow interrupt enable, divide by 256 if precision turned off */
544 // PTPSR = 0x03; /* 4 prescaler gives .1uS resolution and max period of 7ms measured */
545 PTPSR = 0x1F; /* 32 prescaler gives 0.8uS resolution and max period of 52.4288ms measured */
546 // PTPSR = 0x3F; /* 64 prescaler gives 1.6uS resolution and max period of 105ms measured */
547 // PTPSR = 0xFF; /* 256 prescaler gives 6.4uS resolution and max period of 400ms measured */
548 // PTPSR = 0x7F; /* 128 prescaler gives 3.2uS resolution and max period of 200ms measured */
549 /* http://www.google.com/search?hl=en&safe=off&q=1+%2F+%2840MHz+%2F+32+%29&btnG=Search */
550 /* http://www.google.com/search?hl=en&safe=off&q=1+%2F+%2840MHz+%2F+32+%29+*+2%5E16&btnG=Search */
551 /* www.mecheng.adelaide.edu.au/robotics_novell/WWW_Devs/Dragon12/LM4_Timer.pdf */
553 /* Initial actions */
554 TIOS = 0xFC; /* 0b_1111_1100 0 and 1 are input capture, 2 through 7 are output compare */
555 TCTL1 = ZEROS; /* Set disabled at startup time, use these and other flags to switch fueling on and off inside the decoder */
556 TCTL2 = ZEROS; /* 0,1 have compare turned off regardless as they are in IC mode. */
557 TCTL3 = ZEROS; /* Capture off for 4 - 7 */
558 TCTL4 = 0x0F; /* Capture on both edges of two pins for IC (0,1), capture off for 2,3 */
560 // TODO setup delay counters on 0 and 1 to filter noise (nice feature!)
561 //DLYCT = ??; built in noise filter
563 /* Configurable tachometer output */
564 PTMCPSR = fixedConfigs1.tachoSettings.tachoTickFactor - 1; // Precision prescaler - fastest is 1 represented by 0, slowest/longest possible is 256 represented by 255 or 0xFF
565 MCCNT = ONES16; // init to slowest possible, first
566 MCCTL = 0xC4; // turn on and setup the mod down counter
567 MCFLG = 0x80; // clear the flag up front
568 #endif
572 /* Configure the PIT timers for their various uses. */
573 void initPITTimer(){
574 #ifndef NO_INIT
575 /* */
576 // set micro periods
577 PITMTLD0 = 0x1F; /* 32 prescaler gives 0.8uS resolution and max period of 52.4288ms measured */
578 PITMTLD1 = 0x1F; /* ditto */
579 /* http://www.google.com/search?hl=en&safe=off&q=1+%2F+%2840MHz+%2F+32+%29 Exactly the same as for ECT */
581 // set timers running
582 // PITLD0 = dwellPeriod;
583 // enable module
584 PITCFLMT = 0x80;
585 // enable channels
586 //PITCE = 0x03;
587 // enable interrupt
588 // PITINTE = 0x01;
589 // clear flags
590 //PITFLT = ONES;
591 #endif
594 /* Setup the sci module(s) that we need to use. */
595 void initSCIStuff(){
596 /* The alternative register set selector defaults to zero */
598 // set the baud/data speed
599 SCI0BD = fixedConfigs1.serialSettings.baudDivisor;
601 // etc
603 /* Switch to alternative register set? */
605 // etc
607 /* Switch back again? */
610 * 0 = LOOPS (normal two wire operation)
611 * 0 = SCISWAI (Wait mode on)
612 * 0 = RSRC (if loops=1, int/ext wiring)
613 * 1 = M MODE (9 bit operation)
614 * 0 = WAKE (idle line wakeup)
615 * 0 = ILT (idle line type count start pos)
616 * 1 = PE (parity on)
617 * 1 = PT (odd parity) (minicom defaults to no parity)
619 * 00010011 = 0x13
621 SCI0CR1 = 0x13;
624 * 0 = TIE (tx data empty isr disabled)
625 * 0 = TCIE (tx complete isr disabled)
626 * 1 = RIE (rx full isr enabled)
627 * 0 = ILIE (idle line isr disabled)
628 * 1 = TE (transmit enabled)
629 * 1 = RE (receive enabled)
630 * 0 = RWU (rx wake up normal)
631 * 0 = SBK (send break off)
633 * 00101100 = 0x2C
635 SCI0CR2 = 0x2C;
638 /* TODO Load and calculate all configuration data required to run */
639 void initConfiguration(){
640 // // 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.
643 /* Add in tunable physical parameters at boot time TODO move to init.c TODO duplicate for secondary fuel? or split somehow?
644 *nstant = ((masterConst * perCylinderVolume) / (stoichiometricAFR * injectorFlow));
645 *nstant = ((139371764 * 16384 ) / (15053 * 4096 ));
646 * OR
647 *nstant = ((masterConst / injectorFlow) * perCylinderVolume) / stoichiometricAFR;
648 *nstant = ((139371764 / 4096 ) * 16384 ) / 15053 ;
649 * http://www.google.com/search?hl=en&safe=off&q=((139371764++%2F+4096+++++)+*+16384+++)+%2F+15053++++&btnG=Search */
650 bootFuelConst = ((unsigned long)(masterFuelConstant / fixedConfigs1.engineSettings.injectorFlow) * fixedConfigs1.engineSettings.perCylinderVolume) / fixedConfigs1.engineSettings.stoichiometricAFR;
652 /* The MAP range used to convert fake TPS from MAP and vice versa */
653 TPSMAPRange = fixedConfigs2.sensorRanges.TPSOpenMAP - fixedConfigs2.sensorRanges.TPSClosedMAP;
655 /* The ADC range used to generate TPS percentage */
656 TPSADCRange = fixedConfigs2.sensorRanges.TPSMaximumADC - fixedConfigs2.sensorRanges.TPSMinimumADC;
659 /* Use like flags for now, just add one for each later */
660 unsigned char cumulativeConfigErrors = 0;
662 /* Check various aspects of config which will cause problems */
664 /* BRV max bigger than variable that holds it */
665 if(((unsigned long)fixedConfigs2.sensorRanges.BRVMinimum + fixedConfigs2.sensorRanges.BRVRange) > 65535){
666 //sendError(BRV_MAX_TOO_LARGE);
667 cumulativeConfigErrors++;
670 // TODO check all critical variables here!
673 * check ignition settings for range etc, possibly check some of those on the fly too
674 * check fuel settings for being reasonable
675 * check all variable tables for correct sizing
676 * etc
679 while(cumulativeConfigErrors > 0){
680 sleep(1000);
681 PORTS_BA ^= ONES16; // flash leds
682 //send("There were ");
683 //sendUC(cumulativeConfigErrors);
684 //send(" config errors, init aborted!");
685 } // TODO ensure that we can recieve config and settings via serial while this is occuring! If not a bad config will lock us out all together.
689 /* Set up all the remaining interrupts */
690 void initInterrupts(){
691 /* IMPORTANT : Set the s12x vector base register (Thanks Karsten!!) */
692 IVBR = 0xF7; /* Without this the interrupts will never find your code! */
694 /* Set up the Real Time Interrupt */
695 RTICTL = 0x81; /* 0b_1000_0001 0.125ms/125us period http://www.google.com/search?hl=en&safe=off&q=1+%2F+%2816MHz+%2F+%282+*+10%5E3%29+%29&btnG=Search */
696 // RTICTL = 0xF9; /* 0b_1111_1001 0.125s/125ms period http://www.google.com/search?hl=en&safe=off&q=1+%2F+%2816MHz+%2F+%282*10%5E6%29+%29&btnG=Search */
697 CRGINT |= 0x80; /* Enable the RTI */
698 CRGFLG = 0x80; /* Clear the RTI flag */
700 #ifndef NO_INIT
701 // set up port H for testing
702 PPSH = ZEROS; // falling edge/pull up for all
703 PIEH = ONES; // enable all pins interrupts
704 PIFH = ONES; // clear all port H interrupt flags
705 #endif
707 // TODO set up irq and xirq for testing
708 // IRQCR for IRQ
711 /* VReg API setup (only for wait mode? i think so) */
712 // VREGAPIR = 0x09C3; /* For 500ms period : (500ms - 0.2ms) / 0.2ms = 0b100111000011 = 2499 */
713 // VREGAPICL = 0x02; /* Enable the interrupt */
714 // VREGAPICL = 0x04; /* Start the counter running */
715 /* 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 */
717 /* LVI Low Voltage Interrupt enable */
718 VREGCTRL = 0x02; // Counts bad power events for diagnosis reasons