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