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