// Copyright (C) 2026 Hector van der Aa // Copyright (C) 2026 Pierre Barbier // Copyright (C) 2026 Association Exergie // SPDX-License-Identifier: GPL-3.0-or-later #include "cmsis_os2.h" #include "global_state.h" #include "macros.h" #include "main.h" #include "ring_buffer.h" #include "stm32h747xx.h" #include "stm32h7xx.h" #include "stm32h7xx_hal_tim.h" #include "tasks.h" #include static inline void TIM2_CH3_SetOCMode(uint32_t oc_mode) { MODIFY_REG(TIM2->CCMR2, TIM_CCMR2_OC3M | TIM_CCMR2_OC3M_3, oc_mode); } void crankHandler(void *argument) { for (;;) { osThreadFlagsWait(0x01, osFlagsWaitAny, osWaitForever); DEBUG_LOG("Crank pulse detected at: %lu\n\r", ringBufferRead(&state_g.crank_RB, 0)); // FILTER if (state_g.sync_state == SYNC_OK) { uint32_t d1a = CRANK(0) - CRANK(1); uint32_t d1b = CRANK(1) - CRANK(2); int32_t delta_percentage = ((int64_t)d1a - (int64_t)d1b) * 100 / (int64_t)d1b; DEBUG_LOG("%ld\n\r", delta_percentage); if (delta_percentage > 40 || delta_percentage < -40) { // state_g.sync_state = SYNC_NOT_OK; // state_g.crank_state = CYCLE_UNKNOWN; // ringBufferRevert(&state_g.crank_RB, 1); state_g.crank_RB.w_head -= 1; continue; } } // INCREMENT SWITCH switch (state_g.crank_state) { case CYCLE_COMPRESSION: { if (state_g.cam_state != CAM_TRIGD) { DEBUG_LOG("Cam miss detected, sync dynamite incoming\n\r"); state_g.cam_miss_ctr++; if (state_g.cam_miss_ctr > MAX_CAM_MISS) { state_g.sync_state = SYNC_NOT_OK; state_g.crank_state = CYCLE_UNKNOWN; break; } } state_g.crank_state = CYCLE_COMBUSTION; DEBUG_LOG("Crank state incremented\n\r"); state_g.cam_state = CAM_IDLE; break; } case CYCLE_COMBUSTION: case CYCLE_EXHAUST: case CYCLE_INTAKE: { if (state_g.cam_state == CAM_TRIGD) { state_g.sync_state = SYNC_NOT_OK; state_g.crank_state = CYCLE_UNKNOWN; state_g.cam_state = CAM_IDLE; break; } state_g.crank_state++; DEBUG_LOG("Crank state incremented\n\r"); break; } case CYCLE_UNKNOWN: { if (state_g.sync_state == SYNC_PENDING && state_g.cam_state == CAM_TRIGD) { state_g.crank_state = CYCLE_COMBUSTION; state_g.cam_state = CAM_IDLE; } break; } } // SPARK SCHEDULE if (state_g.sync_state == SYNC_OK) { switch (state_g.crank_state) { case CYCLE_COMPRESSION: { DEBUG_LOG("Spark schedule reached, congrats\n\r"); uint32_t d1a = CRANK(0) - CRANK(1); // TODO: Map interpolation rather than SPARK_ADVANCE CONSTANT uint32_t d_spark = d1a * (45 - SPARK_ADVANCE) / 180; uint32_t t_spark = CRANK(0) + d_spark; // TODO: schedule spark if (state_g.current_spark_state != SPARK_CHARGING) { uint32_t force_charge_time = __HAL_TIM_GET_COUNTER(&htim2) + 2000; // TIM2_CH3_SetOCMode(TIM_OCMODE_ACTIVE); __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, force_charge_time); state_g.next_spark_state = SPARK_CHARGING; osThreadFlagsWait(0x02, osFlagsWaitAny, osWaitForever); } DEBUG_LOG("Spark scheduled for: %lu , current time: %lu\n\r", t_spark, __HAL_TIM_GET_COUNTER(&htim2)); // TIM2_CH3_SetOCMode(TIM_OCMODE_INACTIVE); __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, t_spark); state_g.next_spark_state = SPARK_IDLE; break; } case CYCLE_EXHAUST: { uint32_t t_injection = CRANK(0) + (45 + INJECTION_PHASE) * (CRANK(4) - CRANK(0)) / 720; // TODO: Schedule injection break; } default: break; } } } }