PageRenderTime 2ms CodeModel.GetById 2ms app.highlight 45ms RepoModel.GetById 2ms app.codeStats 0ms

/src/main/init.c

https://github.com/fredcooke/freeems-vanilla
C | 699 lines | 306 code | 92 blank | 301 comment | 2 complexity | 713cc8e4c6ab34200daebe67961956ea MD5 | raw file
  1/* FreeEMS - the open source engine management system
  2 *
  3 * Copyright 2008-2013 Fred Cooke
  4 *
  5 * This file is part of the FreeEMS project.
  6 *
  7 * FreeEMS software is free software: you can redistribute it and/or modify
  8 * it under the terms of the GNU General Public License as published by
  9 * the Free Software Foundation, either version 3 of the License, or
 10 * (at your option) any later version.
 11 *
 12 * FreeEMS software is distributed in the hope that it will be useful,
 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15 * GNU General Public License for more details.
 16 *
 17 * You should have received a copy of the GNU General Public License
 18 * along with any FreeEMS software.  If not, see http://www.gnu.org/licenses/
 19 *
 20 * We ask that if you make any changes to this file you email them upstream to
 21 * us at admin(at)diyefi(dot)org or, even better, fork the code on github.com!
 22 *
 23 * Thank you for choosing FreeEMS to run your engine!
 24 */
 25
 26
 27/** @file
 28 *
 29 * @brief Initialise the devices state
 30 *
 31 * Setup, configure and initialise all aspects of the devices state including
 32 * but not limited to:
 33 *
 34 * - Setup the bus clock speed
 35 * - Configuration based variable initialisation
 36 * - I/O register behaviour and initial state
 37 * - Configure and enable interrupts
 38 * - Copy tunable data up to RAM from flash
 39 * - Configure peripheral module behaviour
 40 */
 41
 42
 43#define INIT_C
 44#include "inc/freeEMS.h"
 45#include "inc/interrupts.h"
 46#include "inc/utils.h"
 47#include "inc/commsISRs.h"
 48#include "inc/pagedLocationBuffers.h"
 49#include "inc/init.h"
 50#include "inc/decoderInterface.h"
 51#include "inc/xgateVectors.h"
 52#include <string.h>
 53
 54
 55/** @brief The main top level init
 56 *
 57 * The main init function to be called from main.c before entering the main
 58 * loop. This function is simply a delegator to the finer grained special
 59 * purpose init functions.
 60 */
 61void init(){
 62	ATOMIC_START();         /* Disable ALL interrupts while we configure the board ready for use */
 63	initPLL();              /* Set up the PLL and use it */
 64	initGPIO();
 65	initPWM();
 66	initADC();
 67	initAllPagedRAM();      /* Copy table and config blocks of data from flash to the paged RAM blocks for fast data lookup */
 68	initVariables();        /* Initialise the rest of the running variables etc */
 69	initFlash();            /* TODO, finalise this */
 70	initECTTimer();         /* TODO move this to inside config in an organised way. Set up the timer module and its various aspects */
 71//	initPITTimer();         /* TODO ditto... */
 72	initSCIStuff();         /* Setup the sci module(s) that we will use. */
 73	initConfiguration();    /* TODO Set user/feature/config up here! */
 74#ifdef XGATE
 75	initXgate();            /* Fred is a legend, for good reason as of now */
 76#endif
 77	initInterrupts();       /* still last, reset timers, enable interrupts here TODO move this to inside config in an organised way. Set up the rest of the individual interrupts */
 78	ATOMIC_END();           /* Re-enable any configured interrupts */
 79}
 80
 81
 82#ifdef XGATE
 83#include "xgateInit.c"
 84#endif
 85
 86
 87/** @brief Set the PLL clock frequency
 88 *
 89 * Set the Phase Locked Loop to our desired frequency (80MHz) and enable PLL.
 90 */
 91void initPLL(){
 92	CLKSEL &= PLLSELOFF;  /* Switches to base external OSCCLK to ensure PLL is not being used (off out of reset, but not sure if the monitor turns it on before passing control or not) */
 93	PLLCTL &= PLLOFF;     /* Turn the PLL device off to adjust its speed (on by default out of reset) */
 94	REFDV = PLLDIVISOR;   /* 16MHz / (3 + 1) = 4MHz Bus frequency */
 95	SYNR = PLLMULTIPLIER; /* 4MHz * (9 + 1) = 40MHz Bus frequency */
 96	PLLCTL |= PLLON;      /* Turn the PLL device back on again at 80MHz */
 97	enablePLL();
 98}
 99
