GCC Code Coverage Report


Directory: ./
File: firmware/hw_layer/hardware.cpp
Date: 2025-10-03 00:57:22
Coverage Exec Excl Total
Lines: 83.7% 41 0 49
Functions: 70.0% 7 0 10
Branches: 50.0% 3 0 6
Decisions: 60.0% 3 - 5

Line Branch Decision Exec Source
1 /**
2 * @file hardware.cpp
3 * @brief Hardware package entry point
4 *
5 * @date May 27, 2013
6 * @author Andrey Belomutskiy, (c) 2012-2020
7 */
8
9 #include "pch.h"
10
11
12 #include "trigger_input.h"
13 #include "can_hw.h"
14 #include "hardware.h"
15 #include "rtc_helper.h"
16 #include "bench_test.h"
17 #include "yaw_rate_sensor.h"
18 #include "pin_repository.h"
19 #include "logic_analyzer.h"
20 #include "smart_gpio.h"
21 #include "accelerometer.h"
22 #include "eficonsole.h"
23 #include "console_io.h"
24 #include "idle_thread.h"
25 #include "odometer.h"
26 #include "kline.h"
27 #include "dac.h"
28
29 #if EFI_PROD_CODE
30 #include "mpu_util.h"
31 #endif /* EFI_PROD_CODE */
32
33 #include "mmc_card.h"
34
35 #include "adc_device.h"
36 #include "idle_hardware.h"
37
38 #include "histogram.h"
39 #include "gps_uart.h"
40 #include "sent.h"
41 #include "cdm_ion_sense.h"
42 #include "trigger_central.h"
43 #include "vvt.h"
44 #include "trigger_emulator_algo.h"
45 #include "boost_control.h"
46 #if EFI_SOFTWARE_KNOCK
47 #include "software_knock.h"
48 #endif
49 #include "trigger_scope.h"
50 #include "init.h"
51 #if EFI_MC33816
52 #include "mc33816.h"
53 #endif /* EFI_MC33816 */
54 #if EFI_WS2812
55 #include "WS2812.h"
56 #endif /* EFI_WS2812 */
57
58 #if EFI_MAP_AVERAGING && defined (MODULE_MAP_AVERAGING)
59 #include "map_averaging.h"
60 #endif
61
62 #if EFI_CONFIGURATION_STORAGE
63 #include "flash_main.h"
64 #endif
65
66 #if HAL_USE_PAL && EFI_PROD_CODE
67 #include "digital_input_exti.h"
68 #endif // HAL_USE_PAL
69
70 #if EFI_CAN_SUPPORT
71 #include "can_vss.h"
72 #endif
73
74 #include "board_overrides.h"
75
76 std::optional<setup_custom_board_overrides_type> custom_board_InitHardwareEarly;
77 std::optional<setup_custom_board_overrides_type> custom_board_InitHardware;
78 std::optional<setup_custom_board_overrides_type> custom_board_InitHardwareExtra;
79
80
81 #if HAL_USE_SPI
82 /* zero index is SPI_NONE */
83 extern bool isSpiInitialized[SPI_TOTAL_COUNT + 1];
84
85 /* these are common adapters for engineConfiguration access, move to some common file? */
86 brain_pin_e getMisoPin(spi_device_e device) {
87 switch(device) {
88 case SPI_DEVICE_1:
89 return engineConfiguration->spi1misoPin;
90 case SPI_DEVICE_2:
91 return engineConfiguration->spi2misoPin;
92 case SPI_DEVICE_3:
93 return engineConfiguration->spi3misoPin;
94 case SPI_DEVICE_4:
95 return engineConfiguration->spi4misoPin;
96 case SPI_DEVICE_5:
97 return engineConfiguration->spi5misoPin;
98 case SPI_DEVICE_6:
99 return engineConfiguration->spi6misoPin;
100 default:
101 break;
102 }
103 return Gpio::Unassigned;
104 }
105
106 brain_pin_e getMosiPin(spi_device_e device) {
107 switch(device) {
108 case SPI_DEVICE_1:
109 return engineConfiguration->spi1mosiPin;
110 case SPI_DEVICE_2:
111 return engineConfiguration->spi2mosiPin;
112 case SPI_DEVICE_3:
113 return engineConfiguration->spi3mosiPin;
114 case SPI_DEVICE_4:
115 return engineConfiguration->spi4mosiPin;
116 case SPI_DEVICE_5:
117 return engineConfiguration->spi5mosiPin;
118 case SPI_DEVICE_6:
119 return engineConfiguration->spi6mosiPin;
120 default:
121 break;
122 }
123 return Gpio::Unassigned;
124 }
125
126 brain_pin_e getSckPin(spi_device_e device) {
127 switch(device) {
128 case SPI_DEVICE_1:
129 return engineConfiguration->spi1sckPin;
130 case SPI_DEVICE_2:
131 return engineConfiguration->spi2sckPin;
132 case SPI_DEVICE_3:
133 return engineConfiguration->spi3sckPin;
134 case SPI_DEVICE_4:
135 return engineConfiguration->spi4sckPin;
136 case SPI_DEVICE_5:
137 return engineConfiguration->spi5sckPin;
138 case SPI_DEVICE_6:
139 return engineConfiguration->spi6sckPin;
140 default:
141 break;
142 }
143 return Gpio::Unassigned;
144 }
145
146 /**
147 * @return NULL if SPI device not specified
148 */
149 SPIDriver * getSpiDevice(spi_device_e spiDevice) {
150 if (spiDevice == SPI_NONE) {
151 return nullptr;
152 }
153 #if STM32_SPI_USE_SPI1
154 if (spiDevice == SPI_DEVICE_1) {
155 return &SPID1;
156 }
157 #endif
158 #if STM32_SPI_USE_SPI2
159 if (spiDevice == SPI_DEVICE_2) {
160 return &SPID2;
161 }
162 #endif
163 #if STM32_SPI_USE_SPI3
164 if (spiDevice == SPI_DEVICE_3) {
165 return &SPID3;
166 }
167 #endif
168 #if STM32_SPI_USE_SPI4
169 if (spiDevice == SPI_DEVICE_4) {
170 return &SPID4;
171 }
172 #endif
173 #if STM32_SPI_USE_SPI5
174 if (spiDevice == SPI_DEVICE_5) {
175 return &SPID5;
176 }
177 #endif
178 #if STM32_SPI_USE_SPI6
179 if (spiDevice == SPI_DEVICE_6) {
180 return &SPID6;
181 }
182 #endif
183 firmwareError(ObdCode::CUSTOM_ERR_UNEXPECTED_SPI, "Unexpected SPI device: %d", spiDevice);
184 return nullptr;
185 }
186
187 /**
188 * Only one consumer can use SPI bus at a given time
189 */
190 void lockSpi(spi_device_e device) {
191 efiAssertVoid(ObdCode::CUSTOM_STACK_SPI, hasLotsOfRemainingStack(), "lockSpi");
192 spiAcquireBus(getSpiDevice(device));
193 }
194
195 void unlockSpi(spi_device_e device) {
196 spiReleaseBus(getSpiDevice(device));
197 }
198
199 static void initSpiModules() {
200 if (engineConfiguration->is_enabled_spi_1) {
201 turnOnSpi(SPI_DEVICE_1);
202 }
203 if (engineConfiguration->is_enabled_spi_2) {
204 turnOnSpi(SPI_DEVICE_2);
205 }
206 if (engineConfiguration->is_enabled_spi_3) {
207 turnOnSpi(SPI_DEVICE_3);
208 }
209 if (engineConfiguration->is_enabled_spi_4) {
210 turnOnSpi(SPI_DEVICE_4);
211 }
212 if (engineConfiguration->is_enabled_spi_5) {
213 turnOnSpi(SPI_DEVICE_5);
214 }
215 if (engineConfiguration->is_enabled_spi_6) {
216 turnOnSpi(SPI_DEVICE_6);
217 }
218 }
219
220 void stopSpi(spi_device_e device) {
221 if (!isSpiInitialized[device]) {
222 return; // not turned on
223 }
224 isSpiInitialized[device] = false;
225 efiSetPadUnused(getSckPin(device));
226 efiSetPadUnused(getMisoPin(device));
227 efiSetPadUnused(getMosiPin(device));
228 }
229
230 static void stopSpiModules() {
231 if (isConfigurationChanged(is_enabled_spi_1)) {
232 stopSpi(SPI_DEVICE_1);
233 }
234
235 if (isConfigurationChanged(is_enabled_spi_2)) {
236 stopSpi(SPI_DEVICE_2);
237 }
238
239 if (isConfigurationChanged(is_enabled_spi_3)) {
240 stopSpi(SPI_DEVICE_3);
241 }
242
243 if (isConfigurationChanged(is_enabled_spi_4)) {
244 stopSpi(SPI_DEVICE_4);
245 }
246
247 if (isConfigurationChanged(is_enabled_spi_5)) {
248 stopSpi(SPI_DEVICE_5);
249 }
250
251 if (isConfigurationChanged(is_enabled_spi_6)) {
252 stopSpi(SPI_DEVICE_6);
253 }
254 }
255
256 void printSpiConfig(const char *msg, spi_device_e device) {
257 efiPrintf("%s %s mosi=%s", msg, getSpi_device_e(device), hwPortname(getMosiPin(device)));
258 efiPrintf("%s %s miso=%s", msg, getSpi_device_e(device), hwPortname(getMisoPin(device)));
259 efiPrintf("%s %s sck=%s", msg, getSpi_device_e(device), hwPortname(getSckPin(device)));
260 }
261
262 #endif // HAL_USE_SPI
263
264 #if HAL_USE_ADC
265
266 static AdcToken fastMapSampleIndex;
267
268 #if HAL_TRIGGER_USE_ADC
269 static AdcToken triggerSampleIndex;
270 #endif // HAL_TRIGGER_USE_ADC
271
272 /**
273 * This method is not in the adc* lower-level file because it is more business logic then hardware.
274 */
275 void onFastAdcComplete(adcsample_t*) {
276 ScopePerf perf(PE::AdcCallbackFast);
277
278 #if HAL_TRIGGER_USE_ADC
279 // we need to call this ASAP, because trigger processing is time-critical
280 triggerAdcCallback(getFastAdc(triggerSampleIndex));
281 #endif /* HAL_TRIGGER_USE_ADC */
282
283 /**
284 * this callback is executed 10 000 times a second, it needs to be as fast as possible
285 */
286 efiAssertVoid(ObdCode::CUSTOM_STACK_ADC, hasLotsOfRemainingStack(), "lowstck#9b");
287
288 auto mapRaw = adcRawValueToScaledVoltage(getFastAdc(fastMapSampleIndex), engineConfiguration->map.sensor.hwChannel);
289 engine->outputChannels.rawMapFast = mapRaw;
290 #if EFI_MAP_AVERAGING && defined (MODULE_MAP_AVERAGING)
291 mapAveragingAdcCallback(mapRaw);
292 #endif /* EFI_MAP_AVERAGING */
293 }
294 #endif /* HAL_USE_ADC */
295
296
1/1
✓ Decision 'true' taken 802 times.
802 static void calcFastAdcIndexes() {
297 #if HAL_USE_ADC
298 fastMapSampleIndex = enableFastAdcChannel("Fast MAP", engineConfiguration->map.sensor.hwChannel);
299
300 #if HAL_TRIGGER_USE_ADC
301 triggerSampleIndex = enableFastAdcChannel("Trigger ADC", getAdcChannelForTrigger());
302 #endif /* HAL_TRIGGER_USE_ADC */
303
304 #endif/* HAL_USE_ADC */
305 802 }
306
307 /**
308 * this method is NOT currently invoked on ECU start
309 * todo: reduce code duplication by moving more logic into startHardware method
310 */
311 219 void applyNewHardwareSettings() {
312 /**
313 * All 'stop' methods need to go before we begin starting pins.
314 *
315 * We take settings from 'activeConfiguration' not 'engineConfiguration' while stopping hardware.
316 * Some hardware is restart unconditionally on change of parameters while for some systems we make extra effort and restart only
317 * relevant settings were changes.
318 *
319 */
320 219 ButtonDebounce::stopConfigurationList();
321
322 #if EFI_PROD_CODE
323 stopSensors();
324 #endif // EFI_PROD_CODE
325
326 #if EFI_PROD_CODE && EFI_SHAFT_POSITION_INPUT
327 stopTriggerInputPins();
328 #endif /* EFI_SHAFT_POSITION_INPUT */
329
330 #if EFI_PROD_CODE && EFI_SENT_SUPPORT
331 stopSent();
332 #endif // EFI_SENT_SUPPORT
333
334 #if EFI_CAN_SUPPORT
335 stopCanPins();
336 #endif /* EFI_CAN_SUPPORT */
337
338 219 stopKLine();
339
340
341 219 stopHardware();
342
343 #if HAL_USE_SPI
344 stopSpiModules();
345 #endif /* HAL_USE_SPI */
346
347
2/4
✓ Branch 0 taken 219 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 219 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 219 times.
219 if (isPinOrModeChanged(clutchUpPin, clutchUpPinMode)) {
348 // bug? duplication with stopSwitchPins?
349 efiSetPadUnused(activeConfiguration.clutchUpPin);
350 }
351
352 219 enginePins.unregisterPins();
353
354 #if EFI_PROD_CODE
355 reconfigureSensors();
356 #endif /* EFI_PROD_CODE */
357
358 219 ButtonDebounce::startConfigurationList();
359
360 /*******************************************
361 * Start everything back with new settings *
362 ******************************************/
363 219 startHardware();
364
365 #if EFI_PROD_CODE && (BOARD_EXT_GPIOCHIPS > 0)
366 /* TODO: properly restart gpio chips...
367 * This is only workaround for "CS pin lost" bug
368 * see: https://github.com/rusefi/rusefi/issues/2107
369 * We should provide better way to gracefully stop all
370 * gpio chips: set outputs to safe state, release all
371 * on-chip resources (gpios, SPIs, etc) and then restart
372 * with updated settings.
373 * Following code just re-inits CS pins for all external
374 * gpio chips, but does not update CS pin definition in
375 * gpio chips private data/settings. So changing CS pin
376 * on-fly does not work */
377 startSmartCsPins();
378 #endif /* (BOARD_EXT_GPIOCHIPS > 0) */
379
380 219 startKLine();
381
382 #if EFI_PROD_CODE && EFI_IDLE_CONTROL
383 if (isIdleHardwareRestartNeeded()) {
384 initIdleHardware();
385 }
386 #endif
387
388 #if EFI_BOOST_CONTROL
389 219 startBoostPin();
390 #endif
391 #if EFI_EMULATE_POSITION_SENSORS
392 219 startTriggerEmulatorPins();
393 #endif /* EFI_EMULATE_POSITION_SENSORS */
394 #if EFI_LOGIC_ANALYZER
395 startLogicAnalyzerPins();
396 #endif /* EFI_LOGIC_ANALYZER */
397 #if EFI_VVT_PID
398 startVvtControlPins();
399 #endif /* EFI_VVT_PID */
400
401 #if EFI_PROD_CODE && EFI_SENT_SUPPORT
402 startSent();
403 #endif
404
405 219 calcFastAdcIndexes();
406 219 }
407
408 #if EFI_PROD_CODE && EFI_BOR_LEVEL
409 void setBor(int borValue) {
410 efiPrintf("setting BOR to %d", borValue);
411 BOR_Set((BOR_Level_t)borValue);
412 }
413 #endif /* EFI_BOR_LEVEL */
414
415 // Called before configuration is loaded
416 void boardInitHardwareEarly() {
417 // forcing migration to custom_board_InitHardwareEarly
418 }
419 583 void boardInitHardware() {
420 // time to force migration to custom_board_InitHardware
421 583 }
422 583 void boardInitHardwareExtra() {
423 // forcing migration to custom_board_InitHardwareExtra
424 583 }
425
426 // This function initializes hardware that can do so before configuration is loaded
427 void initHardwareNoConfig() {
428 efiAssertVoid(ObdCode::CUSTOM_IH_STACK, hasLotsOfRemainingStack(), "init h");
429
430 efiPrintf("initHardware()");
431
432 #if EFI_PROD_CODE
433 initPinRepository();
434 #endif
435
436 #if EFI_PROD_CODE
437 boardInitHardwareEarly();
438 call_board_override(custom_board_InitHardwareEarly);
439 #endif
440
441 #if EFI_HISTOGRAMS
442 /**
443 * histograms is a data structure for CPU monitor, it does not depend on configuration
444 */
445 initHistogramsModule();
446 #endif /* EFI_HISTOGRAMS */
447
448 #if EFI_GPIO_HARDWARE
449 /**
450 * We need the LED_ERROR pin even before we read configuration
451 */
452 initPrimaryPins();
453 #endif // EFI_GPIO_HARDWARE
454
455 #if EFI_PROD_CODE && EFI_SIGNAL_EXECUTOR_ONE_TIMER
456 // it's important to initialize this pretty early in the game before any scheduling usages
457 initSingleTimerExecutorHardware();
458 #endif // EFI_PROD_CODE && EFI_SIGNAL_EXECUTOR_ONE_TIMER
459
460 #if EFI_PROD_CODE && EFI_RTC
461 initRtc();
462 #endif // EFI_PROD_CODE && EFI_RTC
463
464 #if EFI_CONFIGURATION_STORAGE
465 initFlash();
466 #endif
467
468 #if EFI_FILE_LOGGING
469 initEarlyMmcCard();
470 #endif // EFI_FILE_LOGGING
471
472 #if HAL_USE_PAL && EFI_PROD_CODE
473 // this should be initialized before detectBoardType()
474 efiExtiInit();
475 #endif // HAL_USE_PAL
476 }
477
478 219 void stopHardware() {
479 219 stopSwitchPins();
480
481 #if EFI_PROD_CODE && (BOARD_EXT_GPIOCHIPS > 0)
482 stopSmartCsPins();
483 #endif /* (BOARD_EXT_GPIOCHIPS > 0) */
484
485 #if EFI_LOGIC_ANALYZER
486 stopLogicAnalyzerPins();
487 #endif /* EFI_LOGIC_ANALYZER */
488
489 #if EFI_EMULATE_POSITION_SENSORS
490 219 stopTriggerEmulatorPins();
491 #endif /* EFI_EMULATE_POSITION_SENSORS */
492
493 #if EFI_VVT_PID
494 stopVvtControlPins();
495 #endif /* EFI_VVT_PID */
496 219 }
497
498 /**
499 * This method is invoked both on ECU start and configuration change
500 * At the moment we have too many system which handle ECU start and configuration change separately
501 * TODO: move move hardware code here
502 */
503 802 void startHardware() {
504 #if EFI_SHAFT_POSITION_INPUT
505 802 initStartStopButton();
506 #endif
507
508 #if EFI_PROD_CODE && EFI_SHAFT_POSITION_INPUT
509 startTriggerInputPins();
510 #endif /* EFI_SHAFT_POSITION_INPUT */
511
512 #if EFI_ENGINE_CONTROL
513 802 enginePins.startPins();
514 #endif /* EFI_ENGINE_CONTROL */
515
516 #if EFI_SHAFT_POSITION_INPUT
517 802 validateTriggerInputs();
518
519 #endif // EFI_SHAFT_POSITION_INPUT
520
521 802 startSwitchPins();
522
523 #if EFI_CAN_SUPPORT
524 startCanPins();
525 #endif /* EFI_CAN_SUPPORT */
526 802 }
527
528 PUBLIC_API_WEAK void setPinConfigurationOverrides() { }
529
530 #if HAL_USE_I2C
531 const I2CConfig i2cfg = {
532 OPMODE_I2C,
533 400000,
534 FAST_DUTY_CYCLE_2,
535 };
536 #endif
537
538 583 void initHardware() {
539
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 583 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 583 times.
583 if (hasFirmwareError()) {
540 return;
541 }
542
543 #if EFI_PROD_CODE && STM32_I2C_USE_I2C3
544 if (engineConfiguration->useEeprom) {
545 i2cStart(&EE_U2CD, &i2cfg);
546 }
547 #endif // STM32_I2C_USE_I2C3
548
549 583 boardInitHardware();
550 583 call_board_override(custom_board_InitHardware);
551 #if EFI_PROD_CODE
552 // this applies some board configurations
553 boardOnConfigurationChange(nullptr);
554 #endif // EFI_PROD_CODE
555 583 boardInitHardwareExtra();
556 583 call_board_override(custom_board_InitHardwareExtra);
557
558 #if HAL_USE_ADC
559 initAdcInputs();
560 #endif /* HAL_USE_ADC */
561
562 #if EFI_SOFTWARE_KNOCK
563 initSoftwareKnock();
564 #endif /* EFI_SOFTWARE_KNOCK */
565
566 #ifdef TRIGGER_SCOPE
567 initTriggerScope();
568 #endif // TRIGGER_SCOPE
569
570 #if HAL_USE_SPI
571 initSpiModules();
572 #endif /* HAL_USE_SPI */
573
574 #if (EFI_PROD_CODE && BOARD_EXT_GPIOCHIPS > 0) || EFI_SIMULATOR
575 // initSmartGpio depends on 'initSpiModules'
576 initSmartGpio();
577 #endif
578
579 // output pins potentially depend on 'initSmartGpio'
580 583 initMiscOutputPins();
581
582 #if EFI_MC33816
583 initMc33816();
584 #endif /* EFI_MC33816 */
585
586 #if EFI_CAN_SUPPORT
587 #if EFI_SIMULATOR
588 // Set CAN device name
589 CAND1.deviceName = "can0";
590 #endif
591
592 initCan();
593 #endif /* EFI_CAN_SUPPORT */
594
595
596 #if EFI_PROD_CODE && EFI_SHAFT_POSITION_INPUT
597 onEcuStartTriggerImplementation();
598 #endif /* EFI_SHAFT_POSITION_INPUT */
599 583 onEcuStartDoSomethingTriggerInputPins();
600
601 #if EFI_WS2812
602 initWS2812();
603 #endif /* EFI_LED_WS2812 */
604
605 #if EFI_ONBOARD_MEMS
606 initAccelerometer();
607 #endif
608
609 #if EFI_BOSCH_YAW
610 initBoschYawRateSensor();
611 #endif /* EFI_BOSCH_YAW */
612
613 #if EFI_UART_GPS
614 initGps();
615 #endif
616
617 #if EFI_CAN_SUPPORT
618 initCanVssSupport();
619 #endif // EFI_CAN_SUPPORT
620
621 #if EFI_CDM_INTEGRATION
622 cdmIonInit();
623 #endif // EFI_CDM_INTEGRATION
624
625 #if EFI_PROD_CODE && EFI_SENT_SUPPORT
626 initSent();
627 #endif
628
629 583 initKLine();
630
631 #if EFI_DAC
632 initDac();
633 #endif
634
635 583 calcFastAdcIndexes();
636
637 583 startHardware();
638
639 583 efiPrintf("initHardware() OK!");
640 }
641