1 /* FreeEMS - the open source engine management system
3 * Copyright 2008-2013 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!
29 * @brief Initialise the devices state
31 * Setup, configure and initialise all aspects of the devices state including
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
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"
50 #include "inc/decoderInterface.h"
51 #include "inc/xgateVectors.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.
62 ATOMIC_START(); /* Disable ALL interrupts while we configure the board ready for use */
63 initPLL(); /* Set up the PLL and use it */
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! */
75 initXgate(); /* Fred is a legend, for good reason as of now */
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 */
83 #include "xgateInit.c"
87 /** @brief Set the PLL clock frequency
89 * Set the Phase Locked Loop to our desired frequency (80MHz) and enable PLL.
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 */
100 /** @brief Switch to using PLL
102 * Switch to using PLL for clock (40MHz bus speed). Interrupt is enabled elsewhere.
104 * Note: Requires busy wait loop, only for init and emergency use.
106 * @todo Should be limited, and have break out with error code and fall back mechanism.
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)) */
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... */
123 /// Set up the analogue inputs
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.
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 */
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 */
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 */
153 /// Set up the PWM module from configuration
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
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
;
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
;
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
189 /// Set up all the pin states as per configuration, but protect key states.
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 */
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 */
225 /** @brief Buffer lookup tables addresses
227 * Save pointers to the lookup tables which live in paged flash.
229 void initLookupAddresses(){
230 IATTransferTableLocation
= (void*)&IATTransferTable
;
231 CHTTransferTableLocation
= (void*)&CHTTransferTable
;
232 MAFTransferTableLocation
= (void*)&MAFTransferTable
;
233 TestTransferTableLocation
= (void*)&TestTransferTable
;
237 /** @brief Buffer fuel tables addresses
239 * Save pointers to the fuel tables which live in paged flash.
241 void 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
;
254 /** @brief Copy fuel tables to RAM
256 * Initialises the fuel tables in RAM by copying them up from flash.
258 void 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
));
273 /** @brief Buffer timing tables addresses
275 * Save pointers to the timing tables which live in paged flash.
277 void initTimingAddresses(){
278 /* Setup addresses within the page to avoid warnings */
279 IgnitionAdvanceTableMainFlashLocation
= (void*)&IgnitionAdvanceTableMainFlash
;
280 IgnitionAdvanceTableSecondaryFlashLocation
= (void*)&IgnitionAdvanceTableSecondaryFlash
;
281 InjectionAdvanceTableMainFlashLocation
= (void*)&InjectionAdvanceTableMainFlash
;
282 InjectionAdvanceTableSecondaryFlashLocation
= (void*)&InjectionAdvanceTableSecondaryFlash
;
283 IgnitionAdvanceTableMainFlash2Location
= (void*)&IgnitionAdvanceTableMainFlash2
;
284 IgnitionAdvanceTableSecondaryFlash2Location
= (void*)&IgnitionAdvanceTableSecondaryFlash2
;
285 InjectionAdvanceTableMainFlash2Location
= (void*)&InjectionAdvanceTableMainFlash2
;
286 InjectionAdvanceTableSecondaryFlash2Location
= (void*)&InjectionAdvanceTableSecondaryFlash2
;
290 /** @brief Copy timing tables to RAM
292 * Initialises the timing tables in RAM by copying them up from flash.
294 void 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
));
309 /** @brief Buffer tunable tables addresses
311 * Save pointers to the tunable tables which live in paged flash and their
314 void 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
;
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
;
344 loggingSettingsLocation
= (void*)&SmallTablesBFlash
.loggingSettings
;
345 loggingSettings2Location
= (void*)&SmallTablesBFlash2
.loggingSettings
;
346 perCylinderFuelTrimsLocation
= (void*)&SmallTablesBFlash
.perCylinderFuelTrims
;
347 perCylinderFuelTrims2Location
= (void*)&SmallTablesBFlash2
.perCylinderFuelTrims
;
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
;
370 void 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));
393 /** @brief Buffer addresses of paged data
395 * Save the paged memory addresses to variables such that we can access them
396 * from another paged block with no warnings.
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.
402 * @note Many thanks to Jean Bélanger for the inspiration/idea to do this!
404 void initAllPagedAddresses(){
405 /* Setup pointers to lookup tables */
406 initLookupAddresses();
407 /* Setup pointers to the main tables */
409 initTimingAddresses();
410 initTunableAddresses();
414 /** @brief Copies paged flash to RAM
416 * Take the tables and config from flash up to RAM to allow live tuning.
418 * For the main tables and other paged config we need to adjust
419 * the RPAGE value to the appropriate one before copying up.
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.
424 void initAllPagedRAM(){
425 /* Setup the flash block pointers before copying flash to RAM using them */
426 initAllPagedAddresses();
428 /* Copy the tables up to their paged RAM blocks through the window from flash */
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)
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 */
440 void initVariables(){
441 /* And the opposite for the other halves */
442 CoreVars
= &CoreVars0
;
443 DerivedVars
= &DerivedVars0
;
444 ADCBuffers
= &ADCBuffers0
;
445 ADCBuffersRecord
= &ADCBuffers1
;
447 ticksPerDegree
= &ticksPerDegree0
; // TODO temp, remove, maybe
448 ticksPerDegreeRecord
= &ticksPerDegree1
; // TODO temp, remove, maybe
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
;
464 coreStatusA
|= FUEL_PUMP_PRIME
;
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;
492 // TODO perhaps read from the ds1302 once at start up and init the values or different ones with the actual time and date then update them in RTI
496 /** @brief Flash module setup
498 * Initialise configuration registers for the flash module to allow burning of
499 * non-volatile flash memory from within the firmware.
501 * The FCLKDIV register can be written once only after reset, thus the lower
502 * seven bits and the PRDIV8 bit must be set at the same time.
504 * We want to put the flash clock as high as possible between 150kHz and 200kHz
506 * The oscillator clock is 16MHz and because that is above 12.8MHz we will set
507 * the PRDIV8 bit to further divide by 8 bits as per the manual.
509 * 16MHz = 16000KHz which pre-divided by 8 is 2000kHz
511 * 2000kHz / 200kHz = 10 thus we want to set the divide register to 10 or 0x0A
513 * Combining 0x0A with PRDIV8 gives us 0x4A (0x0A | 0x40 = 0x4A) so we use that
517 * @note If you use a different crystal lower than 12.8MHz PRDIV8 should not be set.
519 * @warning If the frequency you end up with is outside 150kHz - 200kHz you may
520 * damage your flash module or get corrupt data written to it.
523 FCLKDIV
= 0x4A; /* Set the flash clock frequency */
524 FPROT
= 0xFF; /* Disable all flash protection */
525 FSTAT
= FSTAT
| (PVIOL
| ACCERR
); /* Clear any errors */
529 /* Set up the timer module and its various interrupts */
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.
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
545 // TODO rearrange the order of this stuff and pull enable and interrupt enable out to the last function call of init.
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 */
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 */
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 */
573 // TODO setup delay counters on 0 and 1 to filter noise (nice feature!)
574 //DLYCT = ??; built in noise filter
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
581 decoderInitPreliminary();
585 /* Configure the PIT timers for their various uses. */
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 */
592 // // set timers running
593 // PITLD0 = dwellPeriod;
596 // // enable channels
598 // // enable interrupt
604 /* Setup the sci module(s) that we need to use. */
606 /* The alternative register set selector defaults to zero */
608 // set the baud/data speed
609 SCI0BD
= fixedConfigs1
.serialSettings
.baudDivisor
;
613 /* Switch to alternative register set? */
617 /* Switch back again? */
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)
627 * 1 = PT (odd parity)
629 * 0x13 = ODD (default)
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)
648 /* TODO Load and calculate all configuration data required to run */
649 void 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.
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));
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
;
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
;
666 TPSADCRange
= fixedConfigs2
.sensorRanges
.TPSMinimumADC
- fixedConfigs2
.sensorRanges
.TPSMaximumADC
;
671 /* Set up all the remaining interrupts */
672 void initInterrupts(){
673 /* IMPORTANT : Set the s12x vector base register (Thanks Karsten!!) */
674 IVBR
= 0xF7; /* Without this the interrupts will never find your code! */
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
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
688 // TODO set up irq and xirq for testing
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 */
697 /* LVI Low Voltage Interrupt enable */
698 VREGCTRL
= 0x02; // Counts bad power events for diagnosis reasons