Split IO init out into three chunks and reorder appropriately.
[freeems-vanilla.git] / src / init.c
blobdfb70041f856ee6e7678f31b7a369463c4683b37
1 /* FreeEMS - the open source engine management system
3 * Copyright 2008-2012 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
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
43 #define INIT_C
44 #include "inc/freeEMS.h"
45 #include "inc/interrupts.h"
46 #include "inc/utils.h"
47 #include "inc/commsISRs.h"
48 #include "inc/pagedLocationBuffers.h"
49 #include "inc/init.h"
50 #include "inc/decoderInterface.h"
51 #include "inc/xgateVectors.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 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 */
82 #ifdef XGATE
83 #include "xgateInit.c"
84 #endif
87 /** @brief Set the PLL clock frequency
89 * Set the Phase Locked Loop to our desired frequency (80MHz) and switch to
90 * using it for clock (40MHz bus speed).
92 void initPLL(){
93 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) */
94 PLLCTL &= PLLOFF; /* Turn the PLL device off to adjust its speed (on by default out of reset) */
95 REFDV = PLLDIVISOR; /* 16MHz / (3 + 1) = 4MHz Bus frequency */
96 SYNR = PLLMULTIPLIER; /* 4MHz * (9 + 1) = 40MHz Bus frequency */
97 PLLCTL |= PLLON; /* Turn the PLL device back on again at 80MHz */
99 while (!(CRGFLG & PLLLOCK)){
100 /* Do nothing while we wait till the PLL loop locks onto the target frequency. */
101 /* Target frequency is given by (2 * (crystal frequency / (REFDV + 1)) * (SYNR + 1)) */
102 /* Bus frequency is half PLL frequency and given by ((crystal frequency / (REFDV + 1)) * (SYNR + 1)) */
105 CLKSEL = PLLSELON; /* Switches to PLL clock for internal bus frequency */
106 /* from MC9S12XDP512V2.pdf Section 2.4.1.1.2 page 101 Third paragraph */
107 /* "This takes a MAXIMUM of 4 OSCCLK clock cylces PLUS 4 PLL clock cycles" */
108 /* "During this time ALL clocks freeze, and CPU activity ceases" */
109 /* Therefore there is no point waiting for this to occur, we already are... */
113 /// Set up the analogue inputs
114 void initADC(){
115 // Currently not true, and may never be: TODO When the port something uses
116 // is changed via the tuning interface, the configuration will be done on
117 // 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 /* Digital input buffers on the ATD channels are off by default, leave them this way! */
121 //ATD0DIEN = ZEROS; /* You are out of your mind if you waste this on digital Inputs */
122 //ATD1DIEN0 = ZEROS; /* You are out of your mind if you waste this on digital Inputs (NOT-bonded, can't use) */
123 //ATD1DIEN1 = ZEROS; /* You are out of your mind if you waste this on digital Inputs */
125 /* And configure them all for analog input */
126 //ATD0CTL0 = 0x07/* With mult turned on this is required to be set to cause wrap around, but is correct out of reset */
127 //ATD0CTL1 = 0x07/* Trigger and interrupt configuration, unused for now. */
128 ATD0CTL2 = 0xC0; /* Turns on the ADC block and sets auto flag clear */
129 ATD0CTL3 = 0x40; /* Set sequence length = 8 */
130 ATD0CTL4 = 0x73; /* Set the ADC clock and sample period for best accuracy */
131 ATD0CTL5 = 0xB0; /* Sets justification to right, multiplex and scan all channels. Writing to this causes conversions to begin */
133 /* And configure them all for analog input */
134 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 */
135 //ATD0CTL1 = 0x07/* Trigger and interrupt configuration, unused for now. */
136 ATD1CTL2 = 0xC0; /* Turns on the ADC block and sets auto flag clear */
137 ATD1CTL3 = 0x40; /* Set sequence length = 8 */
138 ATD0CTL4 = 0x73; /* Set the ADC clock and sample period for best accuracy */
139 ATD0CTL5 = 0xB0; /* Sets justification to right, multiplex and scan all channels. Writing to this causes conversions to begin */
143 /// Set up the PWM module from configuration
144 void initPWM(){
145 /* TODO PWM channel concatenation for high resolution */
146 // join channel pairs together here (needs 16 bit regs enabled too)
147 /* TODO Initialise pwm channels with frequency, and initial duty for real use */
148 // initial PWM settings for testing
150 PWMPER0 = fixedConfigs2.inputOutputSettings.PWMPeriod0;
151 PWMPER1 = fixedConfigs2.inputOutputSettings.PWMPeriod1;
152 PWMPER2 = fixedConfigs2.inputOutputSettings.PWMPeriod2;
153 PWMPER3 = fixedConfigs2.inputOutputSettings.PWMPeriod3;
154 PWMPER4 = fixedConfigs2.inputOutputSettings.PWMPeriod4;
155 PWMPER5 = fixedConfigs2.inputOutputSettings.PWMPeriod5;
156 PWMPER6 = fixedConfigs2.inputOutputSettings.PWMPeriod6;
157 PWMPER7 = fixedConfigs2.inputOutputSettings.PWMPeriod7;
159 PWMDTY0 = fixedConfigs2.inputOutputSettings.PWMInitialDuty0;
160 PWMDTY1 = fixedConfigs2.inputOutputSettings.PWMInitialDuty1;
161 PWMDTY2 = fixedConfigs2.inputOutputSettings.PWMInitialDuty2;
162 PWMDTY3 = fixedConfigs2.inputOutputSettings.PWMInitialDuty3;
163 PWMDTY4 = fixedConfigs2.inputOutputSettings.PWMInitialDuty4;
164 PWMDTY5 = fixedConfigs2.inputOutputSettings.PWMInitialDuty5;
165 PWMDTY6 = fixedConfigs2.inputOutputSettings.PWMInitialDuty6;
166 PWMDTY7 = fixedConfigs2.inputOutputSettings.PWMInitialDuty7;
168 PWMCLK = fixedConfigs2.inputOutputSettings.PWMClock;
169 PWMPRCLK = fixedConfigs2.inputOutputSettings.PWMClockPrescaler;
170 PWMSCLA = fixedConfigs2.inputOutputSettings.PWMScalerA;
171 PWMSCLB = fixedConfigs2.inputOutputSettings.PWMScalerB;
172 PWMPOL = fixedConfigs2.inputOutputSettings.PWMPolarity;
173 PWMCAE = fixedConfigs2.inputOutputSettings.PWMCenterAlign;
174 PWMCTL = fixedConfigs2.inputOutputSettings.PWMControl & 0xF0; // Disallow access to power saving and reserved bits
175 PWME = fixedConfigs2.inputOutputSettings.PWMEnable; // MUST be done after concatenation with PWMCTL
179 /// Set up all the pin states as per configuration, but protect key states.
180 void initGPIO(){
181 // Set the initial pin state of pins configured as output
182 PORTA = fixedConfigs2.inputOutputSettings.PortInitialValueA | BIT6 | BIT7; // Mask the fuel pump relay and CEL pins on
183 PORTB = fixedConfigs2.inputOutputSettings.PortInitialValueB;
184 PORTC = fixedConfigs2.inputOutputSettings.PortInitialValueC;
185 PORTD = fixedConfigs2.inputOutputSettings.PortInitialValueD;
186 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.
187 PORTH = fixedConfigs2.inputOutputSettings.PortInitialValueH;
188 PORTJ = fixedConfigs2.inputOutputSettings.PortInitialValueJ;
189 PORTK = fixedConfigs2.inputOutputSettings.PortInitialValueK;
190 PORTM = fixedConfigs2.inputOutputSettings.PortInitialValueM;
191 PORTP = fixedConfigs2.inputOutputSettings.PortInitialValueP;
192 PORTS = fixedConfigs2.inputOutputSettings.PortInitialValueS | 0x02; // Mask the SCI0 TX pin to high between transmissions!
193 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.
194 /* AD0PT1 You are out of your mind if you waste this on digital Inputs */
195 /* AD1PT1 You are out of your mind if you waste this on digital Inputs */
197 // Initialise the Data Direction Registers
198 DDRA = fixedConfigs2.inputOutputSettings.PortDirectionA | BIT6 | BIT7; // Mask the fuel pump relay and CEL pins as outputs
199 DDRB = fixedConfigs2.inputOutputSettings.PortDirectionB;
200 DDRC = fixedConfigs2.inputOutputSettings.PortDirectionC;
201 DDRD = fixedConfigs2.inputOutputSettings.PortDirectionD;
202 DDRE = fixedConfigs2.inputOutputSettings.PortDirectionE; // No need to mask off bits 0 and 1, they have no effect and are always inputs.
203 DDRH = fixedConfigs2.inputOutputSettings.PortDirectionH;
204 DDRJ = fixedConfigs2.inputOutputSettings.PortDirectionJ;
205 DDRK = fixedConfigs2.inputOutputSettings.PortDirectionK;
206 DDRM = fixedConfigs2.inputOutputSettings.PortDirectionM;
207 DDRP = fixedConfigs2.inputOutputSettings.PortDirectionP;
208 DDRS = fixedConfigs2.inputOutputSettings.PortDirectionS & 0xFE; // Mask the SCI0 RX pin as input between receiving
209 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.
210 /* AD0DDR1 You are out of your mind if you waste this on digital Inputs */
211 /* AD1DDR1 You are out of your mind if you waste this on digital Inputs */
215 /** @brief Buffer lookup tables addresses
217 * Save pointers to the lookup tables which live in paged flash.
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 void initFuelAddresses(){
232 /* Setup addresses within the page to avoid warnings */
233 VETableMainFlashLocation = (void*)&VETableMainFlash;
234 VETableSecondaryFlashLocation = (void*)&VETableSecondaryFlash;
235 VETableTertiaryFlashLocation = (void*)&VETableTertiaryFlash;
236 LambdaTableFlashLocation = (void*)&LambdaTableFlash;
237 VETableMainFlash2Location = (void*)&VETableMainFlash2;
238 VETableSecondaryFlash2Location = (void*)&VETableSecondaryFlash2;
239 VETableTertiaryFlash2Location = (void*)&VETableTertiaryFlash2;
240 LambdaTableFlash2Location = (void*)&LambdaTableFlash2;
244 /** @brief Copy fuel tables to RAM
246 * Initialises the fuel tables in RAM by copying them up from flash.
248 void initPagedRAMFuel(void){
249 /* Copy the tables from flash to RAM */
250 RPAGE = RPAGE_FUEL_ONE;
251 memcpy((void*)&TablesA, VETableMainFlashLocation, sizeof(mainTable));
252 memcpy((void*)&TablesB, VETableSecondaryFlashLocation, sizeof(mainTable));
253 memcpy((void*)&TablesC, VETableTertiaryFlashLocation, sizeof(mainTable));
254 memcpy((void*)&TablesD, LambdaTableFlashLocation, sizeof(mainTable));
255 RPAGE = RPAGE_FUEL_TWO;
256 memcpy((void*)&TablesA, VETableMainFlash2Location, sizeof(mainTable));
257 memcpy((void*)&TablesB, VETableSecondaryFlash2Location, sizeof(mainTable));
258 memcpy((void*)&TablesC, VETableTertiaryFlash2Location, sizeof(mainTable));
259 memcpy((void*)&TablesD, LambdaTableFlash2Location, sizeof(mainTable));
263 /** @brief Buffer timing tables addresses
265 * Save pointers to the timing tables which live in paged flash.
267 void initTimingAddresses(){
268 /* Setup addresses within the page to avoid warnings */
269 IgnitionAdvanceTableMainFlashLocation = (void*)&IgnitionAdvanceTableMainFlash;
270 IgnitionAdvanceTableSecondaryFlashLocation = (void*)&IgnitionAdvanceTableSecondaryFlash;
271 InjectionAdvanceTableMainFlashLocation = (void*)&InjectionAdvanceTableMainFlash;
272 InjectionAdvanceTableSecondaryFlashLocation = (void*)&InjectionAdvanceTableSecondaryFlash;
273 IgnitionAdvanceTableMainFlash2Location = (void*)&IgnitionAdvanceTableMainFlash2;
274 IgnitionAdvanceTableSecondaryFlash2Location = (void*)&IgnitionAdvanceTableSecondaryFlash2;
275 InjectionAdvanceTableMainFlash2Location = (void*)&InjectionAdvanceTableMainFlash2;
276 InjectionAdvanceTableSecondaryFlash2Location = (void*)&InjectionAdvanceTableSecondaryFlash2;
280 /** @brief Copy timing tables to RAM
282 * Initialises the timing tables in RAM by copying them up from flash.
284 void initPagedRAMTime(){
285 /* Copy the tables from flash to RAM */
286 RPAGE = RPAGE_TIME_ONE;
287 memcpy((void*)&TablesA, IgnitionAdvanceTableMainFlashLocation, sizeof(mainTable));
288 memcpy((void*)&TablesB, IgnitionAdvanceTableSecondaryFlashLocation, sizeof(mainTable));
289 memcpy((void*)&TablesC, InjectionAdvanceTableMainFlashLocation, sizeof(mainTable));
290 memcpy((void*)&TablesD, InjectionAdvanceTableSecondaryFlashLocation, sizeof(mainTable));
291 RPAGE = RPAGE_TIME_TWO;
292 memcpy((void*)&TablesA, IgnitionAdvanceTableMainFlash2Location, sizeof(mainTable));
293 memcpy((void*)&TablesB, IgnitionAdvanceTableSecondaryFlash2Location, sizeof(mainTable));
294 memcpy((void*)&TablesC, InjectionAdvanceTableMainFlash2Location, sizeof(mainTable));
295 memcpy((void*)&TablesD, InjectionAdvanceTableSecondaryFlash2Location, sizeof(mainTable));
299 /** @brief Buffer tunable tables addresses
301 * Save pointers to the tunable tables which live in paged flash and their
302 * sub-sections too.
304 void initTunableAddresses(){
305 /* Setup addresses within the page to avoid warnings */
306 SmallTablesAFlashLocation = (void*)&SmallTablesAFlash;
307 SmallTablesBFlashLocation = (void*)&SmallTablesBFlash;
308 SmallTablesCFlashLocation = (void*)&SmallTablesCFlash;
309 SmallTablesDFlashLocation = (void*)&SmallTablesDFlash;
310 SmallTablesAFlash2Location = (void*)&SmallTablesAFlash2;
311 SmallTablesBFlash2Location = (void*)&SmallTablesBFlash2;
312 SmallTablesCFlash2Location = (void*)&SmallTablesCFlash2;
313 SmallTablesDFlash2Location = (void*)&SmallTablesDFlash2;
315 /* TablesA */
316 dwellDesiredVersusVoltageTableLocation = (void*)&SmallTablesAFlash.dwellDesiredVersusVoltageTable;
317 dwellDesiredVersusVoltageTable2Location = (void*)&SmallTablesAFlash2.dwellDesiredVersusVoltageTable;
318 injectorDeadTimeTableLocation = (void*)&SmallTablesAFlash.injectorDeadTimeTable;
319 injectorDeadTimeTable2Location = (void*)&SmallTablesAFlash2.injectorDeadTimeTable;
320 postStartEnrichmentTableLocation = (void*)&SmallTablesAFlash.postStartEnrichmentTable;
321 postStartEnrichmentTable2Location = (void*)&SmallTablesAFlash2.postStartEnrichmentTable;
322 engineTempEnrichmentTableFixedLocation = (void*)&SmallTablesAFlash.engineTempEnrichmentTableFixed;
323 engineTempEnrichmentTableFixed2Location = (void*)&SmallTablesAFlash2.engineTempEnrichmentTableFixed;
324 primingVolumeTableLocation = (void*)&SmallTablesAFlash.primingVolumeTable;
325 primingVolumeTable2Location = (void*)&SmallTablesAFlash2.primingVolumeTable;
326 engineTempEnrichmentTablePercentLocation = (void*)&SmallTablesAFlash.engineTempEnrichmentTablePercent;
327 engineTempEnrichmentTablePercent2Location = (void*)&SmallTablesAFlash2.engineTempEnrichmentTablePercent;
328 dwellVersusRPMTableLocation = (void*)&SmallTablesAFlash.dwellVersusRPMTable;
329 dwellVersusRPMTable2Location = (void*)&SmallTablesAFlash2.dwellVersusRPMTable;
331 /* TablesB */
332 loggingSettingsLocation = (void*)&SmallTablesBFlash.loggingSettings;
333 loggingSettings2Location = (void*)&SmallTablesBFlash2.loggingSettings;
334 perCylinderFuelTrimsLocation = (void*)&SmallTablesBFlash.perCylinderFuelTrims;
335 perCylinderFuelTrims2Location = (void*)&SmallTablesBFlash2.perCylinderFuelTrims;
337 /* TablesC */
338 // TODO
340 /* TablesD */
341 // TODO
343 /* filler defs */
344 fillerALocation = (void*)&SmallTablesAFlash.filler;
345 fillerA2Location = (void*)&SmallTablesAFlash2.filler;
346 fillerBLocation = (void*)&SmallTablesBFlash.filler;
347 fillerB2Location = (void*)&SmallTablesBFlash2.filler;
348 fillerCLocation = (void*)&SmallTablesCFlash.filler;
349 fillerC2Location = (void*)&SmallTablesCFlash2.filler;
350 fillerDLocation = (void*)&SmallTablesDFlash.filler;
351 fillerD2Location = (void*)&SmallTablesDFlash2.filler;
358 void initPagedRAMTune(){
359 /* Copy the tables from flash to RAM */
360 RPAGE = RPAGE_TUNE_ONE;
361 memcpy((void*)&TablesA, SmallTablesAFlashLocation, sizeof(mainTable));
362 memcpy((void*)&TablesB, SmallTablesBFlashLocation, sizeof(mainTable));
363 memcpy((void*)&TablesC, SmallTablesCFlashLocation, sizeof(mainTable));
364 memcpy((void*)&TablesD, SmallTablesDFlashLocation, sizeof(mainTable));
365 RPAGE = RPAGE_TUNE_TWO;
366 // &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& WARNING &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //
367 // You will get garbage if you use table switching at this time!!! //
368 // XGATE code being run from this region temporarily!!! //
369 // Writing to these tables WILL corrupt XGATE code/kill your engine! //
370 // &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& WARNING &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //
371 //memcpy(xgateSchedRAMAddress, xgateSchedFlashAddress, (xgateSchedEnd - xgateSched));
372 //memcpy(xgateInjectorsOnRAMAddress, xgateInjectorsOnFlashAddress, (xgateInjectorsOnEnd - xgateInjectorsOn));
373 //memcpy(xgateInjectorsOffRAMAddress, xgateInjectorsOffFlashAddress, (xgateInjectorsOffEnd - xgateInjectorsOff));
374 // memcpy((void*)&TablesA, SmallTablesAFlash2Location, sizeof(mainTable));
375 // memcpy((void*)&TablesB, SmallTablesBFlash2Location, sizeof(mainTable));
376 // memcpy((void*)&TablesC, SmallTablesCFlash2Location, sizeof(mainTable));
377 // memcpy((void*)&TablesD, SmallTablesDFlash2Location, sizeof(mainTable));
381 /** @brief Buffer addresses of paged data
383 * Save the paged memory addresses to variables such that we can access them
384 * from another paged block with no warnings.
386 * If you try to access paged data from the wrong place you get nasty warnings.
387 * These calls to functions that live in the same page that they are addressing
388 * prevent those warnings.
390 * @note Many thanks to Jean Bélanger for the inspiration/idea to do this!
392 void initAllPagedAddresses(){
393 /* Setup pointers to lookup tables */
394 initLookupAddresses();
395 /* Setup pointers to the main tables */
396 initFuelAddresses();
397 initTimingAddresses();
398 initTunableAddresses();
402 /** @brief Copies paged flash to RAM
404 * Take the tables and config from flash up to RAM to allow live tuning.
406 * For the main tables and other paged config we need to adjust
407 * the RPAGE value to the appropriate one before copying up.
409 * This function is simply a delegator to the ones for each flash page. Each
410 * one lives in the same paged space as the data it is copying up.
412 void initAllPagedRAM(){
413 /* Setup the flash block pointers before copying flash to RAM using them */
414 initAllPagedAddresses();
416 /* Copy the tables up to their paged RAM blocks through the window from flash */
417 initPagedRAMFuel();
418 initPagedRAMTime();
419 initPagedRAMTune();
421 /* Default to page one for now, perhaps read the configured port straight out of reset in future? TODO */
422 setupPagedRAM(TRUE); // probably something like (PORTA & TableSwitchingMask)
426 /* Initialise and set up all running variables that require a non-zero start value here */
427 /* All other variables are initialised to zero by the premain built in code */
428 void initVariables(){
429 /* And the opposite for the other halves */
430 CoreVars = &CoreVars0;
431 DerivedVars = &DerivedVars0;
432 ADCBuffers = &ADCBuffers0;
433 ADCBuffersRecord = &ADCBuffers1;
435 ticksPerDegree = &ticksPerDegree0; // TODO temp, remove, maybe
436 ticksPerDegreeRecord = &ticksPerDegree1; // TODO temp, remove, maybe
438 /* Setup the pointers to the registers for fueling use, this does NOT work if done in global.c, I still don't know why. */
439 injectorMainTimeRegisters[0] = TC2_ADDR;
440 injectorMainTimeRegisters[1] = TC3_ADDR;
441 injectorMainTimeRegisters[2] = TC4_ADDR;
442 injectorMainTimeRegisters[3] = TC5_ADDR;
443 injectorMainTimeRegisters[4] = TC6_ADDR;
444 injectorMainTimeRegisters[5] = TC7_ADDR;
445 injectorMainControlRegisters[0] = TCTL2_ADDR;
446 injectorMainControlRegisters[1] = TCTL2_ADDR;
447 injectorMainControlRegisters[2] = TCTL1_ADDR;
448 injectorMainControlRegisters[3] = TCTL1_ADDR;
449 injectorMainControlRegisters[4] = TCTL1_ADDR;
450 injectorMainControlRegisters[5] = TCTL1_ADDR;
452 coreStatusA |= FUEL_PUMP_PRIME;
454 // Initial state is NOT to fire... can be configured by scheduler if required.
455 outputEventInputEventNumbers[0] = 0xFF;
456 outputEventInputEventNumbers[1] = 0xFF;
457 outputEventInputEventNumbers[2] = 0xFF;
458 outputEventInputEventNumbers[3] = 0xFF;
459 outputEventInputEventNumbers[4] = 0xFF;
460 outputEventInputEventNumbers[5] = 0xFF;
461 outputEventInputEventNumbers[6] = 0xFF;
462 outputEventInputEventNumbers[7] = 0xFF;
463 outputEventInputEventNumbers[8] = 0xFF;
464 outputEventInputEventNumbers[9] = 0xFF;
465 outputEventInputEventNumbers[10] = 0xFF;
466 outputEventInputEventNumbers[11] = 0xFF;
467 outputEventInputEventNumbers[12] = 0xFF;
468 outputEventInputEventNumbers[13] = 0xFF;
469 outputEventInputEventNumbers[14] = 0xFF;
470 outputEventInputEventNumbers[15] = 0xFF;
471 outputEventInputEventNumbers[16] = 0xFF;
472 outputEventInputEventNumbers[17] = 0xFF;
473 outputEventInputEventNumbers[18] = 0xFF;
474 outputEventInputEventNumbers[19] = 0xFF;
475 outputEventInputEventNumbers[20] = 0xFF;
476 outputEventInputEventNumbers[21] = 0xFF;
477 outputEventInputEventNumbers[22] = 0xFF;
478 outputEventInputEventNumbers[23] = 0xFF;
480 // 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
484 /** @brief Flash module setup
486 * Initialise configuration registers for the flash module to allow burning of
487 * non-volatile flash memory from within the firmware.
489 * The FCLKDIV register can be written once only after reset, thus the lower
490 * seven bits and the PRDIV8 bit must be set at the same time.
492 * We want to put the flash clock as high as possible between 150kHz and 200kHz
494 * The oscillator clock is 16MHz and because that is above 12.8MHz we will set
495 * the PRDIV8 bit to further divide by 8 bits as per the manual.
497 * 16MHz = 16000KHz which pre-divided by 8 is 2000kHz
499 * 2000kHz / 200kHz = 10 thus we want to set the divide register to 10 or 0x0A
501 * Combining 0x0A with PRDIV8 gives us 0x4A (0x0A | 0x40 = 0x4A) so we use that
503 * @author Sean Keys
505 * @note If you use a different crystal lower than 12.8MHz PRDIV8 should not be set.
507 * @warning If the frequency you end up with is outside 150kHz - 200kHz you may
508 * damage your flash module or get corrupt data written to it.
510 void initFlash(){
511 FCLKDIV = 0x4A; /* Set the flash clock frequency */
512 FPROT = 0xFF; /* Disable all flash protection */
513 FSTAT = FSTAT | (PVIOL | ACCERR); /* Clear any errors */
517 /* Set up the timer module and its various interrupts */
518 void initECTTimer(){
519 /** @todo TODO Take the configuration from the decoder (as is) and mask it such that it does not affect the 6 other channels.
520 * Take the the number of output channels required from configuration and configure that many as outputs
521 * Configure the balance in whatever way is specified in the GPIO configuration - allow second input to be reused as GPI only.
523 * This stuff affects:
524 * - TIE = 0x01 or 0x03, only. OC channels enabled as required and IC only for RPM/position.
525 * - TIOS = nope, always 0xFC for 2 IC and 6 OC
526 * - TCTL (1,2,3,4) 4 = 0x0? mask off high 4 bits and allow low 4 to come from decoder config/init
527 * - PORTT = zeros, with balance from config
528 * - DDRT = 0,1 inputs, or if unused by decoder, from config
533 // TODO rearrange the order of this stuff and pull enable and interrupt enable out to the last function call of 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 // DLYCT = 0xFF; /* max noise filtering as experiment for volvo this will come from flash config */ // just hiding a wiring/circuit issue...
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://duckduckgo.com/?q=1+%2F+%2840MHz+%2F+32+%29 */
551 /* http://duckduckgo.com/?q=%281+%2F+%2840MHz+%2F+32+%29%29+*+2^16 */
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 // PTMCPSR = 0xFF // 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
569 decoderInitPreliminary();
573 /* Configure the PIT timers for their various uses. */
574 void initPITTimer(){
575 // // set micro periods
576 // PITMTLD0 = 0x1F; /* 32 prescaler gives 0.8uS resolution and max period of 52.4288ms measured */
577 // PITMTLD1 = 0x1F; /* ditto */
578 // /* http://duckduckgo.com/?q=1+%2F+%2840MHz+%2F+32+%29 Exactly the same as for ECT */
580 // // set timers running
581 // PITLD0 = dwellPeriod;
582 // // enable module
583 // PITCFLMT = 0x80;
584 // // enable channels
585 // //PITCE = 0x03;
586 // // enable interrupt
587 // PITINTE = 0x01;
588 // // clear flags
589 // //PITFLT = ONES;
592 /* Setup the sci module(s) that we need to use. */
593 void initSCIStuff(){
594 /* The alternative register set selector defaults to zero */
596 // set the baud/data speed
597 SCI0BD = fixedConfigs1.serialSettings.baudDivisor;
599 // etc
601 /* Switch to alternative register set? */
603 // etc
605 /* Switch back again? */
608 * 0 = LOOPS (normal two wire operation)
609 * 0 = SCISWAI (Wait mode on)
610 * 0 = RSRC (if loops=1, int/ext wiring)
611 * 1 = M MODE (9 bit operation)
612 * 0 = WAKE (idle line wakeup)
613 * 0 = ILT (idle line type count start pos)
614 * 1 = PE (parity on)
615 * 1 = PT (odd parity)
617 * 0x13 = ODD (default)
618 * 0x12 = EVEN
619 * 0x00 = NONE
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 * 0 = TE (transmit disabled)
629 * 1 = RE (receive enabled)
630 * 0 = RWU (rx wake up normal)
631 * 0 = SBK (send break off)
633 SCI0CR2 = 0x24;
636 /* TODO Load and calculate all configuration data required to run */
637 void initConfiguration(){
638 // // 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.
641 /* Add in tunable physical parameters at boot time TODO move to init.c TODO duplicate for secondary fuel? or split somehow?
642 *nstant = ((masterConst * perCylinderVolume) / (stoichiometricAFR * injectorFlow));
643 *nstant = ((139371764 * 16384) / (15053 * 4096));
644 * OR
645 *nstant = ((masterConst / injectorFlow) * perCylinderVolume) / stoichiometricAFR;
646 *nstant = ((139371764 / 4096) * 16384) / 15053;
647 * http://duckduckgo.com/?q=%28%28139371764++%2F+4096%29+*+16384%29+%2F+15053 */
648 bootFuelConst = ((unsigned long)(masterFuelConstant / fixedConfigs1.engineSettings.injectorFlow) * fixedConfigs1.engineSettings.perCylinderVolume) / fixedConfigs1.engineSettings.stoichiometricAFR;
650 /* The ADC range used to generate TPS percentage */
651 TPSADCRange = fixedConfigs2.sensorRanges.TPSMaximumADC - fixedConfigs2.sensorRanges.TPSMinimumADC;
655 /* Set up all the remaining interrupts */
656 void initInterrupts(){
657 /* IMPORTANT : Set the s12x vector base register (Thanks Karsten!!) */
658 IVBR = 0xF7; /* Without this the interrupts will never find your code! */
660 /* Set up the Real Time Interrupt */
661 RTICTL = 0x81; /* 0b_1000_0001 0.125ms/125us period http://duckduckgo.com/?q=1+%2F+%2816MHz+%2F+%282+*+10^3%29+%29 */
662 // RTICTL = 0xF9; /* 0b_1111_1001 0.125s/125ms period http://duckduckgo.com/?q=1+%2F+%2816MHz+%2F+%282*10^6%29+%29 */
663 CRGINT |= 0x80; /* Enable the RTI */
664 CRGFLG = 0x80; /* Clear the RTI flag */
666 // set up port H for testing
667 PPSH = ZEROS; // falling edge/pull up for all
668 PIEH = ONES; // enable all pins interrupts
669 PIFH = ONES; // clear all port H interrupt flags
671 // TODO set up irq and xirq for testing
672 // IRQCR for IRQ
674 /* VReg API setup (only for wait mode? i think so) */
675 // VREGAPIR = 0x09C3; /* For 500ms period : (500ms - 0.2ms) / 0.2ms = 0b100111000011 = 2499 */
676 // VREGAPICL = 0x02; /* Enable the interrupt */
677 // VREGAPICL = 0x04; /* Start the counter running */
678 /* 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 */
680 /* LVI Low Voltage Interrupt enable */
681 VREGCTRL = 0x02; // Counts bad power events for diagnosis reasons