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:
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user