refactored real time task to general with configuration structure

This commit is contained in:
Emanuele Trabattoni
2026-03-30 12:36:31 +02:00
parent b75014854d
commit e0af350b89
3 changed files with 300 additions and 318 deletions

View File

@@ -33,14 +33,12 @@ struct Devices {
PCA9555* io = NULL; PCA9555* io = NULL;
}; };
inline float adcReadChannel(ADS1256* adc, const uint32_t drdy_pin, const uint32_t ch){ inline float adcReadChannel(ADS1256* adc, const uint8_t ch){
adc->setMUX(ch); adc->setMUX(ch);
// scarta 3 conversioni // scarta 3 conversioni
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
while (digitalRead(drdy_pin));
adc->readSingle(); adc->readSingle();
} }
// ora lettura valida a 30kSPS → ~100 µs di settling // ora lettura valida a 30kSPS → ~100 µs di settling
while (digitalRead(drdy_pin));
return adc->convertToVoltage(adc->readSingle()); return adc->convertToVoltage(adc->readSingle());
} }

View File

@@ -1,7 +1,9 @@
#pragma once #pragma once
// Test device Flag
#define TEST #define TEST
// Arduino Libraries
#include <Arduino.h> #include <Arduino.h>
#include <map> #include <map>
#include "soc/gpio_struct.h" #include "soc/gpio_struct.h"
@@ -14,37 +16,19 @@
#define CORE_0 0 #define CORE_0 0
#define CORE_1 1 #define CORE_1 1
#define TASK_STACK 4096 // in words #define TASK_STACK 4096 // in words
#define TASK_PRIORITY 2 // priorità leggermente più alta #define TASK_PRIORITY (configMAX_PRIORITIES - 4) // highest priority after wifi tasks
// ===================== // =====================
// Event Flags (bitmask) // Event Flags (bitmask)
// ===================== // =====================
#define TRIG_FLAG_A12P (1 << 0) #define TRIG_FLAG_12P (1 << 0)
#define TRIG_FLAG_A12N (1 << 2) #define TRIG_FLAG_12N (1 << 2)
#define TRIG_FLAG_A34P (1 << 1) #define TRIG_FLAG_34P (1 << 1)
#define TRIG_FLAG_A34N (1 << 3) #define TRIG_FLAG_34N (1 << 3)
#ifndef TEST
#define TRIG_FLAG_B12P (1 << 4)
#define TRIG_FLAG_B12N (1 << 6)
#define TRIG_FLAG_B34P (1 << 5)
#define TRIG_FLAG_B34N (1 << 7)
#endif
#define SPARK_FLAG_A12 (1 << 8) #define SPARK_FLAG_NIL (1 << 8)
#define SPARK_FLAG_A34 (1 << 9) #define SPARK_FLAG_12 (1 << 9)
#ifndef TEST #define SPARK_FLAG_34 (1 << 10)
#define SPARK_FLAG_B12 (1 << 10)
#define SPARK_FLAG_B34 (1 << 11)
#endif
static const std::map<const uint32_t, const char*> names = {
{TRIG_FLAG_A12P, "TRIG_FLAG_A12P"},
{TRIG_FLAG_A12N, "TRIG_FLAG_A12N"},
{TRIG_FLAG_A34P, "TRIG_FLAG_A34P"},
{TRIG_FLAG_A34N, "TRIG_FLAG_A34N"},
{SPARK_FLAG_A12, "SPARK_FLAG_A12"},
{SPARK_FLAG_A34, "SPARK_FLAG_A34"},
};
// Task handle // Task handle
TaskHandle_t trigA_TaskHandle = NULL; TaskHandle_t trigA_TaskHandle = NULL;
@@ -78,20 +62,22 @@ struct coilsStatus
int64_t spark_time; int64_t spark_time;
int64_t spark_delay; int64_t spark_delay;
sparkStatus spark_status; sparkStatus spark_status;
softStartStatus soft_start_status; softStartStatus sstart_status;
float pickup_volts; float peak_p_in, peak_n_in;
float output_volts; float peak_p_out, peak_n_out;
float trigger_spark;
}; };
// Task internal Status // Task internal Status
struct ignitionBoxStatus struct ignitionBoxStatus
{ {
int64_t timestamp;
// coils pairs for each ignition // coils pairs for each ignition
coilsStatus coils12; coilsStatus coils12;
coilsStatus coils34; coilsStatus coils34;
// voltage from generator // voltage from generator
float volts_gen = 0.0; float volts_gen = 0.0;
// spark flags
bool spark12 = false; bool spark12 = false;
bool spark34 = false; bool spark34 = false;
}; };
@@ -103,26 +89,26 @@ ignitionBoxStatus ignB_status;
static uint32_t pin2trig[49] = {0}; static uint32_t pin2trig[49] = {0};
void initTriggerPinMapping() void initTriggerPinMapping()
{ {
pin2trig[TRIG_A12P] = TRIG_FLAG_A12P; pin2trig[TRIG_A12P] = TRIG_FLAG_12P;
pin2trig[TRIG_A12N] = TRIG_FLAG_A12N; pin2trig[TRIG_A12N] = TRIG_FLAG_12N;
pin2trig[TRIG_A34P] = TRIG_FLAG_A34P; pin2trig[TRIG_A34P] = TRIG_FLAG_34P;
pin2trig[TRIG_A34N] = TRIG_FLAG_A34N; pin2trig[TRIG_A34N] = TRIG_FLAG_34N;
#ifndef TEST #ifndef TEST
pin2trig[TRIG_B12P] = TRIG_FLAG_B12P; pin2trig[TRIG_B12P] = TRIG_FLAG_12P;
pin2trig[TRIG_B12N] = TRIG_FLAG_B12N; pin2trig[TRIG_B12N] = TRIG_FLAG_12N;
pin2trig[TRIG_B34P] = TRIG_FLAG_B34P; pin2trig[TRIG_B34P] = TRIG_FLAG_34P;
pin2trig[TRIG_B34N] = TRIG_FLAG_B34N; pin2trig[TRIG_B34N] = TRIG_FLAG_34N;
#endif #endif
}; };
static uint32_t pin2spark[49] = {0}; static uint32_t pin2spark[49] = {0};
void initSparkPinMapping() void initSparkPinMapping()
{ {
pin2spark[SPARK_A12] = SPARK_FLAG_A12; pin2spark[SPARK_A12] = SPARK_FLAG_12;
pin2spark[SPARK_A34] = SPARK_FLAG_A34; pin2spark[SPARK_A34] = SPARK_FLAG_34;
#ifndef TEST #ifndef TEST
pin2spark[SPARK_B12] = SPARK_FLAG_B12; pin2spark[SPARK_B12] = SPARK_FLAG_12;
pin2spark[SPARK_B34] = SPARK_FLAG_B34; pin2spark[SPARK_B34] = SPARK_FLAG_34;
#endif #endif
}; };
@@ -132,97 +118,43 @@ void initSparkPinMapping()
// ===================== // =====================
void IRAM_ATTR trig_isr_a(void *arg) void IRAM_ATTR trig_isr_a(void *arg)
{ {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
volatile const int64_t time_us = esp_timer_get_time(); volatile const int64_t time_us = esp_timer_get_time();
if (!trigA_TaskHandle)
return; // exit if task is not running
uint32_t flag = (uint32_t)arg; // exit if task is not running
if (!trigA_TaskHandle)
return;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
volatile const uint32_t flag = (uint32_t)arg;
// reset spark flags, cannot be same time as trigger flags
ignA_status.spark12 = false; ignA_status.spark12 = false;
ignA_status.spark34 = false; ignA_status.spark34 = false;
if (flag & TRIG_FLAG_A12P) { switch (flag)
{
case TRIG_FLAG_12P:
ignA_status.coils12.trig_time = time_us; ignA_status.coils12.trig_time = time_us;
xTaskNotifyFromISR(trigA_TaskHandle, flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken); xTaskNotifyFromISR(trigA_TaskHandle, flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
} break;
if (flag & TRIG_FLAG_A34P) { case TRIG_FLAG_34P:
ignA_status.coils34.trig_time = time_us; ignA_status.coils34.trig_time = time_us;
xTaskNotifyFromISR(trigA_TaskHandle, flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken); xTaskNotifyFromISR(trigA_TaskHandle, flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
} break;
case SPARK_FLAG_12:
if (flag & SPARK_FLAG_A12) {
ignA_status.spark12 = true; ignA_status.spark12 = true;
ignA_status.coils12.spark_time = time_us; ignA_status.coils12.spark_time = time_us;
xTaskNotifyGive(trigA_TaskHandle); vTaskNotifyGiveFromISR(trigA_TaskHandle, &xHigherPriorityTaskWoken);
} break;
if (flag & SPARK_FLAG_A34) { case SPARK_FLAG_34:
ignA_status.spark12 = false; ignA_status.spark34 = true;
ignA_status.coils34.spark_time = time_us; ignA_status.coils34.spark_time = time_us;
xTaskNotifyGive(trigA_TaskHandle); vTaskNotifyGiveFromISR(trigA_TaskHandle, &xHigherPriorityTaskWoken);
break;
default:
break;
} }
//xTaskNotifyFromISR(trigA_TaskHandle, flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken); if (xHigherPriorityTaskWoken)
if (xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR(); portYIELD_FROM_ISR();
} }
}
// void IRAM_ATTR spark_a(void* arg)
// {
// BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// volatile const int64_t time_us = esp_timer_get_time();
// if (!trigA_TaskHandle)
// return;
// uint32_t flag = (uint32_t) arg;
// xTaskNotifyFromISR(trigA_TaskHandle, flag, eSetBits, &xHigherPriorityTaskWoken);
// portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
// }
#ifndef TEST
void IRAM_ATTR trig_isr_b()
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
volatile const int64_t time_us = esp_timer_get_time();
if (!trigB_TaskHandle)
return; // exit if task is not running
#ifndef TEST
uint32_t status = GPIO.status;
#else
uint32_t status = GPIO.status1.val;
#endif
uint32_t pickup_flags = 0;
while (status)
{
uint32_t pin = __builtin_ctz(status); // trova primo bit attivo
status &= ~(1 << pin); // clear bit
pickup_flags |= pin2trig[pin];
}
if (pickup_flags & TRIG_FLAG_B12P)
ignB_status.coils12.trig_time = time_us;
if (pickup_flags & TRIG_FLAG_B34P)
ignB_status.coils34.trig_time = time_us;
xTaskNotifyFromISR(trigB_TaskHandle, pickup_flags, eSetBits, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void IRAM_ATTR spark_b()
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
volatile const int64_t time_us = esp_timer_get_time();
if (!trigB_TaskHandle)
return;
uint32_t spark_flag = GPIO.status1.val & SPARK_B12 ? SPARK_FLAG_B12 : SPARK_FLAG_B34;
if (spark_flag & SPARK_FLAG_B12)
ignB_status.coils12.spark_time = time_us;
if (spark_flag & SPARK_FLAG_B34)
ignB_status.coils34.spark_time = time_us;
xTaskNotifyFromISR(trigB_TaskHandle, spark_flag, eSetBits, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
#endif

View File

@@ -1,5 +1,8 @@
#pragma once #pragma once
// Serial debug flag
// #define DEBUG
// Arduino Libraries // Arduino Libraries
#include <Arduino.h> #include <Arduino.h>
#include <DebugLog.h> #include <DebugLog.h>
@@ -13,87 +16,153 @@
// Global Variables and Flags // Global Variables and Flags
static bool rt_task_running = true; static bool rt_task_running = true;
const auto spark_timeout_max = 1000; // convert to microsecond timer const auto spark_timeout_max = 2; // in milliseconds
// RT task parameters // Debug Variables
struct rtTaskParams { #ifdef DEBUG
bool rt_running; static const std::map<const uint32_t, const char *> names = {
Devices *dev; {TRIG_FLAG_A12P, "TRIG_FLAG_A12P"},
{TRIG_FLAG_A12N, "TRIG_FLAG_A12N"},
{TRIG_FLAG_A34P, "TRIG_FLAG_A34P"},
{TRIG_FLAG_A34N, "TRIG_FLAG_A34N"},
{SPARK_FLAG_A12, "SPARK_FLAG_A12"},
{SPARK_FLAG_A34, "SPARK_FLAG_A34"},
};
#endif
// RT task Interrupt parameters
struct rtTaskInterrupts
{
void (*isr_ptr)(void *);
const uint8_t trig_pin_12p;
const uint8_t trig_pin_12n;
const uint8_t trig_pin_34p;
const uint8_t trig_pin_34n;
const uint8_t spark_pin_12;
const uint8_t spark_pin_34;
}; };
void ignitionA_task(void *pvParameters) { // RT Task Peak Detector Reset pins
struct rtTaskResets
{
const uint8_t rst_io_12p;
const uint8_t rst_io_12n;
const uint8_t rst_io_34p;
const uint8_t rst_io_34n;
};
if (!pvParameters) { // RT Task Adc channels
struct rtTaskAdChannels
{
const uint8_t adc_gen;
const uint8_t adc_spark_12;
const uint8_t adc_spark_34;
const uint8_t adc_peak_12p_in;
const uint8_t adc_peak_12n_in;
const uint8_t adc_peak_34p_in;
const uint8_t adc_peak_34n_in;
const uint8_t adc_peak_12p_out;
const uint8_t adc_peak_12n_out;
const uint8_t adc_peak_34p_out;
const uint8_t adc_peak_34n_out;
};
// RT task parameters
struct rtTaskParams
{
bool rt_running; // run flag, false to terminate
Devices *dev;
QueueHandle_t rt_queue;
const rtTaskInterrupts rt_int; // interrupt pins to attach
const rtTaskResets rt_resets; // reset ping for peak detectors
const rtTaskAdChannels rt_adcch; // adc channels
};
void ignitionA_task(void *pvParameters)
{
if (!pvParameters)
{
LOG_ERROR("Null task parameters"); LOG_ERROR("Null task parameters");
vTaskDelete(NULL); vTaskDelete(NULL);
} }
// Task Parameters and Devices // Task Parameters and Devices
rtTaskParams* params = (rtTaskParams*) pvParameters; const rtTaskParams *params = (const rtTaskParams *)pvParameters;
Devices* dev = (Devices*) params->dev; const rtTaskInterrupts rt_int = params->rt_int; // copy to avoid external override
const rtTaskResets rt_rst = params->rt_resets; // copy to avoid external override
const rtTaskAdChannels rt_adcch = params->rt_adcch; // copy to avoid external override
QueueHandle_t queue = params->rt_queue;
Devices *dev = params->dev;
ADS1256 *adc = dev->adc_a; ADS1256 *adc = dev->adc_a;
PCA9555 *io = dev->io;
// Ignition A Interrupts // Attach Pin Interrupts
attachInterruptArg(TRIG_A12P, trig_isr_a, (void*)TRIG_FLAG_A12P, RISING); attachInterruptArg(rt_int.trig_pin_12p, rt_int.isr_ptr, (void *)TRIG_FLAG_12P, RISING);
attachInterruptArg(TRIG_A12N, trig_isr_a, (void*)TRIG_FLAG_A12N, RISING); attachInterruptArg(rt_int.trig_pin_12n, rt_int.isr_ptr, (void *)TRIG_FLAG_12N, RISING);
attachInterruptArg(TRIG_A34P, trig_isr_a, (void*)TRIG_FLAG_A34P, RISING); attachInterruptArg(rt_int.trig_pin_34p, rt_int.isr_ptr, (void *)TRIG_FLAG_34P, RISING);
attachInterruptArg(TRIG_A34N, trig_isr_a, (void*)TRIG_FLAG_A34N, RISING); attachInterruptArg(rt_int.trig_pin_34n, rt_int.isr_ptr, (void *)TRIG_FLAG_34N, RISING);
attachInterruptArg(SPARK_A12, trig_isr_a, (void*)SPARK_FLAG_A12, RISING); attachInterruptArg(rt_int.spark_pin_12, rt_int.isr_ptr, (void *)SPARK_FLAG_12, RISING);
attachInterruptArg(SPARK_A34, trig_isr_a, (void*)SPARK_FLAG_A34, RISING); attachInterruptArg(rt_int.spark_pin_34, rt_int.isr_ptr, (void *)SPARK_FLAG_34, RISING);
// Compute Reset Pin Bitmask
const uint16_t rst_bitmask = (1 << rt_rst.rst_io_12p) |
(1 << rt_rst.rst_io_12n) |
(1 << rt_rst.rst_io_34p) |
(1 << rt_rst.rst_io_34n);
uint32_t it = 0; uint32_t it = 0;
while (rt_task_running) { uint32_t q_fail_count = 0;
while (rt_task_running)
{
// Global task variables // Global task variables
uint32_t pickup_flag = 0; uint32_t pickup_flag = 0;
uint32_t spark_flag = 0; uint32_t spark_flag = 0;
#ifdef DEBUG
Serial.print("\033[2J"); // clear screen
Serial.print("\033[H"); // cursor home
LOG_INFO("Iteration [", it, "]");
#endif
// WAIT FOR PICKUP SIGNAL // WAIT FOR PICKUP SIGNAL
xTaskNotifyWait( xTaskNotifyWait(
0x00, // non pulire all'ingresso 0x00, // non pulire all'ingresso
ULONG_MAX, // pulisci i primi 8 bit ULONG_MAX, // pulisci i primi 8 bit
&pickup_flag, // valore ricevuto &pickup_flag, // valore ricevuto
portMAX_DELAY portMAX_DELAY);
);
Serial.print("\033[2J"); // clear screen #ifdef DEBUG
Serial.print("\033[H"); // cursor home LOG_INFO("Pickup Flags: ", printBits(pickup_flag).c_str());
LOG_INFO("Iteration [", it, "]"); if (!names.contains(pickup_flag))
{
//LOG_INFO("Pickup Flags: ", printBits(pickup_flag).c_str());
if (!names.contains(pickup_flag)) {
LOG_ERROR("Wrong Pickup Flag"); LOG_ERROR("Wrong Pickup Flag");
continue; continue;
} else { }
else
{
LOG_INFO("Pickup Trigger: ", names.at(pickup_flag)); LOG_INFO("Pickup Trigger: ", names.at(pickup_flag));
} }
#endif
// WAIT FOR SPARK TO HAPPEN // WAIT FOR SPARK TO HAPPEN
auto spark_timeout = ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(5)); auto spark_timeout = ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(spark_timeout_max));
//auto spark_timeout = xTaskNotifyWait( if (ignA_status.spark12 || ignA_status.spark34) // otherwise timeout if none is set in the ISR
// 0x00, // non pulire all'ingresso spark_flag = ignA_status.spark12 ? SPARK_FLAG_12 : SPARK_FLAG_34;
// ULONG_MAX, // pulisci gli 8 bit successivi
// &spark_flag, // valore ricevuto
// spark_timeout_max
//);
digitalWrite(POT_A_CS, HIGH);
if (ignA_status.spark12 || ignA_status.spark34) { //otherwise timeout
//LOG_INFO("Spark Flags: ", printBits(spark_flag).c_str());
spark_flag = ignA_status.spark12 ? SPARK_FLAG_A12 : SPARK_FLAG_A34;
if (!names.contains(spark_flag)) {
LOG_ERROR("Wrong Spark Flag");
} else {
LOG_INFO("Spark Trigger:", names.at(spark_flag));
}
} else {
LOG_INFO("Spark Timeout");
}
xTaskNotifyStateClear(NULL); xTaskNotifyStateClear(NULL);
ulTaskNotifyValueClear(NULL, 0xFFFFFFFF); ulTaskNotifyValueClear(NULL, 0xFFFFFFFF);
#ifdef DEBUG
LOG_INFO("Spark Flags: ", printBits(spark_flag).c_str());
if (!names.contains(spark_flag))
LOG_ERROR("No Spark");
else
LOG_INFO("Spark Trigger:", names.at(spark_flag));
#endif
// A trigger from pickup 12 is followed by a spark event on 34 or vice versa pickup 34 triggers spark on 12 // A trigger from pickup 12 is followed by a spark event on 34 or vice versa pickup 34 triggers spark on 12
if ((pickup_flag == TRIG_FLAG_A12P || pickup_flag == TRIG_FLAG_A12N) && spark_flag != SPARK_FLAG_A12) { if ((pickup_flag == TRIG_FLAG_12P || pickup_flag == TRIG_FLAG_12N) && spark_flag != SPARK_FLAG_12)
{
ignA_status.coils12.spark_status = ignA_status.coils34.spark_status = sparkStatus::SPARK_SYNC_FAIL; ignA_status.coils12.spark_status = ignA_status.coils34.spark_status = sparkStatus::SPARK_SYNC_FAIL;
// Save error on circular buffer and skip to next cycle // // Save error on circular buffer and skip to next cycle //
LOG_ERROR("Spark Mismatch"); LOG_ERROR("Spark Mismatch");
@@ -103,64 +172,69 @@ void ignitionA_task(void *pvParameters) {
coilsStatus *c; coilsStatus *c;
switch (pickup_flag) switch (pickup_flag)
{ {
case TRIG_FLAG_A12P: case TRIG_FLAG_12P:
case TRIG_FLAG_A12N: case TRIG_FLAG_12N:
//case SPARK_FLAG_A12:
c = &ignA_status.coils12; c = &ignA_status.coils12;
break; break;
case TRIG_FLAG_A34P: case TRIG_FLAG_34P:
case TRIG_FLAG_A34N: case TRIG_FLAG_34N:
//case SPARK_FLAG_A34:
c = &ignA_status.coils34; c = &ignA_status.coils34;
break; break;
} }
bool new_data = false; bool new_data = false;
switch (pickup_flag)
switch (pickup_flag) { {
// CASES for NEGATIVE cycle triggering of pickup and sparks 12 & 34 // CASES for NEGATIVE cycle triggering of pickup and sparks 12 & 34
case TRIG_FLAG_A12P: case TRIG_FLAG_12P:
case TRIG_FLAG_A34P: case TRIG_FLAG_34P:
{ {
LOG_INFO("Trigger Pickup POSITIVE");
// Timeout not occourred, expected POSITIVE edge spark OCCOURRED // Timeout not occourred, expected POSITIVE edge spark OCCOURRED
if (spark_timeout == pdPASS) { if (spark_timeout == pdPASS)
{
c->spark_delay = c->spark_time - c->trig_time; c->spark_delay = c->spark_time - c->trig_time;
c->soft_start_status = softStartStatus::NORMAL; // because spark on positive edge c->sstart_status = softStartStatus::NORMAL; // because spark on positive edge
c->spark_status = sparkStatus::SPARK_POS_OK; // do not wait for spark on negative edge c->spark_status = sparkStatus::SPARK_POS_OK; // do not wait for spark on negative edge
#ifdef DEBUG
LOG_INFO("Trigger Spark POSITIVE"); LOG_INFO("Trigger Spark POSITIVE");
LOG_INFO("Spark12 Delay Timer: ", (int)c->spark_delay); LOG_INFO("Spark12 Delay Timer: ", (int)c->spark_delay);
#endif
} }
// Timeout occourred, expected POSITIVE edge spark NOT OCCOURRED // Timeout occourred, expected POSITIVE edge spark NOT OCCOURRED
else if (spark_timeout == pdFAIL) { else if (spark_timeout == pdFAIL)
{
c->spark_status = sparkStatus::SPARK_NEG_WAIT; c->spark_status = sparkStatus::SPARK_NEG_WAIT;
c->soft_start_status = softStartStatus::NORMAL; c->sstart_status = softStartStatus::NORMAL;
} }
new_data = false; new_data = false;
break; // Do nothing more on positive pulse break; // Do nothing more on positive pulse
} }
// CASES for NEGATIVE cycle triggering of pickup and sparks 12 & 34 // CASES for NEGATIVE cycle triggering of pickup and sparks 12 & 34
case TRIG_FLAG_A12N: case TRIG_FLAG_12N:
case TRIG_FLAG_A34N: case TRIG_FLAG_34N:
{ {
const bool expected_negative12 = c->spark_status == sparkStatus::SPARK_NEG_WAIT; const bool expected_negative12 = c->spark_status == sparkStatus::SPARK_NEG_WAIT;
LOG_INFO("Trigger Pickup NEGATIVE");
// Timeout not occourred, expected NEGATIVE edge spark OCCOURRED // Timeout not occourred, expected NEGATIVE edge spark OCCOURRED
if (spark_timeout == pdPASS && expected_negative12) { if (spark_timeout == pdPASS && expected_negative12)
{
c->spark_delay = c->spark_time - c->trig_time; c->spark_delay = c->spark_time - c->trig_time;
c->soft_start_status = softStartStatus::SOFT_START; c->sstart_status = softStartStatus::SOFT_START;
c->spark_status == sparkStatus::SPARK_NEG_OK; c->spark_status == sparkStatus::SPARK_NEG_OK;
#ifdef DEBUG
LOG_INFO("Trigger Spark NEGATIVE"); LOG_INFO("Trigger Spark NEGATIVE");
LOG_INFO("Spark12 Delay Timer: ", (int)ignA_status.coils12.spark_delay); LOG_INFO("Spark12 Delay Timer: ", (int)ignA_status.coils12.spark_delay);
#endif
} }
// Timeout occourred, expected POSITIVE edge spark NOT OCCOURRED // Timeout occourred, expected POSITIVE edge spark NOT OCCOURRED
else if (spark_timeout == pdFAIL && expected_negative12) { else if (spark_timeout == pdFAIL && expected_negative12)
c->soft_start_status = softStartStatus::NORMAL; {
c->sstart_status = softStartStatus::NORMAL;
c->spark_status = sparkStatus::SPARK_NEG_FAIL; c->spark_status = sparkStatus::SPARK_NEG_FAIL;
} }
// Timeout not occouured, unexpected negative edge spark // Timeout not occouured, unexpected negative edge spark
else if (spark_timeout == pdPASS && !expected_negative12) { else if (spark_timeout == pdPASS && !expected_negative12)
c->soft_start_status = softStartStatus::SOFT_START; {
c->sstart_status = softStartStatus::SOFT_START;
c->spark_status = sparkStatus::SPARK_NEG_UNEXPECTED; c->spark_status = sparkStatus::SPARK_NEG_UNEXPECTED;
} }
// Wait for finish of negative pulse to save data to buffer // Wait for finish of negative pulse to save data to buffer
@@ -168,84 +242,62 @@ void ignitionA_task(void *pvParameters) {
break; break;
} }
default: default:
LOG_ERROR("Invalid A Interrupt"); LOG_ERROR("Invalid Interrupt");
break; break;
} }
it++;
digitalWrite(POT_A_CS, LOW);
continue;
if (new_data) { if (new_data)
{
vTaskDelay(pdMS_TO_TICKS(1)); // delay 1ms to allow peak detectors to charge for negative cycle vTaskDelay(pdMS_TO_TICKS(1)); // delay 1ms to allow peak detectors to charge for negative cycle
// read adc channels: pickup12, out12 [ pos + neg ] // read adc channels: pickup12, out12 [ pos + neg ]
if (adc) // read only if adc initialized if (adc) // read only if adc initialized
{ {
ignA_status.coils12.pickup_volts = adcReadChannel(adc, ADC_A_DRDY, IN_A12_P); ignA_status.volts_gen = adcReadChannel(adc, rt_adcch.adc_gen);
ignA_status.coils12.output_volts = adcReadChannel(adc, ADC_A_DRDY, IN_A12_N); // from peak detector circuits
ignA_status.coils34.pickup_volts = adcReadChannel(adc, ADC_A_DRDY, IN_A34_P); ignA_status.coils12.peak_p_in = adcReadChannel(adc, rt_adcch.adc_peak_12p_in);
ignA_status.coils34.output_volts = adcReadChannel(adc, ADC_A_DRDY, IN_A34_N); ignA_status.coils12.peak_n_in = adcReadChannel(adc, rt_adcch.adc_peak_12n_in);
} else { ignA_status.coils34.peak_p_in = adcReadChannel(adc, rt_adcch.adc_peak_34p_in);
LOG_WARN("ADC not initialized, skipping conversion"); ignA_status.coils34.peak_n_in = adcReadChannel(adc, rt_adcch.adc_peak_34n_in);
} ignA_status.coils12.peak_p_out = adcReadChannel(adc, rt_adcch.adc_peak_12p_out);
// reset peak detectors -> gli output sono sull'expander, temporaneo uso il PC del pot non collegato ignA_status.coils12.peak_n_out = adcReadChannel(adc, rt_adcch.adc_peak_12n_out);
digitalWrite(POT_A_CS, HIGH); ignA_status.coils34.peak_p_out = adcReadChannel(adc, rt_adcch.adc_peak_34p_out);
// digitalWrite(RST_A12P, HIGH); ignA_status.coils34.peak_n_out = adcReadChannel(adc, rt_adcch.adc_peak_34n_out);
// digitalWrite(RST_A12N, HIGH); // from sample and hold triggered from spark interrupt
// digitalWrite(RST_A34P, HIGH); ignA_status.coils12.trigger_spark = adcReadChannel(adc, rt_adcch.adc_spark_12);
// digitalWrite(RST_A34N, HIGH); ignA_status.coils34.trigger_spark = adcReadChannel(adc, rt_adcch.adc_spark_34);
vTaskDelay(1);
digitalWrite(POT_A_CS, HIGH);
// digitalWrite(RST_A12P, LOW);
// digitalWrite(RST_A12N, LOW);
// digitalWrite(RST_A34P, LOW);
// digitalWrite(RST_A34N, LOW);
// save on circluar buffer 12
} }
else // simulate adc read timig
vTaskDelay(pdMS_TO_TICKS(6));
// reset peak detectors + sample and hold
// outputs on io expander
if (io)
{
const uint16_t iostat = io->read();
io->write(iostat | rst_bitmask);
vTaskDelay(pdMS_TO_TICKS(1));
io->write(iostat & ~rst_bitmask);
}
else
vTaskDelay(pdMS_TO_TICKS(2));
// send essage to main loop with ignition info
if (queue)
ignA_status.timestamp = esp_timer_get_time(); // update data timestamp
if (xQueueSendToBack(queue, (void*)&ignA_status, pdMS_TO_TICKS(1)) != pdPASS) {
q_fail_count++;
LOG_ERROR("Failed to send to queue");
}
}
} }
LOG_WARN("Ending realTime Task"); LOG_WARN("Ending realTime Task");
// Ignition A Interrupts DETACH // Ignition A Interrupts DETACH
detachInterrupt(TRIG_A12P); detachInterrupt(rt_int.trig_pin_12p);
detachInterrupt(TRIG_A12N); detachInterrupt(rt_int.trig_pin_12n);
detachInterrupt(TRIG_A34P); detachInterrupt(rt_int.trig_pin_34p);
detachInterrupt(TRIG_A34N); detachInterrupt(rt_int.trig_pin_34n);
detachInterrupt(SPARK_A12); detachInterrupt(rt_int.spark_pin_12);
detachInterrupt(SPARK_A34); detachInterrupt(rt_int.spark_pin_34);
// delete present task // delete present task
vTaskDelete(NULL); vTaskDelete(NULL);
} }
#ifndef TEST
void ignitionB_task(void *pvParameters) {
uint32_t notifiedValue;
// Ignition B Interrupts
attachInterrupt(TRIG_B12P, trig_isr_b, RISING);
attachInterrupt(TRIG_B34P, trig_isr_b, RISING);
attachInterrupt(TRIG_B12N, trig_isr_b, RISING);
attachInterrupt(TRIG_B34N, trig_isr_b, RISING);
attachInterrupt(SPARK_B12, spark_b, RISING);
attachInterrupt(SPARK_B34, spark_b, RISING);
while (true) {
// attende eventi
xTaskNotifyWait(
0x00, // non pulire all'ingresso
0xFFFFFFFF, // pulisci tutti i bit all'uscita
&notifiedValue, // valore ricevuto
portMAX_DELAY
);
switch (notifiedValue) {
case TRIG_FLAG_B12P:
break;
case TRIG_FLAG_B34P:
break;
case TRIG_FLAG_B12N:
break;
case TRIG_FLAG_B34N:
break;
default:
LOG_ERROR("Invalid B Interrupt: ", notifiedValue);
}
}
}
#endif