Implemented "full" ignition timing system
This is a first implementation of a "full" timing system, with proper handling for cases wher the ignition charge time overlaps with the compression pulse, the spark has a more complex state machine system with the option to defer charge from the intake pulse to the compression pulse, and further defferal of the spark release schedule to the ISR that triggers when the output compare triggers for the charge Preliminary error counters have been put in place, they still require handling error conditions that would force a soft shutdown on the ignition IC. Alongside this the code still needs to be verified so that all non critical errors (ie missed charge schedules) reset the state machine and increment a global spark miss counter to avoid having these errors breaking the state machine as they can easily be recovered from Cases where the coil would already be charging and an error occurs require as stated above a full recovery procedure with soft shutdown of the ignition IC and a clean cycle of the state machine to ensure a full recovery
This commit is contained in:
15 files changed
+444
-195
No files matched your search
@@ -8,36 +8,42 @@
|
||||
#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 "timer_utils.h"
|
||||
#include <stdint.h>
|
||||
|
||||
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
|
||||
|
||||
/* WINDOW FILTER
|
||||
*
|
||||
* This filter limits incoming signals to a certain max percentage deviation
|
||||
* to blank out false triggers that would be impossible in real life
|
||||
*
|
||||
* It computes the percantage difference between d1a and d1b then if this
|
||||
* has an absolute value over a certain threshold the signal is discarded
|
||||
*/
|
||||
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;
|
||||
// Updated to use clean API
|
||||
// state_g.crank_RB.w_head -= 1;
|
||||
ringBufferRevert(&state_g.crank_RB, 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// INCREMENT SWITCH
|
||||
switch (state_g.crank_state) {
|
||||
case CYCLE_COMPRESSION: {
|
||||
@@ -81,31 +87,83 @@ void crankHandler(void *argument) {
|
||||
// SPARK SCHEDULE
|
||||
if (state_g.sync_state == SYNC_OK) {
|
||||
switch (state_g.crank_state) {
|
||||
case CYCLE_INTAKE:
|
||||
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);
|
||||
uint32_t d_spark = 0;
|
||||
if (state_g.crank_state == CYCLE_INTAKE) {
|
||||
d_spark += d1a;
|
||||
}
|
||||
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;
|
||||
d_spark += d1a * (45 - SPARK_ADVANCE) / 180;
|
||||
uint32_t t_spark = CRANK(0) + d_spark;
|
||||
uint32_t t_spark_charge = t_spark - SPARK_CHARGE_TIME;
|
||||
if (state_g.crank_state == CYCLE_INTAKE) {
|
||||
if (t_spark_charge > CRANK(0) + 500 + ((d1a * 102U) / 100U)) {
|
||||
state_g.charge_defer = true;
|
||||
} else {
|
||||
state_g.charge_defer = false;
|
||||
if (timer_safe_to_arm(t_spark_charge, &htim2)) {
|
||||
state_g.current_spark_state = SPARK_PENDING_CHARGE;
|
||||
TIM2_CH3_SetOCMode(TIM2_CH3_OC_ACTIVE);
|
||||
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, t_spark_charge);
|
||||
} else {
|
||||
state_g.current_spark_state = SPARK_IDLE;
|
||||
state_g.spark_errors.overspeed_error_ctr++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (state_g.charge_defer) {
|
||||
state_g.spark_defer = true;
|
||||
state_g.t_defer_spark = t_spark;
|
||||
state_g.charge_defer = false;
|
||||
if (timer_safe_to_arm(t_spark_charge, &htim2)) {
|
||||
state_g.current_spark_state = SPARK_PENDING_CHARGE;
|
||||
TIM2_CH3_SetOCMode(TIM2_CH3_OC_ACTIVE);
|
||||
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, t_spark_charge);
|
||||
} else {
|
||||
state_g.spark_errors.defer_charge_error_ctr++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (state_g.current_spark_state) {
|
||||
case SPARK_PENDING_CHARGE: {
|
||||
if (timer_safe_to_arm(t_spark_charge, &htim2)) {
|
||||
state_g.current_spark_state = SPARK_PENDING_CHARGE;
|
||||
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, t_spark_charge);
|
||||
} else {
|
||||
state_g.spark_errors.revised_charge_error_ctr++;
|
||||
}
|
||||
state_g.spark_defer = true;
|
||||
state_g.t_defer_spark = t_spark;
|
||||
break;
|
||||
}
|
||||
case SPARK_CHARGING: {
|
||||
if (timer_safe_to_arm(t_spark, &htim2)) {
|
||||
|
||||
state_g.current_spark_state = SPARK_PENDING_RELEASE;
|
||||
TIM2_CH3_SetOCMode(TIM2_CH3_OC_INACTIVE);
|
||||
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, t_spark);
|
||||
state_g.spark_defer = false;
|
||||
} else {
|
||||
// TODO: Implement SSD on ignition IC if charging and complete
|
||||
// recovery
|
||||
state_g.spark_errors.task_release_error_ctr++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
state_g.spark_errors.state_error_ctr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CYCLE_EXHAUST: {
|
||||
uint32_t t_injection =
|
||||
CRANK(0) + (45 + INJECTION_PHASE) * (CRANK(4) - CRANK(0)) / 720;
|
||||
// TODO: Schedule injection
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user