Compare commits
15 Commits
a210d808da
...
debug
| Author | SHA1 | Date | |
|---|---|---|---|
| c5d80052e5 | |||
| 38c595fd7b | |||
| b0842aadef | |||
| 0dc5d1ce79 | |||
|
|
941a2b4eaa | ||
|
|
48df6a509d | ||
|
|
ebff6281af | ||
|
|
d7e0990e36 | ||
|
|
21e50bdca8 | ||
|
|
6072a603df | ||
|
|
27ad612844 | ||
|
|
ec138553ad | ||
|
|
1adbf7fdb9 | ||
|
|
e0af350b89 | ||
|
|
b75014854d |
4
RotaxMonitor/.vscode/extensions.json
vendored
4
RotaxMonitor/.vscode/extensions.json
vendored
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
|
||||||
// for the documentation about the extensions.json format
|
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
|
"Jason2866.esp-decoder",
|
||||||
|
"pioarduino.pioarduino-ide",
|
||||||
"platformio.platformio-ide"
|
"platformio.platformio-ide"
|
||||||
],
|
],
|
||||||
"unwantedRecommendations": [
|
"unwantedRecommendations": [
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
"-DARDUINO_RUNNING_CORE=1",
|
"-DARDUINO_RUNNING_CORE=1",
|
||||||
"-DARDUINO_EVENT_RUNNING_CORE=1",
|
"-DARDUINO_EVENT_RUNNING_CORE=1",
|
||||||
"-DBOARD_HAS_PSRAM",
|
"-DBOARD_HAS_PSRAM",
|
||||||
"-DARDUINO_USB_MODE=1",
|
"-DARDUINO_USB_MODE=0",
|
||||||
"-DARDUINO_USB_CDC_ON_BOOT=0"
|
"-DARDUINO_USB_CDC_ON_BOOT=1"
|
||||||
],
|
],
|
||||||
"f_cpu": "240000000L",
|
"f_cpu": "240000000L",
|
||||||
"f_flash": "80000000L",
|
"f_flash": "80000000L",
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
; Please visit documentation for the other options and examples
|
; Please visit documentation for the other options and examples
|
||||||
; https://docs.platformio.org/page/projectconf.html
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
[env:esp32-s3-n16r8]
|
[env:esp32-s3-devkitc1-n16r8]
|
||||||
board = esp32-s3-n16r8
|
board = esp32-s3-devkitc1-n16r8
|
||||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.37/platform-espressif32.zip
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/stable/platform-espressif32.zip
|
||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps =
|
lib_deps =
|
||||||
hideakitai/DebugLog@^0.8.4
|
hideakitai/DebugLog@^0.8.4
|
||||||
@@ -18,51 +18,51 @@ lib_deps =
|
|||||||
hideakitai/PCA95x5@^0.1.3
|
hideakitai/PCA95x5@^0.1.3
|
||||||
adafruit/Adafruit SSD1306@^2.5.16
|
adafruit/Adafruit SSD1306@^2.5.16
|
||||||
garfius/Menu-UI@^1.2.0
|
garfius/Menu-UI@^1.2.0
|
||||||
board_build.partitions = partitions/default_16MB.csv
|
|
||||||
board_build.psram = enabled
|
;Upload protocol configuration
|
||||||
monitor_speed = 115200
|
upload_protocol = esptool
|
||||||
|
upload_port = /dev/ttyACM2
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
|
|
||||||
|
;Monitor configuration
|
||||||
|
monitor_speed = 115200
|
||||||
|
monitor_port = /dev/ttyACM2
|
||||||
|
|
||||||
|
; Build configuration
|
||||||
build_type = release
|
build_type = release
|
||||||
|
build_flags =
|
||||||
|
-DARDUINO_USB_CDC_ON_BOOT=0
|
||||||
|
-DARDUINO_USB_MODE=0
|
||||||
|
-fstack-protector-all
|
||||||
|
-DCONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=1
|
||||||
|
-DCONFIG_FREERTOS_USE_TRACE_FACILITY=1
|
||||||
|
|
||||||
[env:esp32-s3-n16r8-debug]
|
[env:esp32-s3-devkitc1-n16r8-debug]
|
||||||
board = ${env:esp32-s3-n16r8.board}
|
board = ${env:esp32-s3-devkitc1-n16r8.board}
|
||||||
platform = ${env:esp32-s3-n16r8.platform}
|
platform = ${env:esp32-s3-devkitc1-n16r8.platform}
|
||||||
framework = ${env:esp32-s3-n16r8.framework}
|
framework = ${env:esp32-s3-devkitc1-n16r8.framework}
|
||||||
lib_deps = ${env:esp32-s3-n16r8.lib_deps}
|
lib_deps = ${env:esp32-s3-devkitc1-n16r8.lib_deps}
|
||||||
board_build.partitions = partitions/default_16MB.csv
|
|
||||||
board_build.psram = enabled
|
;Upload protocol configuration
|
||||||
monitor_speed = 115200
|
upload_protocol = esptool
|
||||||
|
upload_port = /dev/ttyACM2
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
build_type = debug
|
|
||||||
build_flags =
|
|
||||||
-O0
|
|
||||||
-g3
|
|
||||||
-ggdb
|
|
||||||
-fno-inline
|
|
||||||
-fno-ipa-sra
|
|
||||||
-fno-tree-sra
|
|
||||||
-fno-builtin
|
|
||||||
|
|
||||||
|
;Monitor configuration
|
||||||
[env:esp32-devtest-debug]
|
|
||||||
board = esp32dev
|
|
||||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.37/platform-espressif32.zip
|
|
||||||
framework = arduino
|
|
||||||
lib_deps =
|
|
||||||
hideakitai/DebugLog@^0.8.4
|
|
||||||
bblanchon/ArduinoJson@^7.4.2
|
|
||||||
hideakitai/PCA95x5@^0.1.3
|
|
||||||
adafruit/Adafruit SSD1306@^2.5.16
|
|
||||||
garfius/Menu-UI@^1.2.0
|
|
||||||
board_build.flash_size = 4MB
|
|
||||||
board_build.partitions = default.csv
|
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
|
monitor_port = /dev/ttyACM2
|
||||||
|
|
||||||
|
; Debug configuration
|
||||||
|
debug_tool = esp-builtin
|
||||||
|
debug_speed = 15000
|
||||||
|
|
||||||
|
; Build configuration
|
||||||
build_type = debug
|
build_type = debug
|
||||||
build_flags =
|
build_flags =
|
||||||
-O0
|
-O0
|
||||||
-g3
|
-g3
|
||||||
-ggdb
|
-ggdb3
|
||||||
-fno-inline
|
-DCORE_DEBUG_LEVEL=5
|
||||||
-fno-ipa-sra
|
-DARDUINO_USB_CDC_ON_BOOT=0
|
||||||
-fno-tree-sra
|
-DARDUINO_USB_MODE=0
|
||||||
-fno-builtin
|
-fstack-protector-all
|
||||||
|
|||||||
@@ -6,26 +6,17 @@
|
|||||||
#include <Adafruit_SSD1306.h>
|
#include <Adafruit_SSD1306.h>
|
||||||
#include <PCA95x5.h>
|
#include <PCA95x5.h>
|
||||||
|
|
||||||
// ADC Channel mapping Ignition A
|
// ADC Channel mapping
|
||||||
#define IN_A12_P SING_0
|
#define ADC_CH_PEAK_12P_IN SING_0
|
||||||
#define IN_A12_N SING_1
|
#define ADC_CH_PEAK_12N_IN SING_1
|
||||||
#define IN_A34_P SING_2
|
#define ADC_CH_PEAK_34P_IN SING_2
|
||||||
#define IN_A34_N SING_3
|
#define ADC_CH_PEAK_34N_IN SING_3
|
||||||
#define OUT_A12_P SING_4
|
#define ADC_CH_PEAK_12P_OUT SING_4
|
||||||
#define OUT_A12_N SING_5
|
#define ADC_CH_PEAK_12N_OUT SING_5
|
||||||
#define OUT_A34_P SING_6
|
#define ADC_CH_PEAK_34P_OUT SING_6
|
||||||
#define OUT_A34_N SING_7
|
#define ADC_CH_PEAK_34N_OUT SING_7
|
||||||
|
|
||||||
// ADC Channel mapping Ignition B
|
|
||||||
#define IN_A12_P SING_0
|
|
||||||
#define IN_A12_N SING_1
|
|
||||||
#define IN_A34_P SING_2
|
|
||||||
#define IN_A34_N SING_3
|
|
||||||
#define OUT_A12_P SING_4
|
|
||||||
#define OUT_A12_N SING_5
|
|
||||||
#define OUT_A34_P SING_6
|
|
||||||
#define OUT_A34_N SING_7
|
|
||||||
|
|
||||||
|
// Device Pointer structs for tasks
|
||||||
struct Devices {
|
struct Devices {
|
||||||
AD5292 *pot_a = NULL, *pot_b = NULL;
|
AD5292 *pot_a = NULL, *pot_b = NULL;
|
||||||
ADS1256 *adc_a = NULL, *adc_b = NULL;
|
ADS1256 *adc_a = NULL, *adc_b = NULL;
|
||||||
@@ -33,14 +24,13 @@ struct Devices {
|
|||||||
PCA9555* io = NULL;
|
PCA9555* io = NULL;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline float adcReadChannel(ADS1256* adc, const uint32_t drdy_pin, const uint32_t ch){
|
// Adc read channel wrapper to selet mux before reading
|
||||||
|
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());
|
||||||
}
|
}
|
||||||
|
|||||||
58
RotaxMonitor/src/isr.cpp
Normal file
58
RotaxMonitor/src/isr.cpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#include "isr.h"
|
||||||
|
|
||||||
|
// =====================
|
||||||
|
// ISR (Pass return bitmask to ISR management function)
|
||||||
|
// one function for each wake up pin conncted to a trigger
|
||||||
|
// =====================
|
||||||
|
void trig_isr(void *arg)
|
||||||
|
{
|
||||||
|
const int64_t time_us = esp_timer_get_time();
|
||||||
|
|
||||||
|
// exit if invalid args
|
||||||
|
if (!arg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
isrParams *params = (isrParams *)arg;
|
||||||
|
ignitionBoxStatus *box = params->ign_stat;
|
||||||
|
TaskHandle_t task_handle = params->rt_handle_ptr;
|
||||||
|
|
||||||
|
// exit if task not running
|
||||||
|
if (!task_handle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (params->flag)
|
||||||
|
{
|
||||||
|
case TRIG_FLAG_12P:
|
||||||
|
case TRIG_FLAG_12N:
|
||||||
|
// only on first trigger to avoid multiple firing due to noise, to be fixed with hardware debounce
|
||||||
|
box->coils12.trig_time = time_us;
|
||||||
|
xTaskNotifyFromISR(task_handle, params->flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
break;
|
||||||
|
case TRIG_FLAG_34P:
|
||||||
|
case TRIG_FLAG_34N:
|
||||||
|
// only on first trigger to avoid multiple firing due to noise, to be fixed with hardware debounce
|
||||||
|
box->coils34.trig_time = time_us;
|
||||||
|
xTaskNotifyFromISR(task_handle, params->flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
break;
|
||||||
|
case SPARK_FLAG_12:
|
||||||
|
box->coils34.spark_ok = false;
|
||||||
|
box->coils12.spark_ok = true;
|
||||||
|
box->coils12.spark_time = time_us;
|
||||||
|
xTaskNotifyFromISR(task_handle, params->flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
// vTaskNotifyGiveFromISR(task_handle, &xHigherPriorityTaskWoken);
|
||||||
|
break;
|
||||||
|
case SPARK_FLAG_34:
|
||||||
|
box->coils12.spark_ok = false;
|
||||||
|
box->coils34.spark_ok = true;
|
||||||
|
box->coils34.spark_time = time_us;
|
||||||
|
xTaskNotifyFromISR(task_handle, params->flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
// vTaskNotifyGiveFromISR(task_handle, &xHigherPriorityTaskWoken);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xHigherPriorityTaskWoken)
|
||||||
|
portYIELD_FROM_ISR();
|
||||||
|
}
|
||||||
@@ -1,54 +1,35 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define TEST
|
// Test device Flag
|
||||||
|
// #define TEST
|
||||||
|
|
||||||
|
// Arduino Libraries
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <map>
|
|
||||||
#include "soc/gpio_struct.h"
|
#include "soc/gpio_struct.h"
|
||||||
|
#include <map>
|
||||||
#ifndef TEST
|
#ifndef TEST
|
||||||
#include "pins.h"
|
#include "pins.h"
|
||||||
#else
|
#else
|
||||||
#include "pins_test.h"
|
#include "pins_test.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#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)
|
static const uint32_t TRIG_FLAG_12P = (1 << 0);
|
||||||
#define TRIG_FLAG_A12N (1 << 2)
|
static const uint32_t TRIG_FLAG_12N = (1 << 1);
|
||||||
#define TRIG_FLAG_A34P (1 << 1)
|
static const uint32_t TRIG_FLAG_34P = (1 << 2);
|
||||||
#define TRIG_FLAG_A34N (1 << 3)
|
static const uint32_t 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)
|
static const uint32_t SPARK_FLAG_NIL = (1 << 8);
|
||||||
#define SPARK_FLAG_A34 (1 << 9)
|
static const uint32_t SPARK_FLAG_12 = (1 << 9);
|
||||||
#ifndef TEST
|
static const uint32_t SPARK_FLAG_34 = (1 << 10);
|
||||||
#define SPARK_FLAG_B12 (1 << 10)
|
static const uint32_t SPARK_FLAG_TIMEOUT = (1 << 11);
|
||||||
#define SPARK_FLAG_B34 (1 << 11)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const std::map<const uint32_t, const char*> names = {
|
|
||||||
{TRIG_FLAG_A12P, "TRIG_A12P"},
|
|
||||||
{TRIG_FLAG_A12N, "TRIG_A12N"},
|
|
||||||
{TRIG_FLAG_A34P, "TRIG_A34P"},
|
|
||||||
{TRIG_FLAG_A34N, "TRIG_A34N"},
|
|
||||||
{SPARK_FLAG_A12, "SPARK_A12"},
|
|
||||||
{SPARK_FLAG_A34, "SPARK_A34"},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Task handle
|
|
||||||
TaskHandle_t trigA_TaskHandle = NULL;
|
|
||||||
TaskHandle_t trigB_TaskHandle = NULL;
|
|
||||||
|
|
||||||
// Spark Status
|
// Spark Status
|
||||||
enum sparkStatus
|
enum sparkStatus
|
||||||
@@ -66,160 +47,65 @@ enum sparkStatus
|
|||||||
SPARK_SYNC_FAIL,
|
SPARK_SYNC_FAIL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const std::map<const sparkStatus, const char *> sparkStatusNames = {
|
||||||
|
{SPARK_POS_OK, "SPARK_POS_OK"},
|
||||||
|
{SPARK_NEG_OK, "SPARK_NEG_OK"},
|
||||||
|
{SPARK_POS_SKIP, "SPARK_POS_SKIP"},
|
||||||
|
{SPARK_NEG_SKIP, "SPARK_NEG_SKIP"},
|
||||||
|
{SPARK_POS_WAIT, "SPARK_POS_WAIT"},
|
||||||
|
{SPARK_NEG_WAIT, "SPARK_NEG_WAIT"},
|
||||||
|
{SPARK_POS_FAIL, "SPARK_POS_FAIL"},
|
||||||
|
{SPARK_NEG_FAIL, "SPARK_NEG_FAIL"},
|
||||||
|
{SPARK_POS_UNEXPECTED, "SPARK_POS_UNEXPECTED"},
|
||||||
|
{SPARK_NEG_UNEXPECTED, "SPARK_NEG_UNEXPECTED"},
|
||||||
|
{SPARK_SYNC_FAIL, "SPARK_SYNC_FAIL"},
|
||||||
|
};
|
||||||
|
|
||||||
enum softStartStatus
|
enum softStartStatus
|
||||||
{
|
{
|
||||||
|
NORMAL,
|
||||||
SOFT_START,
|
SOFT_START,
|
||||||
NORMAL
|
ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::map<const softStartStatus, const char *> softStartStatusNames = {
|
||||||
|
{NORMAL, "NORMAL"},
|
||||||
|
{SOFT_START, "SOFT_START"},
|
||||||
|
{ERROR, "ERROR"},
|
||||||
};
|
};
|
||||||
|
|
||||||
struct coilsStatus
|
struct coilsStatus
|
||||||
{
|
{
|
||||||
int64_t trig_time;
|
int64_t trig_time = 0;
|
||||||
int64_t spark_time;
|
int64_t spark_time = 0;
|
||||||
int64_t spark_delay;
|
int64_t spark_delay = 0; // in microseconds
|
||||||
sparkStatus spark_status;
|
sparkStatus spark_status = sparkStatus::SPARK_POS_OK;
|
||||||
softStartStatus soft_start_status;
|
softStartStatus sstart_status = softStartStatus::NORMAL;
|
||||||
float pickup_volts;
|
float peak_p_in = 0.0, peak_n_in = 0.0;
|
||||||
float output_volts;
|
float peak_p_out = 0.0, peak_n_out = 0.0;
|
||||||
|
float trigger_spark = 0.0;
|
||||||
|
bool spark_ok = false;
|
||||||
|
uint32_t n_events = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Task internal Status
|
// Task internal Status
|
||||||
struct ignitionBoxStatus
|
struct ignitionBoxStatus
|
||||||
{
|
{
|
||||||
|
int64_t timestamp = 0;
|
||||||
// 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;
|
||||||
|
uint32_t n_queue_errors = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
ignitionBoxStatus ignA_status;
|
struct isrParams
|
||||||
ignitionBoxStatus ignB_status;
|
|
||||||
|
|
||||||
// Pin to flag Map
|
|
||||||
static uint32_t pin2trig[49];
|
|
||||||
void initTriggerPinMapping()
|
|
||||||
{
|
{
|
||||||
pin2trig[TRIG_A12P] = TRIG_FLAG_A12P;
|
const uint32_t flag;
|
||||||
pin2trig[TRIG_A12N] = TRIG_FLAG_A12N;
|
ignitionBoxStatus *ign_stat;
|
||||||
pin2trig[TRIG_A34P] = TRIG_FLAG_A34P;
|
TaskHandle_t rt_handle_ptr;
|
||||||
pin2trig[TRIG_A34N] = TRIG_FLAG_A34N;
|
|
||||||
#ifndef TEST
|
|
||||||
pin2trig[TRIG_B12P] = TRIG_FLAG_B12P;
|
|
||||||
pin2trig[TRIG_B12N] = TRIG_FLAG_B12N;
|
|
||||||
pin2trig[TRIG_B34P] = TRIG_FLAG_B34P;
|
|
||||||
pin2trig[TRIG_B34N] = TRIG_FLAG_B34N;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint32_t pin2spark[49];
|
void IRAM_ATTR trig_isr(void *arg);
|
||||||
void initSparkPinMapping()
|
|
||||||
{
|
|
||||||
pin2spark[SPARK_A12] = SPARK_FLAG_A12;
|
|
||||||
pin2spark[SPARK_A34] = SPARK_FLAG_A34;
|
|
||||||
#ifndef TEST
|
|
||||||
pin2spark[SPARK_B12] = SPARK_FLAG_B12;
|
|
||||||
pin2spark[SPARK_B34] = SPARK_FLAG_B34;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
// =====================
|
|
||||||
// ISR (Pass return bitmask to ISR management function)
|
|
||||||
// one function for each wake up pin conncted to a trigger
|
|
||||||
// =====================
|
|
||||||
void IRAM_ATTR trig_isr_a()
|
|
||||||
{
|
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
||||||
volatile const int64_t time_us = esp_timer_get_time();
|
|
||||||
if (!trigA_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_A12P)
|
|
||||||
ignA_status.coils12.trig_time = time_us;
|
|
||||||
if (pickup_flags & TRIG_FLAG_A34P)
|
|
||||||
ignA_status.coils34.trig_time = time_us;
|
|
||||||
|
|
||||||
xTaskNotifyFromISR(trigA_TaskHandle, GPIO.status1.val, eSetBits, &xHigherPriorityTaskWoken);
|
|
||||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRAM_ATTR spark_a()
|
|
||||||
{
|
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
||||||
volatile const int64_t time_us = esp_timer_get_time();
|
|
||||||
if (!trigA_TaskHandle)
|
|
||||||
return;
|
|
||||||
#ifndef TEST
|
|
||||||
uint32_t spark_flag = GPIO.status1.val & SPARK_A12 ? SPARK_FLAG_A12 : SPARK_FLAG_A34;
|
|
||||||
#else
|
|
||||||
uint32_t spark_flag = GPIO.status & SPARK_A12 ? SPARK_FLAG_A12 : SPARK_FLAG_A34;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (spark_flag & SPARK_FLAG_A12)
|
|
||||||
ignA_status.coils12.spark_time = time_us;
|
|
||||||
if (spark_flag & SPARK_FLAG_A34)
|
|
||||||
ignA_status.coils12.spark_time = time_us;
|
|
||||||
xTaskNotifyFromISR(trigA_TaskHandle, GPIO.status, 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
|
|
||||||
|
|||||||
@@ -10,11 +10,25 @@
|
|||||||
#include <tasks.h>
|
#include <tasks.h>
|
||||||
#include <channels.h>
|
#include <channels.h>
|
||||||
#include <devices.h>
|
#include <devices.h>
|
||||||
|
#include <ui.h>
|
||||||
|
|
||||||
|
// FreeRTOS directives
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
|
// #define CH_B_ENABLE
|
||||||
|
#define TEST
|
||||||
|
|
||||||
|
void printTaskStats() {
|
||||||
|
char buffer[1024];
|
||||||
|
vTaskGetRunTimeStats(buffer);
|
||||||
|
Serial.println(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
|
Serial.begin(921600);
|
||||||
delay(250);
|
delay(250);
|
||||||
Serial.begin(115200);
|
|
||||||
|
|
||||||
// Setup Logger
|
// Setup Logger
|
||||||
LOG_ATTACH_SERIAL(Serial);
|
LOG_ATTACH_SERIAL(Serial);
|
||||||
@@ -22,7 +36,8 @@ void setup()
|
|||||||
|
|
||||||
// Print Processor Info
|
// Print Processor Info
|
||||||
LOG_INFO("ESP32 Chip:", ESP.getChipModel());
|
LOG_INFO("ESP32 Chip:", ESP.getChipModel());
|
||||||
if (psramFound()){
|
if (psramFound())
|
||||||
|
{
|
||||||
LOG_INFO("ESP32 PSram Found");
|
LOG_INFO("ESP32 PSram Found");
|
||||||
LOG_INFO("ESP32 PSram:", ESP.getPsramSize());
|
LOG_INFO("ESP32 PSram:", ESP.getPsramSize());
|
||||||
psramInit();
|
psramInit();
|
||||||
@@ -33,51 +48,98 @@ void setup()
|
|||||||
|
|
||||||
// Initialize Interrupt pins on PICKUP detectors
|
// Initialize Interrupt pins on PICKUP detectors
|
||||||
initTriggerPinsInputs();
|
initTriggerPinsInputs();
|
||||||
initTriggerPinMapping();
|
|
||||||
// Initialize Interrupt pins on SPARK detectors
|
// Initialize Interrupt pins on SPARK detectors
|
||||||
initSparkPinInputs();
|
initSparkPinInputs();
|
||||||
initSparkPinMapping();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
// global variables
|
// global variables
|
||||||
bool running = true;
|
bool running = true;
|
||||||
rtTaskParams taskA_params, taskB_params;
|
static Devices dev;
|
||||||
Devices dev;
|
|
||||||
|
|
||||||
#ifndef TEST
|
// Task handle
|
||||||
|
static TaskHandle_t trigA_TaskHandle = NULL;
|
||||||
|
static TaskHandle_t trigB_TaskHandle = NULL;
|
||||||
|
|
||||||
|
static QueueHandle_t rt_taskA_queue = xQueueCreate(10, sizeof(ignitionBoxStatus));
|
||||||
|
static QueueHandle_t rt_taskB_queue = xQueueCreate(10, sizeof(ignitionBoxStatus));
|
||||||
|
static rtTaskParams taskA_params{
|
||||||
|
.rt_running = true,
|
||||||
|
.dev = &dev,
|
||||||
|
.rt_handle_ptr = &trigA_TaskHandle,
|
||||||
|
.rt_queue = rt_taskA_queue,
|
||||||
|
.rt_int = rtTaskInterrupts{
|
||||||
|
.isr_ptr = trig_isr,
|
||||||
|
.trig_pin_12p = TRIG_PIN_A12P,
|
||||||
|
.trig_pin_12n = TRIG_PIN_A12N,
|
||||||
|
.trig_pin_34p = TRIG_PIN_A34P,
|
||||||
|
.trig_pin_34n = TRIG_PIN_A34N,
|
||||||
|
.spark_pin_12 = SPARK_PIN_A12,
|
||||||
|
.spark_pin_34 = SPARK_PIN_A34},
|
||||||
|
.rt_resets = rtTaskResets{.rst_io_12p = RST_EXT_A12P, .rst_io_12n = RST_EXT_A12N, .rst_io_34p = RST_EXT_A34P, .rst_io_34n = RST_EXT_A34N}};
|
||||||
|
|
||||||
|
LOG_INFO("Task Variables OK");
|
||||||
|
|
||||||
|
#ifdef CH_B_ENABLE
|
||||||
|
QueueHandle_t rt_taskB_queue = xQueueCreate(10, sizeof(ignitionBoxStatus));
|
||||||
|
rtTaskParams taskB_params{
|
||||||
|
.rt_running = true,
|
||||||
|
.dev = &dev,
|
||||||
|
.rt_handle_ptr = &trigB_TaskHandle,
|
||||||
|
.rt_queue = rt_taskB_queue,
|
||||||
|
.rt_int = rtTaskInterrupts{
|
||||||
|
.isr_ptr = trig_isr,
|
||||||
|
.trig_pin_12p = TRIG_PIN_B12P,
|
||||||
|
.trig_pin_12n = TRIG_PIN_B12N,
|
||||||
|
.trig_pin_34p = TRIG_PIN_B34P,
|
||||||
|
.trig_pin_34n = TRIG_PIN_B34N,
|
||||||
|
.spark_pin_12 = SPARK_PIN_B12,
|
||||||
|
.spark_pin_34 = SPARK_PIN_B34},
|
||||||
|
.rt_resets = rtTaskResets{.rst_io_12p = RST_EXT_B12P, .rst_io_12n = RST_EXT_B12N, .rst_io_34p = RST_EXT_B34P, .rst_io_34n = RST_EXT_B34N}};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool spiA_ok = true;
|
||||||
|
bool spiB_ok = true;
|
||||||
|
|
||||||
|
#ifndef TEST
|
||||||
// Init 2 SPI interfaces
|
// Init 2 SPI interfaces
|
||||||
SPIClass SPI_A(FSPI);
|
SPIClass SPI_A(FSPI);
|
||||||
|
spiA_ok = SPI_A.begin(SPI_A_SCK, SPI_A_MISO, SPI_A_MOSI);
|
||||||
SPIClass SPI_B(HSPI);
|
SPIClass SPI_B(HSPI);
|
||||||
if (!SPI_A.begin(SPI_A_SCK, SPI_A_MISO, SPI_A_MOSI) || !SPI_B.begin(SPI_A_SCK, SPI_A_MISO, SPI_A_MOSI)) {
|
spiB_ok = SPI_B.begin(SPI_B_SCK, SPI_B_MISO, SPI_B_MOSI);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!spiA_ok || !spiB_ok)
|
||||||
|
{
|
||||||
LOG_ERROR("Unable to Initialize SPI Busses");
|
LOG_ERROR("Unable to Initialize SPI Busses");
|
||||||
LOG_ERROR("5 seconds to restart...");
|
LOG_ERROR("5 seconds to restart...");
|
||||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||||
esp_restart();
|
esp_restart();
|
||||||
}
|
}
|
||||||
#endif
|
LOG_INFO("Init SPI OK");
|
||||||
|
|
||||||
pinMode(POT_A_CS, OUTPUT); // Temporary!
|
|
||||||
pinMode(POT_B_CS, OUTPUT); // Temporary!
|
|
||||||
LOG_INFO("Init SPI [OK]");
|
|
||||||
|
|
||||||
|
#ifndef TEST
|
||||||
// Init ADC_A
|
// Init ADC_A
|
||||||
// dev.adc_a = new ADS1256(ADC_A_DRDY, ADC_A_RST, ADC_A_SYNC, ADC_A_CS, 2.5, &SPI_A);
|
dev.adc_a = new ADS1256(ADC_A_DRDY, ADC_A_RST, ADC_A_SYNC, ADC_A_CS, 2.5, &SPI_A);
|
||||||
// dev.adc_a->InitializeADC();
|
dev.adc_a->InitializeADC();
|
||||||
// dev.adc_a->setPGA(PGA_1);
|
dev.adc_a->setPGA(PGA_1);
|
||||||
// dev.adc_a->setDRATE(DRATE_1000SPS);
|
dev.adc_a->setDRATE(DRATE_1000SPS);
|
||||||
|
|
||||||
// Init ADC_B
|
// Init ADC_B
|
||||||
// dev.adc_a = new ADS1256(ADC_B_DRDY, ADC_B_RST, ADC_B_SYNC, ADC_B_CS, 2.5, &SPI_B);
|
dev.adc_a = new ADS1256(ADC_B_DRDY, ADC_B_RST, ADC_B_SYNC, ADC_B_CS, 2.5, &SPI_B);
|
||||||
// dev.adc_a->InitializeADC();
|
dev.adc_a->InitializeADC();
|
||||||
// dev.adc_a->setPGA(PGA_1);
|
dev.adc_a->setPGA(PGA_1);
|
||||||
// dev.adc_a->setDRATE(DRATE_1000SPS);
|
dev.adc_a->setDRATE(DRATE_1000SPS);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LOG_INFO("Init ADC OK");
|
||||||
|
|
||||||
// Ignition A on Core 0
|
// Ignition A on Core 0
|
||||||
auto ignA_task_success = xTaskCreatePinnedToCore(
|
auto ignA_task_success = pdPASS;
|
||||||
ignitionA_task,
|
ignA_task_success = xTaskCreatePinnedToCore(
|
||||||
"ignitionA_task",
|
rtIgnitionTask,
|
||||||
|
"rtIgnitionTask_boxA",
|
||||||
TASK_STACK,
|
TASK_STACK,
|
||||||
(void *)&taskA_params,
|
(void *)&taskA_params,
|
||||||
TASK_PRIORITY,
|
TASK_PRIORITY,
|
||||||
@@ -86,14 +148,16 @@ void loop()
|
|||||||
|
|
||||||
// Ignition B on Core 1
|
// Ignition B on Core 1
|
||||||
auto ignB_task_success = pdPASS;
|
auto ignB_task_success = pdPASS;
|
||||||
// auto ignB_task_success = xTaskCreatePinnedToCore(
|
#ifdef CH_B_ENABLE
|
||||||
// ignitionB_task,
|
ignB_task_success = xTaskCreatePinnedToCore(
|
||||||
// "ignitionB_task",
|
rtIgnitionTask,
|
||||||
// TASK_STACK,
|
"rtIgnitionTask_boxB",
|
||||||
// (void *)&taskB_params,
|
TASK_STACK,
|
||||||
// TASK_PRIORITY, // priorità leggermente più alta
|
(void *)&taskB_params,
|
||||||
// &trigA_TaskHandle,
|
TASK_PRIORITY, // priorità leggermente più alta
|
||||||
// CORE_1);
|
&trigB_TaskHandle,
|
||||||
|
CORE_1);
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((ignA_task_success && ignB_task_success) != pdPASS)
|
if ((ignA_task_success && ignB_task_success) != pdPASS)
|
||||||
{
|
{
|
||||||
@@ -102,17 +166,62 @@ void loop()
|
|||||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||||
esp_restart();
|
esp_restart();
|
||||||
}
|
}
|
||||||
LOG_INFO("Real Time Tasks A&B initialized");
|
|
||||||
|
LOG_INFO("Real Time Tasks A & B initialized");
|
||||||
|
|
||||||
////////////////////// MAIN LOOP //////////////////////
|
////////////////////// MAIN LOOP //////////////////////
|
||||||
uint32_t count(0);
|
clearScreen();
|
||||||
|
setCursor(0, 0);
|
||||||
|
ignitionBoxStatus ignA;
|
||||||
|
int64_t last = esp_timer_get_time();
|
||||||
|
uint32_t missed_firings12 = 0;
|
||||||
|
uint32_t missed_firings34 = 0;
|
||||||
|
uint32_t counter = 0;
|
||||||
|
|
||||||
while (running)
|
while (running)
|
||||||
{
|
{
|
||||||
//digitalWrite(POT_B_CS, HIGH);
|
if (xQueueReceive(rt_taskA_queue, &ignA, pdMS_TO_TICKS(1000)) == pdTRUE)
|
||||||
//delay(500);
|
{
|
||||||
//LOG_INFO("Main Loop [", count++, "]");
|
if (ignA.coils12.spark_status == sparkStatus::SPARK_NEG_FAIL || ignA.coils12.spark_status == sparkStatus::SPARK_POS_FAIL)
|
||||||
//digitalWrite(POT_B_CS, LOW);
|
missed_firings12++;
|
||||||
//delay(500);
|
if (ignA.coils34.spark_status == sparkStatus::SPARK_POS_FAIL || ignA.coils34.spark_status == sparkStatus::SPARK_NEG_FAIL)
|
||||||
|
missed_firings34++;
|
||||||
|
clearScreen();
|
||||||
|
setCursor(0, 0);
|
||||||
|
printField("++ Timestamp", (uint32_t)ignA.timestamp, 0, 0);
|
||||||
|
Serial.println("========== Coils 12 =============");
|
||||||
|
printField("Events", (uint32_t)ignA.coils12.n_events, 0, 1);
|
||||||
|
printField("Missed Firing", missed_firings12, 0, 2);
|
||||||
|
printField("Spark Dly", (uint32_t)ignA.coils12.spark_delay, 0, 3);
|
||||||
|
printField("Spark Sts", sparkStatusNames.at(ignA.coils12.spark_status), 0, 4);
|
||||||
|
// printField("Peak P_IN", ignA.coils12.peak_p_in, 0, 5);
|
||||||
|
// printField("Peak P_OUT", ignA.coils12.peak_p_out, 0, 6);
|
||||||
|
// printField("Peak N_IN", ignA.coils12.peak_n_in, 0, 7);
|
||||||
|
// printField("Peak N_OUT", ignA.coils12.peak_n_out, 0, 8);
|
||||||
|
printField("Soft Start ", softStartStatusNames.at(ignA.coils12.sstart_status), 0, 9);
|
||||||
|
|
||||||
|
Serial.println("========== Coils 34 =============");
|
||||||
|
printField("Events", (uint32_t)ignA.coils34.n_events, 0, 11);
|
||||||
|
printField("Missed Firing", missed_firings34, 0, 12);
|
||||||
|
printField("Spark Dly", (uint32_t)ignA.coils34.spark_delay, 0, 13);
|
||||||
|
printField("Spark Sts", sparkStatusNames.at(ignA.coils34.spark_status), 0, 14);
|
||||||
|
// printField("Peak P_IN", ignA.coils34.peak_p_in, 0, 15);
|
||||||
|
// printField("Peak P_OUT", ignA.coils34.peak_p_out, 0, 16);
|
||||||
|
// printField("Peak N_IN", ignA.coils34.peak_n_in, 0, 17);
|
||||||
|
// printField("Peak N_OUT", ignA.coils34.peak_n_out, 0, 18);
|
||||||
|
printField("Soft Start ", softStartStatusNames.at(ignA.coils34.sstart_status), 0, 19);
|
||||||
|
|
||||||
|
Serial.println("========== END =============");
|
||||||
|
Serial.println();
|
||||||
|
auto delta = (esp_timer_get_time() - last) / 1000000.0f; //in seconds
|
||||||
|
delta = delta > 0 ? 1.0f / delta : 0; // Calculate frequency (Hz)
|
||||||
|
printField("Frequency (Hz)", delta, 0, 21);
|
||||||
|
printField("Queue Errors", (uint32_t)ignA.n_queue_errors, 0, 22);
|
||||||
|
last = esp_timer_get_time();
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
Serial.println("Waiting for data... ");;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trigA_TaskHandle)
|
if (trigA_TaskHandle)
|
||||||
|
|||||||
@@ -59,46 +59,46 @@
|
|||||||
// =====================
|
// =====================
|
||||||
// DIGITAL POT
|
// DIGITAL POT
|
||||||
// =====================
|
// =====================
|
||||||
#define POT_A_CS 1
|
//#define POT_A_CS 1
|
||||||
#define POT_B_CS 2
|
//#define POT_B_CS 2
|
||||||
|
|
||||||
// =====================
|
// =====================
|
||||||
// TRIGGER INPUT INTERRUPTS
|
// TRIGGER INPUT INTERRUPTS
|
||||||
// =====================
|
// =====================
|
||||||
#define TRIG_A12P 18
|
#define TRIG_PIN_A12P 18
|
||||||
#define TRIG_A12N 21
|
#define TRIG_PIN_A12N 21
|
||||||
#define TRIG_A34P 33
|
#define TRIG_PIN_A34P 1
|
||||||
#define TRIG_A34N 34
|
#define TRIG_PIN_A34N 2
|
||||||
#define TRIG_B12P 38
|
#define TRIG_PIN_B12P 38
|
||||||
#define TRIG_B12N 39
|
#define TRIG_PIN_B12N 39
|
||||||
#define TRIG_B34P 40
|
#define TRIG_PIN_B34P 40
|
||||||
#define TRIG_B34N 41
|
#define TRIG_PIN_B34N 41
|
||||||
|
|
||||||
// =====================
|
// =====================
|
||||||
// SPARK DETECT INPUTS
|
// SPARK DETECT INPUTS
|
||||||
// =====================
|
// =====================
|
||||||
#define SPARK_A12 42
|
#define SPARK_PIN_A12 42
|
||||||
#define SPARK_A34 45 // OK (strapping ma consentito)
|
#define SPARK_PIN_A34 45 // OK (strapping ma consentito) 45
|
||||||
#define SPARK_B12 46 // OK (strapping ma consentito)
|
#define SPARK_PIN_B12 46 // OK (strapping ma consentito) 46
|
||||||
#define SPARK_B34 47
|
#define SPARK_PIN_B34 47
|
||||||
|
|
||||||
// =====================
|
// =====================
|
||||||
// PCA9555 (I2C EXPANDER)
|
// PCA9555 (I2C EXPANDER)
|
||||||
// =====================
|
// =====================
|
||||||
|
|
||||||
// --- RESET LINES ---
|
// --- RESET LINES ---
|
||||||
#define RST_A12P 0
|
#define RST_EXT_A12P 0
|
||||||
#define RST_A12N 1
|
#define RST_EXT_A12N 1
|
||||||
#define RST_A34P 2
|
#define RST_EXT_A34P 2
|
||||||
#define RST_A34N 3
|
#define RST_EXT_A34N 3
|
||||||
#define RST_B12P 4
|
#define RST_EXT_B12P 4
|
||||||
#define RST_B12N 5
|
#define RST_EXT_B12N 5
|
||||||
#define RST_B34P 6
|
#define RST_EXT_B34P 6
|
||||||
#define RST_B34N 7
|
#define RST_EXT_B34N 7
|
||||||
|
|
||||||
// --- RELAY ---
|
// --- RELAY ---
|
||||||
#define A_RELAY 8
|
#define A_EXT_RELAY 8
|
||||||
#define B_RELAY 9
|
#define B_EXT_RELAY 9
|
||||||
|
|
||||||
// --- STATUS / BUTTON ---
|
// --- STATUS / BUTTON ---
|
||||||
#define BTN_3 10
|
#define BTN_3 10
|
||||||
@@ -111,20 +111,20 @@
|
|||||||
// Init Pin Functions
|
// Init Pin Functions
|
||||||
inline void initTriggerPinsInputs()
|
inline void initTriggerPinsInputs()
|
||||||
{
|
{
|
||||||
pinMode(TRIG_A12P, INPUT);
|
pinMode(TRIG_PIN_A12P, INPUT_PULLDOWN);
|
||||||
pinMode(TRIG_A12N, INPUT);
|
pinMode(TRIG_PIN_A12N, INPUT_PULLDOWN);
|
||||||
pinMode(TRIG_A34P, INPUT);
|
pinMode(TRIG_PIN_A34P, INPUT_PULLDOWN);
|
||||||
pinMode(TRIG_A34N, INPUT);
|
pinMode(TRIG_PIN_A34N, INPUT_PULLDOWN);
|
||||||
pinMode(TRIG_B12P, INPUT);
|
pinMode(TRIG_PIN_B12P, INPUT_PULLDOWN);
|
||||||
pinMode(TRIG_B12N, INPUT);
|
pinMode(TRIG_PIN_B12N, INPUT_PULLDOWN);
|
||||||
pinMode(TRIG_B34P, INPUT);
|
pinMode(TRIG_PIN_B34P, INPUT_PULLDOWN);
|
||||||
pinMode(TRIG_B34N, INPUT);
|
pinMode(TRIG_PIN_B34N, INPUT_PULLDOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void initSparkPinInputs()
|
inline void initSparkPinInputs()
|
||||||
{
|
{
|
||||||
pinMode(SPARK_A12, INPUT);
|
pinMode(SPARK_PIN_A12, INPUT_PULLDOWN);
|
||||||
pinMode(SPARK_A34, INPUT);
|
pinMode(SPARK_PIN_A34, INPUT_PULLDOWN);
|
||||||
pinMode(SPARK_B12, INPUT);
|
pinMode(SPARK_PIN_B12, INPUT_PULLDOWN);
|
||||||
pinMode(SPARK_B34, INPUT);
|
pinMode(SPARK_PIN_B34, INPUT_PULLDOWN);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,30 +42,43 @@
|
|||||||
// =====================
|
// =====================
|
||||||
// TRIGGER INPUT INTERRUPTS
|
// TRIGGER INPUT INTERRUPTS
|
||||||
// =====================
|
// =====================
|
||||||
#define TRIG_A12P 35
|
#define TRIG_PIN_A12P 35
|
||||||
#define TRIG_A12N 32
|
#define TRIG_PIN_A12N 32
|
||||||
#define TRIG_A34P 39
|
#define TRIG_PIN_A34P 39
|
||||||
#define TRIG_A34N 36
|
#define TRIG_PIN_A34N 36
|
||||||
|
|
||||||
|
|
||||||
// =====================
|
// =====================
|
||||||
// SPARK DETECT INTERRUPTS
|
// SPARK DETECT INTERRUPTS
|
||||||
// =====================
|
// =====================
|
||||||
#define SPARK_A12 4
|
#define SPARK_PIN_A12 4
|
||||||
#define SPARK_A34 2
|
#define SPARK_PIN_A34 2
|
||||||
|
|
||||||
|
// =====================
|
||||||
|
// PCA9555 (I2C EXPANDER)
|
||||||
|
// =====================
|
||||||
|
|
||||||
|
// --- RESET LINES ---
|
||||||
|
#define RST_EXT_A12P 0
|
||||||
|
#define RST_EXT_A12N 1
|
||||||
|
#define RST_EXT_A34P 2
|
||||||
|
#define RST_EXT_A34N 3
|
||||||
|
|
||||||
|
// --- RELAY ---
|
||||||
|
#define A_EXT_RELAY 8
|
||||||
|
|
||||||
|
|
||||||
// Init Pin Functions
|
// Init Pin Functions
|
||||||
inline void initTriggerPinsInputs()
|
inline void initTriggerPinsInputs()
|
||||||
{
|
{
|
||||||
pinMode(TRIG_A12P, INPUT_PULLDOWN);
|
pinMode(TRIG_PIN_A12P, INPUT_PULLDOWN);
|
||||||
pinMode(TRIG_A12N, INPUT_PULLDOWN);
|
pinMode(TRIG_PIN_A12N, INPUT_PULLDOWN);
|
||||||
pinMode(TRIG_A34P, INPUT_PULLDOWN);
|
pinMode(TRIG_PIN_A34P, INPUT_PULLDOWN);
|
||||||
pinMode(TRIG_A34N, INPUT_PULLDOWN);
|
pinMode(TRIG_PIN_A34N, INPUT_PULLDOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void initSparkPinInputs()
|
inline void initSparkPinInputs()
|
||||||
{
|
{
|
||||||
pinMode(SPARK_A12, INPUT_PULLDOWN);
|
pinMode(SPARK_PIN_A12, INPUT_PULLDOWN);
|
||||||
pinMode(SPARK_A34, INPUT_PULLDOWN);
|
pinMode(SPARK_PIN_A34, INPUT_PULLDOWN);
|
||||||
}
|
}
|
||||||
303
RotaxMonitor/src/tasks.cpp
Normal file
303
RotaxMonitor/src/tasks.cpp
Normal file
@@ -0,0 +1,303 @@
|
|||||||
|
#include "tasks.h"
|
||||||
|
#include <esp_timer.h>
|
||||||
|
|
||||||
|
// Timeout callback for microsecond precision
|
||||||
|
void spark_timeout_callback(void* arg) {
|
||||||
|
TaskHandle_t handle = (TaskHandle_t)arg;
|
||||||
|
xTaskNotify(handle, SPARK_FLAG_TIMEOUT, eSetValueWithOverwrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtIgnitionTask(void *pvParameters)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Invalid real time rt_task_ptr parameters, exit immediate
|
||||||
|
if (!pvParameters)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Null rt_task_ptr parameters");
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
LOG_INFO("rtTask Params OK");
|
||||||
|
|
||||||
|
// Task Parameters and Devices
|
||||||
|
rtTaskParams *params = (rtTaskParams *)pvParameters;
|
||||||
|
const rtTaskInterrupts rt_int = params->rt_int; // copy to avoid external override
|
||||||
|
const rtTaskResets rt_rst = params->rt_resets; // copy to avoid external override
|
||||||
|
QueueHandle_t rt_queue = params->rt_queue;
|
||||||
|
TaskHandle_t rt_handle_ptr = *params->rt_handle_ptr;
|
||||||
|
Devices *dev = params->dev;
|
||||||
|
ADS1256 *adc = dev->adc_a;
|
||||||
|
PCA9555 *io = dev->io;
|
||||||
|
|
||||||
|
ignitionBoxStatus ign_box_sts;
|
||||||
|
|
||||||
|
// Variables for ISR, static to be fixed in memory locations
|
||||||
|
static isrParams isr_params_t12p{
|
||||||
|
.flag = TRIG_FLAG_12P,
|
||||||
|
.ign_stat = &ign_box_sts,
|
||||||
|
.rt_handle_ptr = rt_handle_ptr};
|
||||||
|
static isrParams isr_params_t12n{
|
||||||
|
.flag = TRIG_FLAG_12N,
|
||||||
|
.ign_stat = &ign_box_sts,
|
||||||
|
.rt_handle_ptr = rt_handle_ptr};
|
||||||
|
static isrParams isr_params_t34p{
|
||||||
|
.flag = TRIG_FLAG_34P,
|
||||||
|
.ign_stat = &ign_box_sts,
|
||||||
|
.rt_handle_ptr = rt_handle_ptr};
|
||||||
|
static isrParams isr_params_t34n{
|
||||||
|
.flag = TRIG_FLAG_34N,
|
||||||
|
.ign_stat = &ign_box_sts,
|
||||||
|
.rt_handle_ptr = rt_handle_ptr};
|
||||||
|
static isrParams isr_params_sp12{
|
||||||
|
.flag = SPARK_FLAG_12,
|
||||||
|
.ign_stat = &ign_box_sts,
|
||||||
|
.rt_handle_ptr = rt_handle_ptr};
|
||||||
|
static isrParams isr_params_sp34{
|
||||||
|
.flag = SPARK_FLAG_34,
|
||||||
|
.ign_stat = &ign_box_sts,
|
||||||
|
.rt_handle_ptr = rt_handle_ptr};
|
||||||
|
|
||||||
|
LOG_INFO("rtTask ISR Params OK");
|
||||||
|
|
||||||
|
// Create esp_timer for microsecond precision timeout
|
||||||
|
esp_timer_handle_t timeout_timer;
|
||||||
|
esp_timer_create_args_t timer_args = {
|
||||||
|
.callback = spark_timeout_callback,
|
||||||
|
.arg = (void*)rt_handle_ptr,
|
||||||
|
.dispatch_method = ESP_TIMER_TASK,
|
||||||
|
.name = "spark_timeout"
|
||||||
|
};
|
||||||
|
esp_timer_create(&timer_args, &timeout_timer);
|
||||||
|
|
||||||
|
// Attach Pin Interrupts
|
||||||
|
attachInterruptArg(digitalPinToInterrupt(rt_int.trig_pin_12p), rt_int.isr_ptr, (void *)&isr_params_t12p, RISING);
|
||||||
|
attachInterruptArg(digitalPinToInterrupt(rt_int.trig_pin_12n), rt_int.isr_ptr, (void *)&isr_params_t12n, RISING);
|
||||||
|
attachInterruptArg(digitalPinToInterrupt(rt_int.trig_pin_34p), rt_int.isr_ptr, (void *)&isr_params_t34p, RISING);
|
||||||
|
attachInterruptArg(digitalPinToInterrupt(rt_int.trig_pin_34n), rt_int.isr_ptr, (void *)&isr_params_t34n, RISING);
|
||||||
|
attachInterruptArg(digitalPinToInterrupt(rt_int.spark_pin_12), rt_int.isr_ptr, (void *)&isr_params_sp12, RISING);
|
||||||
|
attachInterruptArg(digitalPinToInterrupt(rt_int.spark_pin_34), rt_int.isr_ptr, (void *)&isr_params_sp34, RISING);
|
||||||
|
|
||||||
|
LOG_INFO("rtTask ISR Attach OK");
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
LOG_WARN("rtTask Init Correct");
|
||||||
|
// Global rt_task_ptr variables
|
||||||
|
bool first_cycle = true;
|
||||||
|
bool cycle12 = false;
|
||||||
|
bool cycle34 = false;
|
||||||
|
|
||||||
|
while (params->rt_running)
|
||||||
|
{
|
||||||
|
uint32_t pickup_flag = 0;
|
||||||
|
uint32_t spark_flag = 0;
|
||||||
|
|
||||||
|
// WAIT FOR PICKUP SIGNAL
|
||||||
|
xTaskNotifyWait(
|
||||||
|
0x00, // non pulire all'ingresso
|
||||||
|
ULONG_MAX, // pulisci i primi 8 bit
|
||||||
|
&pickup_flag, // valore ricevuto
|
||||||
|
portMAX_DELAY);
|
||||||
|
|
||||||
|
if (first_cycle && pickup_flag != TRIG_FLAG_12P) // skip first cycle because of possible initial noise on pickup signals at startu
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.print("\033[2J"); // clear screen
|
||||||
|
Serial.print("\033[H"); // cursor home
|
||||||
|
LOG_INFO("Iteration [", it++, "]");
|
||||||
|
|
||||||
|
if (!names.contains(pickup_flag))
|
||||||
|
{
|
||||||
|
LOG_ERROR("Wrong Pickup Flag");
|
||||||
|
LOG_ERROR("Pickup Flags: ", printBits(pickup_flag).c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_INFO("Pickup Trigger: ", names.at(pickup_flag));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Start microsecond precision timeout timer
|
||||||
|
esp_timer_stop(timeout_timer); // stop timer in case it was running from previous cycle
|
||||||
|
esp_timer_start_once(timeout_timer, spark_timeout_max);
|
||||||
|
|
||||||
|
spark_flag = SPARK_FLAG_NIL; // default value in case of timeout, to be set by ISR if spark event occours
|
||||||
|
// WAIT FOR SPARK TO HAPPEN OR TIMEOUT
|
||||||
|
BaseType_t sp = pdFALSE;
|
||||||
|
sp = xTaskNotifyWait(
|
||||||
|
0x00, // non pulire all'ingresso
|
||||||
|
ULONG_MAX, // pulisci i primi 8 bit
|
||||||
|
&spark_flag, // valore ricevuto
|
||||||
|
portMAX_DELAY); // wait indefinitely, timeout handled by esp_timer
|
||||||
|
|
||||||
|
// Handle timeout or spark event
|
||||||
|
if (spark_flag == SPARK_FLAG_TIMEOUT) {
|
||||||
|
spark_flag = SPARK_FLAG_NIL;
|
||||||
|
} else {
|
||||||
|
// Spark occurred, stop the timer
|
||||||
|
esp_timer_stop(timeout_timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
// LOG_INFO("Spark Flags: ", printBits(spark_flag).c_str());
|
||||||
|
LOG_INFO("Spark12:", ign_box_sts.coils12.spark_ok ? "TRUE" : "FALSE");
|
||||||
|
LOG_INFO("Spark34:", ign_box_sts.coils34.spark_ok ? "TRUE" : "FALSE");
|
||||||
|
if (names.contains(spark_flag))
|
||||||
|
LOG_INFO("Spark Trigger:", names.at(spark_flag));
|
||||||
|
#endif
|
||||||
|
xTaskNotifyStateClear(NULL);
|
||||||
|
ulTaskNotifyValueClear(NULL, 0xFFFFFFFF);
|
||||||
|
|
||||||
|
// 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_12P || pickup_flag == TRIG_FLAG_12N) && (spark_flag != SPARK_FLAG_12 && spark_flag != SPARK_FLAG_NIL))
|
||||||
|
{
|
||||||
|
ign_box_sts.coils12.spark_status = ign_box_sts.coils34.spark_status = sparkStatus::SPARK_SYNC_FAIL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
coilsStatus *coils;
|
||||||
|
switch (pickup_flag)
|
||||||
|
{
|
||||||
|
case TRIG_FLAG_12P:
|
||||||
|
first_cycle = false;
|
||||||
|
case TRIG_FLAG_12N:
|
||||||
|
coils = &ign_box_sts.coils12;
|
||||||
|
break;
|
||||||
|
case TRIG_FLAG_34P:
|
||||||
|
case TRIG_FLAG_34N:
|
||||||
|
coils = &ign_box_sts.coils34;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (pickup_flag)
|
||||||
|
{
|
||||||
|
case TRIG_FLAG_12P:
|
||||||
|
case TRIG_FLAG_34P:
|
||||||
|
{
|
||||||
|
// Timeout not occourred, expected POSITIVE edge spark OCCOURRED
|
||||||
|
if (spark_flag != SPARK_FLAG_NIL)
|
||||||
|
{
|
||||||
|
coils->spark_delay = coils->spark_time - coils->trig_time;
|
||||||
|
coils->sstart_status = softStartStatus::NORMAL; // because spark on positive edge
|
||||||
|
coils->spark_status = sparkStatus::SPARK_POS_OK; // do not wait for spark on negative edge
|
||||||
|
#ifdef DEBUG
|
||||||
|
LOG_INFO("Spark on POSITIVE pulse");
|
||||||
|
LOG_INFO("Spark Delay Time: ", (int32_t)coils->spark_delay);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
// Timeout occourred, expected POSITIVE edge spark NOT OCCOURRED
|
||||||
|
else if (spark_flag == SPARK_FLAG_NIL)
|
||||||
|
{
|
||||||
|
coils->spark_status = sparkStatus::SPARK_NEG_WAIT;
|
||||||
|
coils->sstart_status = softStartStatus::NORMAL;
|
||||||
|
}
|
||||||
|
continue; // Do nothing more on positive pulse
|
||||||
|
}
|
||||||
|
// CASES for NEGATIVE cycle triggering of pickup and sparks 12 & 34
|
||||||
|
case TRIG_FLAG_12N:
|
||||||
|
case TRIG_FLAG_34N:
|
||||||
|
{
|
||||||
|
const bool expected_negative = coils->spark_status == sparkStatus::SPARK_NEG_WAIT;
|
||||||
|
// Timeout not occourred, expected NEGATIVE edge spark OCCOURRED
|
||||||
|
if (spark_flag != SPARK_FLAG_NIL && expected_negative)
|
||||||
|
{
|
||||||
|
coils->spark_delay = coils->spark_time - coils->trig_time;
|
||||||
|
coils->sstart_status = softStartStatus::SOFT_START;
|
||||||
|
coils->spark_status = sparkStatus::SPARK_NEG_OK;
|
||||||
|
#ifdef DEBUG
|
||||||
|
LOG_INFO("Spark on NEGATIVE pulse");
|
||||||
|
LOG_INFO("Spark Delay Time: ", (int32_t)coils->spark_delay);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
// Timeout occourred, expected POSITIVE edge spark NOT OCCOURRED
|
||||||
|
else if (spark_flag == SPARK_FLAG_NIL && expected_negative)
|
||||||
|
{
|
||||||
|
coils->sstart_status = softStartStatus::ERROR;
|
||||||
|
coils->spark_status = sparkStatus::SPARK_NEG_FAIL;
|
||||||
|
}
|
||||||
|
// Timeout not occouured, unexpected negative edge spark
|
||||||
|
else if (spark_flag != SPARK_FLAG_NIL && !expected_negative)
|
||||||
|
{
|
||||||
|
coils->sstart_status = softStartStatus::SOFT_START;
|
||||||
|
coils->spark_status = sparkStatus::SPARK_NEG_UNEXPECTED;
|
||||||
|
}
|
||||||
|
// Wait for finish of negative pulse to save data to buffer
|
||||||
|
coils->n_events++;
|
||||||
|
if (pickup_flag == TRIG_FLAG_12N)
|
||||||
|
cycle12 = true;
|
||||||
|
else
|
||||||
|
cycle34 = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
#ifdef DEUG
|
||||||
|
LOG_ERROR("Invalid Interrupt");
|
||||||
|
LOG_ERROR("Pickup Flags: ", printBits(pickup_flag).c_str());
|
||||||
|
LOG_ERROR("Spark Flags: ", printBits(spark_flag).c_str());
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cycle12 && cycle34) // wait for both 12 and 34 cycles to complete before sending data to main loop and resetting peak detectors
|
||||||
|
{
|
||||||
|
cycle12 = false;
|
||||||
|
cycle34 = false;
|
||||||
|
// vTaskDelay(pdMS_TO_TICKS(1)); // delay 1ms to allow peak detectors to charge for negative cycle
|
||||||
|
// read adc channels: pickup12, out12 [ pos + neg ]
|
||||||
|
if (adc) // read only if adc initialized
|
||||||
|
{
|
||||||
|
// from peak detector circuits
|
||||||
|
ign_box_sts.coils12.peak_p_in = adcReadChannel(adc, ADC_CH_PEAK_12P_IN);
|
||||||
|
ign_box_sts.coils12.peak_n_in = adcReadChannel(adc, ADC_CH_PEAK_12N_IN);
|
||||||
|
ign_box_sts.coils34.peak_p_in = adcReadChannel(adc, ADC_CH_PEAK_34P_IN);
|
||||||
|
ign_box_sts.coils34.peak_n_in = adcReadChannel(adc, ADC_CH_PEAK_34N_IN);
|
||||||
|
ign_box_sts.coils12.peak_p_out = adcReadChannel(adc, ADC_CH_PEAK_12P_OUT);
|
||||||
|
ign_box_sts.coils12.peak_n_out = adcReadChannel(adc, ADC_CH_PEAK_12N_OUT);
|
||||||
|
ign_box_sts.coils34.peak_p_out = adcReadChannel(adc, ADC_CH_PEAK_34P_OUT);
|
||||||
|
ign_box_sts.coils34.peak_n_out = adcReadChannel(adc, ADC_CH_PEAK_34N_OUT);
|
||||||
|
}
|
||||||
|
else // simulate adc read timig
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(1));
|
||||||
|
|
||||||
|
// 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(1));
|
||||||
|
|
||||||
|
// send essage to main loop with ignition info, by copy so local static variable is ok
|
||||||
|
if (rt_queue)
|
||||||
|
ign_box_sts.timestamp = esp_timer_get_time(); // update data timestamp
|
||||||
|
if (xQueueSendToBack(rt_queue, (void *)&ign_box_sts, 0) != pdPASS)
|
||||||
|
{
|
||||||
|
ign_box_sts.n_queue_errors++;
|
||||||
|
LOG_ERROR("Failed to send to rt_queue");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Delete the timeout timer
|
||||||
|
esp_timer_delete(timeout_timer);
|
||||||
|
LOG_WARN("Ending realTime Task");
|
||||||
|
// Ignition A Interrupts DETACH
|
||||||
|
detachInterrupt(rt_int.trig_pin_12p);
|
||||||
|
detachInterrupt(rt_int.trig_pin_12n);
|
||||||
|
detachInterrupt(rt_int.trig_pin_34p);
|
||||||
|
detachInterrupt(rt_int.trig_pin_34n);
|
||||||
|
detachInterrupt(rt_int.spark_pin_12);
|
||||||
|
detachInterrupt(rt_int.spark_pin_34);
|
||||||
|
// delete present task
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#define DEBUGLOG_DEFAULT_LOG_LEVEL_DEBUG
|
||||||
|
|
||||||
|
// Serial debug flag
|
||||||
|
//#define DEBUG
|
||||||
|
|
||||||
// Arduino Libraries
|
// Arduino Libraries
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
@@ -11,218 +15,52 @@
|
|||||||
// DEVICES
|
// DEVICES
|
||||||
#include "devices.h"
|
#include "devices.h"
|
||||||
|
|
||||||
//Global Variables and Flags
|
// Global Variables and Flags
|
||||||
static bool rt_task_running = true;
|
const uint32_t spark_timeout_max = 500; // in microseconds
|
||||||
const auto spark_timeout_max = 1; // convert to microsecond timer
|
|
||||||
|
|
||||||
// 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_12P, "TRIG_FLAG_12P"},
|
||||||
|
{TRIG_FLAG_12N, "TRIG_FLAG_12N"},
|
||||||
|
{TRIG_FLAG_34P, "TRIG_FLAG_34P"},
|
||||||
|
{TRIG_FLAG_34N, "TRIG_FLAG_34N"},
|
||||||
|
{SPARK_FLAG_12, "SPARK_FLAG_12"},
|
||||||
|
{SPARK_FLAG_34, "SPARK_FLAG_34"},
|
||||||
|
{SPARK_FLAG_TIMEOUT, "SPARK_FLAG_TIMEOUT"},
|
||||||
|
};
|
||||||
|
#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 parameters
|
||||||
LOG_ERROR("Null task parameters");
|
struct rtTaskParams
|
||||||
vTaskDelete(NULL);
|
{
|
||||||
}
|
bool rt_running; // run flag, false to terminate
|
||||||
|
Devices *dev;
|
||||||
|
TaskHandle_t* rt_handle_ptr;
|
||||||
|
const QueueHandle_t rt_queue;
|
||||||
|
const rtTaskInterrupts rt_int; // interrupt pins to attach
|
||||||
|
const rtTaskResets rt_resets; // reset ping for peak detectors
|
||||||
|
};
|
||||||
|
|
||||||
// Task Parameters and Devices
|
void rtIgnitionTask(void *pvParameters);
|
||||||
rtTaskParams* params = (rtTaskParams*) pvParameters;
|
|
||||||
Devices* dev = (Devices*) params->dev;
|
|
||||||
ADS1256* adc = dev->adc_a;
|
|
||||||
|
|
||||||
// Global task variables
|
|
||||||
uint32_t pickup_flag = 0;
|
|
||||||
uint32_t spark_flag = 0;
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
while (rt_task_running) {
|
|
||||||
// WAIT FOR PICKUP SIGNAL
|
|
||||||
xTaskNotifyWait(
|
|
||||||
ULONG_MAX, // non pulire all'ingresso
|
|
||||||
ULONG_MAX, // pulisci i primi 8 bit
|
|
||||||
&pickup_flag, // valore ricevuto
|
|
||||||
portMAX_DELAY
|
|
||||||
);
|
|
||||||
LOG_ERROR("Pickup Interrupt Status", printBits(pickup_flag).c_str());
|
|
||||||
if (!names.contains(pickup_flag)) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
LOG_INFO("Pickup Trigger: ", names.at(pickup_flag));
|
|
||||||
}
|
|
||||||
// WAIT FOR SPARK TO HAPPEN
|
|
||||||
auto spark_timeout = xTaskNotifyWait(
|
|
||||||
ULONG_MAX, // non pulire all'ingresso
|
|
||||||
ULONG_MAX, // pulisci gli 8 bit successivi
|
|
||||||
&spark_flag, // valore ricevuto
|
|
||||||
spark_timeout_max
|
|
||||||
);
|
|
||||||
if (spark_timeout == pdPASS){ //otherwise timeout
|
|
||||||
LOG_ERROR("Spark Interrupt Status", printBits(spark_flag).c_str());
|
|
||||||
if (!names.contains(spark_flag)) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
LOG_INFO("Spark Trigger:", names.at(spark_flag));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG_INFO("Spark Timeout");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.coils12.spark_status = ignA_status.coils34.spark_status = sparkStatus::SPARK_SYNC_FAIL;
|
|
||||||
// Save error on circular buffer and skip to next cycle //
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint32_t combined_flags = pickup_flag & spark_flag;
|
|
||||||
coilsStatus* c;
|
|
||||||
switch (combined_flags)
|
|
||||||
{
|
|
||||||
case TRIG_A12P:
|
|
||||||
case TRIG_A12N:
|
|
||||||
case SPARK_A12:
|
|
||||||
c = &ignA_status.coils12;
|
|
||||||
case TRIG_A34P:
|
|
||||||
case TRIG_A34N:
|
|
||||||
case SPARK_A34:
|
|
||||||
c = &ignA_status.coils34;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool new_data = false;
|
|
||||||
|
|
||||||
switch (pickup_flag) {
|
|
||||||
// CASES for NEGATIVE cycle triggering of pickup and sparks 12 & 34
|
|
||||||
case TRIG_FLAG_A12P:
|
|
||||||
case TRIG_FLAG_A34P:
|
|
||||||
{
|
|
||||||
LOG_INFO("Trigger Pickup POSITIVE");
|
|
||||||
// Timeout not occourred, expected POSITIVE edge spark OCCOURRED
|
|
||||||
if (spark_timeout == pdPASS) {
|
|
||||||
c->spark_delay = c->spark_time - c->trig_time;
|
|
||||||
c->soft_start_status = softStartStatus::NORMAL; // because spark on positive edge
|
|
||||||
c->spark_status = sparkStatus::SPARK_POS_OK; // do not wait for spark on negative edge
|
|
||||||
LOG_INFO("Trigger Spark POSITIVE");
|
|
||||||
}
|
|
||||||
// Timeout occourred, expected POSITIVE edge spark NOT OCCOURRED
|
|
||||||
else if (spark_timeout == pdFAIL) {
|
|
||||||
c->spark_status = sparkStatus::SPARK_NEG_WAIT;
|
|
||||||
c->soft_start_status = softStartStatus::NORMAL;
|
|
||||||
}
|
|
||||||
new_data = false;
|
|
||||||
break; // Do nothing more on positive pulse
|
|
||||||
}
|
|
||||||
// CASES for NEGATIVE cycle triggering of pickup and sparks 12 & 34
|
|
||||||
case TRIG_FLAG_A12N:
|
|
||||||
case TRIG_FLAG_A34N:
|
|
||||||
{
|
|
||||||
const bool expected_negative12 = c->spark_status == sparkStatus::SPARK_NEG_WAIT;
|
|
||||||
LOG_INFO("Trigger Pickup NEGATIVE");
|
|
||||||
// Timeout not occourred, expected NEGATIVE edge spark OCCOURRED
|
|
||||||
if (spark_timeout == pdPASS && expected_negative12) {
|
|
||||||
c->spark_delay = c->spark_time - c->trig_time;
|
|
||||||
c->soft_start_status = softStartStatus::SOFT_START;
|
|
||||||
c->spark_status == sparkStatus::SPARK_NEG_OK;
|
|
||||||
LOG_INFO("Trigger Spark NEGATIVE");
|
|
||||||
}
|
|
||||||
// Timeout occourred, expected POSITIVE edge spark NOT OCCOURRED
|
|
||||||
else if (spark_timeout == pdFAIL && expected_negative12) {
|
|
||||||
c->soft_start_status = softStartStatus::NORMAL;
|
|
||||||
c->spark_status = sparkStatus::SPARK_NEG_FAIL;
|
|
||||||
}
|
|
||||||
// Timeout not occouured, unexpected negative edge spark
|
|
||||||
else if (spark_timeout == pdPASS && !expected_negative12) {
|
|
||||||
c->soft_start_status = softStartStatus::SOFT_START;
|
|
||||||
c->spark_status = sparkStatus::SPARK_NEG_UNEXPECTED;
|
|
||||||
}
|
|
||||||
// Wait for finish of negative pulse to save data to buffer
|
|
||||||
new_data = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
LOG_ERROR("Invalid A Interrupt");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_data) {
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1)); // delay 1ms to allow peak detectors to charge for negative cycle
|
|
||||||
// read adc channels: pickup12, out12 [ pos + neg ]
|
|
||||||
if (adc) // read only if adc initialized
|
|
||||||
{
|
|
||||||
ignA_status.coils12.pickup_volts = adcReadChannel(adc, ADC_A_DRDY, IN_A12_P);
|
|
||||||
ignA_status.coils12.output_volts = adcReadChannel(adc, ADC_A_DRDY, IN_A12_N);
|
|
||||||
ignA_status.coils34.pickup_volts = adcReadChannel(adc, ADC_A_DRDY, IN_A34_P);
|
|
||||||
ignA_status.coils34.output_volts = adcReadChannel(adc, ADC_A_DRDY, IN_A34_N);
|
|
||||||
} else {
|
|
||||||
LOG_WARN("ADC not initialized, skipping conversion");
|
|
||||||
}
|
|
||||||
// reset peak detectors -> gli output sono sull'expander, temporaneo uso il PC del pot non collegato
|
|
||||||
digitalWrite(POT_A_CS, HIGH);
|
|
||||||
// digitalWrite(RST_A12P, HIGH);
|
|
||||||
// digitalWrite(RST_A12N, HIGH);
|
|
||||||
// digitalWrite(RST_A34P, HIGH);
|
|
||||||
// digitalWrite(RST_A34N, HIGH);
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignition A Interrupts DETACH
|
|
||||||
detachInterrupt(TRIG_A12P);
|
|
||||||
detachInterrupt(TRIG_A34P);
|
|
||||||
detachInterrupt(TRIG_A12N);
|
|
||||||
detachInterrupt(TRIG_A34N);
|
|
||||||
detachInterrupt(SPARK_A12);
|
|
||||||
detachInterrupt(SPARK_A34);
|
|
||||||
// delete present task
|
|
||||||
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
|
|
||||||
¬ifiedValue, // 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
|
|
||||||
|
|||||||
59
RotaxMonitor/src/ui.h
Normal file
59
RotaxMonitor/src/ui.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
static bool firstRun = true;
|
||||||
|
|
||||||
|
void clearScreen(){
|
||||||
|
Serial.print("\033[2J"); // clear screen
|
||||||
|
Serial.print("\033[H"); // cursor home
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCursor(const uint8_t x, const uint8_t y) {
|
||||||
|
Serial.printf("\033[%d;%d", y, x+1);
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void printField(const char name[], const uint32_t val, const uint8_t x, const uint8_t y) {
|
||||||
|
if (firstRun) {
|
||||||
|
setCursor(x,y);
|
||||||
|
Serial.printf("%15s: %06d\n", name, val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setCursor(x+16, y);
|
||||||
|
Serial.print(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printField(const char name[], const int64_t val, const uint8_t x, const uint8_t y) {
|
||||||
|
if (firstRun) {
|
||||||
|
setCursor(x,y);
|
||||||
|
Serial.printf("%15s: %06u\n", name, (uint64_t)val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setCursor(x+16, y);
|
||||||
|
Serial.print((uint64_t)val);
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void printField(const char name[], const float val, const uint8_t x, const uint8_t y) {
|
||||||
|
if (firstRun) {
|
||||||
|
setCursor(x,y);
|
||||||
|
Serial.printf("%15s: %4.2f\n", name, val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setCursor(x+16, y);
|
||||||
|
Serial.print(val);
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void printField(const char name[], const char *val, const uint8_t x, const uint8_t y) {
|
||||||
|
if (firstRun) {
|
||||||
|
setCursor(x,y);
|
||||||
|
Serial.printf("%15s: %s\n", name, val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setCursor(x+16, y);
|
||||||
|
Serial.print(val);
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
14
RotaxMonitor/src/utils.cpp
Normal file
14
RotaxMonitor/src/utils.cpp
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
std::string printBits(uint32_t value) {
|
||||||
|
std::string result;
|
||||||
|
for (int i = 31; i >= 0; i--) {
|
||||||
|
// ottieni il singolo bit
|
||||||
|
result += ((value >> i) & 1) ? '1' : '0';
|
||||||
|
// aggiungi uno spazio ogni 8 bit, tranne dopo l'ultimo
|
||||||
|
if (i % 8 == 0 && i != 0) {
|
||||||
|
result += ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -3,15 +3,4 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
std::string printBits(uint32_t value) {
|
std::string printBits(uint32_t value);
|
||||||
std::string result;
|
|
||||||
for (int i = 31; i >= 0; i--) {
|
|
||||||
// ottieni il singolo bit
|
|
||||||
result += ((value >> i) & 1) ? '1' : '0';
|
|
||||||
// aggiungi uno spazio ogni 8 bit, tranne dopo l'ultimo
|
|
||||||
if (i % 8 == 0 && i != 0) {
|
|
||||||
result += ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|||||||
5
RotaxMonitorTester/.gitignore
vendored
Normal file
5
RotaxMonitorTester/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.pio
|
||||||
|
.vscode/.browse.c_cpp.db*
|
||||||
|
.vscode/c_cpp_properties.json
|
||||||
|
.vscode/launch.json
|
||||||
|
.vscode/ipch
|
||||||
10
RotaxMonitorTester/.vscode/extensions.json
vendored
Normal file
10
RotaxMonitorTester/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"Jason2866.esp-decoder",
|
||||||
|
"pioarduino.pioarduino-ide",
|
||||||
|
"platformio.platformio-ide"
|
||||||
|
],
|
||||||
|
"unwantedRecommendations": [
|
||||||
|
"ms-vscode.cpptools-extension-pack"
|
||||||
|
]
|
||||||
|
}
|
||||||
37
RotaxMonitorTester/include/README
Normal file
37
RotaxMonitorTester/include/README
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
This directory is intended for project header files.
|
||||||
|
|
||||||
|
A header file is a file containing C declarations and macro definitions
|
||||||
|
to be shared between several project source files. You request the use of a
|
||||||
|
header file in your project source file (C, C++, etc) located in `src` folder
|
||||||
|
by including it, with the C preprocessing directive `#include'.
|
||||||
|
|
||||||
|
```src/main.c
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Including a header file produces the same results as copying the header file
|
||||||
|
into each source file that needs it. Such copying would be time-consuming
|
||||||
|
and error-prone. With a header file, the related declarations appear
|
||||||
|
in only one place. If they need to be changed, they can be changed in one
|
||||||
|
place, and programs that include the header file will automatically use the
|
||||||
|
new version when next recompiled. The header file eliminates the labor of
|
||||||
|
finding and changing all the copies as well as the risk that a failure to
|
||||||
|
find one copy will result in inconsistencies within a program.
|
||||||
|
|
||||||
|
In C, the convention is to give header files names that end with `.h'.
|
||||||
|
|
||||||
|
Read more about using header files in official GCC documentation:
|
||||||
|
|
||||||
|
* Include Syntax
|
||||||
|
* Include Operation
|
||||||
|
* Once-Only Headers
|
||||||
|
* Computed Includes
|
||||||
|
|
||||||
|
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||||
46
RotaxMonitorTester/lib/README
Normal file
46
RotaxMonitorTester/lib/README
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
This directory is intended for project specific (private) libraries.
|
||||||
|
PlatformIO will compile them to static libraries and link into the executable file.
|
||||||
|
|
||||||
|
The source code of each library should be placed in a separate directory
|
||||||
|
("lib/your_library_name/[Code]").
|
||||||
|
|
||||||
|
For example, see the structure of the following example libraries `Foo` and `Bar`:
|
||||||
|
|
||||||
|
|--lib
|
||||||
|
| |
|
||||||
|
| |--Bar
|
||||||
|
| | |--docs
|
||||||
|
| | |--examples
|
||||||
|
| | |--src
|
||||||
|
| | |- Bar.c
|
||||||
|
| | |- Bar.h
|
||||||
|
| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||||
|
| |
|
||||||
|
| |--Foo
|
||||||
|
| | |- Foo.c
|
||||||
|
| | |- Foo.h
|
||||||
|
| |
|
||||||
|
| |- README --> THIS FILE
|
||||||
|
|
|
||||||
|
|- platformio.ini
|
||||||
|
|--src
|
||||||
|
|- main.c
|
||||||
|
|
||||||
|
Example contents of `src/main.c` using Foo and Bar:
|
||||||
|
```
|
||||||
|
#include <Foo.h>
|
||||||
|
#include <Bar.h>
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
The PlatformIO Library Dependency Finder will find automatically dependent
|
||||||
|
libraries by scanning project source files.
|
||||||
|
|
||||||
|
More information about PlatformIO Library Dependency Finder
|
||||||
|
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||||
39
RotaxMonitorTester/platformio.ini
Normal file
39
RotaxMonitorTester/platformio.ini
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
[env:esp32-devtest-release]
|
||||||
|
board = esp32dev
|
||||||
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/stable/platform-espressif32.zip
|
||||||
|
framework = arduino
|
||||||
|
lib_deps =
|
||||||
|
hideakitai/DebugLog@^0.8.4
|
||||||
|
board_build.flash_size = 4MB
|
||||||
|
board_build.partitions = default.csv
|
||||||
|
monitor_speed = 115200
|
||||||
|
build_type = release
|
||||||
|
|
||||||
|
[env:esp32-devtest-debug]
|
||||||
|
board = esp32dev
|
||||||
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/stable/platform-espressif32.zip
|
||||||
|
|
||||||
|
lib_deps =
|
||||||
|
hideakitai/DebugLog@^0.8.4
|
||||||
|
board_build.flash_size = 4MB
|
||||||
|
board_build.partitions = default.csv
|
||||||
|
monitor_speed = 115200
|
||||||
|
build_type = debug
|
||||||
|
build_flags =
|
||||||
|
-O0
|
||||||
|
-g3
|
||||||
|
-ggdb
|
||||||
|
-fno-inline
|
||||||
|
-fno-ipa-sra
|
||||||
|
-fno-tree-sra
|
||||||
|
-fno-builtin
|
||||||
108
RotaxMonitorTester/src/main.cpp
Normal file
108
RotaxMonitorTester/src/main.cpp
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <DebugLog.h>
|
||||||
|
|
||||||
|
#include "timer.h"
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
static hw_timer_t *timerA = NULL;
|
||||||
|
static hw_timer_t *timerB = NULL;
|
||||||
|
TaskHandle_t main_t = NULL;
|
||||||
|
static uint32_t count = 0;
|
||||||
|
|
||||||
|
#define FREQUENCY 100000 // 100 KHz
|
||||||
|
#define PERIOD_US 10
|
||||||
|
|
||||||
|
#define SPARK_DLY_MIN 10
|
||||||
|
#define SPARK_DLY_MAX 490
|
||||||
|
|
||||||
|
#define PAUSE_LONG_MIN 5000
|
||||||
|
#define PAUSE_LONG_MAX PAUSE_LONG_MIN*100
|
||||||
|
|
||||||
|
void clearScreen(){
|
||||||
|
Serial.print("\033[2J"); // clear screen
|
||||||
|
Serial.print("\033[H"); // cursor home
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
static double filtered = 0;
|
||||||
|
|
||||||
|
static const std::map<const uint32_t, const char *> pin2Name = {
|
||||||
|
{PIN_TRIG_A12P, "HIGH_PIN_TRIG_A12P"},
|
||||||
|
{~PIN_TRIG_A12P, "LOW_PIN_TRIG_A12P"},
|
||||||
|
{PIN_TRIG_A12N, "HIGH_PIN_TRIG_A12N"},
|
||||||
|
{~PIN_TRIG_A12N, "LOW_PIN_TRIG_A12N"},
|
||||||
|
{PIN_TRIG_A34P, "HIGH_PIN_TRIG_A34P"},
|
||||||
|
{~PIN_TRIG_A34P, "LOW_PIN_TRIG_A34P"},
|
||||||
|
{PIN_TRIG_A34N, "HIGH_PIN_TRIG_A34N"},
|
||||||
|
{~PIN_TRIG_A34N, "LOW_PIN_TRIG_A34N"},
|
||||||
|
{SPARK_A12, "HIGH_SPARK_A12"},
|
||||||
|
{~SPARK_A12, "LOW_SPARK_A12"},
|
||||||
|
{SPARK_A34, "HIGH_SPARK_A34"},
|
||||||
|
{~SPARK_A34, "LOW_SPARK_A34"},
|
||||||
|
{State::S_WAIT_10MS_END, "S_WAIT_10MS_END"},
|
||||||
|
{State::S_WAIT_10MS, "S_WAIT_10MS"}};
|
||||||
|
|
||||||
|
static timerStatus stsA = {
|
||||||
|
.clock_period_us = (uint32_t)PERIOD_US,
|
||||||
|
.pause_long_us = 10000,
|
||||||
|
.pause_short_us = 1000,
|
||||||
|
.coil_pulse_us = 1000,
|
||||||
|
.spark_pulse_us = 100,
|
||||||
|
.spark_delay_us = 50,
|
||||||
|
.main_task = NULL};
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
delay(1000);
|
||||||
|
LOG_ATTACH_SERIAL(Serial);
|
||||||
|
|
||||||
|
pinMode(PIN_TRIG_A12P, OUTPUT);
|
||||||
|
pinMode(PIN_TRIG_A12N, OUTPUT);
|
||||||
|
pinMode(PIN_TRIG_A34P, OUTPUT);
|
||||||
|
pinMode(PIN_TRIG_A34N, OUTPUT);
|
||||||
|
pinMode(SPARK_A12, OUTPUT);
|
||||||
|
pinMode(SPARK_A34, OUTPUT);
|
||||||
|
|
||||||
|
pinMode(PIN_TRIG_B12P, OUTPUT);
|
||||||
|
pinMode(PIN_TRIG_B12N, OUTPUT);
|
||||||
|
pinMode(PIN_TRIG_B34P, OUTPUT);
|
||||||
|
pinMode(PIN_TRIG_B34N, OUTPUT);
|
||||||
|
pinMode(SPARK_B12, OUTPUT);
|
||||||
|
pinMode(SPARK_B34, OUTPUT);
|
||||||
|
|
||||||
|
pinMode(SPARK_DELAY_POT, ANALOG);
|
||||||
|
stsA.main_task = xTaskGetCurrentTaskHandleForCore(1);
|
||||||
|
|
||||||
|
timerA = timerBegin(FREQUENCY);
|
||||||
|
timerAttachInterruptArg(timerA, &onTimer, (void *)&stsA);
|
||||||
|
timerAlarm(timerA, 1, true, 0);
|
||||||
|
|
||||||
|
LOG_INFO("Setup Complete");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
LOG_INFO("Loop: ", count++);
|
||||||
|
uint32_t spark_delay = (uint32_t)(map(analogRead(SPARK_DELAY_POT), 0, 4096, SPARK_DLY_MIN, SPARK_DLY_MAX) / PERIOD_US);
|
||||||
|
stsA.spark_delay_us = spark_delay * PERIOD_US;
|
||||||
|
if (stsA.spark_delay_us > (SPARK_DLY_MIN + SPARK_DLY_MAX) / 2) {
|
||||||
|
stsA.soft_start = true;
|
||||||
|
stsA.spark_delay_us -= (SPARK_DLY_MIN + SPARK_DLY_MAX) / 2;
|
||||||
|
} else {
|
||||||
|
stsA.soft_start = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double new_val = (float)(map(analogRead(FREQ_POT), 0, 4096, PAUSE_LONG_MIN, PAUSE_LONG_MAX));
|
||||||
|
filtered = filtered + 0.1 * (new_val - filtered);
|
||||||
|
stsA.pause_long_us = (uint32_t)filtered;
|
||||||
|
LOG_INFO("Spark Delay uS: ", stsA.spark_delay_us, "\tSoft Start: ", stsA.soft_start ? "TRUE" : "FALSE");
|
||||||
|
LOG_INFO("Pause: ", (uint32_t)(stsA.pause_long_us / 1000), "ms");
|
||||||
|
LOG_INFO("Coil Pulse: ", stsA.coil_pulse_us, "us");
|
||||||
|
LOG_INFO("Spark Pulse: ", stsA.spark_pulse_us, "us");
|
||||||
|
|
||||||
|
|
||||||
|
delay(100);
|
||||||
|
clearScreen();
|
||||||
|
}
|
||||||
23
RotaxMonitorTester/src/pins.h
Normal file
23
RotaxMonitorTester/src/pins.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
///// Ignition Box A /////
|
||||||
|
#define PIN_TRIG_A12P 18
|
||||||
|
#define PIN_TRIG_A12N 19
|
||||||
|
#define PIN_TRIG_A34P 21
|
||||||
|
#define PIN_TRIG_A34N 22
|
||||||
|
|
||||||
|
#define SPARK_A12 23
|
||||||
|
#define SPARK_A34 25
|
||||||
|
|
||||||
|
///// Ignition Box /////
|
||||||
|
#define PIN_TRIG_B12P 26
|
||||||
|
#define PIN_TRIG_B12N 27
|
||||||
|
#define PIN_TRIG_B34P 32
|
||||||
|
#define PIN_TRIG_B34N 33
|
||||||
|
|
||||||
|
#define SPARK_B12 4
|
||||||
|
#define SPARK_B34 5
|
||||||
|
|
||||||
|
// Pot
|
||||||
|
#define SPARK_DELAY_POT 13
|
||||||
|
#define FREQ_POT 14
|
||||||
192
RotaxMonitorTester/src/timer.cpp
Normal file
192
RotaxMonitorTester/src/timer.cpp
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
#include "timer.h"
|
||||||
|
|
||||||
|
volatile static bool wait_sent = false;
|
||||||
|
|
||||||
|
void onTimer(void *arg)
|
||||||
|
{
|
||||||
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
timerStatus *params = (timerStatus *)(arg);
|
||||||
|
TaskHandle_t task = params->main_task;
|
||||||
|
|
||||||
|
// increment state time
|
||||||
|
params->state_time += params->clock_period_us;
|
||||||
|
|
||||||
|
digitalWrite(PIN_TRIG_B12P, HIGH);
|
||||||
|
|
||||||
|
switch (params->state)
|
||||||
|
{
|
||||||
|
|
||||||
|
case S_12P:
|
||||||
|
if (params->state_time == params->clock_period_us && !params->coil12p_high)
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, PIN_TRIG_A12P, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
digitalWrite(PIN_TRIG_A12P, HIGH);
|
||||||
|
params->coil12p_high = true;
|
||||||
|
wait_sent = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params->soft_start)
|
||||||
|
{
|
||||||
|
if (params->state_time == params->spark_delay_us)
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, SPARK_A12, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
digitalWrite(SPARK_A12, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->state_time == (params->spark_delay_us + params->spark_pulse_us))
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, ~SPARK_A12, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
digitalWrite(SPARK_A12, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->state_time >= params->coil_pulse_us && params->coil12p_high)
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, ~PIN_TRIG_A12P, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
digitalWrite(PIN_TRIG_A12P, LOW);
|
||||||
|
params->coil12p_high = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->state_time >= params->pause_short_us)
|
||||||
|
{
|
||||||
|
params->state = S_12N;
|
||||||
|
params->state_time = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_12N:
|
||||||
|
if (params->state_time == params->clock_period_us && !params->coil12n_high)
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, PIN_TRIG_A12N, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
digitalWrite(PIN_TRIG_A12N, HIGH);
|
||||||
|
params->coil12n_high = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->soft_start)
|
||||||
|
{
|
||||||
|
if (params->state_time == params->spark_delay_us)
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, SPARK_A12, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
digitalWrite(SPARK_A12, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->state_time == (params->spark_delay_us + params->spark_pulse_us))
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, ~SPARK_A12, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
digitalWrite(SPARK_A12, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->state_time >= params->coil_pulse_us && params->coil12n_high)
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, ~PIN_TRIG_A12N, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
digitalWrite(PIN_TRIG_A12N, LOW);
|
||||||
|
params->coil12n_high = false;
|
||||||
|
params->state = S_WAIT_10MS;
|
||||||
|
params->state_time = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_WAIT_10MS:
|
||||||
|
if (!wait_sent)
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, S_WAIT_10MS, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
wait_sent = true;
|
||||||
|
}
|
||||||
|
if (params->state_time >= params->pause_long_us)
|
||||||
|
{
|
||||||
|
params->state = S_34P;
|
||||||
|
params->state_time = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_34P:
|
||||||
|
if (params->state_time == params->clock_period_us && !params->coil34p_high)
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, PIN_TRIG_A34P, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
digitalWrite(PIN_TRIG_A34P, HIGH);
|
||||||
|
params->coil34p_high = true;;
|
||||||
|
wait_sent = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params->soft_start)
|
||||||
|
{
|
||||||
|
if (params->state_time == params->spark_delay_us)
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, SPARK_A34, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
digitalWrite(SPARK_A34, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->state_time == params->spark_delay_us + params->spark_pulse_us)
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, ~SPARK_A34, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
digitalWrite(SPARK_A34, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->state_time >= params->coil_pulse_us && params->coil34p_high)
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, ~PIN_TRIG_A34P, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
digitalWrite(PIN_TRIG_A34P, LOW);
|
||||||
|
params->coil34p_high = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->state_time >= params->pause_short_us)
|
||||||
|
{
|
||||||
|
params->state = S_34N;
|
||||||
|
params->state_time = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_34N:
|
||||||
|
if (params->state_time == params->clock_period_us && !params->coil34n_high)
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, PIN_TRIG_A34N, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
digitalWrite(PIN_TRIG_A34N, HIGH);
|
||||||
|
params->coil34n_high = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->soft_start)
|
||||||
|
{
|
||||||
|
if (params->state_time == params->spark_delay_us)
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, SPARK_A34, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
digitalWrite(SPARK_A34, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->state_time == params->spark_delay_us + params->spark_pulse_us)
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, ~SPARK_A34, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
digitalWrite(SPARK_A34, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->state_time >= params->coil_pulse_us && params->coil34n_high)
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, ~PIN_TRIG_A34N, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
digitalWrite(PIN_TRIG_A34N, LOW);
|
||||||
|
params->coil34n_high = false;
|
||||||
|
params->state = S_WAIT_10MS_END;
|
||||||
|
params->state_time = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_WAIT_10MS_END:
|
||||||
|
if (!wait_sent)
|
||||||
|
{
|
||||||
|
// xTaskNotifyFromISR(task, S_WAIT_10MS_END, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
|
||||||
|
wait_sent = true;
|
||||||
|
}
|
||||||
|
if (params->state_time >= params->pause_long_us)
|
||||||
|
{
|
||||||
|
params->state = S_12P;
|
||||||
|
params->state_time = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
digitalWrite(PIN_TRIG_B12P, LOW);
|
||||||
|
|
||||||
|
if (xHigherPriorityTaskWoken)
|
||||||
|
portYIELD_FROM_ISR();
|
||||||
|
}
|
||||||
40
RotaxMonitorTester/src/timer.h
Normal file
40
RotaxMonitorTester/src/timer.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <DebugLog.h>
|
||||||
|
#include "pins.h"
|
||||||
|
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
|
||||||
|
enum State
|
||||||
|
{
|
||||||
|
S_12P,
|
||||||
|
S_12N_DELAY,
|
||||||
|
S_12N,
|
||||||
|
S_WAIT_10MS,
|
||||||
|
S_34P,
|
||||||
|
S_34N_DELAY,
|
||||||
|
S_34N,
|
||||||
|
S_WAIT_1MS,
|
||||||
|
S_WAIT_10MS_END
|
||||||
|
};
|
||||||
|
|
||||||
|
struct timerStatus
|
||||||
|
{
|
||||||
|
State state = State::S_12P;
|
||||||
|
uint32_t state_time = 0;
|
||||||
|
uint32_t clock_period_us;
|
||||||
|
uint32_t pause_long_us;
|
||||||
|
uint32_t pause_short_us;
|
||||||
|
uint32_t coil_pulse_us;
|
||||||
|
uint32_t spark_pulse_us;
|
||||||
|
uint32_t spark_delay_us;
|
||||||
|
bool soft_start = false;
|
||||||
|
bool coil12p_high = false;
|
||||||
|
bool coil34p_high = false;
|
||||||
|
bool coil12n_high = false;
|
||||||
|
bool coil34n_high = false;
|
||||||
|
TaskHandle_t main_task;
|
||||||
|
};
|
||||||
|
|
||||||
|
void IRAM_ATTR onTimer(void *arg);
|
||||||
11
RotaxMonitorTester/test/README
Normal file
11
RotaxMonitorTester/test/README
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
This directory is intended for PlatformIO Test Runner and project tests.
|
||||||
|
|
||||||
|
Unit Testing is a software testing method by which individual units of
|
||||||
|
source code, sets of one or more MCU program modules together with associated
|
||||||
|
control data, usage procedures, and operating procedures, are tested to
|
||||||
|
determine whether they are fit for use. Unit testing finds problems early
|
||||||
|
in the development cycle.
|
||||||
|
|
||||||
|
More information about PlatformIO Unit Testing:
|
||||||
|
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
||||||
Reference in New Issue
Block a user