#include "inc/main.h"
Go to the source code of this file.
Functions | |
int | main () |
The main function! |
The function main is traditionally an applications starting point. For us it has two jobs. The first is to call init() which initialises everything before any normal code runs. After that main() is simply an infinite loop from which low priority non-realtime code runs. The most important units of code that runs under the main loop umbrella are the injection, ignition and scheduling calculations.
Definition in file main.c.
int main | ( | ) |
The main function!
The centre of the application is here. From here all non-ISR code is called directly or indirectly. The two coarse blocks are init and the main loop. Init is called first to set everything up and then the main loop is entered where the flow of control continues until the device is switched off or reset (excluding asynchronous ISR code). Currently the main loop only runs the fuel, ignition and scheduling calculation code, and only when actually required. The intention is to maintain a very low latency for calculations such that the behaviour of the device more closely reflects the attached engines rapidly changing requirements. When accessory code is added a new scheduling algorithm will be required to keep the latency low without starving any particular blocks of CPU time.
Definition at line 60 of file main.c.
References ADCArrays, ADCArrays0, ADCArrays1, ADCArraysRecord, adjustPWM(), asyncDatalogADC, asyncDatalogBasic, asyncDatalogCircBuf, asyncDatalogCircCAS, asyncDatalogConfig, asyncDatalogLogic, asyncDatalogOff, asyncDatalogTrigger, asyncDatalogType, ATOMIC_END, ATOMIC_START, BIT2, BIT3, CALC_FUEL_IGN, RuntimeVar::calcsRuntime, calculateFuelAndIgnition(), Counter::calculationsPerformed, checksumAndSend(), CLEAR_CALC_FUEL_IGN, CLEAR_FORCE_READING, COM_SET_SCI0_INTERFACE_ID, configuredBasicDatalogLength, coreStatusA, Counters, currentDwell0, currentDwell1, currentDwellMath, currentDwellRealtime, decodePacketAndRespond(), FALSE, FORCE_READING, RuntimeVar::genCoreVarsRuntime, RuntimeVar::genDerivedVarsRuntime, generateCoreVars(), generateDerivedVars(), HEADER_HAS_LENGTH, init(), injectorMainPulseWidths0, injectorMainPulseWidths1, injectorMainPulseWidthsMath, injectorMainPulseWidthsRealtime, injectorStagedPulseWidths0, injectorStagedPulseWidths1, injectorStagedPulseWidthsMath, injectorStagedPulseWidthsRealtime, ISRLatencyVars, ISRLatencyVar::mathLatency, mathSampleTimeStamp, ISRLatencyVar::mathSampleTimeStamp0, ISRLatencyVar::mathSampleTimeStamp1, mathSampleTimeStampRecord, RuntimeVar::mathSumRuntime, RuntimeVar::mathTotalRuntime, NBIT2, NBIT3, populateBasicDatalog(), PORTJ, PORTK, resetToNonRunningState(), responseBasicDatalog, RPM, RPM0, RPM1, RPMRecord, RuntimeVars, RX_CLEAR_READY_TO_PROCESS, RX_READY_TO_PROCESS, RXStateFlags, sampleEachADC(), SCI0CR2, SCICR2_RX_ENABLE, SCICR2_RX_ISR_ENABLE, ShouldSendLog, sleepMicro(), TCNT, Counter::timeoutADCreadings, TRUE, TXBufferCurrentPositionCAN0, TXBufferCurrentPositionHandler, TXBufferCurrentPositionSCI0, and TXBufferInUseFlags.
00060 { // TODO maybe move this to paged flash ? 00061 // Set everything up. 00062 init(); 00063 00064 //LongNoTime.timeLong = 54; 00065 // Run forever repeating. 00066 while(TRUE){ 00067 // unsigned short start = realTimeClockMillis; 00068 /* If ADCs require forced sampling, sample now */ 00069 if(coreStatusA & FORCE_READING){ 00070 ATOMIC_START(); /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00071 /* Atomic block to ensure a full set of readings are taken together */ 00072 00073 /* Check to ensure that a reading wasn't take before we entered a non interruptable state */ 00074 if(coreStatusA & FORCE_READING){ // do we still need to do this TODO ? 00075 00076 sampleEachADC(ADCArraysRecord); // TODO still need to do a pair of loops and clock these two functions for performance. 00077 //sampleLoopADC(&ADCArrays); 00078 resetToNonRunningState(); 00079 Counters.timeoutADCreadings++; 00080 00081 /* Set flag to say calc required */ 00082 coreStatusA |= CALC_FUEL_IGN; 00083 00084 /* Clear force reading flag */ 00085 coreStatusA &= CLEAR_FORCE_READING; 00086 } 00087 00088 ATOMIC_END(); /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00089 } 00090 00091 /* If required, do main fuel and ignition calcs first */ 00092 if(coreStatusA & CALC_FUEL_IGN){ 00093 ATOMIC_START(); /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00094 /* Atomic block to ensure that we don't clear the flag for the next data set when things are tight */ 00095 00096 /* Switch input bank so that we have a stable set of the latest data */ 00097 if(ADCArrays == &ADCArrays1){ 00098 RPM = &RPM0; // TODO temp, remove 00099 RPMRecord = &RPM1; // TODO temp, remove 00100 ADCArrays = &ADCArrays0; 00101 ADCArraysRecord = &ADCArrays1; 00102 mathSampleTimeStamp = &ISRLatencyVars.mathSampleTimeStamp0; // TODO temp, remove 00103 mathSampleTimeStampRecord = &ISRLatencyVars.mathSampleTimeStamp1; // TODO temp, remove 00104 }else{ 00105 RPM = &RPM1; // TODO temp, remove 00106 RPMRecord = &RPM0; // TODO temp, remove 00107 ADCArrays = &ADCArrays1; 00108 ADCArraysRecord = &ADCArrays0; 00109 mathSampleTimeStamp = &ISRLatencyVars.mathSampleTimeStamp1; // TODO temp, remove 00110 mathSampleTimeStampRecord = &ISRLatencyVars.mathSampleTimeStamp0; // TODO temp, remove 00111 } 00112 00113 /* Clear the calc required flag */ 00114 coreStatusA &= CLEAR_CALC_FUEL_IGN; 00115 00116 ATOMIC_END(); /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00117 00118 /* Store the latency from sample time to runtime */ 00119 ISRLatencyVars.mathLatency = TCNT - *mathSampleTimeStamp; 00120 /* Keep track of how many calcs we are managing per second... */ 00121 Counters.calculationsPerformed++; 00122 /* ...and how long they take each */ 00123 unsigned short mathStartTime = TCNT; 00124 00125 /* Generate the core variables from sensor input and recorded tooth timings */ 00126 generateCoreVars(); 00127 00128 RuntimeVars.genCoreVarsRuntime = TCNT - mathStartTime; 00129 unsigned short derivedStartTime = TCNT; 00130 00131 /* Generate the derived variables from the core variables based on settings */ 00132 generateDerivedVars(); 00133 00134 RuntimeVars.genDerivedVarsRuntime = TCNT - derivedStartTime; 00135 unsigned short calcsStartTime = TCNT; 00136 00137 /* Perform the calculations TODO possibly move this to the software interrupt if it makes sense to do so */ 00138 calculateFuelAndIgnition(); 00139 00140 RuntimeVars.calcsRuntime = TCNT - calcsStartTime; 00141 /* Record the runtime of all the math total */ 00142 RuntimeVars.mathTotalRuntime = TCNT - mathStartTime; 00143 00144 RuntimeVars.mathSumRuntime = RuntimeVars.calcsRuntime + RuntimeVars.genCoreVarsRuntime + RuntimeVars.genDerivedVarsRuntime; 00145 00146 ATOMIC_START(); /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00147 /* Atomic block to ensure that outputBank and outputBank Offsets match */ 00148 00149 /* Switch banks to the latest data */ 00150 if(injectorMainPulseWidthsMath == injectorMainPulseWidths1){ 00151 currentDwellMath = ¤tDwell0; 00152 currentDwellRealtime = ¤tDwell1; 00153 injectorMainPulseWidthsMath = injectorMainPulseWidths0; 00154 injectorMainPulseWidthsRealtime = injectorMainPulseWidths1; 00155 injectorStagedPulseWidthsMath = injectorStagedPulseWidths0; 00156 injectorStagedPulseWidthsRealtime = injectorStagedPulseWidths1; 00157 }else{ 00158 currentDwellMath = ¤tDwell1; 00159 currentDwellRealtime = ¤tDwell0; 00160 injectorMainPulseWidthsMath = injectorMainPulseWidths1; 00161 injectorMainPulseWidthsRealtime = injectorMainPulseWidths0; 00162 injectorStagedPulseWidthsMath = injectorStagedPulseWidths1; 00163 injectorStagedPulseWidthsRealtime = injectorStagedPulseWidths0; 00164 } 00165 00166 ATOMIC_END(); /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00167 }else{ 00168 /* In the event that no calcs are required, sleep a little before returning to retry. */ 00169 sleepMicro(RuntimeVars.mathTotalRuntime); // not doing this will cause the ISR lockouts to run for too high a proportion of the time 00170 /* Using 0.8 ticks as micros so it will run for a little longer than the math did */ 00171 } 00172 00173 00174 if(!(TXBufferInUseFlags)){ 00175 // unsigned short logTimeBuffer = Clocks.realTimeClockTenths; 00176 /* If the flag for com packet processing is set and the TX buffer is available process the data! */ 00177 if(RXStateFlags & RX_READY_TO_PROCESS){ 00178 /* Clear the flag */ 00179 RXStateFlags &= RX_CLEAR_READY_TO_PROCESS; 00180 00181 /* Handle the incoming packet */ 00182 decodePacketAndRespond(); 00183 }else if(ShouldSendLog){//(lastTime != logTimeBuffer) && (lastCalcCount != Counters.calculationsPerformed)){ 00184 00185 /* send asynchronous data log if required */ 00186 if(asyncDatalogType!= asyncDatalogOff){ 00187 switch (asyncDatalogType) { 00188 case asyncDatalogBasic: 00189 { 00190 /* Flag that we are transmitting! */ 00191 TXBufferInUseFlags |= COM_SET_SCI0_INTERFACE_ID; 00192 // SCI0 only for now... 00193 00194 // headers including length... *length = configuredBasicDatalogLength; 00195 TXBufferCurrentPositionHandler = (unsigned char*)&TXBuffer; 00196 00197 /* Initialised here such that override is possible */ 00198 TXBufferCurrentPositionSCI0 = (unsigned char*)&TXBuffer; 00199 TXBufferCurrentPositionCAN0 = (unsigned char*)&TXBuffer; 00200 00201 /* Set the flags : firmware, no ack, no addrs, has length */ 00202 *TXBufferCurrentPositionHandler = HEADER_HAS_LENGTH; 00203 TXBufferCurrentPositionHandler++; 00204 00205 /* Set the payload ID */ 00206 *((unsigned short*)TXBufferCurrentPositionHandler) = responseBasicDatalog; 00207 TXBufferCurrentPositionHandler += 2; 00208 00209 /* Set the length */ 00210 *((unsigned short*)TXBufferCurrentPositionHandler) = configuredBasicDatalogLength; 00211 TXBufferCurrentPositionHandler += 2; 00212 00213 /* populate data log */ 00214 populateBasicDatalog(); 00215 checksumAndSend(); 00216 break; 00217 } 00218 case asyncDatalogConfig: 00219 { 00220 // TODO 00221 break; 00222 } 00223 case asyncDatalogTrigger: 00224 { 00225 // TODO 00226 break; 00227 } 00228 case asyncDatalogADC: 00229 { 00230 // TODO 00231 break; 00232 } 00233 case asyncDatalogCircBuf: 00234 { 00235 // TODO 00236 break; 00237 } 00238 case asyncDatalogCircCAS: 00239 { 00240 // TODO 00241 break; 00242 } 00243 case asyncDatalogLogic: 00244 { 00245 // TODO 00246 break; 00247 } 00248 } 00249 } 00250 ShouldSendLog = FALSE; 00251 // // mechanism to ensure we send once per clock tick without doing it in the RTC section. 00252 // lastTime = logTimeBuffer; 00253 // // mechanism to ensure we only send something if the data has been updated 00254 // lastCalcCount = Counters.calculationsPerformed; 00255 } 00256 } 00257 // on once per cycle for main loop heart beat (J0) 00258 PORTJ ^= 0x01; 00259 00260 00261 // debug... 00262 if(SCI0CR2 & SCICR2_RX_ENABLE){ 00263 PORTK |= BIT2; 00264 }else{ 00265 PORTK &= NBIT2; 00266 } 00267 00268 if(SCI0CR2 & SCICR2_RX_ISR_ENABLE){ 00269 PORTK |= BIT3; 00270 }else{ 00271 PORTK &= NBIT3; 00272 } 00273 00274 // PWM experimentation 00275 adjustPWM(); 00276 } 00277 }