00001 /* FreeEMS - the open source engine management system 00002 * 00003 * Copyright 2008, 2009, 2010 Fred Cooke 00004 * 00005 * This file is part of the FreeEMS project. 00006 * 00007 * FreeEMS software is free software: you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation, either version 3 of the License, or 00010 * (at your option) any later version. 00011 * 00012 * FreeEMS software is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with any FreeEMS software. If not, see http://www.gnu.org/licenses/ 00019 * 00020 * We ask that if you make any changes to this file you email them upstream to 00021 * us at admin(at)diyefi(dot)org or, even better, fork the code on github.com! 00022 * 00023 * Thank you for choosing FreeEMS to run your engine! 00024 */ 00025 00026 00045 #define INIT_C 00046 #include "inc/freeEMS.h" 00047 #include "inc/flashWrite.h" 00048 #include "inc/interrupts.h" 00049 #include "inc/utils.h" 00050 #include "inc/commsISRs.h" 00051 #include "inc/pagedLocationBuffers.h" 00052 #include "inc/init.h" 00053 #include "inc/DecoderInterface.h" 00054 #include "inc/xgateVectors.h" 00055 #include <string.h> 00056 00057 00066 void init(){ 00067 ATOMIC_START(); /* Disable ALL interrupts while we configure the board ready for use */ 00068 initPLL(); /* Set up the PLL and use it */ 00069 initIO(); /* TODO make this config dependent. Set up all the pins and modules to be in low power harmless states */ 00070 initAllPagedRAM(); /* Copy table and config blocks of data from flash to the paged ram blocks for fast data lookup */ 00071 initVariables(); /* Initialise the rest of the running variables etc */ 00072 initFlash(); /* TODO, finalise this */ 00073 initECTTimer(); /* TODO move this to inside config in an organised way. Set up the timer module and its various aspects */ 00074 initPITTimer(); /* TODO ditto... */ 00075 initSCIStuff(); /* Setup the sci module(s) that we will use. */ 00076 initConfiguration(); /* TODO Set user/feature/config up here! */ 00077 initXgate(); 00078 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 */ 00079 ATOMIC_END(); /* Re-enable any configured interrupts */ 00080 } 00081 00082 00083 /* used to chop out all the init stuff at compile time for hardware testing. */ 00084 //#define NO_INIT 00085 00086 00094 void initPLL(){ 00095 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) */ 00096 PLLCTL &= PLLOFF; /* Turn the PLL device off to adjust its speed (on by default out of reset) */ 00097 REFDV = PLLDIVISOR; /* 16MHz / (3 + 1) = 4MHz Bus frequency */ 00098 SYNR = PLLMULTIPLIER; /* 4MHz * (9 + 1) = 40MHz Bus frequency */ 00099 PLLCTL |= PLLON; /* Turn the PLL device back on again at 80MHz */ 00100 00101 while (!(CRGFLG & PLLLOCK)){ 00102 /* Do nothing while we wait till the PLL loop locks onto the target frequency. */ 00103 /* Target frequency is given by (2 * (crystal frequency / (REFDV + 1)) * (SYNR + 1)) */ 00104 /* Bus frequency is half PLL frequency and given by ((crystal frequency / (REFDV + 1)) * (SYNR + 1)) */ 00105 } 00106 00107 CLKSEL = PLLSELON; /* Switches to PLL clock for internal bus frequency */ 00108 /* from MC9S12XDP512V2.pdf Section 2.4.1.1.2 page 101 Third paragraph */ 00109 /* "This takes a MAXIMUM of 4 OSCCLK clock cylces PLUS 4 PLL clock cycles" */ 00110 /* "During this time ALL clocks freeze, and CPU activity ceases" */ 00111 /* Therefore there is no point waiting for this to occur, we already are... */ 00112 } 00113 00114 00115 /* Configure all the I/O to default values to keep power use down etc */ 00116 void initIO(){ 00117 /* for now, hard code all stuff to be outputs as per Freescale documentation, */ 00118 /* later what to do will be pulled from flash configuration such that all */ 00119 /* things are setup at once, and not messed with thereafter. when the port */ 00120 /* something uses is changed via the tuning interface, the confuration will be */ 00121 /* done on the fly, and the value burned to flash such that next boot happens */ 00122 /* correctly and current running devices are used in that way. */ 00123 00124 /* Turn off and on and configure all the modules in an explicit way */ 00125 // TODO set up and turn off all modules (CAN,SCI,SPI,IIC,etc) 00126 00127 /* Digital input buffers on the ATD channels are off by default, leave them this way! */ 00128 //ATD0DIEN = ZEROS; /* You are out of your mind if you waste this on digital Inputs */ 00129 //ATD1DIEN0 = ZEROS; /* You are out of your mind if you waste this on digital Inputs (NOT-bonded, can't use) */ 00130 //ATD1DIEN1 = ZEROS; /* You are out of your mind if you waste this on digital Inputs */ 00131 00132 /* And configure them all for analog input */ 00133 //ATD0CTL0 = 0x07/* With mult turned on this is required to be set to cause wrap around, but is correct out of reset */ 00134 //ATD0CTL1 = 0x07/* Trigger and interrupt configuration, unused for now. */ 00135 ATD0CTL2 = 0xC0; /* Turns on the ADC block and sets auto flag clear */ 00136 ATD0CTL3 = 0x40; /* Set sequence length = 8 */ 00137 ATD0CTL4 = 0x73; /* Set the ADC clock and sample period for best accuracy */ 00138 ATD0CTL5 = 0xB0; /* Sets justification to right, multiplex and scan all channels. Writing to this causes conversions to begin */ 00139 00140 /* And configure them all for analog input */ 00141 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 */ 00142 //ATD0CTL1 = 0x07/* Trigger and interrupt configuration, unused for now. */ 00143 ATD1CTL2 = 0xC0; /* Turns on the ADC block and sets auto flag clear */ 00144 ATD1CTL3 = 0x40; /* Set sequence length = 8 */ 00145 ATD0CTL4 = 0x73; /* Set the ADC clock and sample period for best accuracy */ 00146 ATD0CTL5 = 0xB0; /* Sets justification to right, multiplex and scan all channels. Writing to this causes conversions to begin */ 00147 00148 #ifndef NO_INIT 00149 /* Set up the PWM component and initialise its values to off */ 00150 PWME = 0x7F; /* Turn on PWM 0 - 6 (7 is user LED on main board) */ 00151 PWMCLK = ZEROS; /* The fastest we can go for all channels */ 00152 PWMPRCLK = ZEROS; /* The fastest prescaler we can go for all channels */ 00153 PWMSCLA = ZEROS; /* The fastest we can go */ 00154 PWMSCLB = ZEROS; /* The fastest we can go */ 00155 /* TODO PWM channel concatenation for high resolution */ 00156 // join channel pairs together here (needs 16 bit regs enabled too) 00157 /* TODO Initialise pwm channels with frequency, and initial duty for real use */ 00158 // initial PWM settings for testing 00159 /* PWM periods */ 00160 PWMPER0 = 0xFF; // 255 for ADC0 testing 00161 PWMPER1 = 0xFF; // 255 for ADC1 testing 00162 PWMPER2 = 0xFF; // 255 for ADC1 testing 00163 PWMPER3 = 0xFF; // 255 for ADC1 testing 00164 PWMPER4 = 0xFF; // 255 for ADC1 testing 00165 PWMPER5 = 0xFF; // 255 for ADC1 testing 00166 PWMPER6 = 0xFF; // 255 for ADC1 testing 00167 PWMPER7 = 0xFF; // 255 for ADC1 testing 00168 /* PWM duties */ 00169 PWMDTY0 = 0; 00170 PWMDTY1 = 0; 00171 PWMDTY2 = 0; 00172 PWMDTY3 = 0; 00173 PWMDTY4 = 0; 00174 PWMDTY5 = 0; 00175 PWMDTY6 = 0; 00176 PWMDTY7 = 0; 00177 00178 00179 /* Initialise the state of pins configured as output */ 00180 /* Initialise to low such that transistor grounded things are all turned off by default. */ 00181 PORTA = ZEROS; /* The serial monitor pin is on 0x40, and could cause problems if capacitance at the output is large when a reset occurs. */ 00182 PORTB = ZEROS; /* Init the rest of the spark outputs as off */ 00183 PORTE = 0x1F; /* 0b_0001_1111 : when not in use 0b_1001_1111 PE7 should be high PE5 and PE6 should be low, the rest high */ 00184 PORTK = ZEROS; 00185 PORTS = ZEROS; 00186 PORTT = ZEROS; /* All pins in off state at boot up (only matters for 2 - 7) */ 00187 PORTM = ZEROS; 00188 PORTP = ZEROS; // TODO hook these up to the adc channels such that you can vary the brightness of an led with a pot. 00189 PORTH = ZEROS; 00190 PORTJ = ZEROS; 00191 /* AD0PT1 You are out of your mind if you waste this on digital Inputs */ 00192 /* AD1PT1 You are out of your mind if you waste this on digital Inputs */ 00193 00194 /* Initialise the Data Direction Registers */ 00195 /* To outputs based on the note at the end of chapter 1.2.2 of MC9S12XDP512V2.pdf */ 00196 DDRA = ONES; /* GPIO (8) */ 00197 DDRB = ONES; /* GPIO (8) */ 00198 DDRE = 0xFC; /* 0b_1111_1100 : Clock and mode pins PE0,PE1 are input only pins, the rest are GPIO */ 00199 DDRK = ONES; /* Only 0,1,2,3,4,5,7, NOT 6 (7) */ 00200 DDRS = ONES; /* SCI0, SCI1, SPI0 (8) */ 00201 DDRT = 0xFC; /* 0b_1111_1100 set ECT pins 0,1 to IC and 2:7 to OC (8) */ 00202 DDRM = ONES; /* CAN 0 - 3 (8) */ 00203 DDRP = ONES; /* PWM pins (8) */ 00204 DDRH = ZEROS; /* All pins configured as input for misc isrs (SPI1, SPI2) (8) */ 00205 DDRJ = ONES; /* Only 0,1,6,7 are brought out on the 112 pin chip (4) */ 00206 /* Configure the non bonded pins to output to avoid current drain (112 pin package) */ 00207 DDRC = ONES; /* NON-bonded external data bus pins */ 00208 DDRD = ONES; /* NON-bonded external data bus pins */ 00209 /* AD0DDR1 You are out of your mind if you waste this on digital Inputs */ 00210 /* AD1DDR1 You are out of your mind if you waste this on digital Inputs */ 00211 #endif 00212 } 00213 00214 00223 void initLookupAddresses(){ 00224 IATTransferTableLocation = (void*)&IATTransferTable; 00225 CHTTransferTableLocation = (void*)&CHTTransferTable; 00226 MAFTransferTableLocation = (void*)&MAFTransferTable; 00227 TestTransferTableLocation = (void*)&TestTransferTable; 00228 } 00229 00230 00239 void initFuelAddresses(){ 00240 /* Setup addresses within the page to avoid warnings */ 00241 VETableMainFlashLocation = (void*)&VETableMainFlash; 00242 VETableSecondaryFlashLocation = (void*)&VETableSecondaryFlash; 00243 VETableTertiaryFlashLocation = (void*)&VETableTertiaryFlash; 00244 LambdaTableFlashLocation = (void*)&LambdaTableFlash; 00245 VETableMainFlash2Location = (void*)&VETableMainFlash2; 00246 VETableSecondaryFlash2Location = (void*)&VETableSecondaryFlash2; 00247 VETableTertiaryFlash2Location = (void*)&VETableTertiaryFlash2; 00248 LambdaTableFlash2Location = (void*)&LambdaTableFlash2; 00249 } 00250 00251 00258 void initPagedRAMFuel(void){ 00259 /* Copy the tables from flash to RAM */ 00260 RPAGE = RPAGE_FUEL_ONE; 00261 memcpy((void*)&TablesA, VETableMainFlashLocation, MAINTABLE_SIZE); 00262 memcpy((void*)&TablesB, VETableSecondaryFlashLocation, MAINTABLE_SIZE); 00263 memcpy((void*)&TablesC, VETableTertiaryFlashLocation, MAINTABLE_SIZE); 00264 memcpy((void*)&TablesD, LambdaTableFlashLocation, MAINTABLE_SIZE); 00265 RPAGE = RPAGE_FUEL_TWO; 00266 memcpy((void*)&TablesA, VETableMainFlash2Location, MAINTABLE_SIZE); 00267 memcpy((void*)&TablesB, VETableSecondaryFlash2Location, MAINTABLE_SIZE); 00268 memcpy((void*)&TablesC, VETableTertiaryFlash2Location, MAINTABLE_SIZE); 00269 memcpy((void*)&TablesD, LambdaTableFlash2Location, MAINTABLE_SIZE); 00270 } 00271 00272 00281 void initTimingAddresses(){ 00282 /* Setup addresses within the page to avoid warnings */ 00283 IgnitionAdvanceTableMainFlashLocation = (void*)&IgnitionAdvanceTableMainFlash; 00284 IgnitionAdvanceTableSecondaryFlashLocation = (void*)&IgnitionAdvanceTableSecondaryFlash; 00285 InjectionAdvanceTableMainFlashLocation = (void*)&InjectionAdvanceTableMainFlash; 00286 InjectionAdvanceTableSecondaryFlashLocation = (void*)&InjectionAdvanceTableSecondaryFlash; 00287 IgnitionAdvanceTableMainFlash2Location = (void*)&IgnitionAdvanceTableMainFlash2; 00288 IgnitionAdvanceTableSecondaryFlash2Location = (void*)&IgnitionAdvanceTableSecondaryFlash2; 00289 InjectionAdvanceTableMainFlash2Location = (void*)&InjectionAdvanceTableMainFlash2; 00290 InjectionAdvanceTableSecondaryFlash2Location = (void*)&InjectionAdvanceTableSecondaryFlash2; 00291 } 00292 00293 00300 void initPagedRAMTime(){ 00301 /* Copy the tables from flash to RAM */ 00302 RPAGE = RPAGE_TIME_ONE; 00303 memcpy((void*)&TablesA, IgnitionAdvanceTableMainFlashLocation, MAINTABLE_SIZE); 00304 memcpy((void*)&TablesB, IgnitionAdvanceTableSecondaryFlashLocation, MAINTABLE_SIZE); 00305 memcpy((void*)&TablesC, InjectionAdvanceTableMainFlashLocation, MAINTABLE_SIZE); 00306 memcpy((void*)&TablesD, InjectionAdvanceTableSecondaryFlashLocation, MAINTABLE_SIZE); 00307 RPAGE = RPAGE_TIME_TWO; 00308 memcpy((void*)&TablesA, IgnitionAdvanceTableMainFlash2Location, MAINTABLE_SIZE); 00309 memcpy((void*)&TablesB, IgnitionAdvanceTableSecondaryFlash2Location, MAINTABLE_SIZE); 00310 memcpy((void*)&TablesC, InjectionAdvanceTableMainFlash2Location, MAINTABLE_SIZE); 00311 memcpy((void*)&TablesD, InjectionAdvanceTableSecondaryFlash2Location, MAINTABLE_SIZE); 00312 } 00313 00314 00324 void initTunableAddresses(){ 00325 /* Setup addresses within the page to avoid warnings */ 00326 SmallTablesAFlashLocation = (void*)&SmallTablesAFlash; 00327 SmallTablesBFlashLocation = (void*)&SmallTablesBFlash; 00328 SmallTablesCFlashLocation = (void*)&SmallTablesCFlash; 00329 SmallTablesDFlashLocation = (void*)&SmallTablesDFlash; 00330 SmallTablesAFlash2Location = (void*)&SmallTablesAFlash2; 00331 SmallTablesBFlash2Location = (void*)&SmallTablesBFlash2; 00332 SmallTablesCFlash2Location = (void*)&SmallTablesCFlash2; 00333 SmallTablesDFlash2Location = (void*)&SmallTablesDFlash2; 00334 00335 /* TablesA */ 00336 dwellDesiredVersusVoltageTableLocation = (void*)&SmallTablesAFlash.dwellDesiredVersusVoltageTable; 00337 dwellDesiredVersusVoltageTable2Location = (void*)&SmallTablesAFlash2.dwellDesiredVersusVoltageTable; 00338 injectorDeadTimeTableLocation = (void*)&SmallTablesAFlash.injectorDeadTimeTable; 00339 injectorDeadTimeTable2Location = (void*)&SmallTablesAFlash2.injectorDeadTimeTable; 00340 postStartEnrichmentTableLocation = (void*)&SmallTablesAFlash.postStartEnrichmentTable; 00341 postStartEnrichmentTable2Location = (void*)&SmallTablesAFlash2.postStartEnrichmentTable; 00342 engineTempEnrichmentTableFixedLocation = (void*)&SmallTablesAFlash.engineTempEnrichmentTableFixed; 00343 engineTempEnrichmentTableFixed2Location = (void*)&SmallTablesAFlash2.engineTempEnrichmentTableFixed; 00344 primingVolumeTableLocation = (void*)&SmallTablesAFlash.primingVolumeTable; 00345 primingVolumeTable2Location = (void*)&SmallTablesAFlash2.primingVolumeTable; 00346 engineTempEnrichmentTablePercentLocation = (void*)&SmallTablesAFlash.engineTempEnrichmentTablePercent; 00347 engineTempEnrichmentTablePercent2Location = (void*)&SmallTablesAFlash2.engineTempEnrichmentTablePercent; 00348 dwellMaxVersusRPMTableLocation = (void*)&SmallTablesAFlash.dwellMaxVersusRPMTable; 00349 dwellMaxVersusRPMTable2Location = (void*)&SmallTablesAFlash2.dwellMaxVersusRPMTable; 00350 00351 /* TablesB */ 00352 perCylinderFuelTrimsLocation = (void*)&SmallTablesBFlash.perCylinderFuelTrims; 00353 perCylinderFuelTrims2Location = (void*)&SmallTablesBFlash2.perCylinderFuelTrims; 00354 00355 /* TablesC */ 00356 // TODO 00357 00358 /* TablesD */ 00359 // TODO 00360 00361 /* filler defs */ 00362 fillerALocation = (void*)&SmallTablesAFlash.filler; 00363 fillerA2Location = (void*)&SmallTablesAFlash2.filler; 00364 fillerBLocation = (void*)&SmallTablesBFlash.filler; 00365 fillerB2Location = (void*)&SmallTablesBFlash2.filler; 00366 fillerCLocation = (void*)&SmallTablesCFlash.filler; 00367 fillerC2Location = (void*)&SmallTablesCFlash2.filler; 00368 fillerDLocation = (void*)&SmallTablesDFlash.filler; 00369 fillerD2Location = (void*)&SmallTablesDFlash2.filler; 00370 } 00371 00372 00376 void initPagedRAMTune(){ 00377 /* Copy the tables from flash to RAM */ 00378 RPAGE = RPAGE_TUNE_ONE; 00379 memcpy((void*)&TablesA, SmallTablesAFlashLocation, MAINTABLE_SIZE); 00380 memcpy((void*)&TablesB, SmallTablesBFlashLocation, MAINTABLE_SIZE); 00381 memcpy((void*)&TablesC, SmallTablesCFlashLocation, MAINTABLE_SIZE); 00382 memcpy((void*)&TablesD, SmallTablesDFlashLocation, MAINTABLE_SIZE); 00383 RPAGE = RPAGE_TUNE_TWO; 00384 memcpy((void*)&TablesA, SmallTablesAFlash2Location, MAINTABLE_SIZE); 00385 memcpy((void*)&TablesB, SmallTablesBFlash2Location, MAINTABLE_SIZE); 00386 memcpy((void*)&TablesC, SmallTablesCFlash2Location, MAINTABLE_SIZE); 00387 memcpy((void*)&TablesD, SmallTablesDFlash2Location, MAINTABLE_SIZE); 00388 } 00389 00390 00404 void initAllPagedAddresses(){ 00405 /* Setup pointers to lookup tables */ 00406 initLookupAddresses(); 00407 /* Setup pointers to the main tables */ 00408 initFuelAddresses(); 00409 initTimingAddresses(); 00410 initTunableAddresses(); 00411 } 00412 00413 00426 void initAllPagedRAM(){ 00427 /* Setup the flash block pointers before copying flash to RAM using them */ 00428 initAllPagedAddresses(); 00429 00430 /* Copy the tables up to their paged RAM blocks through the window from flash */ 00431 initPagedRAMFuel(); 00432 initPagedRAMTime(); 00433 initPagedRAMTune(); 00434 00435 /* Default to page one for now, perhaps read the configured port straight out of reset in future? TODO */ 00436 setupPagedRAM(TRUE); // probably something like (PORTA & TableSwitchingMask) 00437 } 00438 00439 00440 /* Initialise and set up all running variables that require a non-zero start value here */ 00441 /* All other variables are initialised to zero by the premain built in code */ 00442 void initVariables(){ 00443 /* And the opposite for the other halves */ 00444 CoreVars = &CoreVars0; 00445 DerivedVars = &DerivedVars0; 00446 ADCArrays = &ADCArrays0; 00447 ADCArraysRecord = &ADCArrays1; 00448 asyncADCArrays = &asyncADCArrays0; 00449 asyncADCArraysRecord = &asyncADCArrays1; 00450 currentDwellMath = ¤tDwell0; 00451 currentDwellRealtime = ¤tDwell1; 00452 00453 injectorMainPulseWidthsMath = injectorMainPulseWidths0; 00454 injectorMainPulseWidthsRealtime = injectorMainPulseWidths1; 00455 injectorStagedPulseWidthsMath = injectorStagedPulseWidths0; 00456 injectorStagedPulseWidthsRealtime = injectorStagedPulseWidths1; 00457 00458 mathSampleTimeStamp = &ISRLatencyVars.mathSampleTimeStamp0; // TODO temp, remove 00459 mathSampleTimeStampRecord = &ISRLatencyVars.mathSampleTimeStamp1; // TODO temp, remove 00460 RPM = &RPM0; // TODO temp, remove 00461 RPMRecord = &RPM1; // TODO temp, remove 00462 00463 /* Setup the pointers to the registers for fueling use, this does NOT work if done in global.c, I still don't know why. */ 00464 injectorMainTimeRegisters[0] = TC2_ADDR; 00465 injectorMainTimeRegisters[1] = TC3_ADDR; 00466 injectorMainTimeRegisters[2] = TC4_ADDR; 00467 injectorMainTimeRegisters[3] = TC5_ADDR; 00468 injectorMainTimeRegisters[4] = TC6_ADDR; 00469 injectorMainTimeRegisters[5] = TC7_ADDR; 00470 injectorMainControlRegisters[0] = TCTL2_ADDR; 00471 injectorMainControlRegisters[1] = TCTL2_ADDR; 00472 injectorMainControlRegisters[2] = TCTL1_ADDR; 00473 injectorMainControlRegisters[3] = TCTL1_ADDR; 00474 injectorMainControlRegisters[4] = TCTL1_ADDR; 00475 injectorMainControlRegisters[5] = TCTL1_ADDR; 00476 00477 configuredBasicDatalogLength = maxBasicDatalogLength; 00478 00479 // 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 00480 } 00481 00482 00509 void initFlash(){ 00510 FCLKDIV = 0x4A; /* Set the flash clock frequency */ 00511 FPROT = 0xFF; /* Disable all flash protection */ 00512 FSTAT = FSTAT | (PVIOL | ACCERR); /* Clear any errors */ 00513 } 00514 00529 void initXgate(){ 00530 /* route interrupt to xgate */ 00531 INT_CFADDR = (0x72 & 0xF0); /* vector address = channel_id * 2 */ 00532 INT_CFDATA0 = 0x01; /* RQST = 1 */ 00533 INT_CFDATA1 = 0x81; /* PRIO = 1 */ 00534 00535 /* HCS12mem currently limits us to half of the available flash, hence this copy code. */ 00536 /* XGATE sees flash starting at paged address 0xE0, 0x8800 */ 00537 00538 // Reuse variables across multiple blocks of unreachable code copying code 00539 unsigned short * xgateDataDestination; 00540 unsigned char destinationPage; 00541 // Save old flash page value 00542 unsigned char OldPPAGE = PPAGE; 00543 00544 // Copy the XGATE vector table into the visible region only if it differs from what is already there (save on flash burns for now) 00545 xgateDataDestination = (unsigned short *)0x8800; 00546 destinationPage = 0xE0; 00547 // Copy to ram first as only one paged flash block at a time is visible 00548 memcpy((void*)&TXBuffer, (void*)&xgateIntVectorTable, sizeof(xgateIntVectorTable)); 00549 // Switch to destination page for comparison 00550 PPAGE = destinationPage; 00551 // Do the check, from the copy in RAM to the destination. 00552 if(compare((unsigned char*)&TXBuffer, (unsigned char*)xgateDataDestination, sizeof(xgateIntVectorTable))){ 00553 eraseSector(destinationPage, xgateDataDestination); 00554 writeSector(RPAGE, (unsigned short*)&TXBuffer, destinationPage, xgateDataDestination); 00555 } 00556 00557 // Copy xgatethread0 code into the visible region only if it differs from what is already there (save on flash burns for now) 00558 xgateDataDestination = (unsigned short *)0x9000; 00559 destinationPage = 0xE1; 00560 unsigned short xgateThread0Size = (void*)&xgateThread0End - (void*)&xgateThread0; 00561 // Copy to ram first as only one paged flash block at a time is visible 00562 memcpy((void*)&TXBuffer, (void*)&xgateThread0, xgateThread0Size); 00563 // Switch to destination page for comparison 00564 PPAGE = destinationPage; 00565 // Do the check, from the copy in RAM to the destination. 00566 if(compare((unsigned char*)&TXBuffer, (unsigned char*)xgateDataDestination, xgateThread0Size)){ 00567 eraseSector(destinationPage, xgateDataDestination); 00568 writeSector(RPAGE, (unsigned short*)&TXBuffer, destinationPage, xgateDataDestination); 00569 } 00570 00571 // Switch the page back to how it was 00572 PPAGE = OldPPAGE; 00573 00574 // XGATE threads execute from flash at the moment 00575 00576 // Set the XGVBR register to its start address in flash (page 0xE0 after 2K register space) 00577 XGVBR = (unsigned short )0x0800; 00578 00579 // Enable XGate and XGate interrupts 00580 XGMCTL= (unsigned short)0x8181; 00581 } 00582 00583 /* Set up the timer module and its various interrupts */ 00584 void initECTTimer(){ 00585 00586 // TODO rearrange the order of this stuff and pull enable and interrupt enable out to the last function call of init. 00587 00588 00589 #ifndef NO_INIT 00590 /* Timer channel interrupts */ 00591 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 */ 00592 TFLG = ONES; /* Clear all the flags such that we are up and running before they first occur */ 00593 TFLGOF = ONES; /* Clear all the flags such that we are up and running before they first occur */ 00594 00595 /* TODO Turn the timer on and set the rate and overflow interrupt */ 00596 // DLYCT = 0xFF; /* max noise filtering as experiment for volvo this will come from flash config */ // just hiding a wiring/circuit issue... 00597 TSCR1 = 0x88; /* 0b_1000_1000 Timer enabled, and precision timer turned on */ 00598 TSCR2 = 0x87; /* 0b_1000_0111 Overflow interrupt enable, divide by 256 if precision turned off */ 00599 // PTPSR = 0x03; /* 4 prescaler gives .1uS resolution and max period of 7ms measured */ 00600 PTPSR = 0x1F; /* 32 prescaler gives 0.8uS resolution and max period of 52.4288ms measured */ 00601 // PTPSR = 0x3F; /* 64 prescaler gives 1.6uS resolution and max period of 105ms measured */ 00602 // PTPSR = 0xFF; /* 256 prescaler gives 6.4uS resolution and max period of 400ms measured */ 00603 // PTPSR = 0x7F; /* 128 prescaler gives 3.2uS resolution and max period of 200ms measured */ 00604 /* http://www.google.com/search?hl=en&safe=off&q=1+%2F+%2840MHz+%2F+32+%29&btnG=Search */ 00605 /* http://www.google.com/search?hl=en&safe=off&q=1+%2F+%2840MHz+%2F+32+%29+*+2%5E16&btnG=Search */ 00606 /* www.mecheng.adelaide.edu.au/robotics_novell/WWW_Devs/Dragon12/LM4_Timer.pdf */ 00607 00608 /* Initial actions */ 00609 TIOS = 0xFC; /* 0b_1111_1100 0 and 1 are input capture, 2 through 7 are output compare */ 00610 TCTL1 = ZEROS; /* Set disabled at startup time, use these and other flags to switch fueling on and off inside the decoder */ 00611 TCTL2 = ZEROS; /* 0,1 have compare turned off regardless as they are in IC mode. */ 00612 TCTL3 = ZEROS; /* Capture off for 4 - 7 */ 00613 TCTL4 = 0x0F; /* Capture on both edges of two pins for IC (0,1), capture off for 2,3 */ 00614 00615 // TODO setup delay counters on 0 and 1 to filter noise (nice feature!) 00616 //DLYCT = ??; built in noise filter 00617 00618 /* Configurable tachometer output */ 00619 PTMCPSR = fixedConfigs1.tachoSettings.tachoTickFactor - 1; // Precision prescaler - fastest is 1 represented by 0, slowest/longest possible is 256 represented by 255 or 0xFF 00620 MCCNT = ONES16; // init to slowest possible, first 00621 MCCTL = 0xC4; // turn on and setup the mod down counter 00622 MCFLG = 0x80; // clear the flag up front 00623 #endif 00624 } 00625 00626 00627 /* Configure the PIT timers for their various uses. */ 00628 void initPITTimer(){ 00629 #ifndef NO_INIT 00630 /* */ 00631 // set micro periods 00632 PITMTLD0 = 0x1F; /* 32 prescaler gives 0.8uS resolution and max period of 52.4288ms measured */ 00633 PITMTLD1 = 0x1F; /* ditto */ 00634 /* http://www.google.com/search?hl=en&safe=off&q=1+%2F+%2840MHz+%2F+32+%29 Exactly the same as for ECT */ 00635 00636 // set timers running 00637 // PITLD0 = dwellPeriod; 00638 // enable module 00639 PITCFLMT = 0x80; 00640 // enable channels 00641 //PITCE = 0x03; 00642 // enable interrupt 00643 // PITINTE = 0x01; 00644 // clear flags 00645 //PITFLT = ONES; 00646 #endif 00647 } 00648 00649 /* Setup the sci module(s) that we need to use. */ 00650 void initSCIStuff(){ 00651 /* The alternative register set selector defaults to zero */ 00652 00653 // set the baud/data speed 00654 SCI0BD = fixedConfigs1.serialSettings.baudDivisor; 00655 00656 // etc 00657 00658 /* Switch to alternative register set? */ 00659 00660 // etc 00661 00662 /* Switch back again? */ 00663 00664 /* 00665 * 0 = LOOPS (normal two wire operation) 00666 * 0 = SCISWAI (Wait mode on) 00667 * 0 = RSRC (if loops=1, int/ext wiring) 00668 * 1 = M MODE (9 bit operation) 00669 * 0 = WAKE (idle line wakeup) 00670 * 0 = ILT (idle line type count start pos) 00671 * 1 = PE (parity on) 00672 * 1 = PT (odd parity) (minicom defaults to no parity) 00673 * 00674 * 00010011 = 0x13 00675 */ 00676 SCI0CR1 = 0x13; 00677 00678 /* 00679 * 0 = TIE (tx data empty isr disabled) 00680 * 0 = TCIE (tx complete isr disabled) 00681 * 1 = RIE (rx full isr enabled) 00682 * 0 = ILIE (idle line isr disabled) 00683 * 1 = TE (transmit enabled) 00684 * 1 = RE (receive enabled) 00685 * 0 = RWU (rx wake up normal) 00686 * 0 = SBK (send break off) 00687 * 00688 * 00101100 = 0x2C 00689 */ 00690 SCI0CR2 = 0x2C; 00691 } 00692 00693 /* TODO Load and calculate all configuration data required to run */ 00694 void initConfiguration(){ 00695 // // 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. 00696 00697 00698 /* Add in tunable physical parameters at boot time TODO move to init.c TODO duplicate for secondary fuel? or split somehow? 00699 *nstant = ((masterConst * perCylinderVolume) / (stoichiometricAFR * injectorFlow)); 00700 *nstant = ((139371764 * 16384 ) / (15053 * 4096 )); 00701 * OR 00702 *nstant = ((masterConst / injectorFlow) * perCylinderVolume) / stoichiometricAFR; 00703 *nstant = ((139371764 / 4096 ) * 16384 ) / 15053 ; 00704 * http://www.google.com/search?hl=en&safe=off&q=((139371764++%2F+4096+++++)+*+16384+++)+%2F+15053++++&btnG=Search */ 00705 bootFuelConst = ((unsigned long)(masterFuelConstant / fixedConfigs1.engineSettings.injectorFlow) * fixedConfigs1.engineSettings.perCylinderVolume) / fixedConfigs1.engineSettings.stoichiometricAFR; 00706 00707 /* The MAP range used to convert fake TPS from MAP and vice versa */ 00708 TPSMAPRange = fixedConfigs2.sensorRanges.TPSOpenMAP - fixedConfigs2.sensorRanges.TPSClosedMAP; 00709 00710 /* The ADC range used to generate TPS percentage */ 00711 TPSADCRange = fixedConfigs2.sensorRanges.TPSMaximumADC - fixedConfigs2.sensorRanges.TPSMinimumADC; 00712 00713 00714 /* Use like flags for now, just add one for each later */ 00715 unsigned char cumulativeConfigErrors = 0; 00716 00717 /* Check various aspects of config which will cause problems */ 00718 00719 /* BRV max bigger than variable that holds it */ 00720 if(((unsigned long)fixedConfigs2.sensorRanges.BRVMinimum + fixedConfigs2.sensorRanges.BRVRange) > 65535){ 00721 //sendError(BRV_MAX_TOO_LARGE); 00722 cumulativeConfigErrors++; 00723 } 00724 00725 // TODO check all critical variables here! 00726 00727 /* 00728 * check ignition settings for range etc, possibly check some of those on the fly too 00729 * check fuel settings for being reasonable 00730 * check all variable tables for correct sizing 00731 * etc 00732 */ 00733 00734 while(cumulativeConfigErrors > 0){ 00735 sleep(1000); 00736 PORTS_BA ^= ONES16; // flash leds 00737 //send("There were "); 00738 //sendUC(cumulativeConfigErrors); 00739 //send(" config errors, init aborted!"); 00740 } // TODO ensure that we can recieve config and settings via serial while this is occuring! If not a bad config will lock us out all together. 00741 } 00742 00743 00744 /* Set up all the remaining interrupts */ 00745 void initInterrupts(){ 00746 /* IMPORTANT : Set the s12x vector base register (Thanks Karsten!!) */ 00747 IVBR = 0xF7; /* Without this the interrupts will never find your code! */ 00748 00749 /* Set up the Real Time Interrupt */ 00750 RTICTL = 0x81; /* 0b_1000_0001 0.125ms/125us period http://www.google.com/search?hl=en&safe=off&q=1+%2F+%2816MHz+%2F+%282+*+10%5E3%29+%29&btnG=Search */ 00751 // RTICTL = 0xF9; /* 0b_1111_1001 0.125s/125ms period http://www.google.com/search?hl=en&safe=off&q=1+%2F+%2816MHz+%2F+%282*10%5E6%29+%29&btnG=Search */ 00752 CRGINT |= 0x80; /* Enable the RTI */ 00753 CRGFLG = 0x80; /* Clear the RTI flag */ 00754 00755 #ifndef NO_INIT 00756 // set up port H for testing 00757 PPSH = ZEROS; // falling edge/pull up for all 00758 PIEH = ONES; // enable all pins interrupts 00759 PIFH = ONES; // clear all port H interrupt flags 00760 #endif 00761 00762 // TODO set up irq and xirq for testing 00763 // IRQCR for IRQ 00764 // 00765 00766 /* VReg API setup (only for wait mode? i think so) */ 00767 // VREGAPIR = 0x09C3; /* For 500ms period : (500ms - 0.2ms) / 0.2ms = 0b100111000011 = 2499 */ 00768 // VREGAPICL = 0x02; /* Enable the interrupt */ 00769 // VREGAPICL = 0x04; /* Start the counter running */ 00770 /* 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 */ 00771 00772 /* LVI Low Voltage Interrupt enable */ 00773 VREGCTRL = 0x02; // Counts bad power events for diagnosis reasons 00774 }