PageRenderTime 62ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/src/init.c

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