100/** @brief Switch to using PLL
101 *
102 * Switch to using PLL for clock (40MHz bus speed). Interrupt is enabled elsewhere.
103 *
104 * Note: Requires busy wait loop, only for init and emergency use.
105 *
106 * @todo Should be limited, and have break out with error code and fall back mechanism.
107 */
108void enablePLL(){
109	while (!(CRGFLG & PLLLOCK)){
110		/* Do nothing while we wait till the PLL loop locks onto the target frequency. */
111		/* Target frequency is given by (2 * (crystal frequency / (REFDV + 1)) * (SYNR + 1)) */
112		/* Bus frequency is half PLL frequency and given by ((crystal frequency / (REFDV + 1)) * (SYNR + 1)) */
113	}
114
115	CLKSEL = PLLSEL; /* Switches to PLL clock for internal bus frequency        */
116	/* from MC9S12XDP512V2.pdf Section 2.4.1.1.2 page 101 Third paragraph       */
117	/* "This takes a MAXIMUM of 4 OSCCLK clock cylces PLUS 4 PLL clock cycles"  */
118	/* "During this time ALL clocks freeze, and CPU activity ceases"            */
119	/* Therefore there is no point waiting for this to occur, we already are... */
120}
121
122
123/// Set up the analogue inputs
124void initADC(){
125	// Currently not true, and may never be: TODO When the port something uses
126	// is changed via the tuning interface, the configuration will be done on
127	// the fly, and the value burned to flash such that next boot happens
128	// correctly and current running devices are used in that way.
129
130	/* Digital input buffers on the ATD channels are off by default, leave them this way! */
131	//ATD0DIEN = ZEROS; /* You are out of your mind if you waste this on digital Inputs */
132	//ATD1DIEN0 = ZEROS; /* You are out of your mind if you waste this on digital Inputs (NOT-bonded, can't use) */
133	//ATD1DIEN1 = ZEROS; /* You are out of your mind if you waste this on digital Inputs */
134
135	/* And configure them all for analog input */
136	//ATD0CTL0 = 0x07/* With mult turned on this is required to be set to cause wrap around, but is correct out of reset */
137	//ATD0CTL1 = 0x07/* Trigger and interrupt configuration, unused for now. */
138	ATD0CTL2 = 0xC0; /* Turns on the ADC block and sets auto flag clear */
139	ATD0CTL3 = 0x40; /* Set sequence length = 8 */
140	ATD0CTL4 = 0x73; /* Set the ADC clock and sample period for best accuracy */
141	ATD0CTL5 = 0xB0; /* Sets justification to right, multiplex and scan all channels. Writing to this causes conversions to begin */
142
143	/* And configure them all for analog input */
144	ATD1CTL0 = 0x07; /* TODO bring this out of config based on chip variant variable. Sets wrap on 8th ADC because we can't use the other 8 on 112 pin version */
145	//ATD0CTL1 = 0x07/* Trigger and interrupt configuration, unused for now. */
146	ATD1CTL2 = 0xC0; /* Turns on the ADC block and sets auto flag clear */
147	ATD1CTL3 = 0x40; /* Set sequence length = 8 */
148	ATD1CTL4 = 0x73; /* Set the ADC clock and sample period for best accuracy */
149	ATD1CTL5 = 0xB0; /* Sets justification to right, multiplex and scan all channels. Writing to this causes conversions to begin */
150}
151
152
153/// Set up the PWM module from configuration
154void initPWM(){
155	/* TODO PWM channel concatenation for high resolution */
156	// join channel pairs together here (needs 16 bit regs enabled too)
157	/* TODO Initialise pwm channels with frequency, and initial duty for real use */
158	// initial PWM settings for testing
159
160	PWMPER0 = fixedConfigs2.inputOutputSettings.PWMPeriod0;
161	PWMPER1 = fixedConfigs2.inputOutputSettings.PWMPeriod1;
162	PWMPER2 = fixedConfigs2.inputOutputSettings.PWMPeriod2;
163	PWMPER3 = fixedConfigs2.inputOutputSettings.PWMPeriod3;
164	PWMPER4 = fixedConfigs2.inputOutputSettings.PWMPeriod4;
165	PWMPER5 = fixedConfigs2.inputOutputSettings.PWMPeriod5;
166	PWMPER6 = fixedConfigs2.inputOutputSettings.PWMPeriod6;
167	PWMPER7 = fixedConfigs2.inputOutputSettings.PWMPeriod7;
168
169	PWMDTY0 = fixedConfigs2.inputOutputSettings.PWMInitialDuty0;
170	PWMDTY1 = fixedConfigs2.inputOutputSettings.PWMInitialDuty1;
171	PWMDTY2 = fixedConfigs2.inputOutputSettings.PWMInitialDuty2;
172	PWMDTY3 = fixedConfigs2.inputOutputSettings.PWMInitialDuty3;
173	PWMDTY4 = fixedConfigs2.inputOutputSettings.PWMInitialDuty4;
174	PWMDTY5 = fixedConfigs2.inputOutputSettings.PWMInitialDuty5;
175	PWMDTY6 = fixedConfigs2.inputOutputSettings.PWMInitialDuty6;
176	PWMDTY7 = fixedConfigs2.inputOutputSettings.PWMInitialDuty7;
177
178	PWMCLK   = fixedConfigs2.inputOutputSettings.PWMClock;
179	PWMPRCLK = fixedConfigs2.inputOutputSettings.PWMClockPrescaler;
180	PWMSCLA  = fixedConfigs2.inputOutputSettings.PWMScalerA;
181	PWMSCLB  = fixedConfigs2.inputOutputSettings.PWMScalerB;
182	PWMPOL   = fixedConfigs2.inputOutputSettings.PWMPolarity;
183	PWMCAE   = fixedConfigs2.inputOutputSettings.PWMCenterAlign;
184	PWMCTL   = fixedConfigs2.inputOutputSettings.PWMControl & 0xF0; // Disallow access to power saving and reserved bits
185	PWME     = fixedConfigs2.inputOutputSettings.PWMEnable; // MUST be done after concatenation with PWMCTL
186}
187
188
189/// Set up all the pin states as per configuration, but protect key states.
190void initGPIO(){
191	// Set the initial pin state of pins configured as output
192	PORTA = fixedConfigs2.inputOutputSettings.PortInitialValueA | BIT6 | BIT7; // Mask the fuel pump relay and CEL pins on
193	PORTB = fixedConfigs2.inputOutputSettings.PortInitialValueB;
194	PORTC = fixedConfigs2.inputOutputSettings.PortInitialValueC;
195	PORTD = fixedConfigs2.inputOutputSettings.PortInitialValueD;
196	PORTE = (fixedConfigs2.inputOutputSettings.PortInitialValueE | BIT7) & (NBIT5 & NBIT6); // 7 should be high, and 5 and 6 low, to reduce current draw. The rest don't matter. 0 and 1 are not outputs.
197	PORTH = fixedConfigs2.inputOutputSettings.PortInitialValueH;
198	PORTJ = fixedConfigs2.inputOutputSettings.PortInitialValueJ;
199	PORTK = fixedConfigs2.inputOutputSettings.PortInitialValueK;
200	PORTM = fixedConfigs2.inputOutputSettings.PortInitialValueM;
201	PORTP = fixedConfigs2.inputOutputSettings.PortInitialValueP;
202	PORTS = fixedConfigs2.inputOutputSettings.PortInitialValueS | 0x02; // Mask the SCI0 TX pin to high between transmissions!
203	PORTT = 0x00; // Set all ECT pins to off state, only matters for 2-7, and only if being used. TODO mask this dynamically based on decoder type and configured channels.
204	/* AD0PT1 You are out of your mind if you waste this on digital Inputs */
205	/* AD1PT1 You are out of your mind if you waste this on digital Inputs */
206
207	// Initialise the Data Direction Registers
208	DDRA = fixedConfigs2.inputOutputSettings.PortDirectionA | BIT6 | BIT7; // Mask the fuel pump relay and CEL pins as outputs
209	DDRB = fixedConfigs2.inputOutputSettings.PortDirectionB;
210	DDRC = fixedConfigs2.inputOutputSettings.PortDirectionC;
211	DDRD = fixedConfigs2.inputOutputSettings.PortDirectionD;
212	DDRE = fixedConfigs2.inputOutputSettings.PortDirectionE; // No need to mask off bits 0 and 1, they have no effect and are always inputs.
213	DDRH = fixedConfigs2.inputOutputSettings.PortDirectionH;
214	DDRJ = fixedConfigs2.inputOutputSettings.PortDirectionJ;
215	DDRK = fixedConfigs2.inputOutputSettings.PortDirectionK;
216	DDRM = fixedConfigs2.inputOutputSettings.PortDirectionM;
217	DDRP = fixedConfigs2.inputOutputSettings.PortDirectionP;
218	DDRS = fixedConfigs2.inputOutputSettings.PortDirectionS & 0xFE; // Mask the SCI0 RX pin as input between receiving
219	DDRT = 0xFC; // Set ECT pins 0,1 to IC and 2:7 to OC (8) TODO mask this dynamically based on decoder type and configured channels.
220	/* AD0DDR1 You are out of your mind if you waste this on digital Inputs */
221	/* AD1DDR1 You are out of your mind if you waste this on digital Inputs */
222}
223
224
225/** @brief Buffer lookup tables addresses
226 *
227 * Save pointers to the lookup tables which live in paged flash.
228 */
229void initLookupAddresses(){
230	IATTransferTableLocation = (void*)&IATTransferTable;
231	CHTTransferTableLocation = (void*)&CHTTransferTable;
232	MAFTransferTableLocation = (void*)&MAFTransferTable;
233	TestTransferTableLocation = (void*)&TestTransferTable;
234}
235
236
237/** @brief Buffer fuel tables addresses
238 *
239 * Save pointers to the fuel tables which live in paged flash.
240 */
241void initFuelAddresses(){
242	/* Setup addresses within the page to avoid warnings */
243	VETableMainFlashLocation       = (void*)&VETableMainFlash;
244	VETableSecondaryFlashLocation  = (void*)&VETableSecondaryFlash;
245	AirflowTableFlashLocation      = (void*)&AirflowTableFlash;
246	LambdaTableFlashLocation       = (void*)&LambdaTableFlash;
247	VETableMainFlash2Location      = (void*)&VETableMainFlash2;
248	VETableSecondaryFlash2Location = (void*)&VETableSecondaryFlash2;
249	AirflowTableFlash2Location     = (void*)&AirflowTableFlash2;
250	LambdaTableFlash2Location      = (void*)&LambdaTableFlash2;
251}
252
253
254/** @brief Copy fuel tables to RAM
255 *
256 * Initialises the fuel tables in RAM by copying them up from flash.
257 */
258void initPagedRAMFuel(void){
259	/* Copy the tables from flash to RAM */
260	RPAGE = RPAGE_FUEL_ONE;
261	memcpy((void*)&TablesA, VETableMainFlashLocation,       sizeof(mainTable));
262	memcpy((void*)&TablesB, VETableSecondaryFlashLocation,  sizeof(mainTable));
263	memcpy((void*)&TablesC, AirflowTableFlashLocation,      sizeof(mainTable));
264	memcpy((void*)&TablesD, LambdaTableFlashLocation,       sizeof(mainTable));
265	RPAGE = RPAGE_FUEL_TWO;
266	memcpy((void*)&TablesA, VETableMainFlash2Location,      sizeof(mainTable));
267	memcpy((void*)&TablesB, VETableSecondaryFlash2Location, sizeof(mainTable));
268	memcpy((void*)&TablesC, AirflowTableFlash2Location,     sizeof(mainTable));
269	memcpy((void*)&TablesD, LambdaTableFlash2Location,      sizeof(mainTable));
270}
271
272
273/** @brief Buffer timing tables addresses
274 *
275 * Save pointers to the timing tables which live in paged flash.
276 */
277void 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;
287}
288
289
290/** @brief Copy timing tables to RAM
291 *
292 * Initialises the timing tables in RAM by copying them up from flash.
293 */
294void initPagedRAMTime(){
295	/* Copy the tables from flash to RAM */
296	RPAGE = RPAGE_TIME_ONE;
297	memcpy((void*)&TablesA, IgnitionAdvanceTableMainFlashLocation,        sizeof(mainTable));
298	memcpy((void*)&TablesB, IgnitionAdvanceTableSecondaryFlashLocation,   sizeof(mainTable));
299	memcpy((void*)&TablesC, InjectionAdvanceTableMainFlashLocation,       sizeof(mainTable));
300	memcpy((void*)&TablesD, InjectionAdvanceTableSecondaryFlashLocation,  sizeof(mainTable));
301	RPAGE = RPAGE_TIME_TWO;
302	memcpy((void*)&TablesA, IgnitionAdvanceTableMainFlash2Location,       sizeof(mainTable));
303	memcpy((void*)&TablesB, IgnitionAdvanceTableSecondaryFlash2Location,  sizeof(mainTable));
304	memcpy((void*)&TablesC, InjectionAdvanceTableMainFlash2Location,      sizeof(mainTable));
305	memcpy((void*)&TablesD, InjectionAdvanceTableSecondaryFlash2Location, sizeof(mainTable));
306}
307
308
309/** @brief Buffer tunable tables addresses
310 *
311 * Save pointers to the tunable tables which live in paged flash and their
312 * sub-sections too.
313 */
314void initTunableAddresses(){
315	/* Setup addresses within the page to avoid warnings */
316	SmallTablesAFlashLocation  = (void*)&SmallTablesAFlash;
317	SmallTablesBFlashLocation  = (void*)&SmallTablesBFlash;
318	SmallTablesCFlashLocation  = (void*)&SmallTablesCFlash;
319	SmallTablesDFlashLocation  = (void*)&SmallTablesDFlash;
320	SmallTablesAFlash2Location = (void*)&SmallTablesAFlash2;
321	SmallTablesBFlash2Location = (void*)&SmallTablesBFlash2;
322	SmallTablesCFlash2Location = (void*)&SmallTablesCFlash2;
323	SmallTablesDFlash2Location = (void*)&SmallTablesDFlash2;
324
325	/* TablesA */
326	dwellDesiredVersusVoltageTableLocation    = (void*)&SmallTablesAFlash.dwellDesiredVersusVoltageTable;
327	dwellDesiredVersusVoltageTable2Location   = (void*)&SmallTablesAFlash2.dwellDesiredVersusVoltageTable;
328	injectorDeadTimeTableLocation             = (void*)&SmallTablesAFlash.injectorDeadTimeTable;
329	injectorDeadTimeTable2Location            = (void*)&SmallTablesAFlash2.injectorDeadTimeTable;
330	postStartEnrichmentTableLocation          = (void*)&SmallTablesAFlash.postStartEnrichmentTable;
331	postStartEnrichmentTable2Location         = (void*)&SmallTablesAFlash2.postStartEnrichmentTable;
332	engineTempEnrichmentTableFixedLocation    = (void*)&SmallTablesAFlash.engineTempEnrichmentTableFixed;
333	engineTempEnrichmentTableFixed2Location   = (void*)&SmallTablesAFlash2.engineTempEnrichmentTableFixed;
334	primingVolumeTableLocation                = (void*)&SmallTablesAFlash.primingVolumeTable;
335	primingVolumeTable2Location               = (void*)&SmallTablesAFlash2.primingVolumeTable;
336	engineTempEnrichmentTablePercentLocation  = (void*)&SmallTablesAFlash.engineTempEnrichmentTablePercent;
337	engineTempEnrichmentTablePercent2Location = (void*)&SmallTablesAFlash2.engineTempEnrichmentTablePercent;
338	dwellVersusRPMTableLocation               = (void*)&SmallTablesAFlash.dwellVersusRPMTable;
339	dwellVersusRPMTable2Location              = (void*)&SmallTablesAFlash2.dwellVersusRPMTable;
340	blendVersusRPMTableLocation               = (void*)&SmallTablesAFlash.blendVersusRPMTable;
341	blendVersusRPMTable2Location              = (void*)&SmallTablesAFlash2.blendVersusRPMTable;
342
343	/* TablesB */
344	loggingSettingsLocation       = (void*)&SmallTablesBFlash.loggingSettings;
345	loggingSettings2Location      = (void*)&SmallTablesBFlash2.loggingSettings;
346	perCylinderFuelTrimsLocation  = (void*)&SmallTablesBFlash.perCylinderFuelTrims;
347	perCylinderFuelTrims2Location = (void*)&SmallTablesBFlash2.perCylinderFuelTrims;
348
349	/* TablesC */
350	// TODO
351
352	/* TablesD */
353	// TODO
354
355	/* filler defs */
356	fillerALocation  = (void*)&SmallTablesAFlash.filler;
357	fillerA2Location = (void*)&SmallTablesAFlash2.filler;
358	fillerBLocation  = (void*)&SmallTablesBFlash.filler;
359	fillerB2Location = (void*)&SmallTablesBFlash2.filler;
360	fillerCLocation  = (void*)&SmallTablesCFlash.filler;
361	fillerC2Location = (void*)&SmallTablesCFlash2.filler;
362	fillerDLocation  = (void*)&SmallTablesDFlash.filler;
363	fillerD2Location = (void*)&SmallTablesDFlash2.filler;
364}
365
366
367/**
368 *
369 */
370void initPagedRAMTune(){
371	/* Copy the tables from flash to RAM */
372	RPAGE = RPAGE_TUNE_ONE;
373	memcpy((void*)&TablesA, SmallTablesAFlashLocation, sizeof(mainTable));
374	memcpy((void*)&TablesB, SmallTablesBFlashLocation, sizeof(mainTable));
375	memcpy((void*)&TablesC, SmallTablesCFlashLocation, sizeof(mainTable));
376	memcpy((void*)&TablesD, SmallTablesDFlashLocation, sizeof(mainTable));
377	RPAGE = RPAGE_TUNE_TWO;
378	// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& WARNING &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //
379	//    You will get garbage if you use table switching at this time!!!    //
380	//         XGATE code being run from this region temporarily!!!          //
381	//   Writing to these tables WILL corrupt XGATE code/kill your engine!   //
382	// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& WARNING &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //
383	//memcpy(xgateSchedRAMAddress, xgateSchedFlashAddress, (xgateSchedEnd - xgateSched));
384	//memcpy(xgateInjectorsOnRAMAddress, xgateInjectorsOnFlashAddress, (xgateInjectorsOnEnd - xgateInjectorsOn));
385	//memcpy(xgateInjectorsOffRAMAddress, xgateInjectorsOffFlashAddress, (xgateInjectorsOffEnd - xgateInjectorsOff));
386//	memcpy((void*)&TablesA,	SmallTablesAFlash2Location, sizeof(mainTable));
387//	memcpy((void*)&TablesB,	SmallTablesBFlash2Location, sizeof(mainTable));
388//	memcpy((void*)&TablesC,	SmallTablesCFlash2Location, sizeof(mainTable));
389//	memcpy((void*)&TablesD,	SmallTablesDFlash2Location, sizeof(mainTable));
390}
391
392
393/** @brief Buffer addresses of paged data
394 *
395 * Save the paged memory addresses to variables such that we can access them
396 * from another paged block with no warnings.
397 *
398 * If you try to access paged data from the wrong place you get nasty warnings.
399 * These calls to functions that live in the same page that they are addressing
400 * prevent those warnings.
401 *
402 * @note Many thanks to Jean BĂ©langer for the inspiration/idea to do this!
403 */
404void initAllPagedAddresses(){
405	/* Setup pointers to lookup tables */
406	initLookupAddresses();
407	/* Setup pointers to the main tables */
408	initFuelAddresses();
409	initTimingAddresses();
410	initTunableAddresses();
411}
412
413
414/** @brief Copies paged flash to RAM
415 *
416 * Take the tables and config from flash up to RAM to allow live tuning.
417 *
418 * For the main tables and other paged config we need to adjust
419 * the RPAGE value to the appropriate one before copying up.
420 *
421 * This function is simply a delegator to the ones for each flash page. Each
422 * one lives in the same paged space as the data it is copying up.
423 */
424void initAllPagedRAM(){
425	/* Setup the flash block pointers before copying flash to RAM using them */
426	initAllPagedAddresses();
427
428	/* Copy the tables up to their paged RAM blocks through the window from flash */
429	initPagedRAMFuel();
430	initPagedRAMTime();
431	initPagedRAMTune();
432
433	/* Default to page one for now, perhaps read the configured port straight out of reset in future? TODO */
434	setupPagedRAM(TRUE); // probably something like (PORTA & TableSwitchingMask)
435}
436
437
438/* Initialise and set up all running variables that require a non-zero start value here */
439/* All other variables are initialised to zero by the premain built in code             */
440void initVariables(){
441	/* And the opposite for the other halves */
442	CoreVars = &CoreVars0;
443	DerivedVars = &DerivedVars0;
444	ADCBuffers = &ADCBuffers0;
445	ADCBuffersRecord = &ADCBuffers1;
446
447	ticksPerDegree = &ticksPerDegree0; // TODO temp, remove, maybe
448	ticksPerDegreeRecord = &ticksPerDegree1; // TODO temp, remove, maybe
449
450	/* Setup the pointers to the registers for fueling use, this does NOT work if done in global.c, I still don't know why. */
451	ectMainTimeRegisters[0] = TC2_ADDR;
452	ectMainTimeRegisters[1] = TC3_ADDR;
453	ectMainTimeRegisters[2] = TC4_ADDR;
454	ectMainTimeRegisters[3] = TC5_ADDR;
455	ectMainTimeRegisters[4] = TC6_ADDR;
456	ectMainTimeRegisters[5] = TC7_ADDR;
457	ectMainControlRegisters[0] = TCTL2_ADDR;
458	ectMainControlRegisters[1] = TCTL2_ADDR;
459	ectMainControlRegisters[2] = TCTL1_ADDR;
460	ectMainControlRegisters[3] = TCTL1_ADDR;
461	ectMainControlRegisters[4] = TCTL1_ADDR;
462	ectMainControlRegisters[5] = TCTL1_ADDR;
463
464	coreStatusA |= FUEL_PUMP_PRIME;
465
466	// Initial state is NOT to fire... can be configured by scheduler if required.
467	outputEventInputEventNumbers[0] = 0xFF;
468	outputEventInputEventNumbers[1] = 0xFF;
469	outputEventInputEventNumbers[2] = 0xFF;
470	outputEventInputEventNumbers[3] = 0xFF;
471	outputEventInputEventNumbers[4] = 0xFF;
472	outputEventInputEventNumbers[5] = 0xFF;
473	outputEventInputEventNumbers[6] = 0xFF;
474	outputEventInputEventNumbers[7] = 0xFF;
475	outputEventInputEventNumbers[8] = 0xFF;
476	outputEventInputEventNumbers[9] = 0xFF;
477	outputEventInputEventNumbers[10] = 0xFF;
478	outputEventInputEventNumbers[11] = 0xFF;
479	outputEventInputEventNumbers[12] = 0xFF;
480	outputEventInputEventNumbers[13] = 0xFF;
481	outputEventInputEventNumbers[14] = 0xFF;
482	outputEventInputEventNumbers[15] = 0xFF;
483	outputEventInputEventNumbers[16] = 0xFF;
484	outputEventInputEventNumbers[17] = 0xFF;
485	outputEventInputEventNumbers[18] = 0xFF;
486	outputEventInputEventNumbers[19] = 0xFF;
487	outputEventInputEventNumbers[20] = 0xFF;
488	outputEventInputEventNumbers[21] = 0xFF;
489	outputEventInputEventNumbers[22] = 0xFF;
490	outputEventInputEventNumbers[23] = 0xFF;
491
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
493}
494
495
496/** @brief Flash module setup
497 *
498 * Initialise configuration registers for the flash module to allow burning of
499 * non-volatile flash memory from within the firmware.
500 *
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.
503 *
504 * We want to put the flash clock as high as possible between 150kHz and 200kHz
505 *
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.
508 *
509 * 16MHz = 16000KHz which pre-divided by 8 is 2000kHz
510 *
511 * 2000kHz / 200kHz = 10 thus we want to set the divide register to 10 or 0x0A
512 *
513 * Combining 0x0A with PRDIV8 gives us 0x4A (0x0A | 0x40 = 0x4A) so we use that
514 *
515 * @author Sean Keys
516 *
517 * @note If you use a different crystal lower than 12.8MHz PRDIV8 should not be set.
518 *
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.
521 */
522void initFlash(){
523	FCLKDIV = 0x4A;                   /* Set the flash clock frequency */
524	FPROT = 0xFF;                     /* Disable all flash protection  */
525	FSTAT = FSTAT | (PVIOL | ACCERR); /* Clear any errors              */
526}
527
528
529/* Set up the timer module and its various interrupts */
530void initECTTimer(){
531	/** @todo TODO Take the configuration from the decoder (as is) and mask it such that it does not affect the 6 other channels.
532	 * Take the the number of output channels required from configuration and configure that many as outputs
533	 * Configure the balance in whatever way is specified in the GPIO configuration - allow second input to be reused as GPI only.
534	 *
535	 * This stuff affects:
536	 * - TIE = 0x01 or 0x03, only. OC channels enabled as required and IC only for RPM/position.
537	 * - TIOS = nope, always 0xFC for 2 IC and 6 OC
538	 * - TCTL (1,2,3,4) 4 = 0x0? mask off high 4 bits and allow low 4 to come from decoder config/init
539	 * - PORTT = zeros, with balance from config
540	 * - DDRT = 0,1 inputs, or if unused by decoder, from config
541	 */
542
543
544
545	// TODO rearrange the order of this stuff and pull enable and interrupt enable out to the last function call of init.
546
547
548	/* Timer channel interrupts */
549	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 */
550	TFLG = ONES; /* Clear all the flags such that we are up and running before they first occur */
551	TFLGOF = ONES; /* Clear all the flags such that we are up and running before they first occur */
552
553	/* TODO Turn the timer on and set the rate and overflow interrupt */
554//	DLYCT = 0xFF; /* max noise filtering as experiment for volvo this will come from flash config */ // just hiding a wiring/circuit issue...
555	TSCR1 = 0x88; /* 0b_1000_1000 Timer enabled, and precision timer turned on */
556	TSCR2 = 0x87; /* 0b_1000_0111 Overflow interrupt enable, divide by 256 if precision turned off */
557//	PTPSR = 0x03; /* 4 prescaler gives .1uS resolution and max period of 7ms measured */
558	PTPSR = 0x1F; /* 32 prescaler gives 0.8uS resolution and max period of 52.4288ms measured */
559//	PTPSR = 0x3F; /* 64 prescaler gives 1.6uS resolution and max period of 105ms measured */
560//	PTPSR = 0xFF; /* 256 prescaler gives 6.4uS resolution and max period of 400ms measured */
561//	PTPSR = 0x7F; /* 128 prescaler gives 3.2uS resolution and max period of 200ms measured */
562	/* http://duckduckgo.com/?q=1+%2F+%2840MHz+%2F+32+%29 */
563	/* http://duckduckgo.com/?q=%281+%2F+%2840MHz+%2F+32+%29%29+*+2^16 */
564	/* www.mecheng.adelaide.edu.au/robotics_novell/WWW_Devs/Dragon12/LM4_Timer.pdf */
565
566	/* Initial actions */
567	TIOS = 0xFC; /* 0b_1111_1100 0 and 1 are input capture, 2 through 7 are output compare */
568	TCTL1 = ZEROS; /* Set disabled at startup time, use these and other flags to switch fueling on and off inside the decoder */
569	TCTL2 = ZEROS; /* 0,1 have compare turned off regardless as they are in IC mode. */
570	TCTL3 = ZEROS; /* Capture off for 4 - 7 */
571	TCTL4 = 0x0F; /* Capture on both edges of two pins for IC (0,1), capture off for 2,3 */
572
573	// TODO setup delay counters on 0 and 1 to filter noise (nice feature!)
574	//DLYCT = ??; built in noise filter
575
576//	PTMCPSR = 0xFF // Precision prescaler - fastest is 1 represented by 0, slowest/longest possible is 256 represented by 255 or 0xFF
577//	MCCNT = ONES16; // init to slowest possible, first
578//	MCCTL = 0xC4; // turn on and setup the mod down counter
579//	MCFLG = 0x80; // clear the flag up front
580
581	decoderInitPreliminary();
582}
583
584
585/* Configure the PIT timers for their various uses. */
586void initPITTimer(){
587//	// set micro periods
588//	PITMTLD0 = 0x1F; /* 32 prescaler gives 0.8uS resolution and max period of 52.4288ms measured */
589//	PITMTLD1 = 0x1F; /* ditto */
590//	/* http://duckduckgo.com/?q=1+%2F+%2840MHz+%2F+32+%29 Exactly the same as for ECT */
591//
592//	// set timers running
593//	PITLD0 = dwellPeriod;
594//	// enable module
595//	PITCFLMT = 0x80;
596//	// enable channels
597//	//PITCE = 0x03;
598//	// enable interrupt
599//	PITINTE = 0x01;
600//	// clear flags
601//	//PITFLT = ONES;
602}
603
604/* Setup the sci module(s) that we need to use. */
605void initSCIStuff(){
606	/* The alternative register set selector defaults to zero */
607
608	// set the baud/data speed
609	SCI0BD = fixedConfigs1.serialSettings.baudDivisor;
610
611	// etc
612
613	/* Switch to alternative register set? */
614
615	// etc
616
617	/* Switch back again? */
618
619	/*
620	 * 0 = LOOPS (normal two wire operation)
621	 * 0 = SCISWAI (Wait mode on)
622	 * 0 = RSRC (if loops=1, int/ext wiring)
623	 * 1 = M MODE (9 bit operation)
624	 * 0 = WAKE (idle line wakeup)
625	 * 0 = ILT (idle line type count start pos)
626	 * 1 = PE (parity on)
627	 * 1 = PT (odd parity)
628	 *
629	 * 0x13 = ODD (default)
630	 * 0x12 = EVEN
631	 * 0x00 = NONE
632	 */
633	SCI0CR1 = 0x13;
634
635	/*
636	 * 0 = TIE (tx data empty isr disabled)
637	 * 0 = TCIE (tx complete isr disabled)
638	 * 1 = RIE (rx full isr enabled)
639	 * 0 = ILIE (idle line isr disabled)
640	 * 0 = TE (transmit disabled)
641	 * 1 = RE (receive enabled)
642	 * 0 = RWU (rx wake up normal)
643	 * 0 = SBK (send break off)
644	 */
645	SCI0CR2 = 0x24;
646}
647
648/* TODO Load and calculate all configuration data required to run */
649void initConfiguration(){
650//	// 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.
651
652
653	/* Add in tunable physical parameters at boot time TODO move to init.c TODO duplicate for secondary fuel? or split somehow?
654	 *nstant = ((masterConst * perCylinderVolume) / (stoichiometricAFR * injectorFlow));
655	 *nstant = ((139371764 * 16384) / (15053 * 4096));
656	 * OR
657	 *nstant = ((masterConst / injectorFlow) * perCylinderVolume) / stoichiometricAFR;
658	 *nstant = ((139371764 /  4096) * 16384) / 15053;
659	 * http://duckduckgo.com/?q=%28%28139371764++%2F+4096%29+*+16384%29+%2F+15053 */
660	bootFuelConst = ((unsigned long)(masterFuelConstant / fixedConfigs1.engineSettings.injectorFlow) * fixedConfigs1.engineSettings.perCylinderVolume) / fixedConfigs1.engineSettings.stoichiometricAFR;
661
662	/* The ADC range used to generate TPS percentage */
663	if(fixedConfigs2.sensorRanges.TPSMaximumADC > fixedConfigs2.sensorRanges.TPSMinimumADC){
664		TPSADCRange = fixedConfigs2.sensorRanges.TPSMaximumADC - fixedConfigs2.sensorRanges.TPSMinimumADC;
665	}else{
666		TPSADCRange = fixedConfigs2.sensorRanges.TPSMinimumADC - fixedConfigs2.sensorRanges.TPSMaximumADC;
667	}
668}
669
670
671/* Set up all the remaining interrupts */
672void initInterrupts(){
673	/* IMPORTANT : Set the s12x vector base register (Thanks Karsten!!) */
674	IVBR = 0xF7; /* Without this the interrupts will never find your code! */
675
676	/* Set up the Real Time Interrupt */
677	RTICTL = 0x81; /* 0b_1000_0001 0.125ms/125us period http://duckduckgo.com/?q=1+%2F+%2816MHz+%2F+%282+*+10^3%29+%29 */
678//	RTICTL = 0xF9; /* 0b_1111_1001 0.125s/125ms period http://duckduckgo.com/?q=1+%2F+%2816MHz+%2F+%282*10^6%29+%29 */
679	CRGINT |= (RTIE | PLLLOCKIE | SCMIE); /* Enable the Real Time Interrupt, PLL Lock Interrupt, and Self Clock Mode Interrupt */
680	CRGFLG = (RTIF | PLLLOCKIF | SCMIF); /* Clear the RTI, LOCKI, and SCMI flags */
681	RAMWPC |= AVIE; // Enable the access protection interrupt for XGATE RAM
682
683	// set up port H for testing
684	PPSH = ZEROS; // falling edge/pull up for all
685	PIEH = ONES; // enable all pins interrupts
686	PIFH = ONES; // clear all port H interrupt flags
687
688	// TODO set up irq and xirq for testing
689	// IRQCR for IRQ
690
691	/* VReg API setup (only for wait mode? i think so) */
692//	VREGAPIR = 0x09C3; /* For 500ms period : (500ms - 0.2ms) / 0.2ms = 0b100111000011 = 2499 */
693//	VREGAPICL = 0x02; /* Enable the interrupt */
694//	VREGAPICL = 0x04; /* Start the counter running */
695	/* 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 */
696
697	/* LVI Low Voltage Interrupt enable */
698	VREGCTRL = 0x02; // Counts bad power events for diagnosis reasons
699}