1 Commits

Author SHA1 Message Date
Obbart 59e4e955ff Merged for debug 2026-04-21 16:08:34 +02:00
48 changed files with 26862 additions and 2178 deletions
-1
View File
@@ -3,4 +3,3 @@
.vscode/c_cpp_properties.json .vscode/c_cpp_properties.json
.vscode/launch.json .vscode/launch.json
.vscode/ipch .vscode/ipch
unpacked_fs
+2 -1
View File
@@ -1,7 +1,8 @@
{ {
"recommendations": [ "recommendations": [
"Jason2866.esp-decoder", "Jason2866.esp-decoder",
"pioarduino.pioarduino-ide" "pioarduino.pioarduino-ide",
"platformio.platformio-ide"
], ],
"unwantedRecommendations": [ "unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack" "ms-vscode.cpptools-extension-pack"
File diff suppressed because one or more lines are too long
-212
View File
@@ -1,212 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Astro Rotax Monitor</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header class="page-header">
<div class="header-content">
<img src="logo_astro_dev.svg" alt="Astro Tecnologie" class="logo">
</div>
<div>
<h1>Rotax Ignition Box Monitor</h1>
</div>
</header>
<!-- TAB BUTTONS -->
<div class="tabs">
<button class="tab-button active" onclick="openTab('tab1')">Monitor</button>
<button class="tab-button" onclick="openTab('tab2')">Grafico</button>
</div>
<!-- TAB 1 (contenuto attuale) -->
<div id="tab1" class="tab-content active">
<div id="loadingIndicator" class="loading-indicator">
<span class="spinner"></span> Waiting for data...
</div>
<div class="tables-container">
<div class="box">
<h2>Box_A</h2>
<div class="box-data">
<p><strong>Timestamp:</strong> <span id="a_timestamp">-</span></p>
<p><strong>Data Valid:</strong> <span id="a_datavalid">-</span></p>
<p><strong>Generator voltage:</strong> <span id="a_volts_gen">-</span></p>
<p><strong>ADC read time:</strong> <span id="a_adc_read_time">-</span></p>
<p><strong>Queue errors:</strong> <span id="a_n_queue_errors">-</span></p>
</div>
<div class="rpm-highlight">
<strong>Engine RPM:</strong> <span id="a_eng_rpm">-</span>
</div>
<table>
<thead>
<tr>
<th>Property</th>
<th>Pickup 12</th>
<th>Pickup 34</th>
</tr>
</thead>
<tbody>
<tr>
<td>Spark delay</td>
<td id="a_coils12_spark_delay">-</td>
<td id="a_coils34_spark_delay">-</td>
</tr>
<tr>
<td>Spark status</td>
<td id="a_coils12_spark_status">-</td>
<td id="a_coils34_spark_status">-</td>
</tr>
<tr>
<td>Soft start status</td>
<td id="a_coils12_sstart_status">-</td>
<td id="a_coils34_sstart_status">-</td>
</tr>
<tr>
<td>Peak P in</td>
<td id="a_coils12_peak_p_in">-</td>
<td id="a_coils34_peak_p_in">-</td>
</tr>
<tr>
<td>Peak N in</td>
<td id="a_coils12_peak_n_in">-</td>
<td id="a_coils34_peak_n_in">-</td>
</tr>
<tr>
<td>Peak P out</td>
<td id="a_coils12_peak_p_out">-</td>
<td id="a_coils34_peak_p_out">-</td>
</tr>
<tr>
<td>Peak N out</td>
<td id="a_coils12_peak_n_out">-</td>
<td id="a_coils34_peak_n_out">-</td>
</tr>
<tr>
<td>Level spark</td>
<td id="a_coils12_level_spark">-</td>
<td id="a_coils34_level_spark">-</td>
</tr>
<tr>
<td>Spark Events</td>
<td id="a_coils12_n_events">-</td>
<td id="a_coils34_n_events">-</td>
</tr>
<tr>
<td>Missed Events</td>
<td id="a_coils12_n_missed_firing">-</td>
<td id="a_coils34_n_missed_firing">-</td>
</tr>
</tbody>
</table>
</div>
<div class="box">
<h2>Box_B</h2>
<div class="box-data">
<p><strong>Timestamp:</strong> <span id="b_timestamp">-</span></p>
<p><strong>Data Valid:</strong> <span id="b_datavalid">-</span></p>
<p><strong>Generator voltage:</strong> <span id="b_volts_gen">-</span></p>
<p><strong>ADC read time:</strong> <span id="b_adc_read_time">-</span></p>
<p><strong>Queue errors:</strong> <span id="b_n_queue_errors">-</span></p>
</div>
<div class="rpm-highlight">
<strong>Engine RPM:</strong> <span id="b_eng_rpm">-</span>
</div>
<table>
<thead>
<tr>
<th>Property</th>
<th>Pickup 12</th>
<th>Pickup 34</th>
</tr>
</thead>
<tbody>
<tr>
<td>Spark delay</td>
<td id="b_coils12_spark_delay">-</td>
<td id="b_coils34_spark_delay">-</td>
</tr>
<tr>
<td>Spark status</td>
<td id="b_coils12_spark_status">-</td>
<td id="b_coils34_spark_status">-</td>
</tr>
<tr>
<td>Soft start status</td>
<td id="b_coils12_sstart_status">-</td>
<td id="b_coils34_sstart_status">-</td>
</tr>
<tr>
<td>Peak P in</td>
<td id="b_coils12_peak_p_in">-</td>
<td id="b_coils34_peak_p_in">-</td>
</tr>
<tr>
<td>Peak N in</td>
<td id="b_coils12_peak_n_in">-</td>
<td id="b_coils34_peak_n_in">-</td>
</tr>
<tr>
<td>Peak P out</td>
<td id="b_coils12_peak_p_out">-</td>
<td id="b_coils34_peak_p_out">-</td>
</tr>
<tr>
<td>Peak N out</td>
<td id="b_coils12_peak_n_out">-</td>
<td id="b_coils34_peak_n_out">-</td>
</tr>
<tr>
<td>Level spark</td>
<td id="b_coils12_level_spark">-</td>
<td id="b_coils34_level_spark">-</td>
</tr>
<tr>
<td>Spark Events</td>
<td id="b_coils12_n_events">-</td>
<td id="b_coils34_n_events">-</td>
</tr>
<tr>
<td>Missed Events</td>
<td id="b_coils12_n_missed_firing">-</td>
<td id="b_coils34_n_missed_firing">-</td>
</tr>
</tbody>
</table>
</div>
</div>
</div> <!-- END TAB1 -->
<!-- TAB 2 (grafico) -->
<div id="tab2" class="tab-content">
<div class="chart-container">
<h3>Box A</h3>
<canvas id="chartA" height="100"></canvas>
</div>
<div class="chart-container">
<h3>Box B</h3>
<canvas id="chartB" height="100"></canvas>
</div>
</div>
</body>
<div class="upload-section">
<h3>Upload file to Flash</h3>
<p>Select a file and upload it to Flash.</p>
<input type="file" id="littlefsFile">
<button onclick="uploadLittleFS()">Upload</button>
<div id="uploadStatus" class="upload-status">No file uploaded yet.</div>
</div>
<script src="chart.js"></script>
<script src="script.js"></script>
</html>
File diff suppressed because it is too large Load Diff
-32
View File
@@ -1,32 +0,0 @@
#include <led.h>
RGBled::RGBled(const uint8_t pin) : m_led(pin)
{
pinMode(m_led, OUTPUT);
writeStatus(RGBled::ERROR);
}
RGBled::~RGBled()
{
pinMode(m_led, INPUT);
}
void RGBled::setStatus(const LedStatus s)
{
if (m_status == s)
return;
std::lock_guard<std::mutex> lock(m_mutex);
m_status = s;
writeStatus(m_status);
}
const RGBled::LedStatus RGBled::getSatus(void)
{
return m_status;
}
void RGBled::writeStatus(const RGBled::LedStatus s)
{
RGBled::color_u u{.status = s};
rgbLedWrite(m_led, u.color.r, u.color.g, u.color.b);
}
-63
View File
@@ -1,63 +0,0 @@
#pragma once
// System Inlcudes
#include <Arduino.h>
#include <mutex>
#define RED 0x00FF00
#define GREEN 0xFF0000
#define BLUE 0x0000FF
#define WHITE 0xFFFFFF
#define YELLOW 0xFFFF00
#define CYAN 0xFF00FF
#define MAGENTA 0x00FFFF
#define ORANGE 0xA5FF00
#define PURPLE 0x008080
#define PINK 0x69FFB4
#define LIME 0xCD3232
#define SKY_BLUE 0xCE87EB
#define GOLD 0xD7FF00
#define TURQUOISE 0xE040D0
#define INDIGO 0x004B82
#define GRAY 0x808080
class RGBled
{
public:
enum LedStatus
{
OK = GREEN,
ERROR = RED,
INIT = YELLOW,
DATA_A = CYAN,
DATA_B = MAGENTA,
DATA_ALL = ORANGE,
IDLE = GRAY
};
struct color_t
{
uint8_t a, r, g, b;
};
union color_u
{
uint32_t status;
color_t color;
};
public:
RGBled(const uint8_t pin = 48);
~RGBled();
void setStatus(const LedStatus s);
const LedStatus getSatus(void);
private:
void writeStatus(const LedStatus s);
private:
LedStatus m_status = LedStatus::IDLE;
std::mutex m_mutex;
const uint8_t m_led;
};
+6
View File
@@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x700000,
app1, app, ota_1, 0x710000,0x700000,
spiffs, data, spiffs, 0xE10000,0x1F0000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x700000
5 app1 app ota_1 0x710000 0x700000
6 spiffs data spiffs 0xE10000 0x1F0000
@@ -1,6 +0,0 @@
# ESP32 Partition Table
# Name, Type, SubType, Offset, Size
nvs, data, nvs, 0x9000, 0x4000
phy_init, data, phy, 0xd000, 0x1000
factory, app, factory, 0x10000, 0x300000
littlefs, data, littlefs, 0x310000, 0xCF0000
1 # ESP32 Partition Table
2 # Name, Type, SubType, Offset, Size
3 nvs, data, nvs, 0x9000, 0x4000
4 phy_init, data, phy, 0xd000, 0x1000
5 factory, app, factory, 0x10000, 0x300000
6 littlefs, data, littlefs, 0x310000, 0xCF0000
@@ -1,6 +0,0 @@
# ESP32 Partition Table
# Name, Type, SubType, Offset, Size
nvs, data, nvs, 0x9000, 0x4000
phy_init, data, phy, 0xd000, 0x1000
factory, app, factory, 0x10000, 0x300000
spiffs, data, spiffs, 0x310000, 0xCF0000
1 # ESP32 Partition Table
2 # Name, Type, SubType, Offset, Size
3 nvs, data, nvs, 0x9000, 0x4000
4 phy_init, data, phy, 0xd000, 0x1000
5 factory, app, factory, 0x10000, 0x300000
6 spiffs, data, spiffs, 0x310000, 0xCF0000
+19 -17
View File
@@ -10,8 +10,6 @@
[env:esp32-s3-devkitc1-n16r8] [env:esp32-s3-devkitc1-n16r8]
board = esp32-s3-devkitc1-n16r8 board = esp32-s3-devkitc1-n16r8
board_build.partitions = partitions/no_ota_10mb_littlefs.csv
board_build.filesystem = littlefs
platform = https://github.com/pioarduino/platform-espressif32/releases/download/stable/platform-espressif32.zip platform = https://github.com/pioarduino/platform-espressif32/releases/download/stable/platform-espressif32.zip
framework = arduino framework = arduino
lib_deps = lib_deps =
@@ -20,40 +18,45 @@ lib_deps =
hideakitai/PCA95x5@^0.1.3 hideakitai/PCA95x5@^0.1.3
me-no-dev/AsyncTCP@^3.3.2 me-no-dev/AsyncTCP@^3.3.2
me-no-dev/ESPAsyncWebServer@^3.6.0 me-no-dev/ESPAsyncWebServer@^3.6.0
adafruit/Adafruit NeoPixel@^1.15.4
upload_protocol = esptool upload_protocol = esptool
upload_port = /dev/ttyACM1 upload_port = /dev/ttyACM2
upload_speed = 921600 upload_speed = 921600
monitor_port = /dev/ttyACM0
monitor_speed = 921600 ;Monitor configuration
monitor_speed = 115200
monitor_port = /dev/ttyACM2
; Build configuration
build_type = release build_type = release
build_flags = build_flags =
-DCORE_DEBUG_LEVEL=1 -DCORE_DEBUG_LEVEL=3
-DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_CDC_ON_BOOT=0
-DARDUINO_USB_MODE=0 -DARDUINO_USB_MODE=0
-DCONFIG_ASYNC_TCP_MAX_ACK_TIME=5000 -DCONFIG_ASYNC_TCP_MAX_ACK_TIME=5000
-DCONFIG_ASYNC_TCP_PRIORITY=21 -DCONFIG_ASYNC_TCP_PRIORITY=21
-DCONFIG_ASYNC_TCP_QUEUE_SIZE=64 -DCONFIG_ASYNC_TCP_QUEUE_SIZE=128
-DCONFIG_ASYNC_TCP_RUNNING_CORE=1 -DCONFIG_ASYNC_TCP_RUNNING_CORE=1
-DCONFIG_ASYNC_TCP_STACK_SIZE=4096 -DCONFIG_ASYNC_TCP_STACK_SIZE=8192
-fstack-protector-all
[env:esp32-s3-devkitc1-n16r8-debug] [env:esp32-s3-devkitc1-n16r8-debug]
board = ${env:esp32-s3-devkitc1-n16r8.board} board = ${env:esp32-s3-devkitc1-n16r8.board}
board_build.partitions = ${env:esp32-s3-devkitc1-n16r8.board_build.partitions}
board_build.filesystem = ${env:esp32-s3-devkitc1-n16r8.board_build.filesystem}
platform = ${env:esp32-s3-devkitc1-n16r8.platform} platform = ${env:esp32-s3-devkitc1-n16r8.platform}
framework = ${env:esp32-s3-devkitc1-n16r8.framework} framework = ${env:esp32-s3-devkitc1-n16r8.framework}
lib_deps = lib_deps =
${env:esp32-s3-devkitc1-n16r8.lib_deps} ${env:esp32-s3-devkitc1-n16r8.lib_deps}
adafruit/Adafruit NeoPixel@^1.15.4
upload_protocol = esptool upload_protocol = esptool
upload_port = /dev/ttyACM1 upload_port = /dev/ttyACM2
upload_speed = 921600 upload_speed = 921600
monitor_port = /dev/ttyACM0
monitor_speed = 921600 ;Monitor configuration
monitor_speed = 115200
monitor_port = /dev/ttyACM2
; Debug configuration
debug_tool = esp-builtin debug_tool = esp-builtin
debug_speed = 15000 debug_speed = 15000
; Build configuration
build_type = debug build_type = debug
build_flags = build_flags =
-O0 -O0
@@ -67,4 +70,3 @@ build_flags =
-DCONFIG_ASYNC_TCP_QUEUE_SIZE=128 -DCONFIG_ASYNC_TCP_QUEUE_SIZE=128
-DCONFIG_ASYNC_TCP_RUNNING_CORE=1 -DCONFIG_ASYNC_TCP_RUNNING_CORE=1
-DCONFIG_ASYNC_TCP_STACK_SIZE=8192 -DCONFIG_ASYNC_TCP_STACK_SIZE=8192
-fstack-protector-all
+766
View File
@@ -0,0 +1,766 @@
//ADS1256 cpp file
/*
Name: ADS1256.cpp
Created: 2022/07/14
Author: Curious Scientist
Editor: Notepad++
Comment: Visit https://curiousscientist.tech/blog/ADS1256-custom-library
Special thanks to:
Abraão Queiroz for spending time on the code and suggesting corrections for ESP32 microcontrollers
Benjamin Pelletier for pointing out and fixing an issue around the handling of the DRDY signal
RadoMmm for suggesting an improvement on the ADC-to-Volts conversion
*/
#include "Arduino.h"
#include "ADS1256.h"
#include "SPI.h"
#define convertSigned24BitToLong(value) ((value) & (1l << 23) ? (value) - 0x1000000 : value)
//Constructor
ADS1256::ADS1256(const int8_t DRDY_pin, const int8_t RESET_pin, const int8_t SYNC_pin, const int8_t CS_pin,float VREF, SPIClass* spi): _spi(spi),
_DRDY_pin(DRDY_pin), _RESET_pin(RESET_pin), _SYNC_pin(SYNC_pin), _CS_pin(CS_pin), _VREF(VREF), _PGA(0)
{
pinMode(_DRDY_pin, INPUT);
if(RESET_pin != PIN_UNUSED)
{
pinMode(_RESET_pin, OUTPUT);
}
if(SYNC_pin != PIN_UNUSED)
{
pinMode(_SYNC_pin, OUTPUT);
}
if(CS_pin != PIN_UNUSED)
{
pinMode(_CS_pin, OUTPUT);
}
updateConversionParameter();
}
//Initialization
void ADS1256::InitializeADC()
{
//Chip select LOW
CS_LOW();
//We do a manual chip reset on the ADS1256 - Datasheet Page 27/ RESET
if(_RESET_pin != PIN_UNUSED)
{
digitalWrite(_RESET_pin, LOW);
delay(200);
digitalWrite(_RESET_pin, HIGH); //RESET is set to high
delay(1000);
}
//Sync pin is also treated if it is defined
if(_SYNC_pin != PIN_UNUSED)
{
digitalWrite(_SYNC_pin, HIGH); //RESET is set to high
}
#ifndef ADS1256_SPI_ALREADY_STARTED //Guard macro to allow external initialization of the SPI
_spi->begin();
#endif
//Applying arbitrary default values to speed up the starting procedure if the user just want to get quick readouts
//We both pass values to the variables and then send those values to the corresponding registers
delay(200);
_STATUS = 0b00110110; //BUFEN and ACAL enabled, Order is MSB, rest is read only
writeRegister(STATUS_REG, _STATUS);
delay(200);
_MUX = 0b00000001; //MUX AIN0+AIN1
writeRegister(MUX_REG, _MUX);
delay(200);
_ADCON = 0b00000000; //ADCON - CLK: OFF, SDCS: OFF, PGA = 0 (+/- 5 V)
writeRegister(ADCON_REG, _ADCON);
delay(200);
updateConversionParameter();
_DRATE = 0b10000010; //100SPS
writeRegister(DRATE_REG, _DRATE);
delay(200);
sendDirectCommand(0b11110000); //Offset and self-gain calibration
delay(200);
_isAcquisitionRunning = false; //MCU will be waiting to start a continuous acquisition
}
void ADS1256::waitForLowDRDY()
{
while (digitalRead(_DRDY_pin) == HIGH) {}
}
void ADS1256::waitForHighDRDY()
{
#if F_CPU >= 48000000 //Fast MCUs need this protection to wait until DRDY goes high after a conversion
while (digitalRead(_DRDY_pin) == LOW) {}
#endif
}
void ADS1256::stopConversion() //Sending SDATAC to stop the continuous conversion
{
waitForLowDRDY(); //SDATAC should be called after DRDY goes LOW (p35. Figure 33)
_spi->transfer(0b00001111); //Send SDATAC to the ADC
CS_HIGH(); //We finished the command sequence, so we switch it back to HIGH
_spi->endTransaction();
_isAcquisitionRunning = false; //Reset to false, so the MCU will be able to start a new conversion
}
void ADS1256::setDRATE(uint8_t drate) //Setting DRATE (sampling frequency)
{
writeRegister(DRATE_REG, drate);
_DRATE = drate;
delay(200);
}
void ADS1256::setMUX(uint8_t mux) //Setting MUX (input channel)
{
writeRegister(MUX_REG, mux);
_MUX = mux;
delay(200);
}
void ADS1256::setPGA(uint8_t pga) //Setting PGA (input voltage range)
{
_PGA = pga;
_ADCON = readRegister(ADCON_REG); //Read the most recent value of the register
_ADCON = (_ADCON & 0b11111000) | (_PGA & 0b00000111); // Clearing and then setting bits 2-0 based on pga
writeRegister(ADCON_REG, _ADCON);
delay(200);
updateConversionParameter(); //Update the multiplier according top the new PGA value
}
uint8_t ADS1256::getPGA() //Reading PGA from the ADCON register
{
uint8_t pgaValue = readRegister(ADCON_REG) & 0b00000111;
//Reading the ADCON_REG and keeping the first three bits.
return(pgaValue);
}
void ADS1256::setCLKOUT(uint8_t clkout) //Setting CLKOUT
{
_ADCON = readRegister(ADCON_REG); //Read the most recent value of the register
//Values: 0, 1, 2, 3
if(clkout == 0)
{
//00
bitWrite(_ADCON, 6, 0);
bitWrite(_ADCON, 5, 0);
}
else if(clkout == 1)
{
//01 (default)
bitWrite(_ADCON, 6, 0);
bitWrite(_ADCON, 5, 1);
}
else if(clkout == 2)
{
//10
bitWrite(_ADCON, 6, 1);
bitWrite(_ADCON, 5, 0);
}
else if(clkout == 3)
{
//11
bitWrite(_ADCON, 6, 1);
bitWrite(_ADCON, 5, 1);
}
else{}
writeRegister(ADCON_REG, _ADCON);
delay(100);
}
void ADS1256::setSDCS(uint8_t sdcs) //Setting SDCS
{
_ADCON = readRegister(ADCON_REG); //Read the most recent value of the register
//Values: 0, 1, 2, 3
if(sdcs == 0)
{
//00 (default)
bitWrite(_ADCON, 4, 0);
bitWrite(_ADCON, 3, 0);
}
else if(sdcs == 1)
{
//01
bitWrite(_ADCON, 4, 0);
bitWrite(_ADCON, 3, 1);
}
else if(sdcs == 2)
{
//10
bitWrite(_ADCON, 4, 1);
bitWrite(_ADCON, 3, 0);
}
else if(sdcs == 3)
{
//11
bitWrite(_ADCON, 4, 1);
bitWrite(_ADCON, 3, 1);
}
else{}
writeRegister(ADCON_REG, _ADCON);
delay(100);
}
void ADS1256::setByteOrder(uint8_t byteOrder) //Setting byte order (MSB/LSB)
{
_STATUS = readRegister(STATUS_REG); //Read the most recent value of the register
if(byteOrder == 0)
{
//Byte order is MSB (default)
bitWrite(_STATUS, 3, 0);
//Set value of _STATUS at the third bit to 0
}
else if(byteOrder == 1)
{
//Byte order is LSB
bitWrite(_STATUS, 3, 1);
//Set value of _STATUS at the third bit to 1
}
else{}
writeRegister(STATUS_REG, _STATUS);
delay(100);
}
uint8_t ADS1256::getByteOrder() //Getting byte order (MSB/LSB)
{
uint8_t statusValue = readRegister(STATUS_REG); //Read the whole STATUS register
return bitRead(statusValue, 3);
}
void ADS1256::setAutoCal(uint8_t acal) //Setting ACAL (Automatic SYSCAL)
{
_STATUS = readRegister(STATUS_REG); //Read the most recent value of the register
if(acal == 0)
{
//Auto-calibration is disabled (default)
bitWrite(_STATUS, 2, 0);
//_STATUS |= B00000000;
}
else if(acal == 1)
{
//Auto-calibration is enabled
bitWrite(_STATUS, 2, 1);
//_STATUS |= B00000100;
}
else{}
writeRegister(STATUS_REG, _STATUS);
delay(100);
}
uint8_t ADS1256::getAutoCal() //Getting ACAL (Automatic SYSCAL)
{
uint8_t statusValue = readRegister(STATUS_REG); //Read the whole STATUS register
return bitRead(statusValue, 2);
}
void ADS1256::setBuffer(uint8_t bufen) //Setting input buffer (Input impedance)
{
_STATUS = readRegister(STATUS_REG); //Read the most recent value of the register
if(bufen == 0)
{
//Analog input buffer is disabled (default)
//_STATUS |= B00000000;
bitWrite(_STATUS, 1, 0);
}
else if(bufen == 1)
{
//Analog input buffer is enabled (recommended)
//_STATUS |= B00000010;
bitWrite(_STATUS, 1, 1);
}
else{}
writeRegister(STATUS_REG, _STATUS);
delay(100);
}
uint8_t ADS1256::getBuffer() //Getting input buffer (Input impedance)
{
uint8_t statusValue = readRegister(STATUS_REG); //Read the whole STATUS register
return bitRead(statusValue, 1);
}
void ADS1256::setGPIO(uint8_t dir0, uint8_t dir1, uint8_t dir2, uint8_t dir3) //Setting GPIO
{
_GPIO = readRegister(IO_REG); //Read the most recent value of the register
//Default: 11100000 - DEC: 224 - Ref: p32 I/O section
//Sets D3-D0 as input or output
uint8_t GPIO_bit7, GPIO_bit6, GPIO_bit5, GPIO_bit4;
//Bit7: DIR3
if(dir3 == 1)
{
GPIO_bit7 = 1; //D3 is input (default)
}
else
{
GPIO_bit7 = 0; //D3 is output
}
bitWrite(_GPIO, 7, GPIO_bit7);
//-----------------------------------------------------
//Bit6: DIR2
if(dir2 == 1)
{
GPIO_bit6 = 1; //D2 is input (default)
}
else
{
GPIO_bit6 = 0; //D2 is output
}
bitWrite(_GPIO, 6, GPIO_bit6);
//-----------------------------------------------------
//Bit5: DIR1
if(dir1 == 1)
{
GPIO_bit5 = 1; //D1 is input (default)
}
else
{
GPIO_bit5 = 0; //D1 is output
}
bitWrite(_GPIO, 5, GPIO_bit5);
//-----------------------------------------------------
//Bit4: DIR0
if(dir0 == 1)
{
GPIO_bit4 = 1; //D0 is input
}
else
{
GPIO_bit4 = 0; //D0 is output (default)
}
bitWrite(_GPIO, 4, GPIO_bit4);
//-----------------------------------------------------
writeRegister(IO_REG, _GPIO);
delay(100);
}
void ADS1256::writeGPIO(uint8_t dir0value, uint8_t dir1value, uint8_t dir2value, uint8_t dir3value) //Writing GPIO
{
_GPIO = readRegister(IO_REG);
//Sets D3-D0 output values
//It is important that first one must use setGPIO, then writeGPIO
uint8_t GPIO_bit3, GPIO_bit2, GPIO_bit1, GPIO_bit0;
//Bit3: DIR3
if(dir3value == 1)
{
GPIO_bit3 = 1;
}
else
{
GPIO_bit3 = 0;
}
bitWrite(_GPIO, 3, GPIO_bit3);
//-----------------------------------------------------
//Bit2: DIR2
if(dir2value == 1)
{
GPIO_bit2 = 1;
}
else
{
GPIO_bit2 = 0;
}
bitWrite(_GPIO, 2, GPIO_bit2);
//-----------------------------------------------------
//Bit1: DIR1
if(dir1value == 1)
{
GPIO_bit1 = 1;
}
else
{
GPIO_bit1 = 0;
}
bitWrite(_GPIO, 1, GPIO_bit1);
//-----------------------------------------------------
//Bit0: DIR0
if(dir0value == 1)
{
GPIO_bit0 = 1;
}
else
{
GPIO_bit0 = 0;
}
bitWrite(_GPIO, 0, GPIO_bit0);
//-----------------------------------------------------
writeRegister(IO_REG, _GPIO);
delay(100);
}
uint8_t ADS1256::readGPIO(uint8_t gpioPin) //Reading GPIO
{
uint8_t GPIO_bit3, GPIO_bit2, GPIO_bit1, GPIO_bit0, GPIO_return;
_GPIO = readRegister(IO_REG); //Read the GPIO register
//Save each bit values in a variable
GPIO_bit3 = bitRead(_GPIO, 3);
GPIO_bit2 = bitRead(_GPIO, 2);
GPIO_bit1 = bitRead(_GPIO, 1);
GPIO_bit0 = bitRead(_GPIO, 0);
delay(100);
switch(gpioPin) //Selecting which value should be returned
{
case 0:
GPIO_return = GPIO_bit0;
break;
case 1:
GPIO_return = GPIO_bit1;
break;
case 2:
GPIO_return = GPIO_bit2;
break;
case 3:
GPIO_return = GPIO_bit3;
break;
}
return GPIO_return;
}
void ADS1256::sendDirectCommand(uint8_t directCommand)
{
//Direct commands can be found in the datasheet Page 34, Table 24.
_spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1));
CS_LOW(); //REF: P34: "CS must stay low during the entire command sequence"
delayMicroseconds(5);
_spi->transfer(directCommand); //Send Command
delayMicroseconds(5);
CS_HIGH(); //REF: P34: "CS must stay low during the entire command sequence"
_spi->endTransaction();
}
float ADS1256::convertToVoltage(int32_t rawData) //Converting the 24-bit data into a voltage value
{
return(conversionParameter * rawData);
}
void ADS1256::writeRegister(uint8_t registerAddress, uint8_t registerValueToWrite)
{
waitForLowDRDY();
_spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1));
//SPI_MODE1 = output edge: rising, data capture: falling; clock polarity: 0, clock phase: 1.
CS_LOW(); //CS must stay LOW during the entire sequence [Ref: P34, T24]
delayMicroseconds(5); //see t6 in the datasheet
_spi->transfer(0x50 | registerAddress); // 0x50 = 01010000 = WREG
_spi->transfer(0x00); //2nd (empty) command byte
_spi->transfer(registerValueToWrite); //pass the value to the register
CS_HIGH();
_spi->endTransaction();
delay(100);
}
long ADS1256::readRegister(uint8_t registerAddress) //Reading a register
{
waitForLowDRDY();
_spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1));
//SPI_MODE1 = output edge: rising, data capture: falling; clock polarity: 0, clock phase: 1.
CS_LOW(); //CS must stay LOW during the entire sequence [Ref: P34, T24]
_spi->transfer(0x10 | registerAddress); //0x10 = 0001000 = RREG - OR together the two numbers (command + address)
_spi->transfer(0x00); //2nd (empty) command byte
delayMicroseconds(5); //see t6 in the datasheet
uint8_t regValue = _spi->transfer(0xFF); //read out the register value
CS_HIGH();
_spi->endTransaction();
delay(100);
return regValue;
}
long ADS1256::readSingle() //Reading a single value ONCE using the RDATA command
{
_spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1));
CS_LOW(); //REF: P34: "CS must stay low during the entire command sequence"
waitForLowDRDY();
_spi->transfer(0b00000001); //Issue RDATA (0000 0001) command
delayMicroseconds(7); //Wait t6 time (~6.51 us) REF: P34, FIG:30.
_outputBuffer[0] = _spi->transfer(0); // MSB
_outputBuffer[1] = _spi->transfer(0); // Mid-byte
_outputBuffer[2] = _spi->transfer(0); // LSB
//Shifting and combining the above three items into a single, 24-bit number
_outputValue = ((long)_outputBuffer[0]<<16) | ((long)_outputBuffer[1]<<8) | (_outputBuffer[2]);
_outputValue = convertSigned24BitToLong(_outputValue);
CS_HIGH(); //We finished the command sequence, so we set CS to HIGH
_spi->endTransaction();
return(_outputValue);
}
long ADS1256::readSingleContinuous() //Reads the recently selected input channel using RDATAC
{
if(_isAcquisitionRunning == false)
{
_isAcquisitionRunning = true;
_spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1));
CS_LOW(); //REF: P34: "CS must stay low during the entire command sequence"
waitForLowDRDY();
_spi->transfer(0b00000011); //Issue RDATAC (0000 0011)
delayMicroseconds(7); //Wait t6 time (~6.51 us) REF: P34, FIG:30.
}
else
{
waitForLowDRDY();
}
_outputBuffer[0] = _spi->transfer(0); // MSB
_outputBuffer[1] = _spi->transfer(0); // Mid-byte
_outputBuffer[2] = _spi->transfer(0); // LSB
_outputValue = ((long)_outputBuffer[0]<<16) | ((long)_outputBuffer[1]<<8) | (_outputBuffer[2]);
_outputValue = convertSigned24BitToLong(_outputValue);
waitForHighDRDY();
return _outputValue;
}
long ADS1256::cycleSingle()
{
if(_isAcquisitionRunning == false)
{
_isAcquisitionRunning = true;
_cycle = 0;
_spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1));
CS_LOW(); //CS must stay LOW during the entire sequence [Ref: P34, T24]
_spi->transfer(0x50 | 1); // 0x50 = WREG //1 = MUX
_spi->transfer(0x00);
_spi->transfer(SING_0); //AIN0+AINCOM
CS_HIGH();
delay(50);
CS_LOW(); //CS must stay LOW during the entire sequence [Ref: P34, T24]
}
else
{}
if(_cycle < 8)
{
_outputValue = 0;
waitForLowDRDY();
//Step 1. - Updating MUX
switch (_cycle)
{
//Channels are written manually
case 0: //Channel 2
updateMUX(SING_1); //AIN1+AINCOM
break;
case 1: //Channel 3
updateMUX(SING_2); //AIN2+AINCOM
break;
case 2: //Channel 4
updateMUX(SING_3); //AIN3+AINCOM
break;
case 3: //Channel 5
updateMUX(SING_4); //AIN4+AINCOM
break;
case 4: //Channel 6
updateMUX(SING_5); //AIN5+AINCOM
break;
case 5: //Channel 7
updateMUX(SING_6); //AIN6+AINCOM
break;
case 6: //Channel 8
updateMUX(SING_7); //AIN7+AINCOM
break;
case 7: //Channel 1
updateMUX(SING_0); //AIN0+AINCOM
break;
}
//Step 2.
_spi->transfer(0b11111100); //SYNC
delayMicroseconds(4); //t11 delay 24*tau = 3.125 us //delay should be larger, so we delay by 4 us
_spi->transfer(0b11111111); //WAKEUP
//Step 3.
//Issue RDATA (0000 0001) command
_spi->transfer(0b00000001);
delayMicroseconds(7); //Wait t6 time (~6.51 us) REF: P34, FIG:30.
_outputBuffer[0] = _spi->transfer(0x0F); // MSB
_outputBuffer[1] = _spi->transfer(0x0F); // Mid-byte
_outputBuffer[2] = _spi->transfer(0x0F); // LSB
_outputValue = ((long)_outputBuffer[0]<<16) | ((long)_outputBuffer[1]<<8) | (_outputBuffer[2]);
_outputValue = convertSigned24BitToLong(_outputValue);
_cycle++; //Increase cycle - This will move to the next MUX input channel
if(_cycle == 8)
{
_cycle = 0; //Reset to 0 - Restart conversion from the 1st input channel
}
}
return _outputValue;
}
long ADS1256::cycleDifferential()
{
if(_isAcquisitionRunning == false)
{
_cycle = 0;
_isAcquisitionRunning = true;
_spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1));
//Set the AIN0+AIN1 as inputs manually
CS_LOW(); //CS must stay LOW during the entire sequence [Ref: P34, T24]
_spi->transfer(0x50 | 1); // 0x50 = WREG //1 = MUX
_spi->transfer(0x00);
_spi->transfer(DIFF_0_1); //AIN0+AIN1
CS_HIGH();
delay(50);
CS_LOW(); //CS must stay LOW during the entire sequence [Ref: P34, T24]
}
else
{}
if(_cycle < 4)
{
_outputValue = 0;
//DRDY has to go low
waitForLowDRDY();
//Step 1. - Updating MUX
switch (_cycle)
{
case 0: //Channel 2
updateMUX(DIFF_2_3); //AIN2+AIN3
break;
case 1: //Channel 3
updateMUX(DIFF_4_5); //AIN4+AIN5
break;
case 2: //Channel 4
updateMUX(DIFF_6_7); //AIN6+AIN7
break;
case 3: //Channel 1
updateMUX(DIFF_0_1); //AIN0+AIN1
break;
}
_spi->transfer(0b11111100); //SYNC
delayMicroseconds(4); //t11 delay 24*tau = 3.125 us //delay should be larger, so we delay by 4 us
_spi->transfer(0b11111111); //WAKEUP
//Step 3.
_spi->transfer(0b00000001); //Issue RDATA (0000 0001) command
delayMicroseconds(7); //Wait t6 time (~6.51 us) REF: P34, FIG:30.
_outputBuffer[0] = _spi->transfer(0); // MSB
_outputBuffer[1] = _spi->transfer(0); // Mid-byte
_outputBuffer[2] = _spi->transfer(0); // LSB
_outputValue = ((long)_outputBuffer[0]<<16) | ((long)_outputBuffer[1]<<8) | (_outputBuffer[2]);
_outputValue = convertSigned24BitToLong(_outputValue);
_cycle++;
if(_cycle == 4)
{
_cycle = 0;
//After the 4th cycle, we reset to zero so the next iteration reads the 1st MUX again
}
}
return _outputValue;
}
void ADS1256::updateConversionParameter()
{
conversionParameter = ((2.0 * _VREF) / 8388608.0) / (pow(2, _PGA)); //Calculate the "bit to Volts" multiplier
//8388608 = 2^{23} - 1, REF: p23, Table 16.
}
void ADS1256::updateMUX(uint8_t muxValue)
{
_spi->transfer(0x50 | MUX_REG); //Write to the MUX register (0x50 is the WREG command)
_spi->transfer(0x00);
_spi->transfer(muxValue); //Write the new MUX value
}
inline void ADS1256::CS_LOW()
{
if (_CS_pin != PIN_UNUSED) //Sets CS LOW if it is not an unused pin
{
digitalWrite(_CS_pin, LOW);
}
}
inline void ADS1256::CS_HIGH()
{
if (_CS_pin != PIN_UNUSED) //Sets CS HIGH if it is not an unused pin
{
digitalWrite(_CS_pin, HIGH);
}
}
+11
View File
@@ -0,0 +1,11 @@
// ADC Channels
#define A1_RAW 0
#define A2_RAW 1
#define B1_RAW 2
#define B2_RAW 3
#define A1_COND 4
#define A2_COND 5
#define B1_COND 6
#define B2_COND 7
-127
View File
@@ -1,127 +0,0 @@
#include "datasave.h"
#include <math.h>
LITTLEFSGuard::LITTLEFSGuard()
{
if (!LittleFS.begin(true, "/littlefs", 10, "littlefs"))
{
LOG_ERROR("Failed to mount LittleFS");
}
else
{
LOG_INFO("LittleFS mounted successfully");
LOG_INFO("LittleFS Free KBytes:", (LittleFS.totalBytes() - LittleFS.usedBytes()) /1024);
}
}
LITTLEFSGuard::~LITTLEFSGuard()
{
LittleFS.end();
LOG_INFO("LittleFS unmounted successfully");
}
void ignitionBoxStatusFiltered::filter(int32_t &old, const int32_t value, const uint32_t k)
{
float alpha = 1.0f / (float)k;
old = old + (int32_t)(alpha * (float)(value - old));
}
void ignitionBoxStatusFiltered::filter(float &old, const float value, const uint32_t k)
{
float alpha = 1.0f / (float)k;
old = old + (float)(alpha * (float)(value - old));
}
void ignitionBoxStatusFiltered::reset()
{
m_last = ignitionBoxStatus();
m_count = 0;
m_data_valid = false;
}
void ignitionBoxStatusFiltered::update(const ignitionBoxStatus &new_status)
{
if (m_count == 0 && !m_data_valid)
{
m_last = new_status;
}
m_count++;
// simple moving average calculation
m_last.timestamp = new_status.timestamp; // keep timestamp of latest status
m_last.coils12.n_events = new_status.coils12.n_events; // sum events instead of averaging
m_last.coils12.n_missed_firing = new_status.coils12.n_missed_firing; // sum missed firings instead of averaging
m_last.coils12.spark_status = new_status.coils12.spark_status; // take latest spark status
m_last.coils12.sstart_status = new_status.coils12.sstart_status; // take latest soft start status
filter(m_last.coils12.spark_delay, new_status.coils12.spark_delay, m_max_count); // incremental average calculation
filter(m_last.coils12.peak_p_in, new_status.coils12.peak_p_in, m_max_count); // incremental average calculation
filter(m_last.coils12.peak_n_in, new_status.coils12.peak_n_in, m_max_count); // incremental average calculation
filter(m_last.coils12.peak_p_out, new_status.coils12.peak_p_out, m_max_count); // incremental average calculation
filter(m_last.coils12.peak_n_out, new_status.coils12.peak_n_out, m_max_count); // incremental average calculation
m_last.coils34.n_events = new_status.coils34.n_events; // sum events instead of averaging
m_last.coils34.n_missed_firing = new_status.coils34.n_missed_firing; // sum missed firings instead of averaging
m_last.coils34.spark_status = new_status.coils34.spark_status; // take latest spark status
m_last.coils34.sstart_status = new_status.coils34.sstart_status; // take latest soft start status
filter(m_last.coils34.spark_delay, new_status.coils34.spark_delay, m_max_count); // incremental average calculation
filter(m_last.coils34.peak_p_in, new_status.coils34.peak_p_in, m_max_count); // incremental average calculation
filter(m_last.coils34.peak_n_in, new_status.coils34.peak_n_in, m_max_count); // incremental average calculation
filter(m_last.coils34.peak_p_out, new_status.coils34.peak_p_out, m_max_count); // incremental average calculation
filter(m_last.coils34.peak_n_out, new_status.coils34.peak_n_out, m_max_count); // incremental average calculation
filter(m_last.eng_rpm, new_status.eng_rpm, m_max_count); // incremental average calculation // incremental average calculation
filter(m_last.adc_read_time, m_last.adc_read_time, m_max_count); // incremental average calculation
m_last.n_queue_errors = new_status.n_queue_errors; // take last of queue errors since it's a cumulative count of errors in the queue, not an average value
if (m_count >= m_max_count)
{
m_count = 0; // reset count after reaching max samples to average
m_data_valid = true; // set data valid flag after first average is calculated
}
}
const bool ignitionBoxStatusFiltered::get(ignitionBoxStatus &status) const
{
if (m_data_valid)
{
status = m_last;
}
return m_data_valid;
}
const ArduinoJson::JsonDocument ignitionBoxStatusFiltered::toJson() const
{
ArduinoJson::JsonDocument doc;
if (m_data_valid)
{
doc["timestamp"] = m_last.timestamp;
doc["datavalid"] = m_data_valid ? "TRUE" : "FALSE";
doc["coils12"]["n_events"] = m_last.coils12.n_events;
doc["coils12"]["n_missed_firing"] = m_last.coils12.n_missed_firing;
doc["coils12"]["spark_delay"] = m_last.coils12.spark_delay;
doc["coils12"]["spark_status"] = sparkStatusNames.at(m_last.coils12.spark_status);
doc["coils12"]["peak_p_in"] = m_last.coils12.peak_p_in;
doc["coils12"]["peak_n_in"] = m_last.coils12.peak_n_in;
doc["coils12"]["peak_p_out"] = m_last.coils12.peak_p_out;
doc["coils12"]["peak_n_out"] = m_last.coils12.peak_n_out;
doc["coils12"]["sstart_status"] = softStartStatusNames.at(m_last.coils12.sstart_status);
doc["coils34"]["n_events"] = m_last.coils34.n_events;
doc["coils34"]["n_missed_firing"] = m_last.coils34.n_missed_firing;
doc["coils34"]["spark_delay"] = m_last.coils34.spark_delay;
doc["coils34"]["spark_status"] = sparkStatusNames.at(m_last.coils34.spark_status);
doc["coils34"]["peak_p_in"] = m_last.coils34.peak_p_in;
doc["coils34"]["peak_n_in"] = m_last.coils34.peak_n_in;
doc["coils34"]["peak_p_out"] = m_last.coils34.peak_p_out;
doc["coils34"]["peak_n_out"] = m_last.coils34.peak_n_out;
doc["coils34"]["sstart_status"] = softStartStatusNames.at(m_last.coils34.sstart_status);
doc["eng_rpm"] = m_last.eng_rpm;
doc["adc_read_time"] = m_last.adc_read_time;
doc["n_queue_errors"] = m_last.n_queue_errors;
}
return doc;
}
-50
View File
@@ -1,50 +0,0 @@
#pragma once
#define DEBUGLOG_DEFAULT_LOG_LEVEL_INFO
// System Includes
#include <Arduino.h>
#include <DebugLog.h>
#include <string>
#include <fstream>
#include <ArduinoJson.h>
#include <filesystem>
#include <LittleFS.h>
// Project Includes
#include "isr.h"
#include "psvector.h"
const uint32_t max_history = 256;
class LITTLEFSGuard
{
public:
LITTLEFSGuard();
~LITTLEFSGuard();
};
class ignitionBoxStatusFiltered
{
private:
ignitionBoxStatus m_last;
uint32_t m_count = 0;
uint32_t m_max_count = 100; // number of samples to average before resetting
bool m_data_valid = false; // flag to indicate if the average data is valid (i.e. at least one sample has been added)
public:
ignitionBoxStatusFiltered() = default;
ignitionBoxStatusFiltered(const uint32_t max_count) : m_max_count(max_count)
{
m_data_valid = false;
m_count = 0;
}
void reset();
void update(const ignitionBoxStatus &new_status);
const bool get(ignitionBoxStatus &status) const;
const ArduinoJson::JsonDocument toJson() const;
private:
void filter(int32_t &old, const int32_t value, const uint32_t k);
void filter(float &old, const float value, const uint32_t k);
};
-95
View File
@@ -1,95 +0,0 @@
#pragma once
#include <Arduino.h>
#include <map>
#include <psvector.h>
// =====================
// Event Flags (bitmask)
// =====================
static const uint32_t TRIG_FLAG_12P = (1 << 0);
static const uint32_t TRIG_FLAG_12N = (1 << 1);
static const uint32_t TRIG_FLAG_34P = (1 << 2);
static const uint32_t TRIG_FLAG_34N = (1 << 3);
static const uint32_t SPARK_FLAG_TIMEOUT = (1 << 8);
static const uint32_t SPARK_FLAG_12 = (1 << 9);
static const uint32_t SPARK_FLAG_34 = (1 << 10);
// 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,
};
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
{
NORMAL,
SOFT_START,
ERROR,
};
const std::map<const softStartStatus, const char *> softStartStatusNames = {
{NORMAL, "NORMAL"},
{SOFT_START, "SOFT_START"},
{ERROR, "ERROR"},
};
struct coilsStatus
{
int64_t trig_time = 0;
int64_t spark_time = 0;
int32_t spark_delay = 0; // in microseconds
sparkStatus spark_status = sparkStatus::SPARK_POS_OK;
softStartStatus sstart_status = softStartStatus::NORMAL;
float peak_p_in = 0.0;
float peak_n_in = 0.0;
float peak_p_out = 0.0;
float peak_n_out = 0.0;
float level_spark = 0.0;
uint32_t n_events = 0;
uint32_t n_missed_firing = 0;
};
// Task internal Status
struct ignitionBoxStatus
{
int64_t timestamp = 0;
// coils pairs for each ignition
coilsStatus coils12;
coilsStatus coils34;
// voltage from generator
float volts_gen = 0.0;
// enine rpm
int32_t eng_rpm = 0;
// debug values
uint32_t n_queue_errors = 0;
int32_t adc_read_time = 0;
};
template <typename T>
using PSRAMVector = std::vector<T, PSRAMAllocator<T>>;
+16 -23
View File
@@ -1,11 +1,5 @@
#pragma once #pragma once
// Library defines
#define ADS1256_SPI_ALREADY_STARTED
// System Includes
#include <memory>
// Device Libraries // Device Libraries
#include <ADS1256.h> #include <ADS1256.h>
#include <AD5292.h> #include <AD5292.h>
@@ -24,32 +18,31 @@
// Device Pointer structs for tasks // Device Pointer structs for tasks
struct Devices struct Devices
{ {
std::unique_ptr<SPIClass> m_spi_a = nullptr; // Busses
std::unique_ptr<SPIClass> m_spi_b = nullptr; TwoWire *m_i2c = NULL;
SPIClass *m_spi_a = NULL;
std::unique_ptr<AD5292> m_pot_a = nullptr; SPIClass *m_spi_b = NULL;
std::unique_ptr<AD5292> m_pot_b = nullptr;
std::unique_ptr<ADS1256> m_adc_a = nullptr;
std::unique_ptr<ADS1256> m_adc_b = nullptr;
std::unique_ptr<PCA9555> m_expander_a = nullptr;
std::unique_ptr<PCA9555> m_expander_b = nullptr;
std::unique_ptr<PCA9555> m_expander_inputs_ab = nullptr;
// Bus Mutextes
std::mutex m_spi_a_mutex; std::mutex m_spi_a_mutex;
std::mutex m_spi_b_mutex; std::mutex m_spi_b_mutex;
std::mutex m_i2c_mutex; std::mutex m_i2c_mutex;
// Device Pointers
AD5292 *m_pot_a = NULL;
AD5292 *m_pot_b = NULL;
ADS1256 *m_adc_a = NULL;
ADS1256 *m_adc_b = NULL;
ExternalIO *m_ext_io = NULL;
}; };
// Adc read channel wrapper to selet mux before reading // Adc read channel wrapper to selet mux before reading
inline float adcReadChannel(ADS1256 *adc, const uint8_t ch) inline float adcReadChannel(ADS1256* adc, const uint8_t ch){
{
adc->setMUX(ch); adc->setMUX(ch);
// scarta 3 conversioni // scarta 3 conversioni
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++) {
{
adc->readSingle(); adc->readSingle();
} }
// ora lettura valida a 30kSPS → ~100 µs di settling // ora lettura valida a 30kSPS → ~100 µs di settling
+7 -51
View File
@@ -4,7 +4,7 @@
// ISR (Pass return bitmask to ISR management function) // ISR (Pass return bitmask to ISR management function)
// one function for each wake up pin conncted to a trigger // one function for each wake up pin conncted to a trigger
// ===================== // =====================
void trig_isr_A(void *arg) void trig_isr(void *arg)
{ {
const int64_t time_us = esp_timer_get_time(); const int64_t time_us = esp_timer_get_time();
@@ -36,62 +36,18 @@ void trig_isr_A(void *arg)
xTaskNotifyFromISR(task_handle, params->flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken); xTaskNotifyFromISR(task_handle, params->flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
break; break;
case SPARK_FLAG_12: case SPARK_FLAG_12:
box->coils34.spark_ok = false;
box->coils12.spark_time = time_us; box->coils12.spark_ok = true;
xTaskNotifyFromISR(task_handle, params->flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
break;
case SPARK_FLAG_34:
box->coils34.spark_time = time_us;
xTaskNotifyFromISR(task_handle, params->flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
break;
default:
break;
}
if (xHigherPriorityTaskWoken)
portYIELD_FROM_ISR();
}
void trig_isr_B(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->coils12.spark_time = time_us; box->coils12.spark_time = time_us;
xTaskNotifyFromISR(task_handle, params->flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken); xTaskNotifyFromISR(task_handle, params->flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
// vTaskNotifyGiveFromISR(task_handle, &xHigherPriorityTaskWoken);
break; break;
case SPARK_FLAG_34: case SPARK_FLAG_34:
box->coils12.spark_ok = false;
box->coils34.spark_ok = true;
box->coils34.spark_time = time_us; box->coils34.spark_time = time_us;
xTaskNotifyFromISR(task_handle, params->flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken); xTaskNotifyFromISR(task_handle, params->flag, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
// vTaskNotifyGiveFromISR(task_handle, &xHigherPriorityTaskWoken);
break; break;
default: default:
break; break;
+86 -5
View File
@@ -12,12 +12,94 @@
#else #else
#include "pins_test.h" #include "pins_test.h"
#endif #endif
#include "datastruct.h"
#define CORE_0 0 #define CORE_0 0
#define CORE_1 1 #define CORE_1 1
#define RT_TASK_STACK 2048 // in words #define TASK_STACK 4096 // in words
#define RT_TASK_PRIORITY (configMAX_PRIORITIES - 5) // highest priority after wifi tasks #define TASK_PRIORITY (configMAX_PRIORITIES - 4) // highest priority after wifi tasks
// =====================
// Event Flags (bitmask)
// =====================
static const uint32_t TRIG_FLAG_12P = (1 << 0);
static const uint32_t TRIG_FLAG_12N = (1 << 1);
static const uint32_t TRIG_FLAG_34P = (1 << 2);
static const uint32_t TRIG_FLAG_34N = (1 << 3);
static const uint32_t SPARK_FLAG_NIL = (1 << 8);
static const uint32_t SPARK_FLAG_12 = (1 << 9);
static const uint32_t SPARK_FLAG_34 = (1 << 10);
static const uint32_t SPARK_FLAG_TIMEOUT = (1 << 11);
// 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,
};
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
{
NORMAL,
SOFT_START,
ERROR,
};
const std::map<const softStartStatus, const char *> softStartStatusNames = {
{NORMAL, "NORMAL"},
{SOFT_START, "SOFT_START"},
{ERROR, "ERROR"},
};
struct coilsStatus
{
int64_t trig_time = 0;
int64_t spark_time = 0;
int64_t spark_delay = 0; // in microseconds
sparkStatus spark_status = sparkStatus::SPARK_POS_OK;
softStartStatus sstart_status = softStartStatus::NORMAL;
float peak_p_in = 0.0, peak_n_in = 0.0;
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
struct ignitionBoxStatus
{
int64_t timestamp = 0;
// coils pairs for each ignition
coilsStatus coils12;
coilsStatus coils34;
// voltage from generator
float volts_gen = 0.0;
uint32_t n_queue_errors = 0;
};
struct isrParams struct isrParams
{ {
@@ -26,5 +108,4 @@ struct isrParams
TaskHandle_t rt_handle_ptr; TaskHandle_t rt_handle_ptr;
}; };
void IRAM_ATTR trig_isr_A(void *arg); void IRAM_ATTR trig_isr(void *arg);
void IRAM_ATTR trig_isr_B(void *arg);
+206 -68
View File
@@ -1,58 +1,61 @@
#define DEBUGLOG_DEFAULT_LOG_LEVEL_DEBUG #define DEBUGLOG_DEFAULT_LOG_LEVEL_INFO
// Arduino Libraries // Arduino Libraries
#include <Arduino.h> #include <Arduino.h>
#include <DebugLog.h> #include <DebugLog.h>
#include <DebugLogEnable.h> #include <DebugLogEnable.h>
#include <SPI.h> #include <SPI.h>
#include <WiFi.h>
#include <ArduinoJson.h>
// Definitions // Definitions
#include <tasks.h> #include <tasks.h>
#include <channels.h>
#include <devices.h> #include <devices.h>
#include <datasave.h>
#include <webserver.h>
#include <ui.h> #include <ui.h>
#include <led.h>
// Defines to enable channel B #define CH_A_ENABLE
#define CH_B_ENABLE #define CH_B_ENABLE
// #define TEST #define CH_A_RT_ENABLE
#define CH_B_RT_ENABLE
// #define I2C_ENABLE
// #define WEB_ENABLE
// Debug Defines // Debug Defines
#define WIFI_SSID "AstroRotaxMonitor" #define WIFI_SSID "AstroRotaxMonitor"
#define WIFI_PASSWORD "maledettirotax" #define WIFI_PASSWORD "maledettirotax"
#define PSRAM_MAX 1024
#define QUEUE_MAX 32
void setup() void setup()
{ {
Serial.begin(921600); Serial.begin(921600);
delay(250); delay(250);
Serial.setTimeout(5000);
// Setup Logger // Setup Logger
LOG_ATTACH_SERIAL(Serial); LOG_ATTACH_SERIAL(Serial);
LOG_SET_LEVEL(DebugLogLevel::LVL_DEBUG); LOG_SET_LEVEL(DebugLogLevel::LVL_INFO);
// Print Processor Info // Print Processor Info
LOG_DEBUG("ESP32 Chip:", ESP.getChipModel()); LOG_INFO("ESP32 Chip:", ESP.getChipModel());
if (psramFound()) if (psramFound())
{ {
LOG_DEBUG("ESP32 PSram Found"); LOG_INFO("ESP32 PSram Found");
LOG_DEBUG("ESP32 PSram:", ESP.getPsramSize()); LOG_INFO("ESP32 PSram:", ESP.getPsramSize());
psramInit(); psramInit();
} }
LOG_DEBUG("ESP32 Flash:", ESP.getFlashChipSize()); LOG_DEBUG("ESP32 Flash:", ESP.getFlashChipSize());
LOG_DEBUG("ESP32 Heap:", ESP.getHeapSize()); LOG_DEBUG("ESP32 Heap:", ESP.getHeapSize());
LOG_DEBUG("ESP32 Sketch:", ESP.getFreeSketchSpace()); LOG_DEBUG("ESP32 Sketch:", ESP.getFreeSketchSpace());
// Init Wifi station // Init Wifi station
#ifdef WEB_ENABLE
LOG_INFO("Initializing WiFi..."); LOG_INFO("Initializing WiFi...");
WiFi.mode(WIFI_AP); WiFi.mode(WIFI_AP);
IPAddress local_IP(10, 11, 12, 1); IPAddress local_IP(10, 11, 12, 1);
IPAddress gateway(10, 11, 12, 1); IPAddress gateway(10, 11, 12, 1);
IPAddress subnet(255, 255, 255, 0); IPAddress subnet(255, 255, 255, 0);
WiFi.softAPConfig(local_IP, gateway, subnet); WiFi.softAPConfig(local_IP, gateway, subnet);
WiFi.setTxPower(WIFI_POWER_13dBm); // reduce wifi power WiFi.setTxPower(WIFI_POWER_5dBm); // reduce wifi power
if (WiFi.softAP(WIFI_SSID, WIFI_PASSWORD)) if (WiFi.softAP(WIFI_SSID, WIFI_PASSWORD))
{ {
LOG_INFO("WiFi AP Mode Started"); LOG_INFO("WiFi AP Mode Started");
@@ -67,6 +70,7 @@ void setup()
vTaskDelay(pdMS_TO_TICKS(5000)); vTaskDelay(pdMS_TO_TICKS(5000));
esp_restart(); esp_restart();
} }
#endif
// Initialize Interrupt pins on PICKUP detectors // Initialize Interrupt pins on PICKUP detectors
initTriggerPinsInputs(); initTriggerPinsInputs();
@@ -74,28 +78,98 @@ void setup()
initSparkPinInputs(); initSparkPinInputs();
} }
////////////////////// MAIN LOOP //////////////////////
void loop() void loop()
{ {
// global variables // global variables
RGBled led; RGBled led;
led.setBrightness(0.025f);
led.setStatus(RGBled::LedStatus::INIT); led.setStatus(RGBled::LedStatus::INIT);
bool running = true;
std::mutex fs_mutex;
LITTLEFSGuard fsGuard;
//////// INIT SPI PORTS //////// Devices dev;
bool running = true;
static Devices dev;
// 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 spiA_ok = true;
bool spiB_ok = true; bool spiB_ok = true;
// Init 2 SPI interfaces //////// INIT SPI INTERFACES ////////
// SPIClass SPI_A(FSPI); LOG_DEBUG("Init SPI Interfaces");
// spiA_ok = SPI_A.begin(SPI_A_SCK, SPI_A_MISO, SPI_A_MOSI); #ifdef CH_A_ENABLE
// SPI_A.setDataMode(SPI_MODE1); // ADS1256 requires SPI mode 1 LOG_DEBUG("Begin Init SPI_A");
// #ifdef CH_B_ENABLE SPIClass SPI_A(HSPI);
// SPIClass SPI_B(HSPI); spiA_ok = SPI_A.begin(SPI_A_SCK, SPI_A_MISO, SPI_A_MOSI);
// spiB_ok = SPI_B.begin(SPI_B_SCK, SPI_B_MISO, SPI_B_MOSI); SPI_A.setDataMode(SPI_MODE1); // ADS1256 requires SPI mode 1
// SPI_B.setDataMode(SPI_MODE1); // ADS1256 requires SPI mode 1 LOG_DEBUG("Init SPI_A -> OK");
// #endif delay(500);
LOG_DEBUG("Begin Init ADC_A");
ADS1256 ADC_A(ADC_A_DRDY, ADS1256::PIN_UNUSED, ADS1256::PIN_UNUSED, ADC_A_CS, 2.5, &SPI_A);
ADC_A.InitializeADC();
ADC_A.setPGA(PGA_1);
ADC_A.setDRATE(DRATE_7500SPS);
dev.m_adc_a = &ADC_A;
dev.m_spi_a = &SPI_A;
LOG_DEBUG("Init ADC_A -> OK");
delay(1000);
#endif
#ifdef CH_B_ENABLE
LOG_DEBUG("Begin Init SPI_B");
SPIClass SPI_B(FSPI);
spiB_ok = SPI_B.begin(SPI_B_SCK, SPI_B_MISO, SPI_B_MOSI);
SPI_B.setDataMode(SPI_MODE1); // ADS1256 requires SPI mode 1
LOG_DEBUG("Init SPI_B -> OK");
delay(500);
LOG_DEBUG("Begin Init ADC_B");
ADS1256 ADC_B(ADC_B_DRDY, ADS1256::PIN_UNUSED, ADS1256::PIN_UNUSED, ADC_B_CS, 2.5, &SPI_B);
ADC_B.InitializeADC();
ADC_B.setPGA(PGA_1);
ADC_B.setDRATE(DRATE_7500SPS);
dev.m_adc_b = &ADC_B;
dev.m_spi_b = &SPI_B;
LOG_DEBUG("Init ADC_B -> OK");
delay(1000);
#endif
if (!spiA_ok || !spiB_ok) if (!spiA_ok || !spiB_ok)
{ {
LOG_ERROR("Unable to Initialize SPI Busses"); LOG_ERROR("Unable to Initialize SPI Busses");
@@ -103,25 +177,31 @@ void loop()
vTaskDelay(pdMS_TO_TICKS(5000)); vTaskDelay(pdMS_TO_TICKS(5000));
esp_restart(); esp_restart();
} }
LOG_DEBUG("Init SPI OK"); LOG_INFO("Init SPI OK");
// Resources Initialization LOG_DEBUG("Init SPI -> OK");
std::shared_ptr<Devices> dev = std::make_shared<Devices>();
// dev->m_spi_a = std::make_unique<SPIClass>(SPI_A);
// dev->m_spi_b = std::make_unique<SPIClass>(SPI_B);
// // Init ADC_A //////// INIT I2C INTERFACES ////////
// dev->m_adc_a = std::make_unique<ADS1256>(ADC_A_DRDY, ADS1256::PIN_UNUSED, ADS1256::PIN_UNUSED, ADC_A_CS, 2.5, &SPI_A); #ifdef I2C_ENABLE
// dev->m_adc_b = std::make_unique<ADS1256>(ADC_B_DRDY, ADS1256::PIN_UNUSED, ADS1256::PIN_UNUSED, ADC_B_CS, 2.5, &SPI_B); LOG_DEBUG("Init I2C Interfaces");
bool i2c_ok = true;
i2c_ok = Wire.begin(SDA, SCL, 100000);
if (!i2c_ok)
{
LOG_ERROR("Unable to Initialize I2C Bus");
LOG_ERROR("5 seconds to restart...");
vTaskDelay(pdMS_TO_TICKS(5000));
esp_restart();
}
LOG_DEBUG("Init I2c ok");
Serial.readStringUntil('\n');
// dev->m_adc_a->InitializeADC(); // Init IO Expanders
// dev->m_adc_a->setPGA(PGA_1); dev->m_ext_io = std::make_unique<ExternalIO>(Wire, dev->m_i2c_mutex, EXPANDER_ALL_INTERRUPT);
// dev->m_adc_a->setDRATE(DRATE_7500SPS); #endif
// dev->m_adc_b->InitializeADC();
// dev->m_adc_b->setPGA(PGA_1);
// dev->m_adc_b->setDRATE(DRATE_7500SPS);
//////// INIT REALTIME TASKS PARAMETERS ////////
#ifdef CH_A_RT_ENABLE
const rtIgnitionTask::rtTaskParams taskA_params{ const rtIgnitionTask::rtTaskParams taskA_params{
.rt_running = true, .rt_running = true,
.name = "rtIgnTask_A", .name = "rtIgnTask_A",
@@ -151,8 +231,9 @@ void loop()
.relay_out_34 = RELAY_OUT_A34, .relay_out_34 = RELAY_OUT_A34,
}, },
.rt_queue = nullptr, .rt_queue = nullptr,
.dev = dev}; .dev = &dev};
#endif
#ifdef CH_B_RT_ENABLE
const rtIgnitionTask::rtTaskParams taskB_params{ const rtIgnitionTask::rtTaskParams taskB_params{
.rt_running = true, .rt_running = true,
.name = "rtIgnTask_B", .name = "rtIgnTask_B",
@@ -182,46 +263,66 @@ void loop()
.relay_out_34 = RELAY_OUT_B34, .relay_out_34 = RELAY_OUT_B34,
}, },
.rt_queue = nullptr, .rt_queue = nullptr,
.dev = dev}; .dev = &dev};
#endif
auto task_A = rtIgnitionTask(taskA_params, 4096, 256, CORE_0, fs_mutex); //////// SPAWN REALTIME TASKS ////////
delay(50); bool tasK_A_rt = true;
auto task_B = rtIgnitionTask(taskB_params, 4096, 256, CORE_1, fs_mutex); bool task_B_rt = true;
BaseType_t ignA_task_success = pdPASS;
BaseType_t ignB_task_success = pdPASS;
#ifdef CH_A_RT_ENABLE
auto task_A = rtIgnitionTask(taskA_params, PSRAM_MAX, QUEUE_MAX, CORE_1, fs_mutex);
ignA_task_success = task_A.getStatus() == rtIgnitionTask::OK ? pdPASS : pdFAIL;
//tasK_A_rt = task_A.start();
delay(1000);
#endif
#ifdef CH_B_RT_ENABLE
auto task_B = rtIgnitionTask(taskB_params, PSRAM_MAX, QUEUE_MAX, CORE_1, fs_mutex);
ignB_task_success = task_B.getStatus() == rtIgnitionTask::OK ? pdPASS : pdFAIL;
//task_B_rt = task_B.start();
delay(1000);
#endif
// Ignition A on Core 0 // Ignition A on Core 0
auto ignA_task_success = task_A.getStatus() == rtIgnitionTask::OK ? pdPASS : pdFAIL;
auto ignB_task_success = task_B.getStatus() == rtIgnitionTask::OK ? pdPASS : pdFAIL;
if (ignA_task_success != pdPASS || ignB_task_success != pdPASS) if (ignA_task_success != pdPASS || ignB_task_success != pdPASS)
{ {
LOG_ERROR("Unable to initialize ISR task"); LOG_ERROR("Unble to initialize ISR task");
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();
} }
const bool tasK_A_rt = task_A.start();
delay(50);
const bool task_B_rt = task_B.start();
if (tasK_A_rt != true || task_B_rt != true) if (tasK_A_rt != true || task_B_rt != true)
{ {
led.setStatus(RGBled::LedStatus::ERROR); led.setStatus(RGBled::LedStatus::ERROR);
LOG_ERROR("Unable to start realtime tasks"); LOG_ERROR("Unable to start realtime tasks");
} else }
else
{
LOG_DEBUG("Real Time Tasks A & B initialized"); LOG_DEBUG("Real Time Tasks A & B initialized");
led.setStatus(RGBled::LedStatus::OK); led.setStatus(RGBled::LedStatus::OK);
}
AstroWebServer webPage(80, LittleFS); // Initialize webserver and Websocket //////// SPAWN WEBSERVER and WEBSOCKET ////////
ArduinoJson::JsonDocument json_data; ArduinoJson::JsonDocument json_data;
bool data_a, data_b; bool data_a = false, data_b = false;
task_A.onMessage([&webPage, &json_data, &data_a](ignitionBoxStatusFiltered sts){ #ifdef WEB_ENABLE
AstroWebServer webPage(80, LittleFS);
delay(1000);
task_A.onMessage([&webPage, &json_data, &data_a](ignitionBoxStatusFiltered sts)
{
json_data["box_a"] = sts.toJson(); json_data["box_a"] = sts.toJson();
data_a = true; data_a = true; });
});
task_B.onMessage([&webPage, &json_data, &data_b](ignitionBoxStatusFiltered sts){ #ifdef CH_B_RT_ENABLE
task_B.onMessage([&webPage, &json_data, &data_b](ignitionBoxStatusFiltered sts)
{
json_data["box_b"] = sts.toJson(); json_data["box_b"] = sts.toJson();
data_b = true; data_b = true; });
}); #endif
#endif
// task_A.enableSave(true, "ignitionA_test.csv"); // task_A.enableSave(true, "ignitionA_test.csv");
// task_B.enableSave(true, "ignitionB_test.csv"); // task_B.enableSave(true, "ignitionB_test.csv");
@@ -232,18 +333,55 @@ void loop()
while (running) while (running)
{ {
uint32_t this_loop = millis(); uint32_t this_loop = millis();
if (this_loop - monitor_loop > 2000) if (this_loop - monitor_loop > 5000)
{ {
if (ignA.coils12.spark_status == sparkStatus::SPARK_NEG_FAIL || ignA.coils12.spark_status == sparkStatus::SPARK_POS_FAIL)
missed_firings12++;
if (ignA.coils34.spark_status == sparkStatus::SPARK_POS_FAIL || ignA.coils34.spark_status == sparkStatus::SPARK_NEG_FAIL)
missed_firings34++;
clearScreen(); clearScreen();
printRunningTasksMod(Serial); printRunningTasksMod(Serial);
monitor_loop = millis(); monitor_loop = millis();
} }
if ((data_a && data_b) || (this_loop - data_loop > 500)) { vTaskDelay(pdMS_TO_TICKS(10));
#ifdef WEB_ENABLE
if ((data_a && data_b) || (this_loop - data_loop > 500))
{
webPage.sendWsData(json_data.as<String>()); webPage.sendWsData(json_data.as<String>());
json_data.clear(); json_data.clear();
data_a = data_b = false; data_a = data_b = false;
data_loop = millis(); data_loop = millis();
} }
#endif
} //////////////// INNER LOOP ///////////////////// } //////////////// INNER LOOP /////////////////////
} ////////////////////// MAIN LOOP ////////////////////// 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)
vTaskDelete(trigA_TaskHandle);
if (trigB_TaskHandle)
vTaskDelete(trigB_TaskHandle);
////////////////////// MAIN LOOP //////////////////////
}
+42 -94
View File
@@ -26,140 +26,88 @@
// ===================== // =====================
// SPI BUS ADC1 (VSPI) // SPI BUS ADC1 (VSPI)
// ===================== // =====================
#define SPI_A_MOSI 10 #define SPI_A_MOSI 11
#define SPI_A_SCK 11 #define SPI_A_MISO 13
#define SPI_A_MISO 12 #define SPI_A_SCK 12
// ===================== // =====================
// SPI BUS ADC2 (HSPI) // SPI BUS ADC2 (HSPI)
// ===================== // =====================
#define SPI_B_MOSI 36 #define SPI_B_MOSI 35
#define SPI_B_SCK 37 #define SPI_B_MISO 37
#define SPI_B_MISO 38 #define SPI_B_SCK 36
// ===================== // =====================
// I2C BUS (PCA9555) // I2C BUS (PCA9555)
// ===================== // =====================
#define SDA 8 #define SDA 8
#define SCL 9 #define SCL 9
#define I2C_INT 17
// ===================== // =====================
// ADC CONTROL // ADC CONTROL
// ===================== // =====================
#define ADC_A_CS 14 #define ADC_A_CS 4
#define ADC_A_DRDY 13 #define ADC_A_DRDY 5
#define ADC_A_RST 6
#define ADC_A_SYNC 7
#define ADC_B_CS 21 #define ADC_B_CS 14
#define ADC_B_DRDY 47 #define ADC_B_DRDY 15
#define ADC_B_RST 16
#define ADC_B_SYNC 17
// ===================== // =====================
// DIGITAL POT // DIGITAL POT
// ===================== // =====================
#define POT_A_CS 18 //#define POT_A_CS 1
#define POT_B_CS 35 //#define POT_B_CS 2
// ===================== // =====================
// TRIGGER INPUT INTERRUPTS // TRIGGER INPUT INTERRUPTS
// ===================== // =====================
#define TRIG_PIN_A12P 6 #define TRIG_PIN_A12P 18
#define TRIG_PIN_A12N 7 #define TRIG_PIN_A12N 21
#define TRIG_PIN_A34P 15 #define TRIG_PIN_A34P 1
#define TRIG_PIN_A34N 16 #define TRIG_PIN_A34N 2
#define TRIG_PIN_B12P 42 #define TRIG_PIN_B12P 38
#define TRIG_PIN_B12N 41 #define TRIG_PIN_B12N 39
#define TRIG_PIN_B34P 40 #define TRIG_PIN_B34P 40
#define TRIG_PIN_B34N 39 #define TRIG_PIN_B34N 41
// ===================== // =====================
// SPARK DETECT INPUTS // SPARK DETECT INPUTS
// ===================== // =====================
#define SPARK_PIN_A12 4 #define SPARK_PIN_A12 42
#define SPARK_PIN_A34 5 #define SPARK_PIN_A34 45 // OK (strapping ma consentito) 45
#define SPARK_PIN_B12 1 #define SPARK_PIN_B12 46 // OK (strapping ma consentito) 46
#define SPARK_PIN_B34 2 #define SPARK_PIN_B34 47
// ===================== // =====================
// PCA9555 I/O EXPANDER BOX_A // PCA9555 (I2C EXPANDER)
// ===================== // =====================
#define EXPANDER_A_ADDR 0x010101 // --- RESET LINES ---
#define RST_EXT_A12P 0
// --- DIGITAL POT CHIP SELECT LINES --- #define RST_EXT_A12N 1
#define POT_CS_A12 0 #define RST_EXT_A34P 2
#define POT_CS_A34 1 #define RST_EXT_A34N 3
#define RST_EXT_B12P 4
// --- SOFT START FORCE LINES --- #define RST_EXT_B12N 5
#define SS_FORCE_A 2 #define RST_EXT_B34P 6
#define SS_INIBHIT_A12 3 #define RST_EXT_B34N 7
#define SS_INHIBIT_A34 4
// --- SAMPLE AND HOLD ARM AND DISCHARGE ---
#define SH_DISCH_A12 5
#define SH_DISCH_A34 6
#define SH_ARM_A12 7
#define SH_ARM_A34 8
// --- RELAY --- // --- RELAY ---
#define RELAY_IN_A12 9 #define A_EXT_RELAY 8
#define RELAY_OUT_A12 10 #define B_EXT_RELAY 9
#define RELAY_IN_A34 11
#define RELAY_OUT_A34 12
// --- STATUS / BUTTON --- // --- STATUS / BUTTON ---
#define BTN_3 10
#define BTN_4 11
#define STA_1 12
#define STA_2 13 #define STA_2 13
#define STA_3 14 #define STA_3 14
#define STA_4 15 #define STA_4 15
// =====================
// PCA9555 I/O EXPANDER BOX_B
// =====================
#define EXPANDER_B_ADDR 0x101010
// --- DIGITAL POT CHIP SELECT LINES ---
#define POT_CS_B12 0
#define POT_CS_B34 1
// --- SOFT START FORCE LINES ---
#define SS_FORCE_B 2
#define SS_INIBHIT_B12 3
#define SS_INHIBIT_B34 4
// --- SAMPLE AND HOLD ARM AND DISCHARGE ---
#define SH_DISCH_B12 5
#define SH_DISCH_B34 6
#define SH_ARM_B12 7
#define SH_ARM_B34 8
// --- RELAY ---
#define RELAY_IN_B12 9
#define RELAY_OUT_B12 10
#define RELAY_IN_B34 11
#define RELAY_OUT_B34 12
// --- STATUS / BUTTON ---
#define STA_2 13
#define STA_3 14
#define STA_4 15
// =====================
// PCA9555 I/O EXPANDER INPUTS A+B
// =====================
#define EXPANDER_IN_ADDR 0x0a0a0a
#define SS_A12_ON
#define SS_A12_OFF
#define SS_A34_ON
#define SS_A34_OFF
#define SS_B12_ON
#define SS_B12_OFF
#define SS_B34_ON
#define SS_B34_OFF
// Init Pin Functions // Init Pin Functions
inline void initTriggerPinsInputs() inline void initTriggerPinsInputs()
{ {
+1 -1
View File
@@ -65,7 +65,7 @@
#define RST_EXT_A34N 3 #define RST_EXT_A34N 3
// --- RELAY --- // --- RELAY ---
#define SH_ARM_A34 8 #define A_EXT_RELAY 8
// Init Pin Functions // Init Pin Functions
-27
View File
@@ -1,27 +0,0 @@
#pragma once
#include <vector>
#include "esp_heap_caps.h"
// Allocator custom per PSRAM
template <typename T>
struct PSRAMAllocator {
using value_type = T;
PSRAMAllocator() noexcept {}
template <typename U>
PSRAMAllocator(const PSRAMAllocator<U>&) noexcept {}
T* allocate(std::size_t n) {
void* ptr = heap_caps_malloc(n * sizeof(T), MALLOC_CAP_SPIRAM);
if (!ptr) {
throw std::bad_alloc();
}
return static_cast<T*>(ptr);
}
void deallocate(T* p, std::size_t) noexcept {
heap_caps_free(p);
}
};
+130 -80
View File
@@ -1,12 +1,8 @@
#include "tasks.h" #include "tasks.h"
#include <esp_timer.h> #include <esp_timer.h>
#include <datasave.h>
//// GLOBAL STATIC FUNCTIONS
// Timeout callback for microsecond precision // Timeout callback for microsecond precision
void spark_timeout_callback(void *arg) void spark_timeout_callback(void* arg) {
{
TaskHandle_t handle = (TaskHandle_t)arg; TaskHandle_t handle = (TaskHandle_t)arg;
xTaskNotify(handle, SPARK_FLAG_TIMEOUT, eSetValueWithOverwrite); xTaskNotify(handle, SPARK_FLAG_TIMEOUT, eSetValueWithOverwrite);
} }
@@ -15,9 +11,16 @@ void spark_timeout_callback(void *arg)
void rtIgnitionTask::rtIgnitionTask_manager(void *pvParameters) void rtIgnitionTask::rtIgnitionTask_manager(void *pvParameters)
{ {
rtIgnitionTask *cls = (rtIgnitionTask *)pvParameters; rtIgnitionTask *cls = (rtIgnitionTask *)pvParameters;
auto last_loop = millis();
uint32_t count(0);
while (cls->m_running) while (cls->m_running)
{ {
cls->run(); cls->run();
// if (millis() - last_loop > 2000) {
// LOG_DEBUG("TASK [", cls->m_name.c_str(), "] Alive -", count++);
// last_loop = millis();
// }
vTaskDelay(pdMS_TO_TICKS(1));
} }
} }
@@ -31,62 +34,65 @@ void rtIgnitionTask::rtIgnitionTask_realtime(void *pvParameters)
LOG_ERROR("Null rt_task_ptr parameters"); LOG_ERROR("Null rt_task_ptr parameters");
vTaskDelete(NULL); vTaskDelete(NULL);
} }
LOG_INFO("rtTask Params OK");
// Task Parameters and Devices // Task Parameters and Devices
rtTaskParams *params = (rtTaskParams *)pvParameters; rtTaskParams *params = (rtTaskParams *)pvParameters;
const rtTaskInterruptParams rt_int = params->rt_int; // copy to avoid external override const rtTaskInterrupts rt_int = params->rt_int; // copy to avoid external override
const rtTaskIOParams rt_rst = params->rt_io; // copy to avoid external override const rtTaskResets rt_rst = params->rt_resets; // copy to avoid external override
QueueHandle_t rt_queue = params->rt_queue; QueueHandle_t rt_queue = params->rt_queue;
Devices *dev = params->dev.get(); Devices *dev = params->dev;
ADS1256 *adc = dev->m_adc_a.get(); ExternalIO *io = dev->m_ext_io;
PCA9555 *io = dev->m_expander_a.get(); // ADS1256 *adc = params->name == "rtIgnTask_A" ? dev->m_adc_a : dev->m_adc_b;
ADS1256 *adc = NULL;
// std::mutex &spi_mutex = params->name == "rtIgnTask_A" ? dev->m_spi_a_mutex : dev->m_spi_b_mutex;
std::mutex spi_mutex;
TaskStatus_t rt_task_info; TaskStatus_t rt_task_info;
vTaskGetInfo(NULL, &rt_task_info, pdFALSE, eInvalid); vTaskGetInfo(NULL, &rt_task_info, pdFALSE, eInvalid);
const auto rt_task_name = pcTaskGetName(rt_task_info.xHandle); LOG_INFO("rtTask Params OK [", params->name.c_str(), "]");
LOG_INFO("rtTask Params OK [", rt_task_name, "]");
ignitionBoxStatus ign_box_sts; ignitionBoxStatus ign_box_sts;
// Variables for ISR, static to be fixed in memory locations // Variables for ISR, static to be fixed in memory locations
isrParams isr_params_t12p{ static isrParams isr_params_t12p{
.flag = TRIG_FLAG_12P, .flag = TRIG_FLAG_12P,
.ign_stat = &ign_box_sts, .ign_stat = &ign_box_sts,
.rt_handle_ptr = rt_task_info.xHandle}; .rt_handle_ptr = rt_handle_ptr};
isrParams isr_params_t12n{ static isrParams isr_params_t12n{
.flag = TRIG_FLAG_12N, .flag = TRIG_FLAG_12N,
.ign_stat = &ign_box_sts, .ign_stat = &ign_box_sts,
.rt_handle_ptr = rt_task_info.xHandle}; .rt_handle_ptr = rt_handle_ptr};
isrParams isr_params_t34p{ static isrParams isr_params_t34p{
.flag = TRIG_FLAG_34P, .flag = TRIG_FLAG_34P,
.ign_stat = &ign_box_sts, .ign_stat = &ign_box_sts,
.rt_handle_ptr = rt_task_info.xHandle}; .rt_handle_ptr = rt_handle_ptr};
isrParams isr_params_t34n{ static isrParams isr_params_t34n{
.flag = TRIG_FLAG_34N, .flag = TRIG_FLAG_34N,
.ign_stat = &ign_box_sts, .ign_stat = &ign_box_sts,
.rt_handle_ptr = rt_task_info.xHandle}; .rt_handle_ptr = rt_handle_ptr};
isrParams isr_params_sp12{ static isrParams isr_params_sp12{
.flag = SPARK_FLAG_12, .flag = SPARK_FLAG_12,
.ign_stat = &ign_box_sts, .ign_stat = &ign_box_sts,
.rt_handle_ptr = rt_task_info.xHandle}; .rt_handle_ptr = rt_handle_ptr};
isrParams isr_params_sp34{ static isrParams isr_params_sp34{
.flag = SPARK_FLAG_34, .flag = SPARK_FLAG_34,
.ign_stat = &ign_box_sts, .ign_stat = &ign_box_sts,
.rt_handle_ptr = rt_task_info.xHandle}; .rt_handle_ptr = rt_task_info.xHandle};
LOG_DEBUG("rtTask HDL Params OK, HDL* [", (uint32_t)rt_task_info.xHandle, "]");
LOG_DEBUG("rtTask ISR Params OK, ISR* [", (uint32_t)rt_int.isr_ptr, "]");
LOG_DEBUG("rtTask QUE Params OK, QUE* [", (uint32_t)rt_queue, "]");
// Create esp_timer for microsecond precision timeout // Create esp_timer for microsecond precision timeout
esp_timer_handle_t timeout_timer; esp_timer_handle_t timeout_timer;
esp_timer_create_args_t timer_args = { esp_timer_create_args_t timer_args = {
.callback = spark_timeout_callback, .callback = spark_timeout_callback,
.arg = (void *)rt_task_info.xHandle, .arg = (void*)rt_handle_ptr,
.dispatch_method = ESP_TIMER_TASK, .dispatch_method = ESP_TIMER_TASK,
.name = "spark_timeout"}; .name = "spark_timeout"};
esp_timer_create(&timer_args, &timeout_timer); if (esp_timer_create(&timer_args, &timeout_timer) != ESP_OK)
{
LOG_INFO("rtTask [", params->name.c_str(), "] Fail to allocate timeoutTimer");
vTaskDelete(NULL);
}
// Attach Pin Interrupts // 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_12p), rt_int.isr_ptr, (void *)&isr_params_t12p, RISING);
@@ -96,14 +102,19 @@ void rtIgnitionTask::rtIgnitionTask_realtime(void *pvParameters)
attachInterruptArg(digitalPinToInterrupt(rt_int.spark_pin_12), rt_int.isr_ptr, (void *)&isr_params_sp12, 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); attachInterruptArg(digitalPinToInterrupt(rt_int.spark_pin_34), rt_int.isr_ptr, (void *)&isr_params_sp34, RISING);
LOG_INFO("rtTask ISR Attach OK [", rt_task_name, "]"); 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 // Global rt_task_ptr variables
bool first_cycle = true; bool first_cycle = true;
bool cycle12 = false; bool cycle12 = false;
bool cycle34 = false; bool cycle34 = false;
int64_t last_cycle_time = 0;
uint32_t n_errors = 0;
while (params->rt_running) while (params->rt_running)
{ {
@@ -118,43 +129,70 @@ void rtIgnitionTask::rtIgnitionTask_realtime(void *pvParameters)
portMAX_DELAY); portMAX_DELAY);
if (first_cycle && pickup_flag != TRIG_FLAG_12P) // skip first cycle because of possible initial noise on pickup signals at startu if (first_cycle && pickup_flag != TRIG_FLAG_12P) // skip first cycle because of possible initial noise on pickup signals at startu
{
continue; 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 // Start microsecond precision timeout timer
esp_timer_stop(timeout_timer); // stop timer in case it was running from previous cycle esp_timer_stop(timeout_timer); // stop timer in case it was running from previous cycle
esp_timer_start_once(timeout_timer, spark_timeout_max); 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 // WAIT FOR SPARK TO HAPPEN OR TIMEOUT
xTaskNotifyWait( BaseType_t sp = pdFALSE;
sp = xTaskNotifyWait(
0x00, // non pulire all'ingresso 0x00, // non pulire all'ingresso
ULONG_MAX, // pulisci i primi 8 bit ULONG_MAX, // pulisci i primi 8 bit
&spark_flag, // valore ricevuto &spark_flag, // valore ricevuto
portMAX_DELAY); // wait indefinitely, timeout handled by esp_timer portMAX_DELAY); // wait indefinitely, timeout handled by esp_timer
// Handle timeout or spark event // Handle timeout or spark event
if (spark_flag != SPARK_FLAG_TIMEOUT) if (spark_flag == SPARK_FLAG_TIMEOUT) {
spark_flag = SPARK_FLAG_NIL;
} else {
// Spark occurred, stop the timer
esp_timer_stop(timeout_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 // 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_TIMEOUT)) 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; ign_box_sts.coils12.spark_status = ign_box_sts.coils34.spark_status = sparkStatus::SPARK_SYNC_FAIL;
continue; continue;
} }
// Select coil status reference based on pickup_flag
coilsStatus *coils; coilsStatus *coils;
switch (pickup_flag) switch (pickup_flag)
{ {
case TRIG_FLAG_12P: case TRIG_FLAG_12P:
{
first_cycle = false; first_cycle = false;
// compute engine rpm from cycle time
auto current_time = esp_timer_get_time();
auto cycle_time = current_time - last_cycle_time;
last_cycle_time = current_time;
ign_box_sts.eng_rpm = (int32_t)(60.0f / (cycle_time / 1000000.0f));
}
case TRIG_FLAG_12N: case TRIG_FLAG_12N:
coils = &ign_box_sts.coils12; coils = &ign_box_sts.coils12;
break; break;
@@ -164,21 +202,24 @@ void rtIgnitionTask::rtIgnitionTask_realtime(void *pvParameters)
break; break;
} }
// Select logic based on pickup and spark flags
switch (pickup_flag) switch (pickup_flag)
{ {
case TRIG_FLAG_12P: case TRIG_FLAG_12P:
case TRIG_FLAG_34P: case TRIG_FLAG_34P:
{ {
// Timeout not occourred, expected POSITIVE edge spark OCCOURRED // Timeout not occourred, expected POSITIVE edge spark OCCOURRED
if (spark_flag != SPARK_FLAG_TIMEOUT) if (spark_flag != SPARK_FLAG_NIL)
{ {
coils->spark_delay = (int32_t)(coils->spark_time - coils->trig_time); coils->spark_delay = coils->spark_time - coils->trig_time;
coils->sstart_status = softStartStatus::NORMAL; // because spark on positive edge 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 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 // Timeout occourred, expected POSITIVE edge spark NOT OCCOURRED
else if (spark_flag == SPARK_FLAG_TIMEOUT) else if (spark_flag == SPARK_FLAG_NIL)
{ {
coils->spark_status = sparkStatus::SPARK_NEG_WAIT; coils->spark_status = sparkStatus::SPARK_NEG_WAIT;
coils->sstart_status = softStartStatus::NORMAL; coils->sstart_status = softStartStatus::NORMAL;
@@ -191,20 +232,24 @@ void rtIgnitionTask::rtIgnitionTask_realtime(void *pvParameters)
{ {
const bool expected_negative = coils->spark_status == sparkStatus::SPARK_NEG_WAIT; const bool expected_negative = coils->spark_status == sparkStatus::SPARK_NEG_WAIT;
// Timeout not occourred, expected NEGATIVE edge spark OCCOURRED // Timeout not occourred, expected NEGATIVE edge spark OCCOURRED
if (spark_flag != SPARK_FLAG_TIMEOUT && expected_negative) if (spark_flag != SPARK_FLAG_NIL && expected_negative)
{ {
coils->spark_delay = (int32_t)(coils->spark_time - coils->trig_time); coils->spark_delay = coils->spark_time - coils->trig_time;
coils->sstart_status = softStartStatus::SOFT_START; coils->sstart_status = softStartStatus::SOFT_START;
coils->spark_status = sparkStatus::SPARK_NEG_OK; 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 // Timeout occourred, expected POSITIVE edge spark NOT OCCOURRED
else if (spark_flag == SPARK_FLAG_TIMEOUT && expected_negative) else if (spark_flag == SPARK_FLAG_NIL && expected_negative)
{ {
coils->sstart_status = softStartStatus::ERROR; coils->sstart_status = softStartStatus::ERROR;
coils->spark_status = sparkStatus::SPARK_NEG_FAIL; coils->spark_status = sparkStatus::SPARK_NEG_FAIL;
} }
// Timeout not occouured, unexpected negative edge spark // Timeout not occouured, unexpected negative edge spark
else if (spark_flag != SPARK_FLAG_TIMEOUT && !expected_negative) else if (spark_flag != SPARK_FLAG_NIL && !expected_negative)
{ {
coils->sstart_status = softStartStatus::SOFT_START; coils->sstart_status = softStartStatus::SOFT_START;
coils->spark_status = sparkStatus::SPARK_NEG_UNEXPECTED; coils->spark_status = sparkStatus::SPARK_NEG_UNEXPECTED;
@@ -218,6 +263,11 @@ void rtIgnitionTask::rtIgnitionTask_realtime(void *pvParameters)
break; break;
} }
default: 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; break;
} }
@@ -225,51 +275,50 @@ void rtIgnitionTask::rtIgnitionTask_realtime(void *pvParameters)
{ {
cycle12 = false; cycle12 = false;
cycle34 = false; cycle34 = false;
// vTaskDelay(pdMS_TO_TICKS(1)); // delay 1ms to allow peak detectors to charge for negative cycle
if (ign_box_sts.coils12.spark_status == sparkStatus::SPARK_POS_FAIL || ign_box_sts.coils12.spark_status == sparkStatus::SPARK_NEG_FAIL)
ign_box_sts.coils12.n_missed_firing++;
if (ign_box_sts.coils34.spark_status == sparkStatus::SPARK_POS_FAIL || ign_box_sts.coils34.spark_status == sparkStatus::SPARK_NEG_FAIL)
ign_box_sts.coils34.n_missed_firing++;
// read adc channels: pickup12, out12 [ pos + neg ] // read adc channels: pickup12, out12 [ pos + neg ]
if (adc) // read only if adc initialized if (adc) // read only if adc initialized
{ {
uint32_t start_adc_read = esp_timer_get_time();
// from peak detector circuits // from peak detector circuits
ign_box_sts.coils12.peak_p_in = adcReadChannel(adc, ADC_CH_PEAK_12P_IN); ign_box_sts.coils12.peak_p_in = adc->convertToVoltage(adc->cycleSingle());
ign_box_sts.coils12.peak_n_in = adcReadChannel(adc, ADC_CH_PEAK_12N_IN); ign_box_sts.coils12.peak_n_in = adc->convertToVoltage(adc->cycleSingle());
ign_box_sts.coils34.peak_p_in = adcReadChannel(adc, ADC_CH_PEAK_34P_IN); ign_box_sts.coils34.peak_p_in = adc->convertToVoltage(adc->cycleSingle());
ign_box_sts.coils34.peak_n_in = adcReadChannel(adc, ADC_CH_PEAK_34N_IN); ign_box_sts.coils34.peak_n_in = adc->convertToVoltage(adc->cycleSingle());
ign_box_sts.coils12.peak_p_out = adcReadChannel(adc, ADC_CH_PEAK_12P_OUT); ign_box_sts.coils12.peak_p_out = adc->convertToVoltage(adc->cycleSingle());
ign_box_sts.coils12.peak_n_out = adcReadChannel(adc, ADC_CH_PEAK_12N_OUT); ign_box_sts.coils12.peak_n_out = adc->convertToVoltage(adc->cycleSingle());
ign_box_sts.coils34.peak_p_out = adcReadChannel(adc, ADC_CH_PEAK_34P_OUT); ign_box_sts.coils34.peak_p_out = adc->convertToVoltage(adc->cycleSingle());
ign_box_sts.coils34.peak_n_out = adcReadChannel(adc, ADC_CH_PEAK_34N_OUT); ign_box_sts.coils34.peak_n_out = adc->convertToVoltage(adc->cycleSingle());
ign_box_sts.adc_read_time = (int32_t)(esp_timer_get_time() - start_adc_read); ign_box_sts.adc_read_time = (int32_t)(esp_timer_get_time() - start_adc_read);
adc->stopConversion();
} }
else // simulate adc read timig else // simulate adc read timig
vTaskDelay(pdMS_TO_TICKS(c_adc_time)); vTaskDelay(pdMS_TO_TICKS(1));
// reset peak detectors + sample and hold // reset peak detectors + sample and hold
// outputs on io expander // outputs on io expander
if (io) if (io)
{ {
// [TODO] code to reset sample and hold and arm trigger level detectors const uint16_t iostat = io->read();
io->write(iostat | rst_bitmask);
vTaskDelay(pdMS_TO_TICKS(1));
io->write(iostat & ~rst_bitmask);
} }
else else
vTaskDelay(pdMS_TO_TICKS(1)); vTaskDelay(pdMS_TO_TICKS(1));
// send essage to main loop with ignition info, by copy so local static variable is ok // send essage to main loop with ignition info, by copy so local static variable is ok
if (rt_queue) if (rt_queue)
{
ign_box_sts.timestamp = esp_timer_get_time(); // update data timestamp ign_box_sts.timestamp = esp_timer_get_time(); // update data timestamp
if (xQueueSendToBack(rt_queue, (void *)&ign_box_sts, 0) != pdPASS) if (xQueueSendToBack(rt_queue, (void *)&ign_box_sts, 0) != pdPASS)
ign_box_sts.n_queue_errors = ++n_errors; {
ign_box_sts.n_queue_errors++;
LOG_ERROR("Failed to send to rt_queue");
} }
} }
} }
// Delete the timeout timer // Delete the timeout timer
esp_timer_delete(timeout_timer); esp_timer_delete(timeout_timer);
LOG_WARN("rtTask Ending [", rt_task_name, "]"); LOG_WARN("Ending realTime Task");
// Ignition A Interrupts DETACH // Ignition A Interrupts DETACH
detachInterrupt(rt_int.trig_pin_12p); detachInterrupt(rt_int.trig_pin_12p);
detachInterrupt(rt_int.trig_pin_12n); detachInterrupt(rt_int.trig_pin_12n);
@@ -284,6 +333,7 @@ void rtIgnitionTask::rtIgnitionTask_realtime(void *pvParameters)
///////////// CLASS MEMBER DEFINITIONS ///////////// ///////////// CLASS MEMBER DEFINITIONS /////////////
rtIgnitionTask::rtIgnitionTask(const rtTaskParams params, const uint32_t history_size, const uint32_t queue_size, const uint8_t core, std::mutex &fs_mutex, fs::FS &filesystem) : m_params(params), m_filesystem(filesystem), m_fs_mutex(fs_mutex), m_core(core), m_max_history(history_size) rtIgnitionTask::rtIgnitionTask(const rtTaskParams params, const uint32_t history_size, const uint32_t queue_size, const uint8_t core, std::mutex &fs_mutex, fs::FS &filesystem) : m_params(params), m_filesystem(filesystem), m_fs_mutex(fs_mutex), m_core(core), m_max_history(history_size)
{ {
LOG_WARN("Starting Manager for [", m_params.name.c_str(), "]");
// create queue buffers // create queue buffers
m_queue = xQueueCreate(queue_size, sizeof(ignitionBoxStatus)); m_queue = xQueueCreate(queue_size, sizeof(ignitionBoxStatus));
if (!m_queue) if (!m_queue)
@@ -302,12 +352,12 @@ rtIgnitionTask::rtIgnitionTask(const rtTaskParams params, const uint32_t history
m_active_history = std::unique_ptr<PSHistory>(&m_history_0); m_active_history = std::unique_ptr<PSHistory>(&m_history_0);
m_save_history = std::unique_ptr<PSHistory>(&m_history_1); m_save_history = std::unique_ptr<PSHistory>(&m_history_1);
LOG_WARN("Starting Manager for [", m_params.name.c_str(), "]"); m_name = (std::string("man_") + m_params.name).c_str();
// auto task_success = pdPASS; // auto task_success = pdPASS;
auto task_success = xTaskCreatePinnedToCore( auto task_success = xTaskCreatePinnedToCore(
rtIgnitionTask_manager, rtIgnitionTask_manager,
(std::string("man_") + m_params.name).c_str(), m_name.c_str(),
8192, RT_TASK_STACK,
(void *)this, (void *)this,
m_params.rt_priority >> 2, m_params.rt_priority >> 2,
&m_manager_handle, &m_manager_handle,
@@ -346,14 +396,15 @@ void rtIgnitionTask::run()
m_last_data = millis(); m_last_data = millis();
m_manager_status = rtTaskStatus::RUNNING; m_manager_status = rtTaskStatus::RUNNING;
// if history buffer is full swap buffers and if enabled save history buffer // if history buffer is full swap buffers and if enabled save history buffer
if (m_counter_status >= m_active_history->size()) if (m_counter_status >= m_max_history)
{ {
LOG_DEBUG("Save for Buffer Full: ", m_counter_status); LOG_DEBUG("Save for Buffer Full: ", m_counter_status);
m_counter_status = 0; m_counter_status = 0;
m_partial_save = false; // reset partial save flag on new data cycle m_partial_save = false; // reset partial save flag on new data cycle
std::swap(m_active_history, m_save_history); std::swap(m_active_history, m_save_history);
if (m_enable_save) if (m_enable_save)
saveHistory(*m_save_history, m_history_path); // directly call the save task function to save without delay // saveHistory(m_save_history, m_history_path); // directly call the save task function to save without delay
LOG_INFO("Save History");
} }
// update filtered data // update filtered data
@@ -375,15 +426,14 @@ void rtIgnitionTask::run()
if (m_counter_status > 0 && !m_partial_save) if (m_counter_status > 0 && !m_partial_save)
{ {
LOG_DEBUG("Save Partial: ", m_counter_status); LOG_DEBUG("Save Partial: ", m_counter_status);
m_active_history->resize(m_counter_status); // m_active_history->resize(m_counter_status);
saveHistory(*m_active_history, m_history_path); // saveHistory(m_active_history, m_history_path);
m_active_history->resize(m_max_history); // m_active_history->resize(m_max_history);
m_counter_status = 0; m_counter_status = 0;
m_partial_save = true; m_partial_save = true;
} }
m_manager_status = rtTaskStatus::IDLE; m_manager_status = rtTaskStatus::IDLE;
} }
delay(5); // yeld to another task
} }
} }
+41 -23
View File
@@ -2,19 +2,12 @@
#define DEBUGLOG_DEFAULT_LOG_LEVEL_DEBUG #define DEBUGLOG_DEFAULT_LOG_LEVEL_DEBUG
// Serial debug flag // Serial debug flag
// #define DEBUG //#define DEBUG
// Arduino Libraries // Arduino Libraries
#include <Arduino.h> #include <Arduino.h>
#include <DebugLog.h> #include <DebugLog.h>
#include "utils.h" #include "utils.h"
#include <memory>
#include <mutex>
#include <filesystem>
#include <FS.h>
#include <LittleFS.h>
#include <datasave.h>
#include <functional>
// ISR // ISR
#include "isr.h" #include "isr.h"
@@ -38,9 +31,11 @@ static const std::map<const uint32_t, const char *> names = {
}; };
#endif #endif
class rtIgnitionTask // RT task Interrupt parameters
struct rtTaskInterrupts
{ {
using PSHistory = PSRAMVector<ignitionBoxStatus>; using PSHistory = PSRAMVector<ignitionBoxStatus>;
// using PSHistory = std::vector<ignitionBoxStatus>;
public: public:
// RT task Interrupt parameters // RT task Interrupt parameters
@@ -59,19 +54,19 @@ public:
struct rtTaskIOParams struct rtTaskIOParams
{ {
const uint32_t expander_addr; const uint32_t expander_addr;
const uint8_t pot_cs_12; const uint32_t pot_cs_12;
const uint8_t pot_cs_34; const uint32_t pot_cs_34;
const uint8_t ss_force; const uint32_t ss_force;
const uint8_t ss_inhibit_12; const uint32_t ss_inhibit_12;
const uint8_t ss_inhibit_34; const uint32_t ss_inhibit_34;
const uint8_t sh_disch_12; const uint32_t sh_disch_12;
const uint8_t sh_disch_34; const uint32_t sh_disch_34;
const uint8_t sh_arm_12; const uint32_t sh_arm_12;
const uint8_t sh_arm_34; const uint32_t sh_arm_34;
const uint8_t relay_in_12; const uint32_t relay_in_12;
const uint8_t relay_in_34; const uint32_t relay_in_34;
const uint8_t relay_out_12; const uint32_t relay_out_12;
const uint8_t relay_out_34; const uint32_t relay_out_34;
}; };
// RT task parameters // RT task parameters
@@ -84,7 +79,7 @@ public:
const rtTaskInterruptParams rt_int; // interrupt pins to attach const rtTaskInterruptParams rt_int; // interrupt pins to attach
const rtTaskIOParams rt_io; // reset ping for peak detectors const rtTaskIOParams rt_io; // reset ping for peak detectors
QueueHandle_t rt_queue; // queue for task io QueueHandle_t rt_queue; // queue for task io
const std::shared_ptr<Devices> dev; Devices *dev;
}; };
enum rtTaskStatus enum rtTaskStatus
@@ -124,6 +119,7 @@ private: // static functions for FreeRTOS
private: private:
bool m_running = true; bool m_running = true;
rtTaskStatus m_manager_status = INIT; rtTaskStatus m_manager_status = INIT;
std::string m_name;
rtTaskParams m_params; rtTaskParams m_params;
const uint8_t m_core; const uint8_t m_core;
@@ -157,3 +153,25 @@ private:
static const uint8_t c_adc_time = 4; // in mS static const uint8_t c_adc_time = 4; // in mS
static const uint8_t c_io_time = 2; // in mS static const uint8_t c_io_time = 2; // in mS
}; };
// 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;
};
// RT task parameters
struct rtTaskParams
{
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
};
void rtIgnitionTask(void *pvParameters);
-73
View File
@@ -1,73 +0,0 @@
#include <ui.h>
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)
{
Serial.printf("%15s: %06u\n", name, val);
}
void printField(const char name[], const int32_t val)
{
Serial.printf("%15s: %06d\n", name, val);
}
void printField(const char name[], const int64_t val)
{
Serial.printf("%15s: %06u\n", name, (uint64_t)val);
}
void printField(const char name[], const float val)
{
Serial.printf("%15s: %4.2f\n", name, val);
}
void printField(const char name[], const char *val)
{
Serial.printf("%15s: %s\n", name, val);
}
void printInfo(const ignitionBoxStatus &info)
{
clearScreen();
setCursor(0, 0);
printField("++ Timestamp ++", (uint32_t)info.timestamp);
Serial.println("========== Coils 12 =============");
printField("Events", info.coils12.n_events);
printField("Events Missed", info.coils12.n_missed_firing);
printField("Spark Dly", (uint32_t)info.coils12.spark_delay);
printField("Spark Sts", sparkStatusNames.at(info.coils12.spark_status));
printField("Peak P_IN", info.coils12.peak_p_in);
printField("Peak N_IN", info.coils12.peak_n_in);
printField("Peak P_OUT", info.coils12.peak_p_out);
printField("Peak N_OUT", info.coils12.peak_n_out);
printField("Soft Start ", softStartStatusNames.at(info.coils12.sstart_status));
Serial.println("========== Coils 34 =============");
printField("Events", info.coils34.n_events);
printField("Events Missed", info.coils34.n_missed_firing);
printField("Spark Dly", (uint32_t)info.coils34.spark_delay);
printField("Spark Sts", sparkStatusNames.at(info.coils34.spark_status));
printField("Peak P_IN", info.coils34.peak_p_in);
printField("Peak N_IN", info.coils34.peak_n_in);
printField("Peak P_OUT", info.coils34.peak_p_out);
printField("Peak N_OUT", info.coils34.peak_n_out);
printField("Soft Start ", softStartStatusNames.at(info.coils34.sstart_status));
Serial.println("============ END ===============");
Serial.println();
printField("Engine RPM", info.eng_rpm);
printField("ADC Read Time", info.adc_read_time);
printField("Queue Errors", info.n_queue_errors);
}
+53 -10
View File
@@ -1,16 +1,59 @@
#pragma once #pragma once
#include <Arduino.h> #include <Arduino.h>
#include <datastruct.h>
#include <string>
void clearScreen(); static bool firstRun = true;
void setCursor(const uint8_t x, const uint8_t y);
void printField(const char name[], const uint32_t val);
void printField(const char name[], const int32_t val);
void printField(const char name[], const int64_t val);
void printField(const char name[], const float val);
void printField(const char name[], const char *val);
void printInfo(const ignitionBoxStatus &info); 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();
}
+19 -23
View File
@@ -1,13 +1,14 @@
#include "utils.h" #include "utils.h"
#include "freertos_stats.h"
#include "sdkconfig.h"
<<<<<<< Updated upstream
std::string printBits(uint32_t value) {
=======
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/portable.h" #include "freertos/portable.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "esp_system.h" #include "esp_system.h"
#include "esp_spi_flash.h" #include "spi_flash_mmap.h"
#include "esp_partition.h" #include "esp_partition.h"
#include "LittleFS.h" #include "LittleFS.h"
@@ -19,14 +20,13 @@
std::string printBits(uint32_t value) std::string printBits(uint32_t value)
{ {
>>>>>>> Stashed changes
std::string result; std::string result;
for (int i = 31; i >= 0; i--) for (int i = 31; i >= 0; i--) {
{
// ottieni il singolo bit // ottieni il singolo bit
result += ((value >> i) & 1) ? '1' : '0'; result += ((value >> i) & 1) ? '1' : '0';
// aggiungi uno spazio ogni 8 bit, tranne dopo l'ultimo // aggiungi uno spazio ogni 8 bit, tranne dopo l'ultimo
if (i % 8 == 0 && i != 0) if (i % 8 == 0 && i != 0) {
{
result += ' '; result += ' ';
} }
} }
@@ -49,23 +49,27 @@ void printBar(Print &printer, const char *label, size_t used, size_t total, cons
{ {
float perc = total > 0 ? ((float)used / total) : 0; float perc = total > 0 ? ((float)used / total) : 0;
int filled = perc * BAR_WIDTH; int filled = perc * BAR_WIDTH;
char str[256] = {0};
uint16_t k(0);
printer.printf("%s%-12s [" COLOR_RESET, color, label); k += sprintf(str, "%s%-12s [" COLOR_RESET, color, label);
for (int i = 0; i < BAR_WIDTH; i++) for (int i = 0; i < BAR_WIDTH; i++)
{ {
if (i < filled) if (i < filled)
printer.printf("%s#%s", color, COLOR_RESET); k += sprintf(&str[k], "%s#%s", color, COLOR_RESET);
else else
printer.printf("-"); k += sprintf(&str[k], "-");
} }
printer.printf("] %s%6.2f%%%s (%5.3f/%5.3f)MB\n", sprintf(&str[k], "] %s%6.2f%%%s (%5.3f/%5.3f)MB\n",
color, color,
perc * 100.0, perc * 100.0,
COLOR_RESET, COLOR_RESET,
(used / 1024.0f / 1024.0f), (used / 1024.0f / 1024.0f),
(total / 1024.0f / 1024.0f)); (total / 1024.0f / 1024.0f));
printer.println(str);
} }
void printRunningTasksMod(Print &printer, std::function<bool(const TaskStatus_t &a, const TaskStatus_t &b)> orderBy) void printRunningTasksMod(Print &printer, std::function<bool(const TaskStatus_t &a, const TaskStatus_t &b)> orderBy)
@@ -95,6 +99,7 @@ void printRunningTasksMod(Print &printer, std::function<bool(const TaskStatus_t
// Compute system total runtime // Compute system total runtime
ulCurrentRunTime = ulTotalRunTime - ulLastRunTime; ulCurrentRunTime = ulTotalRunTime - ulLastRunTime;
ulCurrentRunTime = ulCurrentRunTime > 0 ? ulCurrentRunTime : 1;
ulLastRunTime = ulTotalRunTime; ulLastRunTime = ulTotalRunTime;
// PRINT MEMORY INFO // PRINT MEMORY INFO
@@ -134,17 +139,6 @@ void printRunningTasksMod(Print &printer, std::function<bool(const TaskStatus_t
ESP_PARTITION_SUBTYPE_APP_FACTORY, ESP_PARTITION_SUBTYPE_APP_FACTORY,
NULL); NULL);
if (app_partition)
{
size_t totalAPP = app_partition->size; // dimensione reale partizione
size_t sketchSize = ESP.getSketchSize();
printBar(printer, "FLASH APP", sketchSize, totalAPP, COLOR_CYAN);
}
else
{
printer.printf(COLOR_YELLOW "%-12s [NOT FOUND]\n" COLOR_RESET, "FLASH APP");
}
// ===== LITTLEFS (corretto con partition table) ===== // ===== LITTLEFS (corretto con partition table) =====
const esp_partition_t *fs_partition = const esp_partition_t *fs_partition =
esp_partition_find_first(ESP_PARTITION_TYPE_DATA, esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
@@ -164,7 +158,9 @@ void printRunningTasksMod(Print &printer, std::function<bool(const TaskStatus_t
// ===== MIN HEAP ===== // ===== MIN HEAP =====
size_t minHeap = esp_get_minimum_free_heap_size(); size_t minHeap = esp_get_minimum_free_heap_size();
printer.printf("%s\nMin Heap Ever:%s %u KB\n\n", COLOR_RED, COLOR_RESET, minHeap / 1024); printer.printf("%s\nMin Heap Ever:%s %u KB\n", COLOR_RED, COLOR_RESET, minHeap / 1024);
size_t max_block = heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM);
printer.printf("%s\nMax PSRAM Block:%s %u KB\n\n", COLOR_RED, COLOR_RESET, max_block / 1024);
// Print Runtime Information // Print Runtime Information
printer.printf("Tasks: %u, Runtime: %lus, Period: %luus\r\n", uxArraySize, ulTotalRunTime / 1000000, ulCurrentRunTime); printer.printf("Tasks: %u, Runtime: %lus, Period: %luus\r\n", uxArraySize, ulTotalRunTime / 1000000, ulCurrentRunTime);
-9
View File
@@ -2,14 +2,5 @@
#include <Arduino.h> #include <Arduino.h>
#include <string> #include <string>
#include <datastruct.h>
std::string printBits(uint32_t value); std::string printBits(uint32_t value);
void printRunningTasksMod(Print &printer, std::function<bool(const TaskStatus_t &a, const TaskStatus_t &b)> orderBy = nullptr);
inline void swapHistory(PSRAMVector<ignitionBoxStatus>* active, PSRAMVector<ignitionBoxStatus>* writable) {
auto *temp = active;
active = writable; // switch active and writable buffers
writable = temp; // ensure writable_history points to the buffer we just filled
}
-166
View File
@@ -1,166 +0,0 @@
#include <webserver.h>
#include <ArduinoJson.h>
static std::map<const std::string, AstroWebServer::c_commandEnum> s_webserverCommands = {
{"setTime", AstroWebServer::SET_TIME},
};
void on_ping(TimerHandle_t xTimer)
{
if (!xTimer)
return;
auto ws = (AsyncWebSocket *)pvTimerGetTimerID(xTimer);
ws->pingAll();
ws->cleanupClients();
}
AstroWebServer::AstroWebServer(const uint8_t port, fs::FS &filesystem) : m_port(port), m_webserver(AsyncWebServer(port)), m_websocket(AsyncWebSocket("/ws")), m_filesystem(filesystem)
{
LOG_DEBUG("Initializing Web Server");
m_websocket.onEvent([this](AsyncWebSocket *server, AsyncWebSocketClient *client,
AwsEventType type, void *arg, uint8_t *data, size_t len)
{ onWsEvent(server, client, type, arg, data, len); });
m_webserver.addHandler(&m_websocket);
m_webserver.serveStatic("/", m_filesystem, "/").setDefaultFile("index.html");
m_webserver.on("/upload", HTTP_POST, [this](AsyncWebServerRequest *request)
{ onUploadRequest(request); }, [this](AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final)
{ onUploadHandler(request, filename, index, data, len, final); });
m_webserver.begin();
m_websocket.enable(true);
m_pingTimer = xTimerCreate("wsPingTimer", pdMS_TO_TICKS(2000), pdTRUE, (void *)&m_websocket, on_ping);
LOG_DEBUG("Webserver Init OK");
}
AstroWebServer::~AstroWebServer()
{
xTimerDelete(m_pingTimer, pdMS_TO_TICKS(10));
m_webserver.removeHandler(&m_websocket);
m_webserver.end();
}
void AstroWebServer::sendWsData(const String &data)
{
if (m_websocket.count())
{
m_websocket.textAll(data);
}
}
void AstroWebServer::onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)
{
switch (type)
{
case WS_EVT_CONNECT:
LOG_DEBUG("WS client IP[", client->remoteIP().toString().c_str(), "]-ID[", client->id(), "] CONNECTED");
break;
case WS_EVT_DISCONNECT:
LOG_DEBUG("WS client IP[", client->remoteIP().toString().c_str(), "]-ID[", client->id(), "] DISCONNECTED");
break;
case WS_EVT_PONG:
LOG_DEBUG("WS client IP[", client->remoteIP().toString().c_str(), "]-ID[", client->id(), "] PONG");
break;
case WS_EVT_DATA:
{
AwsFrameInfo *info = (AwsFrameInfo *)arg;
if (info->final && info->index == 0 && info->len == len)
{
std::string data_str((char *)data, len);
ArduinoJson::JsonDocument doc;
if (auto rv = ArduinoJson::deserializeJson(doc, data_str) != ArduinoJson::DeserializationError::Ok)
{
LOG_ERROR("WS Client unable to deserialize Json");
return;
}
if (!doc["cmd"].is<std::string>() || !s_webserverCommands.contains(doc["cmd"]))
{
LOG_WARN("WS Client Invalid Json command [", doc["cmd"].as<std::string>().c_str(), "]");
return;
}
std::string buffer;
switch (s_webserverCommands.at(doc["cmd"]))
{
case SET_TIME:
{
auto epoch = doc["time"].as<time_t>();
timeval te{
.tv_sec = epoch,
.tv_usec = 0,
};
timezone tz{
.tz_minuteswest = 0,
.tz_dsttime = DST_MET,
};
settimeofday(&te, &tz);
time_t now = time(nullptr);
struct tm *t = localtime(&now);
buffer.resize(64);
strftime(buffer.data(), sizeof(buffer), "%Y-%m-%d %H:%M:%S", t);
LOG_DEBUG("WS Client set Datetime to: ", buffer.c_str());
break;
}
default:
// call external command callback
break;
}
}
}
}
}
void AstroWebServer::onUploadRequest(AsyncWebServerRequest *request)
{
if (m_uploadFailed)
request->send(500, "text/plain", "Upload failed");
else
request->send(200, "text/plain", "Upload successful");
}
void AstroWebServer::onUploadHandler(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final)
{
if (index == 0) // only on first iteration to open file
{
m_uploadFailed = false;
String safeName = filename;
int slashIndex = safeName.lastIndexOf('/');
if (slashIndex >= 0)
safeName = safeName.substring(slashIndex + 1);
if (safeName.length() == 0)
{
m_uploadFailed = true;
LOG_ERROR("Invalid file name");
return;
}
const std::filesystem::path filePath = std::filesystem::path(m_filesystem.mountpoint()) / safeName.c_str();
if (m_filesystem.exists(filePath.c_str()))
m_filesystem.remove(filePath.c_str());
m_uploadFile = m_filesystem.open(filePath.c_str(), FILE_WRITE);
if (!m_uploadFile)
{
m_uploadFailed = true;
LOG_ERROR("Failed to open upload file:", filePath.c_str());
return;
}
}
// Actual write of file data
if (!m_uploadFailed && m_uploadFile)
{
if (m_uploadFile.write(data, len) != len)
m_uploadFailed = true;
}
// close the file and save on final call
if (final && m_uploadFile)
{
m_uploadFile.close();
if (!m_uploadFailed)
LOG_INFO("Uploaded file to LittleFS:", filename.c_str());
}
}
-48
View File
@@ -1,48 +0,0 @@
#pragma once
#define DEBUGLOG_DEFAULT_LOG_LEVEL_DEBUG
// System includes
#include <Arduino.h>
#include <DebugLog.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>
#include <filesystem>
#include <map>
#include <FS.h>
class AstroWebServer
{
public:
AstroWebServer(const uint8_t port, fs::FS &filesystem);
~AstroWebServer();
void sendWsData(const String &data);
private:
void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client,
AwsEventType type, void *arg, uint8_t *data, size_t len);
void onUploadRequest(AsyncWebServerRequest *request);
void onUploadHandler(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final);
void onStart(AsyncWebServerRequest *request);
void onStop(AsyncWebServerRequest *request);
void onDownload(AsyncWebServerRequest *request);
private:
const uint8_t m_port = 80;
fs::FS &m_filesystem;
AsyncWebServer m_webserver;
AsyncWebSocket m_websocket;
bool m_uploadFailed = false;
fs::File m_uploadFile;
TimerHandle_t m_pingTimer = NULL;
public:
enum c_commandEnum
{
SET_TIME
};
};
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+188
View File
@@ -0,0 +1,188 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Astro Rotax Monitor</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header class="page-header">
<div class="header-content">
<img src="logo_astro_dev.svg" alt="Astro Tecnologie" class="logo">
</div>
<div>
<h1>Rotax Ignition Box Monitor</h1>
</div>
</header>
<div id="loadingIndicator" class="loading-indicator">
<span class="spinner"></span> Waiting for data...
</div>
<div class="tables-container">
<div class="box">
<h2>Box_A</h2>
<div class="box-data">
<p><strong>Timestamp:</strong> <span id="a_timestamp">-</span></p>
<p><strong>Data Valid:</strong> <span id="a_datavalid">-</span></p>
<p><strong>Generator voltage:</strong> <span id="a_volts_gen">-</span></p>
<p><strong>ADC read time:</strong> <span id="a_adc_read_time">-</span></p>
<p><strong>Queue errors:</strong> <span id="a_n_queue_errors">-</span></p>
</div>
<div class="rpm-highlight">
<strong>Engine RPM:</strong> <span id="a_eng_rpm">-</span>
</div>
<table>
<thead>
<tr>
<th>Property</th>
<th>Pickup 12</th>
<th>Pickup 34</th>
</tr>
</thead>
<tbody>
<tr>
<td>Spark delay</td>
<td id="a_coils12_spark_delay">-</td>
<td id="a_coils34_spark_delay">-</td>
</tr>
<tr>
<td>Spark status</td>
<td id="a_coils12_spark_status">-</td>
<td id="a_coils34_spark_status">-</td>
</tr>
<tr>
<td>Soft start status</td>
<td id="a_coils12_sstart_status">-</td>
<td id="a_coils34_sstart_status">-</td>
</tr>
<tr>
<td>Peak P in</td>
<td id="a_coils12_peak_p_in">-</td>
<td id="a_coils34_peak_p_in">-</td>
</tr>
<tr>
<td>Peak N in</td>
<td id="a_coils12_peak_n_in">-</td>
<td id="a_coils34_peak_n_in">-</td>
</tr>
<tr>
<td>Peak P out</td>
<td id="a_coils12_peak_p_out">-</td>
<td id="a_coils34_peak_p_out">-</td>
</tr>
<tr>
<td>Peak N out</td>
<td id="a_coils12_peak_n_out">-</td>
<td id="a_coils34_peak_n_out">-</td>
</tr>
<tr>
<td>Level spark</td>
<td id="a_coils12_level_spark">-</td>
<td id="a_coils34_level_spark">-</td>
</tr>
<tr>
<td>Spark Events</td>
<td id="a_coils12_n_events">-</td>
<td id="a_coils34_n_events">-</td>
</tr>
<tr>
<td>Missed Events</td>
<td id="a_coils12_n_missed_firing">-</td>
<td id="a_coils34_n_missed_firing">-</td>
</tr>
</tbody>
</table>
</div>
<div class="box">
<h2>Box_B</h2>
<div class="box-data">
<p><strong>Timestamp:</strong> <span id="b_timestamp">-</span></p>
<p><strong>Data Valid:</strong> <span id="b_datavalid">-</span></p>
<p><strong>Generator voltage:</strong> <span id="b_volts_gen">-</span></p>
<p><strong>ADC read time:</strong> <span id="b_adc_read_time">-</span></p>
<p><strong>Queue errors:</strong> <span id="b_n_queue_errors">-</span></p>
</div>
<div class="rpm-highlight">
<strong>Engine RPM:</strong> <span id="b_eng_rpm">-</span>
</div>
<table>
<thead>
<tr>
<th>Property</th>
<th>Pickup 12</th>
<th>Pickup 34</th>
</tr>
</thead>
<tbody>
<tr>
<td>Spark delay</td>
<td id="b_coils12_spark_delay">-</td>
<td id="b_coils34_spark_delay">-</td>
</tr>
<tr>
<td>Spark status</td>
<td id="b_coils12_spark_status">-</td>
<td id="b_coils34_spark_status">-</td>
</tr>
<tr>
<td>Soft start status</td>
<td id="b_coils12_sstart_status">-</td>
<td id="b_coils34_sstart_status">-</td>
</tr>
<tr>
<td>Peak P in</td>
<td id="b_coils12_peak_p_in">-</td>
<td id="b_coils34_peak_p_in">-</td>
</tr>
<tr>
<td>Peak N in</td>
<td id="b_coils12_peak_n_in">-</td>
<td id="b_coils34_peak_n_in">-</td>
</tr>
<tr>
<td>Peak P out</td>
<td id="b_coils12_peak_p_out">-</td>
<td id="b_coils34_peak_p_out">-</td>
</tr>
<tr>
<td>Peak N out</td>
<td id="b_coils12_peak_n_out">-</td>
<td id="b_coils34_peak_n_out">-</td>
</tr>
<tr>
<td>Level spark</td>
<td id="b_coils12_level_spark">-</td>
<td id="b_coils34_level_spark">-</td>
</tr>
<tr>
<td>Spark Events</td>
<td id="b_coils12_n_events">-</td>
<td id="b_coils34_n_events">-</td>
</tr>
<tr>
<td>Missed Events</td>
<td id="b_coils12_n_missed_firing">-</td>
<td id="b_coils34_n_missed_firing">-</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="upload-section">
<h3>Upload file to Flash</h3>
<p>Select a file and upload it to Flash.</p>
<input type="file" id="littlefsFile">
<button onclick="uploadLittleFS()">Upload</button>
<div id="uploadStatus" class="upload-status">No file uploaded yet.</div>
</div>
<script src="script.js"></script>
</body>
</html>

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

@@ -3,26 +3,6 @@ let lastMessageTimestamp = 0;
const IDLE_THRESHOLD_MS = 1000; const IDLE_THRESHOLD_MS = 1000;
const loadingIndicator = document.getElementById("loadingIndicator"); const loadingIndicator = document.getElementById("loadingIndicator");
let chartA, chartB;
let dataA = {
labels: [],
datasets: [
{ label: "RPM", data: [] },
{ label: "Coils12 Delay", data: [] },
{ label: "Coils34 Delay", data: [] }
]
};
let dataB = {
labels: [],
datasets: [
{ label: "RPM", data: [] },
{ label: "Coils12 Delay", data: [] },
{ label: "Coils34 Delay", data: [] }
]
};
function setLoadingIndicator(visible) { function setLoadingIndicator(visible) {
if (!loadingIndicator) { if (!loadingIndicator) {
return; return;
@@ -45,11 +25,6 @@ function connectWS() {
console.log("WebSocket connesso"); console.log("WebSocket connesso");
lastMessageTimestamp = Date.now(); lastMessageTimestamp = Date.now();
setLoadingIndicator(false); setLoadingIndicator(false);
ws.send(JSON.stringify({
cmd: "setTime",
time: Math.floor(Date.now() / 1000)
}));
}; };
ws.onclose = () => { ws.onclose = () => {
@@ -71,8 +46,6 @@ function connectWS() {
lastMessageTimestamp = Date.now(); lastMessageTimestamp = Date.now();
setLoadingIndicator(false); setLoadingIndicator(false);
updateCharts(data)
// Update Box_A // Update Box_A
if (data.box_a) { if (data.box_a) {
const boxA = data.box_a; const boxA = data.box_a;
@@ -145,51 +118,6 @@ function connectWS() {
}; };
} }
function updateCharts(data) {
const t = new Date().toLocaleTimeString();
// ===== BOX A =====
dataA.labels.push(t);
if (data.box_a) {
dataA.datasets[0].data.push(data.box_a.eng_rpm / 10);
dataA.datasets[1].data.push(data.box_a.coils12.spark_delay);
dataA.datasets[2].data.push(data.box_a.coils34.spark_delay);
} else {
dataA.datasets[0].data.push(undefined);
dataA.datasets[1].data.push(undefined);
dataA.datasets[2].data.push(undefined);
}
// ===== BOX B =====
dataB.labels.push(t);
if (data.box_b) {
dataB.datasets[0].data.push(data.box_b.eng_rpm / 10);
dataB.datasets[1].data.push(data.box_b.coils12.spark_delay);
dataB.datasets[2].data.push(data.box_b.coils34.spark_delay);
} else {
dataB.datasets[0].data.push(undefined);
dataB.datasets[1].data.push(undefined);
dataB.datasets[2].data.push(undefined);
}
// limite buffer
const maxPoints = 100;
if (dataA.labels.length > maxPoints) {
dataA.labels.shift();
dataA.datasets.forEach(d => d.data.shift());
}
if (dataB.labels.length > maxPoints) {
dataB.labels.shift();
dataB.datasets.forEach(d => d.data.shift());
}
chartA.update();
chartB.update();
}
function start() { function start() {
fetch("/start"); fetch("/start");
} }
@@ -232,61 +160,5 @@ function uploadLittleFS() {
}); });
} }
function openTab(tabId) {
document.querySelectorAll('.tab-content').forEach(tab => {
tab.classList.remove('active');
});
document.querySelectorAll('.tab-button').forEach(btn => {
btn.classList.remove('active');
});
document.getElementById(tabId).classList.add('active');
event.target.classList.add('active');
}
function initCharts() {
const ctxA = document.getElementById('chartA').getContext('2d');
const ctxB = document.getElementById('chartB').getContext('2d');
chartA = new Chart(ctxA, {
type: 'line',
data: dataA,
options: {
animation: false,
responsive: true,
scales: {
x: {
display: true
},
y: {
beginAtZero: true
}
}
}
});
chartB = new Chart(ctxB, {
type: 'line',
data: dataB,
options: {
animation: false,
responsive: true,
scales: {
x: {
display: true
},
y: {
beginAtZero: true
}
}
}
});
}
window.onload = () => {
initCharts();
};
setInterval(updateLoadingState, 200); setInterval(updateLoadingState, 200);
connectWS(); connectWS();
@@ -219,41 +219,3 @@ button:hover {
span { span {
color: var(--text-dark); color: var(--text-dark);
} }
/* TABS */
.tabs {
display: flex;
justify-content: center;
margin: 20px;
}
.tab-button {
padding: 10px 20px;
margin: 0 5px;
border: none;
cursor: pointer;
background: var(--border-color);
border-radius: 4px;
}
.tab-button.active {
background: var(--primary-blue);
color: white;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
.chart-container {
max-width: 1000px;
margin: 20px auto;
background: white;
padding: 20px;
border-radius: 6px;
box-shadow: 0 1px 3px rgba(0,0,0,0.08);
}
+2 -1
View File
@@ -1,7 +1,8 @@
{ {
"recommendations": [ "recommendations": [
"Jason2866.esp-decoder", "Jason2866.esp-decoder",
"pioarduino.pioarduino-ide" "pioarduino.pioarduino-ide",
"platformio.platformio-ide"
], ],
"unwantedRecommendations": [ "unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack" "ms-vscode.cpptools-extension-pack"
+2 -2
View File
@@ -16,7 +16,7 @@ lib_deps =
hideakitai/DebugLog@^0.8.4 hideakitai/DebugLog@^0.8.4
board_build.flash_size = 4MB board_build.flash_size = 4MB
board_build.partitions = default.csv board_build.partitions = default.csv
monitor_speed = 921600 monitor_speed = 115200
build_type = release build_type = release
[env:esp32-devtest-debug] [env:esp32-devtest-debug]
@@ -27,7 +27,7 @@ lib_deps =
hideakitai/DebugLog@^0.8.4 hideakitai/DebugLog@^0.8.4
board_build.flash_size = 4MB board_build.flash_size = 4MB
board_build.partitions = default.csv board_build.partitions = default.csv
monitor_speed = 921600 monitor_speed = 115200
build_type = debug build_type = debug
build_flags = build_flags =
-O0 -O0
+10 -97
View File
@@ -1,5 +1,3 @@
#define DEBUGLOG_DEFAULT_LOG_LEVEL_DEBUG
#include <Arduino.h> #include <Arduino.h>
#include <DebugLog.h> #include <DebugLog.h>
@@ -18,19 +16,15 @@ static uint32_t count = 0;
#define SPARK_DLY_MAX 490 #define SPARK_DLY_MAX 490
#define PAUSE_LONG_MIN 5000 #define PAUSE_LONG_MIN 5000
#define PAUSE_LONG_MAX PAUSE_LONG_MIN * 100 #define PAUSE_LONG_MAX PAUSE_LONG_MIN*100
#define RPM_MIN 250 void clearScreen(){
#define RPM_MAX 5500
void clearScreen()
{
Serial.print("\033[2J"); // clear screen Serial.print("\033[2J"); // clear screen
Serial.print("\033[H"); // cursor home Serial.print("\033[H"); // cursor home
Serial.flush(); Serial.flush();
} }
static double filtered_rpm = 0; static double filtered = 0;
static const std::map<const uint32_t, const char *> pin2Name = { static const std::map<const uint32_t, const char *> pin2Name = {
{PIN_TRIG_A12P, "HIGH_PIN_TRIG_A12P"}, {PIN_TRIG_A12P, "HIGH_PIN_TRIG_A12P"},
@@ -55,34 +49,8 @@ static timerStatus stsA = {
.coil_pulse_us = 1000, .coil_pulse_us = 1000,
.spark_pulse_us = 100, .spark_pulse_us = 100,
.spark_delay_us = 50, .spark_delay_us = 50,
.pins = {
.pin_trig_12p = PIN_TRIG_A12P,
.pin_trig_12n = PIN_TRIG_A12N,
.pin_trig_34p = PIN_TRIG_A34P,
.pin_trig_34n = PIN_TRIG_A34N,
.pin_spark_12 = SPARK_A12,
.pin_spark_34 = SPARK_A34},
.main_task = NULL}; .main_task = NULL};
static timerStatus stsB = {
.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,
.pins = {
.pin_trig_12p = PIN_TRIG_B12P,
.pin_trig_12n = PIN_TRIG_B12N,
.pin_trig_34p = PIN_TRIG_B34P,
.pin_trig_34n = PIN_TRIG_B34N,
.pin_spark_12 = SPARK_B12,
.pin_spark_34 = SPARK_B34},
.main_task = NULL};
static bool isEnabled_A = false;
static bool isEnabled_B = false;
void setup() void setup()
{ {
@@ -105,28 +73,11 @@ void setup()
pinMode(SPARK_B34, OUTPUT); pinMode(SPARK_B34, OUTPUT);
pinMode(SPARK_DELAY_POT, ANALOG); pinMode(SPARK_DELAY_POT, ANALOG);
pinMode(FREQ_POT, ANALOG);
pinMode(ENABLE_PIN_A, INPUT_PULLUP);
pinMode(ENABLE_PIN_B, INPUT_PULLUP);
// get the task handle for the main loop
stsA.main_task = xTaskGetCurrentTaskHandleForCore(1); stsA.main_task = xTaskGetCurrentTaskHandleForCore(1);
stsB.main_task = xTaskGetCurrentTaskHandleForCore(1);
// Begin timer with preset fixed frequency
timerA = timerBegin(FREQUENCY); timerA = timerBegin(FREQUENCY);
timerB = timerBegin(FREQUENCY);
// Stop timers because of autostart
timerStop(timerA);
timerStop(timerB);
// Attach interrupts and call callback every timer expiry
timerAttachInterruptArg(timerA, &onTimer, (void *)&stsA); timerAttachInterruptArg(timerA, &onTimer, (void *)&stsA);
timerAttachInterruptArg(timerB, &onTimer, (void *)&stsB); timerAlarm(timerA, 1, true, 0);
timerAlarm(timerA, 1, true, 0); // infinite number of reloads
timerAlarm(timerB, 1, true, 0);
LOG_INFO("Setup Complete"); LOG_INFO("Setup Complete");
} }
@@ -136,59 +87,21 @@ void loop()
LOG_INFO("Loop: ", count++); 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); 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; stsA.spark_delay_us = spark_delay * PERIOD_US;
if (stsA.spark_delay_us > (SPARK_DLY_MIN + SPARK_DLY_MAX) / 2) if (stsA.spark_delay_us > (SPARK_DLY_MIN + SPARK_DLY_MAX) / 2) {
{
stsA.soft_start = true; stsA.soft_start = true;
stsA.spark_delay_us -= (SPARK_DLY_MIN + SPARK_DLY_MAX) / 2; stsA.spark_delay_us -= (SPARK_DLY_MIN + SPARK_DLY_MAX) / 2;
} } else {
else
{
stsA.soft_start = false; stsA.soft_start = false;
} }
stsB.soft_start = stsA.soft_start;
stsB.spark_delay_us = stsA.spark_delay_us;
double new_rpm = (double)(map(analogRead(FREQ_POT), 0, 4096, RPM_MIN, RPM_MAX));
filtered_rpm = filtered_rpm + 0.1 * (new_rpm - filtered_rpm);
stsA.pause_long_us = (uint32_t)(60000000.0f / filtered_rpm / 2.0f);
stsB.pause_long_us = stsA.pause_long_us;
if (isEnabled_A)
LOG_INFO("==== System A is ENABLED ====");
else
LOG_INFO("==== System A is DISABLED ====");
if (isEnabled_B)
LOG_INFO("==== System B is ENABLED ====");
else
LOG_INFO("==== System B is DISABLED ====");
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("Spark Delay uS: ", stsA.spark_delay_us, "\tSoft Start: ", stsA.soft_start ? "TRUE" : "FALSE");
LOG_INFO("Engine Rpm: ", (uint32_t)(filtered_rpm)); LOG_INFO("Pause: ", (uint32_t)(stsA.pause_long_us / 1000), "ms");
LOG_INFO("Coil Pulse: ", stsA.coil_pulse_us, "us"); LOG_INFO("Coil Pulse: ", stsA.coil_pulse_us, "us");
LOG_INFO("Spark Pulse: ", stsA.spark_pulse_us, "us"); LOG_INFO("Spark Pulse: ", stsA.spark_pulse_us, "us");
if (digitalRead(ENABLE_PIN_A) == LOW && !isEnabled_A)
{
timerStart(timerA);
isEnabled_A = true;
}
else if (digitalRead(ENABLE_PIN_A) == HIGH && isEnabled_A)
{
timerStop(timerA);
isEnabled_A = false;
}
if (digitalRead(ENABLE_PIN_B) == LOW && !isEnabled_B)
{
timerStart(timerB);
isEnabled_B = true;
}
else if (digitalRead(ENABLE_PIN_B) == HIGH && isEnabled_B)
{
timerStop(timerB);
isEnabled_B = false;
}
delay(100); delay(100);
clearScreen(); clearScreen();
-4
View File
@@ -1,9 +1,5 @@
#pragma once #pragma once
// Enable Pin
#define ENABLE_PIN_A 16
#define ENABLE_PIN_B 15
///// Ignition Box A ///// ///// Ignition Box A /////
#define PIN_TRIG_A12P 18 #define PIN_TRIG_A12P 18
#define PIN_TRIG_A12N 19 #define PIN_TRIG_A12N 19
+38 -17
View File
@@ -7,18 +7,20 @@ void onTimer(void *arg)
BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t xHigherPriorityTaskWoken = pdFALSE;
timerStatus *params = (timerStatus *)(arg); timerStatus *params = (timerStatus *)(arg);
TaskHandle_t task = params->main_task; TaskHandle_t task = params->main_task;
const timerPins pins = params->pins;
// increment state time // increment state time
params->state_time += params->clock_period_us; params->state_time += params->clock_period_us;
digitalWrite(PIN_TRIG_B12P, HIGH);
switch (params->state) switch (params->state)
{ {
case S_12P: case S_12P:
if (params->state_time == params->clock_period_us && !params->coil12p_high) if (params->state_time == params->clock_period_us && !params->coil12p_high)
{ {
digitalWrite(pins.pin_trig_12p, HIGH); // xTaskNotifyFromISR(task, PIN_TRIG_A12P, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
digitalWrite(PIN_TRIG_A12P, HIGH);
params->coil12p_high = true; params->coil12p_high = true;
wait_sent = false; wait_sent = false;
} }
@@ -27,18 +29,21 @@ void onTimer(void *arg)
{ {
if (params->state_time == params->spark_delay_us) if (params->state_time == params->spark_delay_us)
{ {
digitalWrite(pins.pin_spark_12, HIGH); // xTaskNotifyFromISR(task, SPARK_A12, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
digitalWrite(SPARK_A12, HIGH);
} }
if (params->state_time == (params->spark_delay_us + params->spark_pulse_us)) if (params->state_time == (params->spark_delay_us + params->spark_pulse_us))
{ {
digitalWrite(pins.pin_spark_12, LOW); // xTaskNotifyFromISR(task, ~SPARK_A12, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
digitalWrite(SPARK_A12, LOW);
} }
} }
if (params->state_time >= params->coil_pulse_us && params->coil12p_high) if (params->state_time >= params->coil_pulse_us && params->coil12p_high)
{ {
digitalWrite(pins.pin_trig_12p, LOW); // xTaskNotifyFromISR(task, ~PIN_TRIG_A12P, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
digitalWrite(PIN_TRIG_A12P, LOW);
params->coil12p_high = false; params->coil12p_high = false;
} }
@@ -52,7 +57,8 @@ void onTimer(void *arg)
case S_12N: case S_12N:
if (params->state_time == params->clock_period_us && !params->coil12n_high) if (params->state_time == params->clock_period_us && !params->coil12n_high)
{ {
digitalWrite(pins.pin_trig_12n, HIGH); // xTaskNotifyFromISR(task, PIN_TRIG_A12N, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
digitalWrite(PIN_TRIG_A12N, HIGH);
params->coil12n_high = true; params->coil12n_high = true;
} }
@@ -60,18 +66,21 @@ void onTimer(void *arg)
{ {
if (params->state_time == params->spark_delay_us) if (params->state_time == params->spark_delay_us)
{ {
digitalWrite(pins.pin_spark_12, HIGH); // xTaskNotifyFromISR(task, SPARK_A12, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
digitalWrite(SPARK_A12, HIGH);
} }
if (params->state_time == (params->spark_delay_us + params->spark_pulse_us)) if (params->state_time == (params->spark_delay_us + params->spark_pulse_us))
{ {
digitalWrite(pins.pin_spark_12, LOW); // xTaskNotifyFromISR(task, ~SPARK_A12, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
digitalWrite(SPARK_A12, LOW);
} }
} }
if (params->state_time >= params->coil_pulse_us && params->coil12n_high) if (params->state_time >= params->coil_pulse_us && params->coil12n_high)
{ {
digitalWrite(pins.pin_trig_12n, LOW); // xTaskNotifyFromISR(task, ~PIN_TRIG_A12N, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
digitalWrite(PIN_TRIG_A12N, LOW);
params->coil12n_high = false; params->coil12n_high = false;
params->state = S_WAIT_10MS; params->state = S_WAIT_10MS;
params->state_time = 0; params->state_time = 0;
@@ -81,6 +90,7 @@ void onTimer(void *arg)
case S_WAIT_10MS: case S_WAIT_10MS:
if (!wait_sent) if (!wait_sent)
{ {
// xTaskNotifyFromISR(task, S_WAIT_10MS, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
wait_sent = true; wait_sent = true;
} }
if (params->state_time >= params->pause_long_us) if (params->state_time >= params->pause_long_us)
@@ -93,7 +103,8 @@ void onTimer(void *arg)
case S_34P: case S_34P:
if (params->state_time == params->clock_period_us && !params->coil34p_high) if (params->state_time == params->clock_period_us && !params->coil34p_high)
{ {
digitalWrite(pins.pin_trig_34p, HIGH); // xTaskNotifyFromISR(task, PIN_TRIG_A34P, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
digitalWrite(PIN_TRIG_A34P, HIGH);
params->coil34p_high = true;; params->coil34p_high = true;;
wait_sent = false; wait_sent = false;
} }
@@ -102,18 +113,21 @@ void onTimer(void *arg)
{ {
if (params->state_time == params->spark_delay_us) if (params->state_time == params->spark_delay_us)
{ {
digitalWrite(pins.pin_spark_34, HIGH); // xTaskNotifyFromISR(task, SPARK_A34, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
digitalWrite(SPARK_A34, HIGH);
} }
if (params->state_time == params->spark_delay_us + params->spark_pulse_us) if (params->state_time == params->spark_delay_us + params->spark_pulse_us)
{ {
digitalWrite(pins.pin_spark_34, LOW); // xTaskNotifyFromISR(task, ~SPARK_A34, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
digitalWrite(SPARK_A34, LOW);
} }
} }
if (params->state_time >= params->coil_pulse_us && params->coil34p_high) if (params->state_time >= params->coil_pulse_us && params->coil34p_high)
{ {
digitalWrite(pins.pin_trig_34p, LOW); // xTaskNotifyFromISR(task, ~PIN_TRIG_A34P, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
digitalWrite(PIN_TRIG_A34P, LOW);
params->coil34p_high = false; params->coil34p_high = false;
} }
@@ -127,7 +141,8 @@ void onTimer(void *arg)
case S_34N: case S_34N:
if (params->state_time == params->clock_period_us && !params->coil34n_high) if (params->state_time == params->clock_period_us && !params->coil34n_high)
{ {
digitalWrite(pins.pin_trig_34n, HIGH); // xTaskNotifyFromISR(task, PIN_TRIG_A34N, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
digitalWrite(PIN_TRIG_A34N, HIGH);
params->coil34n_high = true; params->coil34n_high = true;
} }
@@ -135,18 +150,21 @@ void onTimer(void *arg)
{ {
if (params->state_time == params->spark_delay_us) if (params->state_time == params->spark_delay_us)
{ {
digitalWrite(pins.pin_spark_34, HIGH); // xTaskNotifyFromISR(task, SPARK_A34, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
digitalWrite(SPARK_A34, HIGH);
} }
if (params->state_time == params->spark_delay_us + params->spark_pulse_us) if (params->state_time == params->spark_delay_us + params->spark_pulse_us)
{ {
digitalWrite(pins.pin_spark_34, LOW); // xTaskNotifyFromISR(task, ~SPARK_A34, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
digitalWrite(SPARK_A34, LOW);
} }
} }
if (params->state_time >= params->coil_pulse_us && params->coil34n_high) if (params->state_time >= params->coil_pulse_us && params->coil34n_high)
{ {
digitalWrite(pins.pin_trig_34n, LOW); // xTaskNotifyFromISR(task, ~PIN_TRIG_A34N, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
digitalWrite(PIN_TRIG_A34N, LOW);
params->coil34n_high = false; params->coil34n_high = false;
params->state = S_WAIT_10MS_END; params->state = S_WAIT_10MS_END;
params->state_time = 0; params->state_time = 0;
@@ -156,6 +174,7 @@ void onTimer(void *arg)
case S_WAIT_10MS_END: case S_WAIT_10MS_END:
if (!wait_sent) if (!wait_sent)
{ {
// xTaskNotifyFromISR(task, S_WAIT_10MS_END, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
wait_sent = true; wait_sent = true;
} }
if (params->state_time >= params->pause_long_us) if (params->state_time >= params->pause_long_us)
@@ -166,6 +185,8 @@ void onTimer(void *arg)
break; break;
} }
digitalWrite(PIN_TRIG_B12P, LOW);
if (xHigherPriorityTaskWoken) if (xHigherPriorityTaskWoken)
portYIELD_FROM_ISR(); portYIELD_FROM_ISR();
} }
-12
View File
@@ -1,7 +1,5 @@
#pragma once #pragma once
#define DEBUGLOG_DEFAULT_LOG_LEVEL_DEBUG
#include <Arduino.h> #include <Arduino.h>
#include <DebugLog.h> #include <DebugLog.h>
#include "pins.h" #include "pins.h"
@@ -21,15 +19,6 @@ enum State
S_WAIT_10MS_END S_WAIT_10MS_END
}; };
struct timerPins {
const uint8_t pin_trig_12p;
const uint8_t pin_trig_12n;
const uint8_t pin_trig_34p;
const uint8_t pin_trig_34n;
const uint8_t pin_spark_12;
const uint8_t pin_spark_34;
};
struct timerStatus struct timerStatus
{ {
State state = State::S_12P; State state = State::S_12P;
@@ -45,7 +34,6 @@ struct timerStatus
bool coil34p_high = false; bool coil34p_high = false;
bool coil12n_high = false; bool coil12n_high = false;
bool coil34n_high = false; bool coil34n_high = false;
timerPins pins;
TaskHandle_t main_task; TaskHandle_t main_task;
}; };