Add full automotive RTOS project

Add kernel (Cortex-M0/M3/M4, Tricore, S32K, RISC-V ports), drivers,
middleware (CAN stack, diagnostics, safety), applications, board
support, build/test tooling, and documentation.
This commit is contained in:
root
2026-08-23 03:35:29 -04:00
parent f113bf0a05
commit ca13734bf0
151 changed files with 23945 additions and 0 deletions
@@ -0,0 +1,28 @@
/**
* @file engine_control.h
* @brief Engine control module interface
*/
#ifndef ENGINE_CONTROL_H
#define ENGINE_CONTROL_H
#include "kernel.h"
#include "engine_parameters.h"
/* Engine Control Functions */
KernelStatus_t engine_control_init(void);
KernelStatus_t engine_control_start(void);
KernelStatus_t engine_control_stop(void);
KernelStatus_t engine_control_get_sensor_data(EngineSensorData_t* data);
KernelStatus_t engine_control_get_actuator_data(EngineActuatorData_t* data);
KernelStatus_t engine_control_set_actuator_data(const EngineActuatorData_t* data);
EngineState_t engine_control_get_state(void);
KernelStatus_t engine_control_get_faults(EngineFaultCode_t* faults,
uint8_t* count);
KernelStatus_t engine_control_clear_faults(void);
void engine_control_task(void* parameters);
void fuel_injection_task(void* parameters);
void ignition_control_task(void* parameters);
void sensor_reading_task(void* parameters);
#endif /* ENGINE_CONTROL_H */
@@ -0,0 +1,177 @@
/**
* @file engine_parameters.h
* @brief Engine control parameters and calibration data
*/
#ifndef ENGINE_PARAMETERS_H
#define ENGINE_PARAMETERS_H
#include <stdint.h>
/* Engine Operating Parameters */
#define ENGINE_MAX_RPM 6500
#define ENGINE_IDLE_RPM 800
#define ENGINE_REDLINE_RPM 6000
#define ENGINE_MAX_TORQUE_RPM 4000
#define ENGINE_MAX_POWER_RPM 5500
/* Temperature Limits */
#define ENGINE_MAX_COOLANT_TEMP 120 /* °C */
#define ENGINE_MIN_COOLANT_TEMP -40 /* °C */
#define ENGINE_OPTIMAL_TEMP 90 /* °C */
#define ENGINE_MAX_OIL_TEMP 150 /* °C */
#define ENGINE_MAX_INTAKE_TEMP 80 /* °C */
/* Pressure Limits */
#define ENGINE_MAX_MANIFOLD_PRESSURE 250 /* kPa */
#define ENGINE_MIN_OIL_PRESSURE 100 /* kPa */
#define ENGINE_MAX_FUEL_PRESSURE 500 /* kPa */
/* Fuel System Parameters */
#define FUEL_STOICHIOMETRIC_RATIO 14.7f
#define FUEL_MAX_INJECTION_TIME 20.0f /* ms */
#define FUEL_MIN_INJECTION_TIME 0.5f /* ms */
#define FUEL_INJECTOR_FLOW_RATE 250.0f /* cc/min */
/* Ignition Parameters */
#define IGNITION_MAX_ADVANCE 45.0f /* degrees BTDC */
#define IGNITION_MIN_ADVANCE -10.0f /* degrees ATDC */
#define IGNITION_BASE_ADVANCE 10.0f /* degrees BTDC */
#define IGNITION_DWELL_TIME 3.5f /* ms */
/* Control Loop Parameters */
#define ENGINE_CONTROL_PERIOD_MS 1 /* 1ms control loop */
#define FUEL_CONTROL_PERIOD_MS 10 /* 10ms fuel update */
#define IGNITION_CONTROL_PERIOD_MS 5 /* 5ms ignition update */
#define SENSOR_READ_PERIOD_MS 2 /* 2ms sensor reading */
/* PID Controller Gains */
typedef struct {
float kp;
float ki;
float kd;
float integral_limit;
float output_limit;
} PidGains_t;
/* Fuel Control PID */
static const PidGains_t fuel_pid_gains = {
.kp = 0.5f,
.ki = 0.1f,
.kd = 0.05f,
.integral_limit = 100.0f,
.output_limit = 100.0f
};
/* Idle Control PID */
static const PidGains_t idle_pid_gains = {
.kp = 0.8f,
.ki = 0.2f,
.kd = 0.1f,
.integral_limit = 50.0f,
.output_limit = 100.0f
};
/* Boost Control PID */
static const PidGains_t boost_pid_gains = {
.kp = 0.3f,
.ki = 0.05f,
.kd = 0.02f,
.integral_limit = 200.0f,
.output_limit = 250.0f
};
/* Engine State Enumeration */
typedef enum {
ENGINE_STATE_OFF = 0,
ENGINE_STATE_CRANKING = 1,
ENGINE_STATE_RUNNING = 2,
ENGINE_STATE_IDLE = 3,
ENGINE_STATE_ACCELERATING = 4,
ENGINE_STATE_DECELERATING = 5,
ENGINE_STATE_FAULT = 6,
ENGINE_STATE_LIMP_HOME = 7
} EngineState_t;
/* Engine Sensor Data */
typedef struct {
uint16_t rpm;
uint16_t vehicle_speed;
int16_t coolant_temp;
int16_t intake_air_temp;
int16_t oil_temp;
uint16_t manifold_pressure;
uint16_t oil_pressure;
uint16_t fuel_pressure;
uint16_t throttle_position;
uint16_t accelerator_pedal;
float mass_air_flow;
float lambda;
float battery_voltage;
} EngineSensorData_t;
/* Engine Actuator Data */
typedef struct {
uint16_t injector_pulse_width;
float ignition_advance;
uint16_t idle_air_control;
uint16_t boost_control;
uint16_t fuel_pump_duty;
uint16_t cooling_fan_duty;
} EngineActuatorData_t;
/* Engine Fault Codes */
typedef enum {
ENGINE_FAULT_NONE = 0,
ENGINE_FAULT_COOLANT_TEMP_SENSOR = 1,
ENGINE_FAULT_INTAKE_TEMP_SENSOR = 2,
ENGINE_FAULT_MANIFOLD_PRESSURE_SENSOR = 3,
ENGINE_FAULT_MAF_SENSOR = 4,
ENGINE_FAULT_OXYGEN_SENSOR = 5,
ENGINE_FAULT_KNOCK_SENSOR = 6,
ENGINE_FAULT_CRANKSHAFT_SENSOR = 7,
ENGINE_FAULT_CAMSHAFT_SENSOR = 8,
ENGINE_FAULT_INJECTOR_1 = 9,
ENGINE_FAULT_INJECTOR_2 = 10,
ENGINE_FAULT_INJECTOR_3 = 11,
ENGINE_FAULT_INJECTOR_4 = 12,
ENGINE_FAULT_IGNITION_COIL = 13,
ENGINE_FAULT_FUEL_PUMP = 14,
ENGINE_FAULT_OVERHEAT = 15,
ENGINE_FAULT_LOW_OIL_PRESSURE = 16
} EngineFaultCode_t;
/* Lookup Tables */
typedef struct {
const uint16_t* rpm_points;
const uint16_t* load_points;
const uint16_t* values;
uint8_t rpm_count;
uint8_t load_count;
} LookupTable2D_t;
/* Fuel Map (injection time in microseconds) */
static const uint16_t fuel_map_rpm[] = {0, 500, 1000, 2000, 3000, 4000, 5000, 6000};
static const uint16_t fuel_map_load[] = {0, 20, 40, 60, 80, 100};
static const uint16_t fuel_map_values[][8] = {
{0, 1000, 800, 700, 650, 600, 550, 500},
{1000, 1500, 1300, 1200, 1100, 1000, 950, 900},
{2000, 2500, 2200, 2000, 1800, 1700, 1600, 1500},
{3000, 3500, 3200, 3000, 2800, 2600, 2400, 2200},
{4000, 4500, 4200, 4000, 3800, 3600, 3400, 3200},
{5000, 5500, 5200, 5000, 4800, 4600, 4400, 4200}
};
/* Ignition Advance Map (degrees BTDC) */
static const uint16_t ignition_map_rpm[] = {0, 500, 1000, 2000, 3000, 4000, 5000, 6000};
static const uint16_t ignition_map_load[] = {0, 20, 40, 60, 80, 100};
static const int16_t ignition_map_values[][8] = {
{10, 12, 15, 18, 20, 22, 25, 28},
{10, 12, 15, 18, 20, 22, 25, 28},
{8, 10, 13, 16, 18, 20, 23, 26},
{6, 8, 11, 14, 16, 18, 21, 24},
{4, 6, 9, 12, 14, 16, 19, 22},
{2, 4, 7, 10, 12, 14, 17, 20}
};
#endif /* ENGINE_PARAMETERS_H */
@@ -0,0 +1,366 @@
/**
* @file engine_control_task.c
* @brief Main engine control task
*/
#include "engine_control.h"
#include "fuel_injection.h"
#include "ignition_control.h"
#include "adc_driver.h"
#include "gpio_driver.h"
#include "pwm_driver.h"
#include "dtc_manager.h"
#include <string.h>
#include <math.h>
/* Engine Control State */
typedef struct {
EngineState_t state;
EngineSensorData_t sensors;
EngineActuatorData_t actuators;
EngineFaultCode_t faults[20];
uint8_t fault_count;
uint32_t engine_run_time;
Mutex_t data_mutex;
bool initialized;
} EngineControlState_t;
static EngineControlState_t engine_control;
/* PID Controller Structure */
typedef struct {
PidGains_t gains;
float integral;
float previous_error;
float output;
} PidController_t;
static PidController_t fuel_pid;
static PidController_t idle_pid;
static PidController_t boost_pid;
/* Initialize Engine Control */
KernelStatus_t engine_control_init(void) {
if (engine_control.initialized) {
return KERNEL_ERROR;
}
/* Initialize state */
memset(&engine_control, 0, sizeof(EngineControlState_t));
engine_control.state = ENGINE_STATE_OFF;
engine_control.fault_count = 0;
/* Initialize PID controllers */
fuel_pid.gains = fuel_pid_gains;
fuel_pid.integral = 0;
fuel_pid.previous_error = 0;
fuel_pid.output = 0;
idle_pid.gains = idle_pid_gains;
idle_pid.integral = 0;
idle_pid.previous_error = 0;
idle_pid.output = 0;
boost_pid.gains = boost_pid_gains;
boost_pid.integral = 0;
boost_pid.previous_error = 0;
boost_pid.output = 0;
/* Create mutex */
mutex_create(&engine_control.data_mutex, false);
/* Initialize sensors */
adc_init(0, &(AdcConfig_t){
.resolution = ADC_RESOLUTION_12BIT,
.mode = ADC_MODE_SCAN,
.trigger_source = ADC_TRIGGER_TIMER,
.reference = ADC_REFERENCE_VDD,
.channel_count = 8,
.channels = {
{.channel = 0, .sampling_time = ADC_SAMPLING_28_5_CYCLES}, /* Coolant temp */
{.channel = 1, .sampling_time = ADC_SAMPLING_28_5_CYCLES}, /* Intake temp */
{.channel = 2, .sampling_time = ADC_SAMPLING_28_5_CYCLES}, /* Manifold pressure */
{.channel = 3, .sampling_time = ADC_SAMPLING_28_5_CYCLES}, /* Throttle position */
{.channel = 4, .sampling_time = ADC_SAMPLING_28_5_CYCLES}, /* Accelerator pedal */
{.channel = 5, .sampling_time = ADC_SAMPLING_28_5_CYCLES}, /* Oil pressure */
{.channel = 6, .sampling_time = ADC_SAMPLING_28_5_CYCLES}, /* Fuel pressure */
{.channel = 7, .sampling_time = ADC_SAMPLING_28_5_CYCLES} /* Battery voltage */
}
});
/* Initialize actuators */
pwm_init(0, &(PwmConfig_t){
.frequency_hz = 1000,
.alignment = PWM_ALIGNMENT_EDGE,
.channel_count = 4,
.channels = {
{.channel = 0, .duty_cycle = 0}, /* Injector 1 */
{.channel = 1, .duty_cycle = 0}, /* Injector 2 */
{.channel = 2, .duty_cycle = 0}, /* Idle air control */
{.channel = 3, .duty_cycle = 0} /* Boost control */
}
});
engine_control.initialized = true;
return KERNEL_OK;
}
/* Start Engine */
KernelStatus_t engine_control_start(void) {
if (!engine_control.initialized) {
return KERNEL_ERROR;
}
engine_control.state = ENGINE_STATE_CRANKING;
/* Start PWM outputs */
pwm_start(0);
/* Start ADC conversions */
adc_start_conversion(0);
return KERNEL_OK;
}
/* Stop Engine */
KernelStatus_t engine_control_stop(void) {
if (!engine_control.initialized) {
return KERNEL_ERROR;
}
/* Stop actuators */
pwm_stop(0);
/* Stop ADC */
adc_stop_conversion(0);
engine_control.state = ENGINE_STATE_OFF;
return KERNEL_OK;
}
/* Main Engine Control Task */
void engine_control_task(void* parameters) {
(void)parameters;
TickType_t last_wake_time = kernel_get_tick_count();
while (1) {
/* Wait for next control period */
kernel_delay(ENGINE_CONTROL_PERIOD_MS);
switch (engine_control.state) {
case ENGINE_STATE_CRANKING:
/* Check RPM for engine start */
if (engine_control.sensors.rpm > 400) {
engine_control.state = ENGINE_STATE_RUNNING;
}
break;
case ENGINE_STATE_RUNNING:
/* Check for idle condition */
if (engine_control.sensors.rpm < ENGINE_IDLE_RPM + 50 &&
engine_control.sensors.accelerator_pedal < 5) {
engine_control.state = ENGINE_STATE_IDLE;
}
/* Check for acceleration */
if (engine_control.sensors.accelerator_pedal > 80) {
engine_control.state = ENGINE_STATE_ACCELERATING;
}
break;
case ENGINE_STATE_IDLE:
/* Idle speed control */
idle_pid_control();
/* Check if leaving idle */
if (engine_control.sensors.accelerator_pedal > 5) {
engine_control.state = ENGINE_STATE_RUNNING;
}
break;
case ENGINE_STATE_ACCELERATING:
/* Acceleration enrichment */
engine_control.actuators.injector_pulse_width *= 1.2f;
/* Check if still accelerating */
if (engine_control.sensors.accelerator_pedal < 80) {
engine_control.state = ENGINE_STATE_RUNNING;
}
break;
case ENGINE_STATE_DECELERATING:
/* Deceleration fuel cutoff */
if (engine_control.sensors.rpm > 1500 &&
engine_control.sensors.accelerator_pedal < 2) {
engine_control.actuators.injector_pulse_width = 0;
}
/* Check if still decelerating */
if (engine_control.sensors.accelerator_pedal > 2) {
engine_control.state = ENGINE_STATE_RUNNING;
}
break;
case ENGINE_STATE_FAULT:
/* Handle faults */
handle_engine_faults();
break;
case ENGINE_STATE_LIMP_HOME:
/* Limp home mode */
engine_control.actuators.injector_pulse_width =
fuel_map_values[0][3]; /* Fixed fuel */
engine_control.actuators.ignition_advance =
ignition_map_values[0][3]; /* Fixed timing */
break;
default:
break;
}
/* Update engine run time */
engine_control.engine_run_time += ENGINE_CONTROL_PERIOD_MS;
/* Check for faults */
check_engine_faults();
last_wake_time = kernel_get_tick_count();
}
}
/* Idle Speed Control */
static void idle_pid_control(void) {
int32_t rpm_error = ENGINE_IDLE_RPM - engine_control.sensors.rpm;
/* PID calculation */
idle_pid.integral += rpm_error * (IDLE_CONTROL_PERIOD_MS / 1000.0f);
/* Limit integral */
if (idle_pid.integral > idle_pid.gains.integral_limit) {
idle_pid.integral = idle_pid.gains.integral_limit;
} else if (idle_pid.integral < -idle_pid.gains.integral_limit) {
idle_pid.integral = -idle_pid.gains.integral_limit;
}
float derivative = (rpm_error - idle_pid.previous_error) /
(IDLE_CONTROL_PERIOD_MS / 1000.0f);
idle_pid.output = idle_pid.gains.kp * rpm_error +
idle_pid.gains.ki * idle_pid.integral +
idle_pid.gains.kd * derivative;
/* Limit output */
if (idle_pid.output > idle_pid.gains.output_limit) {
idle_pid.output = idle_pid.gains.output_limit;
} else if (idle_pid.output < 0) {
idle_pid.output = 0;
}
/* Update actuator */
engine_control.actuators.idle_air_control = (uint16_t)idle_pid.output;
idle_pid.previous_error = rpm_error;
}
/* Check Engine Faults */
static void check_engine_faults(void) {
/* Check coolant temperature */
if (engine_control.sensors.coolant_temp > ENGINE_MAX_COOLANT_TEMP) {
add_engine_fault(ENGINE_FAULT_OVERHEAT);
engine_control.state = ENGINE_STATE_FAULT;
}
/* Check oil pressure */
if (engine_control.sensors.oil_pressure < ENGINE_MIN_OIL_PRESSURE &&
engine_control.sensors.rpm > 1000) {
add_engine_fault(ENGINE_FAULT_LOW_OIL_PRESSURE);
engine_control.state = ENGINE_STATE_FAULT;
}
/* Check battery voltage */
if (engine_control.sensors.battery_voltage < 9.0f ||
engine_control.sensors.battery_voltage > 16.0f) {
add_engine_fault(ENGINE_FAULT_NONE); // Just log the condition
}
}
/* Add Engine Fault */
static void add_engine_fault(EngineFaultCode_t fault) {
if (engine_control.fault_count < 20) {
/* Check if fault already exists */
for (uint8_t i = 0; i < engine_control.fault_count; i++) {
if (engine_control.faults[i] == fault) {
return;
}
}
engine_control.faults[engine_control.fault_count] = fault;
engine_control.fault_count++;
/* Add DTC */
DtcCode_t dtc_code = {
.high_byte = 0x00, /* Powertrain */
.middle_byte = 0x00,
.low_byte = fault
};
dtc_manager_add_dtc(&dtc_code, 3); /* Medium severity */
}
}
/* Handle Engine Faults */
static void handle_engine_faults(void) {
for (uint8_t i = 0; i < engine_control.fault_count; i++) {
switch (engine_control.faults[i]) {
case ENGINE_FAULT_OVERHEAT:
/* Enable cooling fan */
engine_control.actuators.cooling_fan_duty = 100;
/* Reduce power */
engine_control.actuators.injector_pulse_width *= 0.5f;
break;
case ENGINE_FAULT_LOW_OIL_PRESSURE:
/* Immediate engine shutdown */
engine_control_stop();
break;
default:
/* Enter limp home mode */
engine_control.state = ENGINE_STATE_LIMP_HOME;
break;
}
}
}
/* Get Engine State */
EngineState_t engine_control_get_state(void) {
return engine_control.state;
}
/* Get Sensor Data */
KernelStatus_t engine_control_get_sensor_data(EngineSensorData_t* data) {
if (data == NULL) {
return KERNEL_ERROR;
}
mutex_lock(&engine_control.data_mutex, 100);
memcpy(data, &engine_control.sensors, sizeof(EngineSensorData_t));
mutex_unlock(&engine_control.data_mutex);
return KERNEL_OK;
}
/* Get Actuator Data */
KernelStatus_t engine_control_get_actuator_data(EngineActuatorData_t* data) {
if (data == NULL) {
return KERNEL_ERROR;
}
mutex_lock(&engine_control.data_mutex, 100);
memcpy(data, &engine_control.actuators, sizeof(EngineActuatorData_t));
mutex_unlock(&engine_control.data_mutex);
return KERNEL_OK;
}
@@ -0,0 +1,164 @@
/**
* @file fuel_injection.c
* @brief Fuel injection control
*/
#include "engine_control.h"
#include "fuel_injection.h"
#include "adc_driver.h"
#include "pwm_driver.h"
#include <math.h>
/* Fuel Injection State */
typedef struct {
bool initialized;
float fuel_pressure;
float injection_time;
uint16_t injector_duty;
uint8_t injection_mode; /* 0=sequential, 1=batch, 2=simultaneous */
Mutex_t mutex;
} FuelInjectionState_t;
static FuelInjectionState_t fuel_injection;
/* Initialize Fuel Injection */
KernelStatus_t fuel_injection_init(void) {
if (fuel_injection.initialized) {
return KERNEL_ERROR;
}
fuel_injection.fuel_pressure = 0;
fuel_injection.injection_time = 0;
fuel_injection.injector_duty = 0;
fuel_injection.injection_mode = 0; /* Sequential */
mutex_create(&fuel_injection.mutex, false);
fuel_injection.initialized = true;
return KERNEL_OK;
}
/* Fuel Injection Control Task */
void fuel_injection_task(void* parameters) {
(void)parameters;
while (1) {
/* Wait for next fuel update period */
kernel_delay(FUEL_CONTROL_PERIOD_MS);
EngineSensorData_t sensors;
engine_control_get_sensor_data(&sensors);
/* Calculate required fuel */
float required_fuel = calculate_fuel_requirement(&sensors);
/* Apply corrections */
required_fuel = apply_fuel_corrections(required_fuel, &sensors);
/* Convert to injector pulse width */
uint16_t pulse_width = (uint16_t)(required_fuel * 1000); /* Convert to microseconds */
/* Limit pulse width */
if (pulse_width > (uint16_t)(FUEL_MAX_INJECTION_TIME * 1000)) {
pulse_width = (uint16_t)(FUEL_MAX_INJECTION_TIME * 1000);
}
/* Update injector PWM */
mutex_lock(&fuel_injection.mutex, 100);
fuel_injection.injection_time = required_fuel;
fuel_injection.injector_duty = calculate_injector_duty(pulse_width,
sensors.rpm);
mutex_unlock(&fuel_injection.mutex);
/* Update PWM output */
pwm_set_duty_cycle(0, 0, fuel_injection.injector_duty); /* Injector 1 */
pwm_set_duty_cycle(0, 1, fuel_injection.injector_duty); /* Injector 2 */
}
}
/* Calculate Fuel Requirement */
static float calculate_fuel_requirement(const EngineSensorData_t* sensors) {
/* Basic fuel calculation using speed-density method */
float air_mass = 0;
if (sensors->mass_air_flow > 0) {
/* Use MAF sensor if available */
air_mass = sensors->mass_air_flow / (sensors->rpm / 2);
} else {
/* Speed-density calculation */
float air_density = 1.225f; /* kg/m³ at sea level */
float engine_displacement = 2.0f; /* 2.0L engine */
float volumetric_efficiency = 0.85f;
air_mass = air_density * engine_displacement *
volumetric_efficiency * sensors->manifold_pressure / 101.3f;
}
/* Calculate fuel mass for stoichiometric mixture */
float fuel_mass = air_mass / FUEL_STOICHIOMETRIC_RATIO;
/* Convert to injection time */
float injection_time = (fuel_mass * 1000000) / FUEL_INJECTOR_FLOW_RATE;
return injection_time;
}
/* Apply Fuel Corrections */
static float apply_fuel_corrections(float base_fuel, const EngineSensorData_t* sensors) {
float corrected_fuel = base_fuel;
/* Lambda correction */
if (sensors->lambda > 0) {
float lambda_error = 1.0f - sensors->lambda;
corrected_fuel *= (1.0f + lambda_error * 0.5f);
}
/* Coolant temperature correction */
if (sensors->coolant_temp < 70) {
float enrichment = (70 - sensors->coolant_temp) * 0.01f;
corrected_fuel *= (1.0f + enrichment);
}
/* Acceleration enrichment */
if (sensors->accelerator_pedal > 80) {
corrected_fuel *= 1.2f;
}
/* Battery voltage correction */
if (sensors->battery_voltage < 12.0f) {
corrected_fuel *= (12.0f / sensors->battery_voltage);
}
return corrected_fuel;
}
/* Calculate Injector Duty Cycle */
static uint16_t calculate_injector_duty(uint16_t pulse_width_us, uint16_t rpm) {
/* Calculate period in microseconds */
uint32_t period_us = (60000000UL) / rpm; /* 2 revolutions per cycle */
/* Calculate duty cycle */
uint32_t duty = (pulse_width_us * PWM_MAX_DUTY_CYCLE) / period_us;
if (duty > PWM_MAX_DUTY_CYCLE) {
duty = PWM_MAX_DUTY_CYCLE;
}
return (uint16_t)duty;
}
/* Get Fuel Injection Data */
KernelStatus_t fuel_injection_get_data(float* pressure, float* injection_time,
uint16_t* duty_cycle) {
if (pressure == NULL || injection_time == NULL || duty_cycle == NULL) {
return KERNEL_ERROR;
}
mutex_lock(&fuel_injection.mutex, 100);
*pressure = fuel_injection.fuel_pressure;
*injection_time = fuel_injection.injection_time;
*duty_cycle = fuel_injection.injector_duty;
mutex_unlock(&fuel_injection.mutex);
return KERNEL_OK;
}
@@ -0,0 +1,134 @@
/**
* @file ignition_control.c
* @brief Ignition timing control
*/
#include "engine_control.h"
#include "ignition_control.h"
#include "gpio_driver.h"
#include <math.h>
/* Ignition Control State */
typedef struct {
bool initialized;
float ignition_advance;
float dwell_time;
uint8_t ignition_mode;
bool knock_detected;
uint32_t knock_count;
Mutex_t mutex;
} IgnitionControlState_t;
static IgnitionControlState_t ignition_control;
/* Initialize Ignition Control */
KernelStatus_t ignition_control_init(void) {
if (ignition_control.initialized) {
return KERNEL_ERROR;
}
ignition_control.ignition_advance = IGNITION_BASE_ADVANCE;
ignition_control.dwell_time = IGNITION_DWELL_TIME;
ignition_control.ignition_mode = 0;
ignition_control.knock_detected = false;
ignition_control.knock_count = 0;
mutex_create(&ignition_control.mutex, false);
ignition_control.initialized = true;
return KERNEL_OK;
}
/* Ignition Control Task */
void ignition_control_task(void* parameters) {
(void)parameters;
while (1) {
/* Wait for next ignition update period */
kernel_delay(IGNITION_CONTROL_PERIOD_MS);
EngineSensorData_t sensors;
engine_control_get_sensor_data(&sensors);
/* Calculate ignition advance */
float advance = calculate_ignition_advance(&sensors);
/* Apply knock correction */
if (ignition_control.knock_detected) {
advance -= 5.0f; /* Retard timing */
ignition_control.knock_detected = false;
ignition_control.knock_count++;
}
/* Limit advance */
if (advance > IGNITION_MAX_ADVANCE) {
advance = IGNITION_MAX_ADVANCE;
} else if (advance < IGNITION_MIN_ADVANCE) {
advance = IGNITION_MIN_ADVANCE;
}
/* Update ignition control */
mutex_lock(&ignition_control.mutex, 100);
ignition_control.ignition_advance = advance;
mutex_unlock(&ignition_control.mutex);
/* Update actuator */
EngineActuatorData_t actuators;
engine_control_get_actuator_data(&actuators);
actuators.ignition_advance = advance;
engine_control_set_actuator_data(&actuators);
}
}
/* Calculate Ignition Advance */
static float calculate_ignition_advance(const EngineSensorData_t* sensors) {
float advance = IGNITION_BASE_ADVANCE;
/* RPM correction */
if (sensors->rpm < 1000) {
advance += 5.0f; /* More advance at low RPM */
} else if (sensors->rpm > 5000) {
advance -= 3.0f; /* Less advance at high RPM */
}
/* Load correction */
if (sensors->manifold_pressure < 40) {
advance += 2.0f; /* More advance at light load */
} else if (sensors->manifold_pressure > 80) {
advance -= 4.0f; /* Less advance at high load */
}
/* Temperature correction */
if (sensors->coolant_temp < 0) {
advance += 3.0f; /* More advance when cold */
} else if (sensors->coolant_temp > 100) {
advance -= 5.0f; /* Less advance when hot */
}
return advance;
}
/* Detect Knock */
void ignition_control_detect_knock(void) {
/* Read knock sensor */
uint16_t knock_signal = adc_read_single(7);
/* Check for knock */
if (knock_signal > 200) {
ignition_control.knock_detected = true;
}
}
/* Get Ignition Data */
KernelStatus_t ignition_control_get_data(float* advance, float* dwell) {
if (advance == NULL || dwell == NULL) {
return KERNEL_ERROR;
}
mutex_lock(&ignition_control.mutex, 100);
*advance = ignition_control.ignition_advance;
*dwell = ignition_control.dwell_time;
mutex_unlock(&ignition_control.mutex);
return KERNEL_OK;
}