00001 /* init.c 00002 00003 Copyright 2008 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 send them upstream to us at admin@diyefi.org 00021 00022 Thank you for choosing FreeEMS to run your engine! */ 00023 00024 #define INIT_C 00025 #include "inc/freeEMS.h" 00026 #include "inc/interrupts.h" 00027 #include "inc/utils.h" 00028 #include "inc/commsISRs.h" 00029 #include "inc/init.h" 00030 #include <string.h> 00031 00032 00033 /* If these are moved back to the header then */ 00034 /* wrap them in an if to keep them hidden away */ 00035 void initPLL(void) FPAGE_FE; 00036 void initIO(void) FPAGE_FE; 00037 void initAllPagedRAM(void) FPAGE_FE; 00038 void initVariables(void) FPAGE_FE; 00039 void initFlash(void) FPAGE_FE; 00040 void initECTTimer(void) FPAGE_FE; 00041 void initPITTimer(void) FPAGE_FE; 00042 void initSCIStuff(void) FPAGE_FE; 00043 void initConfiguration(void) FPAGE_FE; 00044 void initInterrupts(void) FPAGE_FE; 00045 00046 void initLookupAddresses(void) LOOKUPF; 00047 void initPagedRAMFuel(void) FUELTABLESF; 00048 void initPagedRAMTime(void) TIMETABLESF; 00049 void initPagedRAMTune(void) TUNETABLESF; 00050 00051 00052 /* Main init function to be called from main.c before entering the main loop */ 00053 void init(){ 00054 ATOMIC_START(); /* Disable ALL interrupts while we configure the board ready for use */ 00055 initPLL(); /* Set up the PLL and use it */ 00056 initIO(); /* TODO make this config dependent. Set up all the pins and modules to be in low power harmless states */ 00057 initAllPagedRAM(); /* Copy table and config blocks of data from flash to the paged ram blocks for fast data lookup */ 00058 initVariables(); /* Initialise the rest of the running variables etc */ 00059 initFlash(); /* TODO, populate */ 00060 initECTTimer(); /* TODO move this to inside config in an organised way. Set up the timer module and its various aspects */ 00061 initPITTimer(); /* TODO ditto... */ 00062 initSCIStuff(); /* Setup the sci module(s) that we will use. */ 00063 initConfiguration(); /* TODO Set user/feature/config up here! */ 00064 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 */ 00065 ATOMIC_END(); /* Re-enable any configured interrupts */ 00066 } 00067 00068 00069 /* used to chop out all the init stuff at compile time for hardware testing. */ 00070 //#define NO_INIT 00071 00072 00073 /* Set the Phase Locked Loop to our desired frequency (80MHz) and switch to using it for clock (40MHz bus speed) */ 00074 void initPLL(){ 00075 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) */ 00076 PLLCTL &= PLLOFF; /* Turn the PLL device off to adjust its speed (on by default out of reset) */ 00077 REFDV = PLLDIVISOR; /* 16MHz / (3 + 1) = 4MHz Bus frequency */ 00078 SYNR = PLLMULTIPLIER; /* 4MHz * (9 + 1) = 40MHz Bus frequency */ 00079 PLLCTL |= PLLON; /* Turn the PLL device back on again at 80MHz */ 00080 00081 while (!(CRGFLG & PLLLOCK)){ 00082 /* Do nothing while we wait till the PLL loop locks onto the target frequency. */ 00083 /* Target frequency is given by (2 * (crystal frequency / (REFDV + 1)) * (SYNR + 1)) */ 00084 /* Bus frequency is half PLL frequency and given by ((crystal frequency / (REFDV + 1)) * (SYNR + 1)) */ 00085 } 00086 00087 CLKSEL = PLLSELON; /* Switches to PLL clock for internal bus frequency */ 00088 /* from MC9S12XDP512V2.pdf Section 2.4.1.1.2 page 101 Third paragraph */ 00089 /* "This takes a MAXIMUM of 4 OSCCLK clock cylces PLUS 4 PLL clock cycles" */ 00090 /* "During this time ALL clocks freeze, and CPU activity ceases" */ 00091 /* Therefore there is no point waiting for this to occur, we already are... */ 00092 } 00093 00094 00095 /* Configure all the I/O to default values to keep power use down etc */ 00096 void initIO(){ 00097 /* for now, hard code all stuff to be outputs as per Freescale documentation, */ 00098 /* later what to do will be pulled from flash configuration such that all */ 00099 /* things are setup at once, and not messed with thereafter. when the port */ 00100 /* something uses is changed via the tuning interface, the confuration will be */ 00101 /* done on the fly, and the value burned to flash such that next boot happens */ 00102 /* correctly and current running devices are used in that way. */ 00103 00104 /* Turn off and on and configure all the modules in an explicit way */ 00105 // TODO set up and turn off all modules (CAN,SCI,SPI,IIC,etc) 00106 00107 /* Turn off the digital input buffers on the ATD channels */ 00108 ATD0DIEN = ZEROS; /* You are out of your mind if you waste this on digital Inputs */ 00109 ATD1DIEN0 = ZEROS; /* You are out of your mind if you waste this on digital Inputs (NOT-bonded, can't use) */ 00110 ATD1DIEN1 = ZEROS; /* You are out of your mind if you waste this on digital Inputs */ 00111 /* TODO Second half of ATD1 - can we disable this somehow */ 00112 00113 /* And configure them all for analog input */ 00114 ATD0CTL2 = 0x80; /* Turns on the ADC block. */ 00115 ATD0CTL3 = 0x40; /* Set sequence length = 8 */ 00116 ATD0CTL5 = 0xB0; /* Sets justification to right, multiplex and scan all channels. */ 00117 // TODO find out if this is the default (i suspect it is) 00118 // TODO look into sampling techniques 00119 00120 /* And configure them all for analog input */ 00121 ATD1CTL0 = 0x07; /* Sets wrap on 8th ADC because we can't use the other 8 */ 00122 ATD1CTL2 = 0x80; /* Turns on the ADC block. */ 00123 ATD1CTL3 = 0x40; /* Set sequence length = 8 */ 00124 ATD1CTL5 = 0xB0; /* Sets justification to right, multiplex and scan all channels. */ 00125 // TODO find out if this is the default (i suspect it is) 00126 // TODO look into sampling techniques 00127 00128 #ifndef NO_INIT 00129 /* Set up the PWM component and initialise its values to off */ 00130 PWME = 0x7F; /* Turn on PWM 0 - 6 (7 is user LED on main board) */ 00131 PWMCLK = ZEROS; /* The fastest we can go for all channels */ 00132 PWMPRCLK = ZEROS; /* The fastest prescaler we can go for all channels */ 00133 PWMSCLA = ZEROS; /* The fastest we can go */ 00134 PWMSCLB = ZEROS; /* The fastest we can go */ 00135 /* TODO PWM channel concatenation for high resolution */ 00136 // join channel pairs together here (needs 16 bit regs enabled too) 00137 /* TODO Initialise pwm channels with frequency, and initial duty for real use */ 00138 // initial PWM settings for testing 00139 /* PWM periods */ 00140 PWMPER0 = 0xFF; // 255 for ADC0 testing 00141 PWMPER1 = 0xFF; // 255 for ADC1 testing 00142 PWMPER2 = 0xFF; // 255 for ADC1 testing 00143 PWMPER3 = 0xFF; // 255 for ADC1 testing 00144 PWMPER4 = 0xFF; // 255 for ADC1 testing 00145 PWMPER5 = 0xFF; // 255 for ADC1 testing 00146 PWMPER6 = 0xFF; // 255 for ADC1 testing 00147 PWMPER7 = 0xFF; // 255 for ADC1 testing 00148 /* PWM duties */ 00149 PWMDTY0 = 0; 00150 PWMDTY1 = 0; 00151 PWMDTY2 = 0; 00152 PWMDTY3 = 0; 00153 PWMDTY4 = 0; 00154 PWMDTY5 = 0; 00155 PWMDTY6 = 0; 00156 PWMDTY7 = 0; 00157 00158 00159 /* Initialise the state of pins configured as output */ 00160 /* Initialise to low such that transistor grounded things are all turned off by default. */ 00161 PORTA = ZEROS; /* The serial monitor pin is on 0x40, and could cause problems if capacitance at the output is large when a reset occurs. */ 00162 PORTB = ZEROS; /* Init the rest of the spark outputs as off */ 00163 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 */ 00164 PORTK = ZEROS; 00165 PORTS = ZEROS; 00166 PORTT = ZEROS; /* All pins in off state at boot up (only matters for 2 - 7) */ 00167 PORTM = ZEROS; 00168 PORTP = ZEROS; // TODO hook these up to the adc channels such that you can vary the brightness of an led with a pot. 00169 PORTH = ZEROS; 00170 PORTJ = ZEROS; 00171 /* AD0PT1 You are out of your mind if you waste this on digital Inputs */ 00172 /* AD1PT1 You are out of your mind if you waste this on digital Inputs */ 00173 00174 /* Initialise the Data Direction Registers */ 00175 /* To outputs based on the note at the end of chapter 1.2.2 of MC9S12XDP512V2.pdf */ 00176 DDRA = ONES; /* GPIO (8) */ 00177 DDRB = ONES; /* GPIO (8) */ 00178 DDRE = 0xFC; /* 0b_1111_1100 : Clock and mode pins PE0,PE1 are input only pins, the rest are GPIO */ 00179 DDRK = ONES; /* Only 0,1,2,3,4,5,7, NOT 6 (7) */ 00180 DDRS = ONES; /* SCI0, SCI1, SPI0 (8) */ 00181 DDRT = 0xFC; /* 0b_1111_1100 set ECT pins 0,1 to IC and 2:7 to OC (8) */ 00182 DDRM = ONES; /* CAN 0 - 3 (8) */ 00183 DDRP = ONES; /* PWM pins (8) */ 00184 DDRH = ZEROS; /* All pins configured as input for misc isrs (SPI1, SPI2) (8) */ 00185 DDRJ = ONES; /* Only 0,1,6,7 are brought out on the 112 pin chip (4) */ 00186 /* Configure the non bonded pins to output to avoid current drain (112 pin package) */ 00187 DDRC = ONES; /* NON-bonded external data bus pins */ 00188 DDRD = ONES; /* NON-bonded external data bus pins */ 00189 /* AD0DDR1 You are out of your mind if you waste this on digital Inputs */ 00190 /* AD1DDR1 You are out of your mind if you waste this on digital Inputs */ 00191 #endif 00192 } 00193 00194 00195 /* Many thanks to Jean Bélanger for the inspiration/idea to do this! */ 00196 void initLookupAddresses(void){ 00197 IATTransferTableLocation = (void*)&IATTransferTable; 00198 CHTTransferTableLocation = (void*)&CHTTransferTable; 00199 MAFTransferTableLocation = (void*)&MAFTransferTable; 00200 TestTransferTableLocation = (void*)&TestTransferTable; 00201 } 00202 00203 00204 /* Many thanks to Jean Bélanger for the inspiration/idea to do this! */ 00205 void initPagedRAMFuel(void){ 00206 /* Setup addresses within the page to avoid warnings */ 00207 VETableMainFlashLocation = (void*)&VETableMainFlash; 00208 VETableSecondaryFlashLocation = (void*)&VETableSecondaryFlash; 00209 VETableTertiaryFlashLocation = (void*)&VETableTertiaryFlash; 00210 LambdaTableFlashLocation = (void*)&LambdaTableFlash; 00211 VETableMainFlash2Location = (void*)&VETableMainFlash2; 00212 VETableSecondaryFlash2Location = (void*)&VETableSecondaryFlash2; 00213 VETableTertiaryFlash2Location = (void*)&VETableTertiaryFlash2; 00214 LambdaTableFlash2Location = (void*)&LambdaTableFlash2; 00215 /* Copy the tables from flash to RAM */ 00216 RPAGE = RPAGE_FUEL_ONE; 00217 memcpy((void*)&TablesA, VETableMainFlashLocation, MAINTABLE_SIZE); 00218 memcpy((void*)&TablesB, (void*)&VETableSecondaryFlash, MAINTABLE_SIZE); 00219 memcpy((void*)&TablesC, (void*)&VETableTertiaryFlash, MAINTABLE_SIZE); 00220 memcpy((void*)&TablesD, (void*)&LambdaTableFlash, MAINTABLE_SIZE); 00221 RPAGE = RPAGE_FUEL_TWO; 00222 memcpy((void*)&TablesA, (void*)&VETableMainFlash2, MAINTABLE_SIZE); 00223 memcpy((void*)&TablesB, (void*)&VETableSecondaryFlash2, MAINTABLE_SIZE); 00224 memcpy((void*)&TablesC, (void*)&VETableTertiaryFlash2, MAINTABLE_SIZE); 00225 memcpy((void*)&TablesD, (void*)&LambdaTableFlash2, MAINTABLE_SIZE); 00226 } 00227 00228 00229 /* Many thanks to Jean Bélanger for the inspiration/idea to do this! */ 00230 void initPagedRAMTime(void){ 00231 /* Setup addresses within the page to avoid warnings */ 00232 IgnitionAdvanceTableMainFlashLocation = (void*)&IgnitionAdvanceTableMainFlash; 00233 IgnitionAdvanceTableSecondaryFlashLocation = (void*)&IgnitionAdvanceTableSecondaryFlash; 00234 InjectionAdvanceTableMainFlashLocation = (void*)&InjectionAdvanceTableMainFlash; 00235 InjectionAdvanceTableSecondaryFlashLocation = (void*)&InjectionAdvanceTableSecondaryFlash; 00236 IgnitionAdvanceTableMainFlash2Location = (void*)&IgnitionAdvanceTableMainFlash2; 00237 IgnitionAdvanceTableSecondaryFlash2Location = (void*)&IgnitionAdvanceTableSecondaryFlash2; 00238 InjectionAdvanceTableMainFlash2Location = (void*)&InjectionAdvanceTableMainFlash2; 00239 InjectionAdvanceTableSecondaryFlash2Location = (void*)&InjectionAdvanceTableSecondaryFlash2; 00240 /* Copy the tables from flash to RAM */ 00241 RPAGE = RPAGE_TIME_ONE; 00242 memcpy((void*)&TablesA, IgnitionAdvanceTableMainFlashLocation, MAINTABLE_SIZE); 00243 memcpy((void*)&TablesB, IgnitionAdvanceTableSecondaryFlashLocation, MAINTABLE_SIZE); 00244 memcpy((void*)&TablesC, InjectionAdvanceTableMainFlashLocation, MAINTABLE_SIZE); 00245 memcpy((void*)&TablesD, InjectionAdvanceTableSecondaryFlashLocation, MAINTABLE_SIZE); 00246 RPAGE = RPAGE_TIME_TWO; 00247 memcpy((void*)&TablesA, IgnitionAdvanceTableMainFlash2Location, MAINTABLE_SIZE); 00248 memcpy((void*)&TablesB, IgnitionAdvanceTableSecondaryFlash2Location, MAINTABLE_SIZE); 00249 memcpy((void*)&TablesC, InjectionAdvanceTableMainFlash2Location, MAINTABLE_SIZE); 00250 memcpy((void*)&TablesD, InjectionAdvanceTableSecondaryFlash2Location, MAINTABLE_SIZE); 00251 } 00252 00253 00254 /* Many thanks to Jean Bélanger for the inspiration/idea to do this! */ 00255 void initPagedRAMTune(void){ 00256 /* Setup addresses within the page to avoid warnings */ 00257 SmallTablesAFlashLocation = (void*)&SmallTablesAFlash; 00258 SmallTablesBFlashLocation = (void*)&SmallTablesBFlash; 00259 SmallTablesCFlashLocation = (void*)&SmallTablesCFlash; 00260 SmallTablesDFlashLocation = (void*)&SmallTablesDFlash; 00261 SmallTablesAFlash2Location = (void*)&SmallTablesAFlash2; 00262 SmallTablesBFlash2Location = (void*)&SmallTablesBFlash2; 00263 SmallTablesCFlash2Location = (void*)&SmallTablesCFlash2; 00264 SmallTablesDFlash2Location = (void*)&SmallTablesDFlash2; 00265 /* Copy the tables from flash to RAM */ 00266 RPAGE = RPAGE_TUNE_ONE; 00267 memcpy((void*)&TablesA, SmallTablesAFlashLocation, MAINTABLE_SIZE); 00268 memcpy((void*)&TablesB, SmallTablesBFlashLocation, MAINTABLE_SIZE); 00269 memcpy((void*)&TablesC, SmallTablesCFlashLocation, MAINTABLE_SIZE); 00270 memcpy((void*)&TablesD, SmallTablesDFlashLocation, MAINTABLE_SIZE); 00271 RPAGE = RPAGE_TUNE_TWO; 00272 memcpy((void*)&TablesA, SmallTablesAFlash2Location, MAINTABLE_SIZE); 00273 memcpy((void*)&TablesB, SmallTablesBFlash2Location, MAINTABLE_SIZE); 00274 memcpy((void*)&TablesC, SmallTablesCFlash2Location, MAINTABLE_SIZE); 00275 memcpy((void*)&TablesD, SmallTablesDFlash2Location, MAINTABLE_SIZE); 00276 } 00277 00278 00279 /* Take the tables and config from flash up to RAM and initialise pointers to them. 00280 * 00281 * For the main tables and other paged config we need to adjust 00282 * the RPAGE value to the appropriate one before copying up. 00283 */ 00284 void initAllPagedRAM(){ 00285 /* Setup pointers to lookup tables */ 00286 initLookupAddresses(); 00287 00288 /* Copy the tables up to their paged ram blocks through the window from flash */ 00289 initPagedRAMFuel(); 00290 initPagedRAMTime(); 00291 initPagedRAMTune(); 00292 00293 /* Init all pointers to tunable items with direct addresses */ 00294 /* Pointers remain the same when switching pages so are initialised only once */ 00295 // VETableMain = &TablesA.VETableMain; 00296 // VETableSecondary = &TablesB.VETableSecondary; 00297 // VETableTertiary = &TablesC.VETableMainTertiary; 00298 // LambdaTable = &TablesD.LambdaTable; 00299 // 00300 // IgnitionAdvanceTableMain = &TablesA.IgnitionAdvanceTableMain; 00301 // IgnitionAdvanceTableSecondary = &TablesB.IgnitionAdvanceTableSecondary; 00302 // InjectionAdvanceTableMain = &TablesC.InjectionAdvanceTableMain; 00303 // InjectionAdvanceTableSecondary = &TablesD.InjectionAdvanceTableSecondary; 00304 // 00305 // dwellDesiredVersusVoltageTable = &TablesA.SmallTablesA.dwellDesiredVersusVoltageTable; 00306 // injectorDeadTimeTable = &TablesA.SmallTablesA.injectorDeadTimeTable; 00307 // postStartEnrichmentTable = &TablesA.SmallTablesA.postStartEnrichmentTable; 00308 // engineTempEnrichmentTableFixed = &TablesA.SmallTablesA.engineTempEnrichmentTableFixed; 00309 // primingVolumeTable = &TablesA.SmallTablesA.primingVolumeTable; 00310 // engineTempEnrichmentTablePercent = &TablesA.SmallTablesA.engineTempEnrichmentTablePercent; 00311 // dwellMaxVersusRPMTable = &TablesA.SmallTablesA.dwellMaxVersusRPMTable; 00312 // 00313 // perCylinderFuelTrims = TablesB.SmallTablesB.perCylinderFuelTrims; 00314 00315 /* Default to page one for now, perhaps read the configured port straight out of reset in future? TODO */ 00316 setupPagedRAM(TRUE); // probably something like (PORTA & TableSwitchingMask) 00317 } 00318 00319 00320 /* Initialise and set up all running variables that require a non-zero start value here */ 00321 /* All other variables are initialised to zero by the premain built in code */ 00322 void initVariables(){ 00323 /* And the opposite for the other halves */ 00324 CoreVars = &CoreVars0; 00325 DerivedVars = &DerivedVars0; 00326 ADCArrays = &ADCArrays0; 00327 ADCArraysRecord = &ADCArrays1; 00328 asyncADCArrays = &asyncADCArrays0; 00329 asyncADCArraysRecord = &asyncADCArrays1; 00330 currentDwellMath = ¤tDwell0; 00331 currentDwellRealtime = ¤tDwell1; 00332 00333 injectorMainPulseWidthsMath = injectorMainPulseWidths0; 00334 injectorMainPulseWidthsRealtime = injectorMainPulseWidths1; 00335 injectorStagedPulseWidthsMath = injectorStagedPulseWidths0; 00336 injectorStagedPulseWidthsRealtime = injectorStagedPulseWidths1; 00337 00338 mathSampleTimeStamp = &ISRLatencyVars.mathSampleTimeStamp0; // TODO temp, remove 00339 mathSampleTimeStampRecord = &ISRLatencyVars.mathSampleTimeStamp1; // TODO temp, remove 00340 RPM = &RPM0; // TODO temp, remove 00341 RPMRecord = &RPM1; // TODO temp, remove 00342 00343 /* Setup the pointers to the registers for fueling use, this does NOT work if done in global.c, I still don't know why. */ 00344 injectorMainTimeRegisters[0] = TC2_ADDR; 00345 injectorMainTimeRegisters[1] = TC3_ADDR; 00346 injectorMainTimeRegisters[2] = TC4_ADDR; 00347 injectorMainTimeRegisters[3] = TC5_ADDR; 00348 injectorMainTimeRegisters[4] = TC6_ADDR; 00349 injectorMainTimeRegisters[5] = TC7_ADDR; 00350 injectorMainControlRegisters[0] = TCTL2_ADDR; 00351 injectorMainControlRegisters[1] = TCTL2_ADDR; 00352 injectorMainControlRegisters[2] = TCTL1_ADDR; 00353 injectorMainControlRegisters[3] = TCTL1_ADDR; 00354 injectorMainControlRegisters[4] = TCTL1_ADDR; 00355 injectorMainControlRegisters[5] = TCTL1_ADDR; 00356 00357 configuredBasicDatalogLength = maxBasicDatalogLength; 00358 00359 // 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 00360 } 00361 00362 /* TODO initialise the flash burning configuration regs */ 00363 void initFlash(){ 00364 // TBC 00365 unsigned char flashclock; 00366 unsigned short SysClock = 16000; //TODO see if Fred already specified this var and/or move to configs/constants 00367 00368 if (SysClock >= 12000){ 00369 flashclock = (unsigned char) (SysClock/8/200 ); 00370 } 00371 else{ 00372 flashclock = (unsigned char) (SysClock/200 +1); 00373 } 00374 // TODO FIX SO EQUASION WORKS 00375 // FCLKDIV = FCLKDIV|flashclock; 00376 FCLKDIV = 0x4A; 00377 00378 FPROT = 0xFF; //disable all flash protection 00379 FSTAT = FSTAT|(PVIOL|ACCERR); //clear any errors 00380 00381 } 00382 00383 /* Set up the timer module and its various interrupts */ 00384 void initECTTimer(){ 00385 00386 // TODO rearrange the order of this stuff and pull enable and interrupt enable out to the last function call of init. 00387 00388 #ifndef NO_INIT 00389 /* Timer channel interrupts */ 00390 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 */ 00391 TFLG = ONES; /* Clear all the flags such that we are up and running before they first occur */ 00392 TFLGOF = ONES; /* Clear all the flags such that we are up and running before they first occur */ 00393 00394 /* TODO Turn the timer on and set the rate and overflow interrupt */ 00395 TSCR1 = 0x88; /* 0b_1000_1000 Timer enabled, and precision timer turned on */ 00396 TSCR2 = 0x87; /* 0b_1000_0111 Overflow interrupt enable, divide by 256 if precision turned off */ 00397 // PTPSR = 0x03; /* 4 prescaler gives .1uS resolution and max period of 7ms measured */ 00398 PTPSR = 0x1F; /* 32 prescaler gives 0.8uS resolution and max period of 52.4288ms measured */ 00399 // PTPSR = 0x3F; /* 64 prescaler gives 1.6uS resolution and max period of 105ms measured */ 00400 // PTPSR = 0xFF; /* 256 prescaler gives 6.4uS resolution and max period of 400ms measured */ 00401 // PTPSR = 0x7F; /* 128 prescaler gives 3.2uS resolution and max period of 200ms measured */ 00402 /* http://www.google.com/search?hl=en&safe=off&q=1+%2F+%2840MHz+%2F+32+%29&btnG=Search */ 00403 /* http://www.google.com/search?hl=en&safe=off&q=1+%2F+%2840MHz+%2F+32+%29+*+2%5E16&btnG=Search */ 00404 /* www.mecheng.adelaide.edu.au/robotics_novell/WWW_Devs/Dragon12/LM4_Timer.pdf */ 00405 00406 /* Initial actions */ 00407 TIOS = 0xFC; /* 0b_1111_1100 0 and 1 are input capture, 2 through 7 are output compare */ 00408 TCTL1 = ZEROS; /* Set disabled at startup time, use these and other flags to switch fueling on and off inside the decoder */ 00409 TCTL2 = ZEROS; /* 0,1 have compare turned off regardless as they are in IC mode. */ 00410 TCTL3 = ZEROS; /* Capture off for 4 - 7 */ 00411 TCTL4 = 0x0F; /* Capture on both edges of two pins for IC (0,1), capture off for 2,3 */ 00412 00413 // TODO setup delay counters on 0 and 1 to filter noise (nice feature!) 00414 //DLYCT = ??; built in noise filter 00415 00416 /* Configurable tachometer output */ 00417 PTMCPSR = fixedConfigs2.tachoTickFactor - 1; // Precision prescaler - fastest is 1 represented by 0, slowest/longest possible is 256 represented by 255 or 0xFF 00418 MCCNT = ONES16; // init to slowest possible, first 00419 MCCTL = 0xC4; // turn on and setup the mod down counter 00420 MCFLG = 0x80; // clear the flag up front 00421 #endif 00422 } 00423 00424 /* Configure the PIT timers for their various uses. */ 00425 void initPITTimer(){ 00426 #ifndef NO_INIT 00427 /* */ 00428 // set micro periods 00429 PITMTLD0 = 0x1F; /* 32 prescaler gives 0.8uS resolution and max period of 52.4288ms measured */ 00430 PITMTLD1 = 0x1F; /* ditto */ 00431 /* http://www.google.com/search?hl=en&safe=off&q=1+%2F+%2840MHz+%2F+32+%29 Exactly the same as for ECT */ 00432 00433 // set timers running 00434 // PITLD0 = dwellPeriod; 00435 // enable module 00436 PITCFLMT = 0x80; 00437 // enable channels 00438 //PITCE = 0x03; 00439 // enable interrupt 00440 // PITINTE = 0x01; 00441 // clear flags 00442 //PITFLT = ONES; 00443 #endif 00444 } 00445 00446 /* Setup the sci module(s) that we need to use. */ 00447 void initSCIStuff(){ 00448 /* The alternative register set selector defaults to zero */ 00449 00450 // set the baud/data speed 00451 SCI0BD = fixedConfigs2.baudDivisor; 00452 00453 // etc 00454 00455 /* Switch to alternative register set? */ 00456 00457 // etc 00458 00459 /* Switch back again? */ 00460 00461 /* 00462 * 0 = LOOPS (normal two wire operation) 00463 * 0 = SCISWAI (Wait mode on) 00464 * 0 = RSRC (if loops=1, int/ext wiring) 00465 * 1 = M MODE (9 bit operation) 00466 * 0 = WAKE (idle line wakeup) 00467 * 0 = ILT (idle line type count start pos) 00468 * 1 = PE (parity on) 00469 * 1 = PT (odd parity) (minicom defaults to no parity) 00470 * 00471 * 00010011 = 0x13 00472 */ 00473 SCI0CR1 = 0x13; 00474 00475 /* 00476 * 0 = TIE (tx data empty isr disabled) 00477 * 0 = TCIE (tx complete isr disabled) 00478 * 1 = RIE (rx full isr enabled) 00479 * 0 = ILIE (idle line isr disabled) 00480 * 1 = TE (transmit enabled) 00481 * 1 = RE (receive enabled) 00482 * 0 = RWU (rx wake up normal) 00483 * 0 = SBK (send break off) 00484 * 00485 * 00101100 = 0x2C 00486 */ 00487 SCI0CR2 = 0x2C; 00488 } 00489 00490 /* TODO Load and calculate all configuration data required to run */ 00491 void initConfiguration(){ 00492 // // 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. 00493 00494 00495 /* Add in tunable physical parameters at boot time TODO move to init.c TODO duplicate for secondary fuel? or split somehow? 00496 *nstant = ((masterConst * perCylinderVolume) / (stoichiometricAFR * injectorFlow)); 00497 *nstant = ((139371764 * 16384 ) / (15053 * 4096 )); 00498 * OR 00499 *nstant = ((masterConst / injectorFlow) * perCylinderVolume) / stoichiometricAFR; 00500 *nstant = ((139371764 / 4096 ) * 16384 ) / 15053 ; 00501 * http://www.google.com/search?hl=en&safe=off&q=((139371764++%2F+4096+++++)+*+16384+++)+%2F+15053++++&btnG=Search */ 00502 bootFuelConst = ((unsigned long)(masterFuelConstant / fixedConfigs1.injectorFlow) * fixedConfigs1.perCylinderVolume) / fixedConfigs1.stoichiometricAFR; 00503 00504 /* The MAP range used to convert fake TPS from MAP and vice versa */ 00505 TPSMAPRange = fixedConfigs1.TPSOpenMAP - fixedConfigs1.TPSClosedMAP; 00506 00507 /* The ADC range used to generate TPS percentage */ 00508 TPSADCRange = fixedConfigs1.TPSMaximumADC - fixedConfigs1.TPSMinimumADC; 00509 00510 00511 /* Use like flags for now, just add one for each later */ 00512 unsigned char cumulativeConfigErrors = 0; 00513 00514 /* Check various aspects of config which will cause problems */ 00515 00516 /* BRV max bigger than variable that holds it */ 00517 if(((unsigned long)fixedConfigs1.BRVMinimum + fixedConfigs1.BRVRange) > 65535){ 00518 //sendError(BRV_MAX_TOO_LARGE); 00519 cumulativeConfigErrors++; 00520 } 00521 00522 // TODO check all critical variables here! 00523 00524 /* 00525 * check ignition settings for range etc, possibly check some of those on the fly too 00526 * check fuel settings for being reasonable 00527 * check all variable tables for correct sizing 00528 * etc 00529 */ 00530 00531 while(cumulativeConfigErrors > 0){ 00532 sleep(1000); 00533 PORTS_BA ^= ONES16; // flash leds 00534 //send("There were "); 00535 //sendUC(cumulativeConfigErrors); 00536 //send(" config errors, init aborted!"); 00537 } // 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. 00538 } 00539 00540 00541 /* Set up all the remaining interrupts */ 00542 void initInterrupts(){ 00543 /* IMPORTANT : Set the s12x vector base register (Thanks Karsten!!) */ 00544 IVBR = 0xF7; /* Without this the interrupts will never find your code! */ 00545 00546 /* Set up the Real Time Interrupt */ 00547 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 */ 00548 // 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 */ 00549 CRGINT |= 0x80; /* Enable the RTI */ 00550 CRGFLG = 0x80; /* Clear the RTI flag */ 00551 00552 #ifndef NO_INIT 00553 // set up port H for testing 00554 PPSH = ZEROS; // falling edge/pull up for all 00555 PIEH = ONES; // enable all pins interrupts 00556 PIFH = ONES; // clear all port H interrupt flags 00557 #endif 00558 00559 // TODO set up irq and xirq for testing 00560 // IRQCR for IRQ 00561 // 00562 00563 /* VReg API setup (only for wait mode? i think so) */ 00564 // VREGAPIR = 0x09C3; /* For 500ms period : (500ms - 0.2ms) / 0.2ms = 0b100111000011 = 2499 */ 00565 // VREGAPICL = 0x02; /* Enable the interrupt */ 00566 // VREGAPICL = 0x04; /* Start the counter running */ 00567 /* 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 */ 00568 00569 /* LVI Low Voltage Interrupt enable */ 00570 VREGCTRL = 0x02; // Counts bad power events for diagnosis reasons 00571 }