rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
rusefi.cpp
Go to the documentation of this file.
1/**
2 * @file rusefi.cpp
3 * @brief Initialization code and main status reporting look
4 *
5 * @date Dec 25, 2013
6 * @author Andrey Belomutskiy, (c) 2012-2021
7 */
8
9/**
10 * @mainpage
11 * This documentation https://rusefi.com/docs/html/
12 *
13 * For version see engine_controller.cpp getRusEfiVersion
14 *
15 * @section sec_intro Intro
16 *
17 * rusEFI is implemented based on the idea that with modern 100+ MHz microprocessors the relatively
18 * undemanding task of internal combustion engine control could be implemented in a high-level, processor-independent
19 * (to some extent) manner. Thus the key concepts of rusEfi: dependency on high-level hardware abstraction layer, software-based PWM etc.
20 *
21 * @section sec_main Brief overview
22 *
23 * rusEfi runs on crank shaft or cam shaft ('trigger') position sensor events.
24 * Once per crank shaft revolution we evaluate the amount of needed fuel and
25 * the spark timing. Once we have decided on the parameters for this revolution
26 * we schedule all the actions to be triggered by the closest trigger event.
27 *
28 * We also have some utility threads like idle control thread and communication threads.
29 *
30 *
31 *
32 * @section sec_trigger Trigger Decoding
33 *
34 * Our primary trigger decoder is based on the idea of synchronizing the primary shaft signal and simply counting events on
35 * the secondary signal. A typical scenario would be when cam shaft positions sensor is the primary signal and crankshaft is secondary,
36 * but sometimes there would be two signals generated by two cam shaft sensors.
37 * Another scenario is when we only have crank shaft position sensor, this would make it the primary signal and there would be no secondary signal.
38 *
39 * There is no software filtering so the signals are expected to be valid. TODO: in reality we are still catching engine stop noise as unrealisticly high RPM.
40 *
41 * The decoder is configured to act either on the primary signal rise or on the primary signal fall. It then compares the duration
42 * of time from the previous signal to the duration of time from the signal before previous, and if the ratio falls into the configurable
43 * range between 'syncRatioFrom' and 'syncRatioTo' this is assumed to be the synchronizing event.
44 *
45 * For instance, for a 36/1 skipped tooth wheel the ratio range for synchronization is from 1.5 to 3
46 *
47 * Some triggers do not require synchronization, this case we just count signals.
48 * A single tooth primary signal would be a typical example when synchronization is not needed.
49 *
50 *
51 * @section sec_timers Timers
52 * At the moment rusEfi is build using 5 timers:
53 * <BR>1) 1MHz microsecond_timer.cpp
54 * <BR>2) 10KHz fast ADC callback pwmpcb_fast adc_inputs.cpp
55 * <BR>3) slow ADC callback pwmpcb_slow adc_inputs.cpp
56 * <BR>4) periodicFastTimer engine_controller.cpp
57 * <BR>5) periodicSlowTimer engine_controller.cpp
58 *
59 *
60 *
61 * @section sec_scheduler Event Scheduler
62 *
63 * It is a general agreement to measure all angles in crank shaft angles. In a four stroke
64 * engine, a full cycle consists of two revolutions of the crank shaft, so all the angles are
65 * running between 0 and 720 degrees.
66 *
67 * Ignition timing is a great example of a process which highlights the need of a hybrid
68 * approach to event scheduling.
69 * The most important part of controlling ignition
70 * is firing up the spark at the right moment - so, for this job we need 'angle-based' timing,
71 * for example we would need to fire up the spark at 700 degrees. Before we can fire up the spark
72 * at 700 degrees, we need to charge the ignition coil, for example this dwell time is 4ms - that
73 * means we need to turn on the coil at '4 ms before 700 degrees'. Let's assume that the engine is
74 * current at 600 RPM - that means 360 degrees would take 100ms so 4ms is 14.4 degrees at current RPM which
75 * means we need to start charging the coil at 685.6 degrees.
76 *
77 * The position sensors at our disposal are not providing us the current position at any moment of time -
78 * all we've got is a set of events which are happening at the knows positions. For instance, let's assume that
79 * our sensor sends as an event at 0 degrees, at 90 degrees, at 600 degrees and and 690 degrees.
80 *
81 * So, for this particular sensor the most precise scheduling would be possible if we schedule coil charging
82 * as '85.6 degrees after the 600 degrees position sensor event', and spark firing as
83 * '10 degrees after the 690 position sensor event'. Considering current RPM, we calculate that '10 degress after' is
84 * 2.777ms, so we schedule spark firing at '2.777ms after the 690 position sensor event', thus combining trigger events
85 * with time-based offset.
86 *
87 * @section tunerstudio Getting Data To and From Tunerstudio
88 *
89 * Contains the enum with values to be output to Tunerstudio.
90 * console/binary/output_channels.txt
91 *
92 * [Changing gauge limits](http://www.tunerstudio.com/index.php/manuals/63-changing-gauge-limits)
93 *
94 * Definition of the Tunerstudio configuration interface, gauges, and indicators
95 * tunerstudio/tunerstudio.template.ini
96 *
97 * @section config Persistent Configuration
98 *
99 * Definition of configuration data structure:
100 * integration/rusefi_config.txt
101 * This file has a lot of information and instructions in its comment header.
102 * Please note that due to TunerStudio protocol it's important to have the total structure size in sync between the firmware and TS .ini file -
103 * just to make sure that this is not forgotten the size of the structure is hard-coded as PAGE_0_SIZE constant. There is always some 'unused' fields added in advance so that
104 * one can add some fields without the pain of increasing the total configuration page size.
105 * <br>See flash_main.cpp
106 *
107 * @section sec_fuel_injection Fuel Injection
108 *
109 *
110 * @section sec_misc Misc
111 *
112 * <BR>See main_trigger_callback.cpp for main trigger event handler
113 * <BR>See fuel_math.cpp for details on fuel amount logic
114 * <BR>See rpm_calculator.cpp for details on how RPM is calculated
115 *
116 */
117
118#include "pch.h"
119
120#include "trigger_structure.h"
121#include "hardware.h"
122
123#include "rfi_perftest.h"
124#include "rusefi.h"
125#include "memstreams.h"
126
127#include "eficonsole.h"
128#include "status_loop.h"
129#include "custom_engine.h"
130#include "mpu_util.h"
131#include "tunerstudio.h"
132#include "mmc_card.h"
133#include "mass_storage_init.h"
135#include "rusefi_lua.h"
136
137#include <setjmp.h>
138
139#if EFI_ENGINE_EMULATOR
140#include "engine_emulator.h"
141#endif /* EFI_ENGINE_EMULATOR */
142
143bool main_loop_started = false;
144
145static char panicMessage[200];
146
147static virtual_timer_t resetTimer;
148
149// todo: move this into a hw-specific file
150void rebootNow() {
151 NVIC_SystemReset();
152}
153
154/**
155 * Some configuration changes require full firmware reset.
156 * Once day we will write graceful shutdown, but that would be one day.
157 */
159 efiPrintf("Rebooting in 3 seconds...");
160 chibios_rt::CriticalSectionLocker csl;
161 chVTSetI(&resetTimer, TIME_MS2I(3000), (vtfunc_t) rebootNow, NULL);
162}
163
164static jmp_buf jmpEnv;
166 // There's been an assertion failure: instead of hanging, jump back to where we check
167 // if (setjmp(jmpEnv)) (see below for more complete explanation)
168 longjmp(jmpEnv, 1);
169}
170
171void initEfiWithConfig();
172__NO_RETURN void runMainLoop();
173
174void runRusEfi() {
175 engine->setConfig();
176
177#if EFI_TEXT_LOGGING
178 // Initialize logging system early - we can't log until this is called
180#endif
181
182#if HAL_USE_WDG
183 setWatchdogResetPeriod(WATCHDOG_RESET_MS);
185#endif // HAL_USE_WDG
186
187#if EFI_PROD_CODE
190#endif
191
192#if defined(STM32F4) || defined(STM32F7)
193 addConsoleAction("stm32_standby", stm32_standby);
194#endif
195
196 addConsoleAction(CMD_REBOOT, scheduleReboot);
197#if EFI_DFU_JUMP
198 addConsoleAction(CMD_REBOOT_DFU, jump_to_bootloader);
199#endif /* EFI_DFU_JUMP */
200
201#if EFI_USE_OPENBLT
202 addConsoleAction(CMD_REBOOT_OPENBLT, jump_to_openblt);
203#endif
204
205 /**
206 * we need to initialize table objects before default configuration can set values
207 */
209
210 // Perform hardware initialization that doesn't need configuration
212
213 // at the moment that's always hellen board ID
215
216 engine->engineModules.apply_all([](auto & m) {
217 m.initNoConfiguration();
218 });
219
220#if EFI_USB_SERIAL
222#endif
223
224#if HAL_USE_USB_MSD
225 initUsbMsd();
226#endif
227
228 /**
229 * Next we should initialize serial port console, it's important to know what's going on
230 */
232
233 // Read configuration from flash memory
235
236#if EFI_TUNER_STUDIO
238#endif /* EFI_TUNER_STUDIO */
239
240 // Start hardware serial ports (including bluetooth, if present)
241#if EFI_TUNER_STUDIO
243#endif // EFI_TUNER_STUDIO
244
246
247 // periodic events need to be initialized after fuel&spark pins to avoid a warning
249 initMainLoop();
250
251 runMainLoop();
252}
253
255 // If some config operation caused an OS assertion failure, return immediately
256 // This sets the "unwind point" that we can jump back to later with longjmp if we have
257 // an assertion failure. If that happens, setjmp() will return non-zero, so we will
258 // return immediately from this function instead of trying to init hardware again (which failed last time)
259 if (setjmp(jmpEnv)) {
260 return;
261 }
262
264
265#if EFI_WIFI
267#endif
268
269 // Config could be completely bogus - don't start anything else!
271 /**
272 * Now let's initialize actual engine control logic
273 * todo: should we initialize some? most? controllers before hardware?
274 */
276
277
278 // This has to happen after RegisteredOutputPins are init'd: otherwise no change will be detected, and no init will happen
280
281 #if EFI_PERF_METRICS
283 #endif
284
285 }
286}
287
289 efiPrintf("Running main loop");
290 main_loop_started = true;
291 /**
292 * This loop is the closes we have to 'main loop' - but here we only publish the status. The main logic of engine
293 * control is around main_trigger_callback
294 */
295 while (true) {
296#if EFI_CLI_SUPPORT && !EFI_UART_ECHO_TEST_MODE
297 // sensor state + all pending messages for our own rusEfi console
298 // todo: is this mostly dead code?
300#endif /* EFI_CLI_SUPPORT */
301
302 chThdSleepMilliseconds(200);
303 }
304}
305
306/**
307 * this depends on chcore.h patch
308+void chDbgStackOverflowPanic(thread_t *otp);
309+
310- chSysHalt("stack overflow"); \
311+ chDbgStackOverflowPanic(otp); \
312
313 *
314 */
315void chDbgStackOverflowPanic(thread_t *otp) {
316 (void)otp;
317 strcpy(panicMessage, "stack overflow: ");
318#if defined(CH_USE_REGISTRY)
319 int p_name_len = strlen(otp->p_name);
320 if (p_name_len < sizeof(panicMessage) - 2)
321 strcat(panicMessage, otp->p_name);
322#endif
323 chDbgPanic3(panicMessage, __FILE__, __LINE__);
324}
void stm32_standby()
Definition mpu_util.cpp:18
void startWatchdog(int)
void setWatchdogResetPeriod(int)
void jump_to_openblt()
void jump_to_bootloader()
void chDbgPanic3(const char *, const char *, int)
void setConfig()
Definition engine.cpp:397
type_list< Mockable< InjectorModelPrimary >, Mockable< InjectorModelSecondary >,#if EFI_IDLE_CONTROL Mockable< IdleController >,#endif TriggerScheduler,#if EFI_HPFP &&EFI_ENGINE_CONTROL Mockable< HpfpController >,#endif #if EFI_ENGINE_CONTROL Mockable< ThrottleModel >,#endif #if EFI_ALTERNATOR_CONTROL AlternatorController,#endif MainRelayController, Mockable< IgnitionController >, Mockable< AcController >, PrimeController, DfcoController,#if EFI_HD_ACR HarleyAcr,#endif Mockable< WallFuelController >, KnockController, SensorChecker,#if EFI_ENGINE_CONTROL Mockable< LimpManager >,#endif #if EFI_VVT_PID VvtController1, VvtController2, VvtController3, VvtController4,#endif #if EFI_BOOST_CONTROL BoostController,#endif TpsAccelEnrichment,#if EFI_LAUNCH_CONTROL NitrousController,#endif #if EFI_LTFT_CONTROL LongTermFuelTrim,#endif ShortTermFuelTrim,#include "modules_list_generated.h" EngineModule > engineModules
Definition engine.h:194
void addConsoleAction(const char *token, Void callback)
Register console action without parameters.
void detectBoardType()
void initializeConsole()
Console package entry point header.
void startUsbConsole()
void startWifiConsole()
static EngineAccessor engine
Definition engine.h:413
void loadConfiguration()
void rememberCurrentConfiguration()
bool validateConfigOnStartUpOrBurn()
void commonEarlyInit()
void initPeriodicEvents()
void initDataStructures()
void initRealHardwareEngineController()
void errorHandlerInit()
void errorHandlerShowBootReasonAndErrors()
void initHardwareNoConfig()
Definition hardware.cpp:427
int setjmp(jmp_buf)
void longjmp(jmp_buf, int)
void startLoggingProcessor()
void initMainLoop()
Definition main_loop.cpp:67
void initUsbMsd()
void initTimePerfActions()
void chDbgStackOverflowPanic(thread_t *otp)
Definition rusefi.cpp:315
void scheduleReboot()
Definition rusefi.cpp:158
void initEfiWithConfig()
Definition rusefi.cpp:254
bool main_loop_started
Definition rusefi.cpp:143
static jmp_buf jmpEnv
Definition rusefi.cpp:164
__NO_RETURN void runMainLoop()
Definition rusefi.cpp:288
void runRusEfi()
Definition rusefi.cpp:174
static virtual_timer_t resetTimer
Definition rusefi.cpp:147
void onAssertionFailure()
Definition rusefi.cpp:165
static char panicMessage[200]
Definition rusefi.cpp:145
void rebootNow()
Definition rusefi.cpp:150
void updateDevConsoleState()
Sends all pending data to rusEfi console.
void startTunerStudioConnectivity()
void startSerialChannels()