diff --git a/RotaxMonitor/src/isr.h b/RotaxMonitor/src/isr.h index 8a9b77a..a034a75 100644 --- a/RotaxMonitor/src/isr.h +++ b/RotaxMonitor/src/isr.h @@ -1,13 +1,16 @@ +#pragma once + #include #include "soc/gpio_struct.h" #include "pins.h" - #define CORE_0 0 #define CORE_1 1 #define TASK_STACK 4096 // in words #define TASK_PRIORITY 2 // priorità leggermente più alta +#define IGN_BUF_SIZE 128 + // ===================== // Event Flags (bitmask) // ===================== @@ -20,41 +23,82 @@ #define TRIG_FLAG_B34P (1 << 5) #define TRIG_FLAG_B34N (1 << 7) +#define SPARK_FLAG_A12 (1 << 0) +#define SPARK_FLAG_A34 (1 << 2) +#define SPARK_FLAG_B12 (1 << 1) +#define SPARK_FLAG_B34 (1 << 3) + // Task handle TaskHandle_t trigA_TaskHandle = NULL; TaskHandle_t trigB_TaskHandle = NULL; -// Task internal Status -struct taskStatus { - int64_t trig12_start; - int64_t trig34_start; - - int64_t trig12_time; - int64_t trig34_time; - - bool trig12_complete = false; - bool trig34_complete = false; - - bool soft12 = false; - bool soft34 = false; - - bool error12 = false; - bool error34 = false; +// Spark Status +enum sparkStatus { + SPARK_POS_OK, + SPARK_NEG_OK, + SPARK_POS_SKIP, + SPARK_NEG_SKIP, + SPARK_POS_WAIT, + SPARK_NEG_WAIT, + SPARK_POS_FAIL, + SPARK_NEG_FAIL, + SPARK_POS_UNEXPECTED, + SPARK_NEG_UNEXPECTED, + SPARK_SYNC_FAIL, }; -taskStatus ignA_status; -taskStatus ignB_status; +// Task internal Status +struct ignitionBoxStatus { + // start time from ISR + int64_t trig12_start; + int64_t trig34_start; + // time at which spark occours + int64_t trig12_end; + int64_t trig34_end; + // computed delay from pickup to spark + int64_t spark12_delay; + int64_t spark34_delay; + // spark status + sparkStatus spark12_status = sparkStatus::SPARK_POS_OK; + sparkStatus spark34_status = sparkStatus::SPARK_POS_OK; + // soft start status for circuits 12 and 34 + bool soft12_engaged = false; + bool soft34_engaged = false; + // peak voltage from circuits 12 and 34 + float volts12_pickup; + float volts34_pickup; + // peak voltage from conditioned output 12 and 34 + float volts12_out; + float volts34_out; + // voltage from generator + float volts_gen; +}; + +ignitionBoxStatus ignA_status; +ignitionBoxStatus ignB_status; + +ignitionBoxStatus ingA_statusBuffer[IGN_BUF_SIZE]; +ignitionBoxStatus ingB_statusBuffer[IGN_BUF_SIZE]; // Pin to flag Map -static const uint32_t int2flag[] = { - [TRIG_A12P] = TRIG_FLAG_A12P, - [TRIG_A12N] = TRIG_FLAG_A34P, - [TRIG_A34P] = TRIG_FLAG_A12N, - [TRIG_A34N] = TRIG_FLAG_A34N, - [TRIG_B12P] = TRIG_FLAG_B12P, - [TRIG_B12N] = TRIG_FLAG_B34P, - [TRIG_B34P] = TRIG_FLAG_B12N, - [TRIG_B34N] = TRIG_FLAG_B34N, +static uint32_t pin2trig[49]; +void initTriggerPinMapping() { + pin2trig[TRIG_A12P] = TRIG_FLAG_A12P; + pin2trig[TRIG_A12N] = TRIG_FLAG_A12N; + pin2trig[TRIG_A34P] = TRIG_FLAG_A34P; + pin2trig[TRIG_A34N] = TRIG_FLAG_A34N; + pin2trig[TRIG_B12P] = TRIG_FLAG_B12P; + pin2trig[TRIG_B12N] = TRIG_FLAG_B12N; + pin2trig[TRIG_B34P] = TRIG_FLAG_B34P; + pin2trig[TRIG_B34N] = TRIG_FLAG_B34N; +}; + +static uint32_t pin2spark[49]; +void initSparkPinMapping() { + pin2spark[SPARK_A12] = SPARK_FLAG_A12; + pin2spark[SPARK_A34] = SPARK_FLAG_A34; + pin2spark[SPARK_B12] = SPARK_FLAG_B12; + pin2spark[SPARK_B34] = SPARK_FLAG_B34; }; // ===================== @@ -72,7 +116,7 @@ void IRAM_ATTR trig_isr_a() { uint32_t pin = __builtin_ctz(status); // trova primo bit attivo status &= ~(1 << pin); // clear bit - flags |= int2flag[pin]; + flags |= pin2trig[pin]; } if (flags & (TRIG_FLAG_A12P | TRIG_FLAG_A12N)) @@ -86,17 +130,26 @@ void IRAM_ATTR trig_isr_a() { } } +void IRAM_ATTR spark_a() { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + uint32_t spark_flag = GPIO.status1.val & SPARK_A12 ? SPARK_FLAG_A12 : SPARK_FLAG_A34 ; + if (trigA_TaskHandle) { + xTaskNotifyFromISR(trigA_TaskHandle, spark_flag, eSetBits, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + } +} + void IRAM_ATTR trig_isr_b() { BaseType_t xHigherPriorityTaskWoken = pdFALSE; - uint32_t status = GPIO.status; + uint32_t status = GPIO.status1.val; uint32_t flags = 0; while (status) { uint32_t pin = __builtin_ctz(status); // trova primo bit attivo status &= ~(1 << pin); // clear bit - flags |= int2flag[pin]; + flags |= pin2trig[pin]; } if (trigB_TaskHandle) { @@ -104,3 +157,12 @@ void IRAM_ATTR trig_isr_b() { portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } + +void IRAM_ATTR spark_b() { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + uint32_t spark_flag = GPIO.status1.val & SPARK_B12 ? SPARK_FLAG_B12 : SPARK_FLAG_B34 ; + if (trigB_TaskHandle) { + xTaskNotifyFromISR(trigB_TaskHandle, spark_flag, eSetBits, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + } +} diff --git a/RotaxMonitor/src/main.cpp b/RotaxMonitor/src/main.cpp index cecd668..1204614 100644 --- a/RotaxMonitor/src/main.cpp +++ b/RotaxMonitor/src/main.cpp @@ -7,7 +7,6 @@ #include // Definitions -#include #include #include #include @@ -31,7 +30,7 @@ void setup() { LOG_INFO("ESP32 Heap:", ESP.getHeapSize()); LOG_INFO("ESP32 Sketch:", ESP.getFreeSketchSpace()); - // Initialize Interrupt pins on peak detectors + // Initialize Interrupt pins on coil detectors pinMode(TRIG_A12P, INPUT_PULLDOWN); pinMode(TRIG_A12N, INPUT_PULLDOWN); pinMode(TRIG_A34P, INPUT_PULLDOWN); @@ -40,17 +39,29 @@ void setup() { pinMode(TRIG_B12N, INPUT_PULLDOWN); pinMode(TRIG_B34P, INPUT_PULLDOWN); pinMode(TRIG_B34N, INPUT_PULLDOWN); + initTriggerPinMapping(); + + // Initialize Interrupt pins on spark detectors + pinMode(SPARK_A12, INPUT_PULLDOWN); + pinMode(SPARK_A34, INPUT_PULLDOWN); + pinMode(SPARK_B12, INPUT_PULLDOWN); + pinMode(SPARK_B34, INPUT_PULLDOWN); + initSparkPinMapping(); // Ignition A Interrupts attachInterrupt(TRIG_A12P, trig_isr_a, RISING); attachInterrupt(TRIG_A34P, trig_isr_a, RISING); attachInterrupt(TRIG_A12N, trig_isr_a, RISING); attachInterrupt(TRIG_A34N, trig_isr_a, RISING); + attachInterrupt(SPARK_A12, spark_a, RISING); + attachInterrupt(SPARK_A34, spark_a, RISING); // 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); // Init SPI interface SPI.begin(); diff --git a/RotaxMonitor/src/pins.h b/RotaxMonitor/src/pins.h index 30e5491..b558dec 100644 --- a/RotaxMonitor/src/pins.h +++ b/RotaxMonitor/src/pins.h @@ -1,3 +1,5 @@ +#pragma once + // ===================== // SPI BUS // ===================== diff --git a/RotaxMonitor/src/tasks.h b/RotaxMonitor/src/tasks.h index 52454b6..4b8ac7c 100644 --- a/RotaxMonitor/src/tasks.h +++ b/RotaxMonitor/src/tasks.h @@ -1,3 +1,5 @@ +#pragma once + // Arduino Libraries #include #include @@ -5,67 +7,91 @@ // ISR #include "isr.h" -const uint16_t spark_delay_us = 500; +const auto spark_timeout_max = 1; void ignitionA_task(void *pvParameters) { - uint32_t notifiedValue; + uint32_t pickup_flag; + uint32_t spark_flag; while (true) { - // attende eventi + // WAIT FOR PICKUP SIGNAL xTaskNotifyWait( 0x00, // non pulire all'ingresso ULONG_MAX, // pulisci tutti i bit all'uscita - ¬ifiedValue, // valore ricevuto + &pickup_flag, // valore ricevuto portMAX_DELAY ); - - uint64_t wait_time=0; - switch (notifiedValue) { - case TRIG_FLAG_A12P: - case TRIG_FLAG_A12N: - bool spark12_timeout = false; - if (ignA_status.trig12_complete) { - // read peak adc values from sample and hold - } else { - while(!digitalRead(SPARK_A12)) { - wait_time = ignA_status.trig12_start - esp_timer_get_time(); - if (wait_time >= spark_delay_us) { - spark12_timeout = true; - break; - } - } - if (spark12_timeout) { // spark did not happen, timeout - ignA_status.trig12_complete = false; - } else { // spark did happen - ignA_status.trig12_complete = true; - ignA_status.trig12_time = wait_time; - } + // WAIT FOR SPARK TO HAPPEN + auto spark_timeout = xTaskNotifyWait( + 0x00, // non pulire all'ingresso + ULONG_MAX, // pulisci tutti i bit all'uscita + &spark_flag, // valore ricevuto + spark_timeout_max + ); + // Save current time to compute delay from pickup to spark + auto curr_time = esp_timer_get_time(); + + // 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_A12) { + ignA_status.trig12_start = ignA_status.trig34_start = -1; + ignA_status.trig12_end = ignA_status.trig34_end = -1; + ignA_status.spark12_delay = ignA_status.spark34_delay = -1; + ignA_status.soft12_engaged = ignA_status.soft34_engaged = false; + ignA_status.spark12_status = ignA_status.spark12_status = sparkStatus::SPARK_SYNC_FAIL; + // Save error on circular buffer and skip to next cycle // + // [TODO] + continue; + } + + switch (pickup_flag) { + case TRIG_FLAG_A12P: { + // Timeout not occourred, expected POSITIVE edge spark OCCOURRED + if (spark_timeout == pdPASS) { + ignA_status.trig12_end = curr_time; + ignA_status.spark12_delay = ignA_status.trig12_end - ignA_status.trig12_end; + ignA_status.soft12_engaged = false; // because spark on positive edge + ignA_status.spark12_status = sparkStatus::SPARK_POS_OK; // do not wait for spark on negative edge + } + // Timeout occourred, expected POSITIVE edge spark NOT OCCOURRED + else if (spark_timeout == pdFAIL) { + ignA_status.spark12_status = sparkStatus::SPARK_NEG_WAIT; + ignA_status.soft12_engaged = false; } + // Do nothing more on positive pulse break; + } + case TRIG_FLAG_A12N: { + bool expected_negative12 = ignA_status.spark12_status == sparkStatus::SPARK_NEG_WAIT; + // Timeout not occourred, expected NEGATIVE edge spark OCCOURRED + if (spark_timeout == pdPASS && expected_negative12) { + ignA_status.trig12_end = curr_time; + ignA_status.spark12_delay = ignA_status.trig12_end - ignA_status.trig12_end; + ignA_status.soft12_engaged = true; + ignA_status.spark12_status == sparkStatus::SPARK_NEG_OK; + } + // Timeout occourred, expected POSITIVE edge spark NOT OCCOURRED + else if (spark_timeout == pdFAIL && expected_negative12) { + ignA_status.trig12_start = 0; + ignA_status.trig12_end = 0; + ignA_status.soft12_engaged = false; + ignA_status.spark12_status = sparkStatus::SPARK_NEG_FAIL; + } + // Timeout not occouured, unexpected negative edge spark + else if (spark_timeout == pdPASS && !expected_negative12) { + ignA_status.soft12_engaged = true; + ignA_status.spark12_status = sparkStatus::SPARK_NEG_UNEXPECTED; + } + + // Save status on circular buffer + + break; + } case TRIG_FLAG_A34P: case TRIG_FLAG_A34N: - bool spark34_timeout = false; - if (ignA_status.trig12_complete) { - // read peak adc values from sample and hold - } else { - while(!digitalRead(SPARK_A34)) { - wait_time = ignA_status.trig34_start - esp_timer_get_time(); - if (wait_time >= spark_delay_us) { - spark12_timeout = true; - break; - } - } - if (spark34_timeout) { // spark did not happen, timeout - ignA_status.trig34_complete = false; - } else { // spark did happen - ignA_status.trig34_complete = true; - ignA_status.trig34_time = wait_time; - } - } break; default: - LOG_ERROR("Invalid A Interrupt: ", notifiedValue); + LOG_ERROR("Invalid A Interrupt"); } }