6 Commits

Author SHA1 Message Date
Obbart 7e7d0a1c59 Second ADC debugging in process 2026-04-21 16:11:07 +02:00
Emanuele Trabattoni dce6b0fd4f working on second adc 2026-04-17 13:24:43 +02:00
Emanuele Trabattoni bea29dc8f5 ADC ok with interrupt or drdy 2026-04-17 12:21:35 +02:00
Emanuele Trabattoni 1b8ba88b05 ADC working ok in sync with system 2026-04-17 11:01:41 +02:00
Obbart 5aa5aaa07a ADC Testing 2026-04-17 09:13:05 +02:00
Obbart 1b7a531d54 Updated test instrument with cli commands 2026-04-17 09:11:41 +02:00
13 changed files with 656 additions and 491 deletions
+208 -201
View File
@@ -14,34 +14,64 @@
#include "Arduino.h" #include "Arduino.h"
#include "ADS1256.h" #include "ADS1256.h"
#include "SPI.h" #include "SPI.h"
#include <DebugLog.h>
#include "DebugLog.h"
#define convertSigned24BitToLong(value) ((value) & (1l << 23) ? (value) - 0x1000000 : value) #define convertSigned24BitToLong(value) ((value) & (1l << 23) ? (value) - 0x1000000 : value)
void IRAM_ATTR drdyCallback(void *arg)
{
auto cls = (ADS1256 *)arg;
if (!arg)
return;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (digitalRead(cls->getDRDYpin())) // impose wait on low
{
xSemaphoreTakeFromISR(cls->getDRDYsemaphoreLow(), &xHigherPriorityTaskWoken);
xSemaphoreGiveFromISR(cls->getDRDYsemaphoreHigh(), &xHigherPriorityTaskWoken);
}
else // impose wait on high
{
xSemaphoreTakeFromISR(cls->getDRDYsemaphoreHigh(), &xHigherPriorityTaskWoken);
xSemaphoreGiveFromISR(cls->getDRDYsemaphoreLow(), &xHigherPriorityTaskWoken);
}
if (xHigherPriorityTaskWoken)
portYIELD_FROM_ISR();
}
// Constructor // 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), 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) m_DRDY_pin(DRDY_pin), m_RESET_pin(RESET_pin), m_SYNC_pin(SYNC_pin), m_CS_pin(CS_pin), m_VREF(VREF), m_PGA(0)
{ {
pinMode(_DRDY_pin, INPUT); pinMode(m_DRDY_pin, INPUT);
if (RESET_pin != PIN_UNUSED) if (RESET_pin != PIN_UNUSED)
{ {
pinMode(_RESET_pin, OUTPUT); pinMode(m_RESET_pin, OUTPUT);
} }
if (SYNC_pin != PIN_UNUSED) if (SYNC_pin != PIN_UNUSED)
{ {
pinMode(_SYNC_pin, OUTPUT); pinMode(m_SYNC_pin, OUTPUT);
} }
if (CS_pin != PIN_UNUSED) if (CS_pin != PIN_UNUSED)
{ {
pinMode(_CS_pin, OUTPUT); pinMode(m_CS_pin, OUTPUT);
} }
LOG_DEBUG("ADC Class Init OK");
updateConversionParameter(); updateConversionParameter();
// m_drdyHigh = xSemaphoreCreateBinary();
// m_drdyLow = xSemaphoreCreateBinary();
// if (!m_drdyHigh || !m_drdyLow) {
// LOG_ERROR("ADC Unable to create interrupt semaphores");
// return;
// }
// xSemaphoreGive(m_drdyHigh);
// xSemaphoreGive(m_drdyLow);
//attachInterruptArg(DRDY_pin, drdyCallback, (void *)this, CHANGE);
} }
// Initialization // Initialization
@@ -51,101 +81,95 @@ void ADS1256::InitializeADC()
CS_LOW(); CS_LOW();
// We do a manual chip reset on the ADS1256 - Datasheet Page 27/ RESET // We do a manual chip reset on the ADS1256 - Datasheet Page 27/ RESET
if (_RESET_pin != PIN_UNUSED) if (m_RESET_pin != PIN_UNUSED)
{ {
digitalWrite(_RESET_pin, LOW); digitalWrite(m_RESET_pin, LOW);
delay(200); delay(200);
digitalWrite(_RESET_pin, HIGH); // RESET is set to high digitalWrite(m_RESET_pin, HIGH); // RESET is set to high
delay(1000); delay(1000);
} }
// Sync pin is also treated if it is defined // Sync pin is also treated if it is defined
if (_SYNC_pin != PIN_UNUSED) if (m_SYNC_pin != PIN_UNUSED)
{ {
digitalWrite(_SYNC_pin, HIGH); // RESET is set to high digitalWrite(m_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 // 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 // We both pass values to the variables and then send those values to the corresponding registers
delay(200); delay(200);
_STATUS = 0b00110110; // BUFEN and ACAL enabled, Order is MSB, rest is read only m_STATUS = 0b00110110; // BUFEN and ACAL enabled, Order is MSB, rest is read only
writeRegister(STATUS_REG, _STATUS); writeRegister(STATUS_REG, m_STATUS);
delay(200); delay(200);
_MUX = 0b00000001; // MUX AIN0+AIN1 m_MUX = DIFF_0_1; // MUX AIN0+AIN1
writeRegister(MUX_REG, _MUX); writeRegister(MUX_REG, m_MUX);
delay(200); delay(200);
_ADCON = 0b00000000; // ADCON - CLK: OFF, SDCS: OFF, PGA = 0 (+/- 5 V) m_ADCON = WAKEUP; // ADCON - CLK: OFF, SDCS: OFF, PGA = 0 (+/- 5 V)
writeRegister(ADCON_REG, _ADCON); writeRegister(ADCON_REG, m_ADCON);
delay(200); delay(200);
updateConversionParameter(); updateConversionParameter();
_DRATE = 0b10000010; // 100SPS m_DRATE = DRATE_100SPS; // 100SPS
writeRegister(DRATE_REG, _DRATE); writeRegister(DRATE_REG, m_DRATE);
delay(200);
sendDirectCommand(0b11110000); // Offset and self-gain calibration
delay(200); delay(200);
_isAcquisitionRunning = false; // MCU will be waiting to start a continuous acquisition sendDirectCommand(SELFCAL); // Offset and self-gain calibration
delay(200);
m_isAcquisitionRunning = false; // MCU will be waiting to start a continuous acquisition
} }
void ADS1256::waitForLowDRDY() void ADS1256::waitForLowDRDY()
{ {
while (digitalRead(_DRDY_pin) == HIGH) while(digitalRead(m_DRDY_pin) == HIGH) {vTaskDelay(1);};
{ // xSemaphoreTake(m_drdyLow, pdMS_TO_TICKS(10));
} // xSemaphoreGive(m_drdyLow);
} }
void ADS1256::waitForHighDRDY() void ADS1256::waitForHighDRDY()
{ {
#if F_CPU >= 48000000 // Fast MCUs need this protection to wait until DRDY goes high after a conversion while(digitalRead(m_DRDY_pin) == LOW) {vTaskDelay(1);};
while (digitalRead(_DRDY_pin) == LOW) // xSemaphoreTake(m_drdyHigh, pdMS_TO_TICKS(10));
{ // xSemaphoreGive(m_drdyHigh);
}
#endif
} }
void ADS1256::stopConversion() // Sending SDATAC to stop the continuous conversion void ADS1256::stopConversion() // Sending SDATAC to stop the continuous conversion
{ {
waitForLowDRDY(); // SDATAC should be called after DRDY goes LOW (p35. Figure 33) waitForLowDRDY(); // SDATAC should be called after DRDY goes LOW (p35. Figure 33)
_spi->transfer(0b00001111); // Send SDATAC to the ADC _spi->transfer(SDATAC); // Send SDATAC to the ADC
CS_HIGH(); // We finished the command sequence, so we switch it back to HIGH CS_HIGH(); // We finished the command sequence, so we switch it back to HIGH
_spi->endTransaction(); _spi->endTransaction();
_isAcquisitionRunning = false; // Reset to false, so the MCU will be able to start a new conversion m_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) void ADS1256::setDRATE(uint8_t drate) // Setting DRATE (sampling frequency)
{ {
writeRegister(DRATE_REG, drate); writeRegister(DRATE_REG, drate);
_DRATE = drate; m_DRATE = drate;
delayMicroseconds(500); delay(200);
} }
void ADS1256::setMUX(uint8_t mux) // Setting MUX (input channel) void ADS1256::setMUX(uint8_t mux) // Setting MUX (input channel)
{ {
writeRegister(MUX_REG, mux); writeRegister(MUX_REG, mux);
_MUX = mux; m_MUX = mux;
// delayMicroseconds(500); delay(200);
} }
void ADS1256::setPGA(uint8_t pga) // Setting PGA (input voltage range) void ADS1256::setPGA(uint8_t pga) // Setting PGA (input voltage range)
{ {
_PGA = pga; m_PGA = pga;
_ADCON = readRegister(ADCON_REG); // Read the most recent value of the register m_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 m_ADCON = (m_ADCON & 0b11111000) | (m_PGA & 0b00000111); // Clearing and then setting bits 2-0 based on pga
writeRegister(ADCON_REG, _ADCON); writeRegister(ADCON_REG, m_ADCON);
delayMicroseconds(1000); // Delay to allow the PGA to settle after changing its value delay(200);
updateConversionParameter(); // Update the multiplier according top the new PGA value updateConversionParameter(); // Update the multiplier according top the new PGA value
} }
@@ -160,101 +184,101 @@ uint8_t ADS1256::getPGA() // Reading PGA from the ADCON register
void ADS1256::setCLKOUT(uint8_t clkout) // Setting CLKOUT void ADS1256::setCLKOUT(uint8_t clkout) // Setting CLKOUT
{ {
_ADCON = readRegister(ADCON_REG); // Read the most recent value of the register m_ADCON = readRegister(ADCON_REG); // Read the most recent value of the register
// Values: 0, 1, 2, 3 // Values: 0, 1, 2, 3
if (clkout == 0) if (clkout == 0)
{ {
// 00 // 00
bitWrite(_ADCON, 6, 0); bitWrite(m_ADCON, 6, 0);
bitWrite(_ADCON, 5, 0); bitWrite(m_ADCON, 5, 0);
} }
else if (clkout == 1) else if (clkout == 1)
{ {
// 01 (default) // 01 (default)
bitWrite(_ADCON, 6, 0); bitWrite(m_ADCON, 6, 0);
bitWrite(_ADCON, 5, 1); bitWrite(m_ADCON, 5, 1);
} }
else if (clkout == 2) else if (clkout == 2)
{ {
// 10 // 10
bitWrite(_ADCON, 6, 1); bitWrite(m_ADCON, 6, 1);
bitWrite(_ADCON, 5, 0); bitWrite(m_ADCON, 5, 0);
} }
else if (clkout == 3) else if (clkout == 3)
{ {
// 11 // 11
bitWrite(_ADCON, 6, 1); bitWrite(m_ADCON, 6, 1);
bitWrite(_ADCON, 5, 1); bitWrite(m_ADCON, 5, 1);
} }
else else
{ {
} }
writeRegister(ADCON_REG, _ADCON); writeRegister(ADCON_REG, m_ADCON);
delay(100); delay(100);
} }
void ADS1256::setSDCS(uint8_t sdcs) // Setting SDCS void ADS1256::setSDCS(uint8_t sdcs) // Setting SDCS
{ {
_ADCON = readRegister(ADCON_REG); // Read the most recent value of the register m_ADCON = readRegister(ADCON_REG); // Read the most recent value of the register
// Values: 0, 1, 2, 3 // Values: 0, 1, 2, 3
if (sdcs == 0) if (sdcs == 0)
{ {
// 00 (default) // 00 (default)
bitWrite(_ADCON, 4, 0); bitWrite(m_ADCON, 4, 0);
bitWrite(_ADCON, 3, 0); bitWrite(m_ADCON, 3, 0);
} }
else if (sdcs == 1) else if (sdcs == 1)
{ {
// 01 // 01
bitWrite(_ADCON, 4, 0); bitWrite(m_ADCON, 4, 0);
bitWrite(_ADCON, 3, 1); bitWrite(m_ADCON, 3, 1);
} }
else if (sdcs == 2) else if (sdcs == 2)
{ {
// 10 // 10
bitWrite(_ADCON, 4, 1); bitWrite(m_ADCON, 4, 1);
bitWrite(_ADCON, 3, 0); bitWrite(m_ADCON, 3, 0);
} }
else if (sdcs == 3) else if (sdcs == 3)
{ {
// 11 // 11
bitWrite(_ADCON, 4, 1); bitWrite(m_ADCON, 4, 1);
bitWrite(_ADCON, 3, 1); bitWrite(m_ADCON, 3, 1);
} }
else else
{ {
} }
writeRegister(ADCON_REG, _ADCON); writeRegister(ADCON_REG, m_ADCON);
delay(100); delay(100);
} }
void ADS1256::setByteOrder(uint8_t byteOrder) // Setting byte order (MSB/LSB) void ADS1256::setByteOrder(uint8_t byteOrder) // Setting byte order (MSB/LSB)
{ {
_STATUS = readRegister(STATUS_REG); // Read the most recent value of the register m_STATUS = readRegister(STATUS_REG); // Read the most recent value of the register
if (byteOrder == 0) if (byteOrder == 0)
{ {
// Byte order is MSB (default) // Byte order is MSB (default)
bitWrite(_STATUS, 3, 0); bitWrite(m_STATUS, 3, 0);
// Set value of _STATUS at the third bit to 0 // Set value of _STATUS at the third bit to 0
} }
else if (byteOrder == 1) else if (byteOrder == 1)
{ {
// Byte order is LSB // Byte order is LSB
bitWrite(_STATUS, 3, 1); bitWrite(m_STATUS, 3, 1);
// Set value of _STATUS at the third bit to 1 // Set value of _STATUS at the third bit to 1
} }
else else
{ {
} }
writeRegister(STATUS_REG, _STATUS); writeRegister(STATUS_REG, m_STATUS);
delay(100); delay(100);
} }
@@ -267,25 +291,25 @@ uint8_t ADS1256::getByteOrder() // Getting byte order (MSB/LSB)
void ADS1256::setAutoCal(uint8_t acal) // Setting ACAL (Automatic SYSCAL) void ADS1256::setAutoCal(uint8_t acal) // Setting ACAL (Automatic SYSCAL)
{ {
_STATUS = readRegister(STATUS_REG); // Read the most recent value of the register m_STATUS = readRegister(STATUS_REG); // Read the most recent value of the register
if (acal == 0) if (acal == 0)
{ {
// Auto-calibration is disabled (default) // Auto-calibration is disabled (default)
bitWrite(_STATUS, 2, 0); bitWrite(m_STATUS, 2, 0);
//_STATUS |= B00000000; //_STATUS |= B00000000;
} }
else if (acal == 1) else if (acal == 1)
{ {
// Auto-calibration is enabled // Auto-calibration is enabled
bitWrite(_STATUS, 2, 1); bitWrite(m_STATUS, 2, 1);
//_STATUS |= B00000100; //_STATUS |= B00000100;
} }
else else
{ {
} }
writeRegister(STATUS_REG, _STATUS); writeRegister(STATUS_REG, m_STATUS);
delay(100); delay(100);
} }
@@ -298,25 +322,25 @@ uint8_t ADS1256::getAutoCal() // Getting ACAL (Automatic SYSCAL)
void ADS1256::setBuffer(uint8_t bufen) // Setting input buffer (Input impedance) void ADS1256::setBuffer(uint8_t bufen) // Setting input buffer (Input impedance)
{ {
_STATUS = readRegister(STATUS_REG); // Read the most recent value of the register m_STATUS = readRegister(STATUS_REG); // Read the most recent value of the register
if (bufen == 0) if (bufen == 0)
{ {
// Analog input buffer is disabled (default) // Analog input buffer is disabled (default)
//_STATUS |= B00000000; //_STATUS |= B00000000;
bitWrite(_STATUS, 1, 0); bitWrite(m_STATUS, 1, 0);
} }
else if (bufen == 1) else if (bufen == 1)
{ {
// Analog input buffer is enabled (recommended) // Analog input buffer is enabled (recommended)
//_STATUS |= B00000010; //_STATUS |= B00000010;
bitWrite(_STATUS, 1, 1); bitWrite(m_STATUS, 1, 1);
} }
else else
{ {
} }
writeRegister(STATUS_REG, _STATUS); writeRegister(STATUS_REG, m_STATUS);
delay(100); delay(100);
} }
@@ -329,7 +353,7 @@ uint8_t ADS1256::getBuffer() // Getting input buffer (Input impedance)
void ADS1256::setGPIO(uint8_t dir0, uint8_t dir1, uint8_t dir2, uint8_t dir3) // Setting GPIO 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 m_GPIO = readRegister(IO_REG); // Read the most recent value of the register
// Default: 11100000 - DEC: 224 - Ref: p32 I/O section // Default: 11100000 - DEC: 224 - Ref: p32 I/O section
// Sets D3-D0 as input or output // Sets D3-D0 as input or output
@@ -344,7 +368,7 @@ void ADS1256::setGPIO(uint8_t dir0, uint8_t dir1, uint8_t dir2, uint8_t dir3) //
{ {
GPIO_bit7 = 0; // D3 is output GPIO_bit7 = 0; // D3 is output
} }
bitWrite(_GPIO, 7, GPIO_bit7); bitWrite(m_GPIO, 7, GPIO_bit7);
//----------------------------------------------------- //-----------------------------------------------------
// Bit6: DIR2 // Bit6: DIR2
if (dir2 == 1) if (dir2 == 1)
@@ -355,7 +379,7 @@ void ADS1256::setGPIO(uint8_t dir0, uint8_t dir1, uint8_t dir2, uint8_t dir3) //
{ {
GPIO_bit6 = 0; // D2 is output GPIO_bit6 = 0; // D2 is output
} }
bitWrite(_GPIO, 6, GPIO_bit6); bitWrite(m_GPIO, 6, GPIO_bit6);
//----------------------------------------------------- //-----------------------------------------------------
// Bit5: DIR1 // Bit5: DIR1
if (dir1 == 1) if (dir1 == 1)
@@ -366,7 +390,7 @@ void ADS1256::setGPIO(uint8_t dir0, uint8_t dir1, uint8_t dir2, uint8_t dir3) //
{ {
GPIO_bit5 = 0; // D1 is output GPIO_bit5 = 0; // D1 is output
} }
bitWrite(_GPIO, 5, GPIO_bit5); bitWrite(m_GPIO, 5, GPIO_bit5);
//----------------------------------------------------- //-----------------------------------------------------
// Bit4: DIR0 // Bit4: DIR0
if (dir0 == 1) if (dir0 == 1)
@@ -377,16 +401,16 @@ void ADS1256::setGPIO(uint8_t dir0, uint8_t dir1, uint8_t dir2, uint8_t dir3) //
{ {
GPIO_bit4 = 0; // D0 is output (default) GPIO_bit4 = 0; // D0 is output (default)
} }
bitWrite(_GPIO, 4, GPIO_bit4); bitWrite(m_GPIO, 4, GPIO_bit4);
//----------------------------------------------------- //-----------------------------------------------------
writeRegister(IO_REG, _GPIO); writeRegister(IO_REG, m_GPIO);
delay(100); delay(100);
} }
void ADS1256::writeGPIO(uint8_t dir0value, uint8_t dir1value, uint8_t dir2value, uint8_t dir3value) // Writing GPIO void ADS1256::writeGPIO(uint8_t dir0value, uint8_t dir1value, uint8_t dir2value, uint8_t dir3value) // Writing GPIO
{ {
_GPIO = readRegister(IO_REG); m_GPIO = readRegister(IO_REG);
// Sets D3-D0 output values // Sets D3-D0 output values
// It is important that first one must use setGPIO, then writeGPIO // It is important that first one must use setGPIO, then writeGPIO
@@ -402,7 +426,7 @@ void ADS1256::writeGPIO(uint8_t dir0value, uint8_t dir1value, uint8_t dir2value,
{ {
GPIO_bit3 = 0; GPIO_bit3 = 0;
} }
bitWrite(_GPIO, 3, GPIO_bit3); bitWrite(m_GPIO, 3, GPIO_bit3);
//----------------------------------------------------- //-----------------------------------------------------
// Bit2: DIR2 // Bit2: DIR2
if (dir2value == 1) if (dir2value == 1)
@@ -413,7 +437,7 @@ void ADS1256::writeGPIO(uint8_t dir0value, uint8_t dir1value, uint8_t dir2value,
{ {
GPIO_bit2 = 0; GPIO_bit2 = 0;
} }
bitWrite(_GPIO, 2, GPIO_bit2); bitWrite(m_GPIO, 2, GPIO_bit2);
//----------------------------------------------------- //-----------------------------------------------------
// Bit1: DIR1 // Bit1: DIR1
if (dir1value == 1) if (dir1value == 1)
@@ -424,7 +448,7 @@ void ADS1256::writeGPIO(uint8_t dir0value, uint8_t dir1value, uint8_t dir2value,
{ {
GPIO_bit1 = 0; GPIO_bit1 = 0;
} }
bitWrite(_GPIO, 1, GPIO_bit1); bitWrite(m_GPIO, 1, GPIO_bit1);
//----------------------------------------------------- //-----------------------------------------------------
// Bit0: DIR0 // Bit0: DIR0
if (dir0value == 1) if (dir0value == 1)
@@ -435,10 +459,10 @@ void ADS1256::writeGPIO(uint8_t dir0value, uint8_t dir1value, uint8_t dir2value,
{ {
GPIO_bit0 = 0; GPIO_bit0 = 0;
} }
bitWrite(_GPIO, 0, GPIO_bit0); bitWrite(m_GPIO, 0, GPIO_bit0);
//----------------------------------------------------- //-----------------------------------------------------
writeRegister(IO_REG, _GPIO); writeRegister(IO_REG, m_GPIO);
delay(100); delay(100);
} }
@@ -446,13 +470,13 @@ uint8_t ADS1256::readGPIO(uint8_t gpioPin) // Reading GPIO
{ {
uint8_t GPIO_bit3, GPIO_bit2, GPIO_bit1, GPIO_bit0, GPIO_return; uint8_t GPIO_bit3, GPIO_bit2, GPIO_bit1, GPIO_bit0, GPIO_return;
_GPIO = readRegister(IO_REG); // Read the GPIO register m_GPIO = readRegister(IO_REG); // Read the GPIO register
// Save each bit values in a variable // Save each bit values in a variable
GPIO_bit3 = bitRead(_GPIO, 3); GPIO_bit3 = bitRead(m_GPIO, 3);
GPIO_bit2 = bitRead(_GPIO, 2); GPIO_bit2 = bitRead(m_GPIO, 2);
GPIO_bit1 = bitRead(_GPIO, 1); GPIO_bit1 = bitRead(m_GPIO, 1);
GPIO_bit0 = bitRead(_GPIO, 0); GPIO_bit0 = bitRead(m_GPIO, 0);
delay(100); delay(100);
@@ -480,156 +504,141 @@ uint8_t ADS1256::readGPIO(uint8_t gpioPin) // Reading GPIO
void ADS1256::sendDirectCommand(uint8_t directCommand) void ADS1256::sendDirectCommand(uint8_t directCommand)
{ {
LOG_DEBUG("Direct Command");
// Direct commands can be found in the datasheet Page 34, Table 24. // Direct commands can be found in the datasheet Page 34, Table 24.
LOG_DEBUG("Direct Command Begin"); _spi->beginTransaction(SPISettings(SPI_FREQ, MSBFIRST, SPI_MODE1));
_spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1));
CS_LOW(); // REF: P34: "CS must stay low during the entire command sequence" CS_LOW(); // REF: P34: "CS must stay low during the entire command sequence"
LOG_DEBUG("Direct Command CS LOW");
delayMicroseconds(5); delayMicroseconds(5);
_spi->transfer(directCommand); // Send Command _spi->transfer(directCommand); // Send Command
LOG_DEBUG("Transfer OK");
delayMicroseconds(5); delayMicroseconds(5);
CS_HIGH(); // REF: P34: "CS must stay low during the entire command sequence" CS_HIGH(); // REF: P34: "CS must stay low during the entire command sequence"
LOG_DEBUG("Direct Command CS HIGH");
_spi->endTransaction(); _spi->endTransaction();
LOG_DEBUG("Direct Command End");
} }
float ADS1256::convertToVoltage(int32_t rawData) // Converting the 24-bit data into a voltage value float ADS1256::convertToVoltage(int32_t rawData) // Converting the 24-bit data into a voltage value
{ {
return (conversionParameter * rawData); return (m_conversionParameter * rawData);
} }
void ADS1256::writeRegister(uint8_t registerAddress, uint8_t registerValueToWrite) void ADS1256::writeRegister(uint8_t registerAddress, uint8_t registerValueToWrite)
{ {
waitForLowDRDY(); waitForLowDRDY();
LOG_DEBUG("DRDY Low");
_spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1)); _spi->beginTransaction(SPISettings(SPI_FREQ, MSBFIRST, SPI_MODE1));
// SPI_MODE1 = output edge: rising, data capture: falling; clock polarity: 0, clock phase: 1. // SPI_MODE1 = output edge: rising, data capture: falling; clock polarity: 0, clock phase: 1.
LOG_DEBUG("SPI Begin");
CS_LOW(); // CS must stay LOW during the entire sequence [Ref: P34, T24] CS_LOW(); // CS must stay LOW during the entire sequence [Ref: P34, T24]
LOG_DEBUG("CS Low");
delayMicroseconds(5); // see t6 in the datasheet delayMicroseconds(5); // see t6 in the datasheet
_spi->transfer(0x50 | registerAddress); // 0x50 = 01010000 = WREG _spi->transfer(WREG | registerAddress); // 0x50 = 01010000 = WREG
LOG_DEBUG("Transfer 1");
_spi->transfer(0x00); // 2nd (empty) command byte _spi->transfer(0x00); // 2nd (empty) command byte
LOG_DEBUG("Transfer 2");
_spi->transfer(registerValueToWrite); // pass the value to the register _spi->transfer(registerValueToWrite); // pass the value to the register
LOG_DEBUG("Transfer 3");
CS_HIGH(); CS_HIGH();
LOG_DEBUG("CS High");
_spi->endTransaction(); _spi->endTransaction();
LOG_DEBUG("SPI End"); delay(100);
} }
long ADS1256::readRegister(uint8_t registerAddress) // Reading a register long ADS1256::readRegister(uint8_t registerAddress) // Reading a register
{ {
waitForLowDRDY(); waitForLowDRDY();
_spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1)); _spi->beginTransaction(SPISettings(SPI_FREQ, MSBFIRST, SPI_MODE1));
// SPI_MODE1 = output edge: rising, data capture: falling; clock polarity: 0, clock phase: 1. // 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] 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(RREG | registerAddress); // 0x10 = 0001000 = RREG - OR together the two numbers (command + address)
_spi->transfer(0x00); // 2nd (empty) command byte _spi->transfer(0x00); // 2nd (empty) command byte
delayMicroseconds(5); // see t6 in the datasheet delayMicroseconds(5); // see t6 in the datasheet
uint8_t regValue = _spi->transfer(0xFF); // read out the register value uint8_t regValue = _spi->transfer(0x00); // read out the register value
CS_HIGH(); CS_HIGH();
_spi->endTransaction(); _spi->endTransaction();
delay(100);
return regValue; return regValue;
} }
long ADS1256::readSingle() // Reading a single value ONCE using the RDATA command long ADS1256::readSingle() // Reading a single value ONCE using the RDATA command
{ {
_spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1)); _spi->beginTransaction(SPISettings(SPI_FREQ, MSBFIRST, SPI_MODE1));
CS_LOW(); // REF: P34: "CS must stay low during the entire command sequence" CS_LOW(); // REF: P34: "CS must stay low during the entire command sequence"
waitForLowDRDY(); waitForLowDRDY();
_spi->transfer(0b00000001); // Issue RDATA (0000 0001) command _spi->transfer(RDATA); // Issue RDATA (0000 0001) command
delayMicroseconds(7); // Wait t6 time (~6.51 us) REF: P34, FIG:30. delayMicroseconds(7); // Wait t6 time (~6.51 us) REF: P34, FIG:30.
_outputBuffer[0] = _spi->transfer(0); // MSB m_outputBuffer[0] = _spi->transfer(0); // MSB
_outputBuffer[1] = _spi->transfer(0); // Mid-byte m_outputBuffer[1] = _spi->transfer(0); // Mid-byte
_outputBuffer[2] = _spi->transfer(0); // LSB m_outputBuffer[2] = _spi->transfer(0); // LSB
// Shifting and combining the above three items into a single, 24-bit number // Shifting and combining the above three items into a single, 24-bit number
_outputValue = ((long)_outputBuffer[0] << 16) | ((long)_outputBuffer[1] << 8) | (_outputBuffer[2]); m_outputValue = ((long)m_outputBuffer[0] << 16) | ((long)m_outputBuffer[1] << 8) | (m_outputBuffer[2]);
_outputValue = convertSigned24BitToLong(_outputValue); m_outputValue = convertSigned24BitToLong(m_outputValue);
CS_HIGH(); // We finished the command sequence, so we set CS to HIGH CS_HIGH(); // We finished the command sequence, so we set CS to HIGH
_spi->endTransaction(); _spi->endTransaction();
return (_outputValue); return (m_outputValue);
} }
long ADS1256::readSingleContinuous() // Reads the recently selected input channel using RDATAC long ADS1256::readSingleContinuous() // Reads the recently selected input channel using RDATAC
{ {
if (_isAcquisitionRunning == false) if (m_isAcquisitionRunning == false)
{ {
_isAcquisitionRunning = true; m_isAcquisitionRunning = true;
_spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1)); _spi->beginTransaction(SPISettings(SPI_FREQ, MSBFIRST, SPI_MODE1));
CS_LOW(); // REF: P34: "CS must stay low during the entire command sequence" CS_LOW(); // REF: P34: "CS must stay low during the entire command sequence"
waitForLowDRDY(); waitForLowDRDY();
_spi->transfer(0b00000011); // Issue RDATAC (0000 0011) _spi->transfer(RDATAC); // Issue RDATAC (0000 0011)
delayMicroseconds(7); // Wait t6 time (~6.51 us) REF: P34, FIG:30. delayMicroseconds(7); // Wait t6 time (~6.51 us) REF: P34, FIG:30.
} }
else else
{ {
waitForLowDRDY(); waitForLowDRDY();
} }
_outputBuffer[0] = _spi->transfer(0); // MSB m_outputBuffer[0] = _spi->transfer(0); // MSB
_outputBuffer[1] = _spi->transfer(0); // Mid-byte m_outputBuffer[1] = _spi->transfer(0); // Mid-byte
_outputBuffer[2] = _spi->transfer(0); // LSB m_outputBuffer[2] = _spi->transfer(0); // LSB
_outputValue = ((long)_outputBuffer[0] << 16) | ((long)_outputBuffer[1] << 8) | (_outputBuffer[2]); m_outputValue = ((long)m_outputBuffer[0] << 16) | ((long)m_outputBuffer[1] << 8) | (m_outputBuffer[2]);
_outputValue = convertSigned24BitToLong(_outputValue); m_outputValue = convertSigned24BitToLong(m_outputValue);
waitForHighDRDY(); waitForHighDRDY();
return _outputValue; return m_outputValue;
} }
long ADS1256::cycleSingle() long ADS1256::cycleSingle()
{ {
if (_isAcquisitionRunning == false) if (m_isAcquisitionRunning == false)
{ {
_isAcquisitionRunning = true; m_isAcquisitionRunning = true;
_cycle = 0; m_cycle = 0;
_spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1)); _spi->beginTransaction(SPISettings(SPI_FREQ, MSBFIRST, SPI_MODE1));
CS_LOW(); // CS must stay LOW during the entire sequence [Ref: P34, T24] CS_LOW(); // CS must stay LOW during the entire sequence [Ref: P34, T24]
_spi->transfer(0x50 | 1); // 0x50 = WREG //1 = MUX _spi->transfer(WREG | MUX_REG); // 0x50 = WREG //1 = MUX
_spi->transfer(0x00); _spi->transfer(0x00);
_spi->transfer(SING_0); // AIN0+AINCOM _spi->transfer(SING_0); // AIN0+AINCOM
CS_HIGH(); delayMicroseconds(250);
delay(50);
CS_LOW(); // CS must stay LOW during the entire sequence [Ref: P34, T24]
} }
else else
{ {
} }
if (_cycle < 8) if (m_cycle < 8)
{ {
_outputValue = 0; m_outputValue = 0;
waitForLowDRDY(); waitForLowDRDY();
// Step 1. - Updating MUX // Step 1. - Updating MUX
switch (_cycle) switch (m_cycle)
{ {
// Channels are written manually // Channels are written manually
case 0: // Channel 2 case 0: // Channel 2
@@ -665,61 +674,59 @@ long ADS1256::cycleSingle()
break; break;
} }
// Step 2. // Step 2.
_spi->transfer(0b11111100); // SYNC _spi->transfer(SYNC); // SYNC
delayMicroseconds(4); // t11 delay 24*tau = 3.125 us //delay should be larger, so we delay by 4 us delayMicroseconds(4); // t11 delay 24*tau = 3.125 us //delay should be larger, so we delay by 4 us
_spi->transfer(0b11111111); // WAKEUP _spi->transfer(WAKEUP); // WAKEUP
// Step 3. // Step 3.
// Issue RDATA (0000 0001) command // Issue RDATA (0000 0001) command
_spi->transfer(0b00000001); _spi->transfer(RDATA);
delayMicroseconds(7); // Wait t6 time (~6.51 us) REF: P34, FIG:30. delayMicroseconds(7); // Wait t6 time (~6.51 us) REF: P34, FIG:30.
_outputBuffer[0] = _spi->transfer(0x0F); // MSB m_outputBuffer[0] = _spi->transfer(0); // MSB
_outputBuffer[1] = _spi->transfer(0x0F); // Mid-byte m_outputBuffer[1] = _spi->transfer(0); // Mid-byte
_outputBuffer[2] = _spi->transfer(0x0F); // LSB m_outputBuffer[2] = _spi->transfer(0); // LSB
_outputValue = ((long)_outputBuffer[0] << 16) | ((long)_outputBuffer[1] << 8) | (_outputBuffer[2]); m_outputValue = ((long)m_outputBuffer[0] << 16) | ((long)m_outputBuffer[1] << 8) | (m_outputBuffer[2]);
_outputValue = convertSigned24BitToLong(_outputValue); m_outputValue = convertSigned24BitToLong(m_outputValue);
_cycle++; // Increase cycle - This will move to the next MUX input channel m_cycle++; // Increase cycle - This will move to the next MUX input channel
if (_cycle == 8) if (m_cycle == 8)
{ {
_cycle = 0; // Reset to 0 - Restart conversion from the 1st input channel m_cycle = 0; // Reset to 0 - Restart conversion from the 1st input channel
} }
} }
return _outputValue; return m_outputValue;
} }
long ADS1256::cycleDifferential() long ADS1256::cycleDifferential()
{ {
if (_isAcquisitionRunning == false) if (m_isAcquisitionRunning == false)
{ {
_cycle = 0; m_cycle = 0;
_isAcquisitionRunning = true; m_isAcquisitionRunning = true;
_spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1)); _spi->beginTransaction(SPISettings(SPI_FREQ, MSBFIRST, SPI_MODE1));
// Set the AIN0+AIN1 as inputs manually // Set the AIN0+AIN1 as inputs manually
CS_LOW(); // CS must stay LOW during the entire sequence [Ref: P34, T24] CS_LOW(); // CS must stay LOW during the entire sequence [Ref: P34, T24]
_spi->transfer(0x50 | 1); // 0x50 = WREG //1 = MUX _spi->transfer(WREG | MUX_REG); // 0x50 = WREG //1 = MUX
_spi->transfer(0x00); _spi->transfer(0x00);
_spi->transfer(DIFF_0_1); // AIN0+AIN1 _spi->transfer(DIFF_0_1); // AIN0+AIN1
CS_HIGH(); delayMicroseconds(250);
delay(50);
CS_LOW(); // CS must stay LOW during the entire sequence [Ref: P34, T24]
} }
else else
{ {
} }
if (_cycle < 4) if (m_cycle < 4)
{ {
_outputValue = 0; m_outputValue = 0;
// DRDY has to go low // DRDY has to go low
waitForLowDRDY(); waitForLowDRDY();
// Step 1. - Updating MUX // Step 1. - Updating MUX
switch (_cycle) switch (m_cycle)
{ {
case 0: // Channel 2 case 0: // Channel 2
updateMUX(DIFF_2_3); // AIN2+AIN3 updateMUX(DIFF_2_3); // AIN2+AIN3
@@ -738,57 +745,57 @@ long ADS1256::cycleDifferential()
break; break;
} }
_spi->transfer(0b11111100); // SYNC _spi->transfer(SYNC); // SYNC
delayMicroseconds(4); // t11 delay 24*tau = 3.125 us //delay should be larger, so we delay by 4 us delayMicroseconds(4); // t11 delay 24*tau = 3.125 us //delay should be larger, so we delay by 4 us
_spi->transfer(0b11111111); // WAKEUP _spi->transfer(WAKEUP); // WAKEUP
// Step 3. // Step 3.
_spi->transfer(0b00000001); // Issue RDATA (0000 0001) command _spi->transfer(RDATA); // Issue RDATA (0000 0001) command
delayMicroseconds(7); // Wait t6 time (~6.51 us) REF: P34, FIG:30. delayMicroseconds(7); // Wait t6 time (~6.51 us) REF: P34, FIG:30.
_outputBuffer[0] = _spi->transfer(0); // MSB m_outputBuffer[0] = _spi->transfer(0); // MSB
_outputBuffer[1] = _spi->transfer(0); // Mid-byte m_outputBuffer[1] = _spi->transfer(0); // Mid-byte
_outputBuffer[2] = _spi->transfer(0); // LSB m_outputBuffer[2] = _spi->transfer(0); // LSB
_outputValue = ((long)_outputBuffer[0] << 16) | ((long)_outputBuffer[1] << 8) | (_outputBuffer[2]); m_outputValue = ((long)m_outputBuffer[0] << 16) | ((long)m_outputBuffer[1] << 8) | (m_outputBuffer[2]);
_outputValue = convertSigned24BitToLong(_outputValue); m_outputValue = convertSigned24BitToLong(m_outputValue);
_cycle++; m_cycle++;
if (_cycle == 4) if (m_cycle == 4)
{ {
_cycle = 0; m_cycle = 0;
// After the 4th cycle, we reset to zero so the next iteration reads the 1st MUX again // After the 4th cycle, we reset to zero so the next iteration reads the 1st MUX again
} }
} }
return _outputValue; return m_outputValue;
} }
void ADS1256::updateConversionParameter() void ADS1256::updateConversionParameter()
{ {
conversionParameter = ((2.0 * _VREF) / 8388608.0) / (pow(2, _PGA)); // Calculate the "bit to Volts" multiplier m_conversionParameter = ((2.0 * m_VREF) / 8388608.0) / (pow(2, m_PGA)); // Calculate the "bit to Volts" multiplier
// 8388608 = 2^{23} - 1, REF: p23, Table 16. // 8388608 = 2^{23} - 1, REF: p23, Table 16.
} }
void ADS1256::updateMUX(uint8_t muxValue) void ADS1256::updateMUX(uint8_t muxValue)
{ {
_spi->transfer(0x50 | MUX_REG); // Write to the MUX register (0x50 is the WREG command) _spi->transfer(WREG | MUX_REG); // Write to the MUX register (0x50 is the WREG command)
_spi->transfer(0x00); _spi->transfer(0x00);
_spi->transfer(muxValue); // Write the new MUX value _spi->transfer(muxValue); // Write the new MUX value
} }
inline void ADS1256::CS_LOW() inline void ADS1256::CS_LOW()
{ {
if (_CS_pin != PIN_UNUSED) // Sets CS LOW if it is not an unused pin if (m_CS_pin != PIN_UNUSED) // Sets CS LOW if it is not an unused pin
{ {
digitalWrite(_CS_pin, LOW); digitalWrite(m_CS_pin, LOW);
} }
} }
inline void ADS1256::CS_HIGH() inline void ADS1256::CS_HIGH()
{ {
if (_CS_pin != PIN_UNUSED) // Sets CS HIGH if it is not an unused pin if (m_CS_pin != PIN_UNUSED) // Sets CS HIGH if it is not an unused pin
{ {
digitalWrite(_CS_pin, HIGH); digitalWrite(m_CS_pin, HIGH);
} }
} }
+129 -103
View File
@@ -1,11 +1,11 @@
//ADS1256 header file // ADS1256 header file
/* /*
Name: ADS1256.h Name: ADS1256.h
Created: 2022/07/14 Created: 2022/07/14
Author: Curious Scientist Author: Curious Scientist
Editor: Notepad++ Editor: Notepad++
Comment: Visit https://curiousscientist.tech/blog/ADS1256-custom-library Comment: Visit https://curiousscientist.tech/blog/ADS1256-custom-library
Special thanks to Special thanks to
Abraão Queiroz for spending time on the code and suggesting corrections for ESP32 microcontrollers 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 Benjamin Pelletier for pointing out and fixing an issue around the handling of the DRDY signal
*/ */
@@ -14,51 +14,55 @@
#define _ADS1256_h #define _ADS1256_h
#include <SPI.h> #include <SPI.h>
#include <Arduino.h>
//Differential inputs // SPI Frequency
#define DIFF_0_1 0b00000001 //A0 + A1 as differential input #define SPI_FREQ 1920000
#define DIFF_2_3 0b00100011 //A2 + A3 as differential input
#define DIFF_4_5 0b01000101 //A4 + A5 as differential input
#define DIFF_6_7 0b01100111 //A6 + A7 as differential input
//Single-ended inputs // Differential inputs
#define SING_0 0b00001111 //A0 + GND (common) as single-ended input #define DIFF_0_1 0b00000001 // A0 + A1 as differential input
#define SING_1 0b00011111 //A1 + GND (common) as single-ended input #define DIFF_2_3 0b00100011 // A2 + A3 as differential input
#define SING_2 0b00101111 //A2 + GND (common) as single-ended input #define DIFF_4_5 0b01000101 // A4 + A5 as differential input
#define SING_3 0b00111111 //A3 + GND (common) as single-ended input #define DIFF_6_7 0b01100111 // A6 + A7 as differential input
#define SING_4 0b01001111 //A4 + GND (common) as single-ended input
#define SING_5 0b01011111 //A5 + GND (common) as single-ended input
#define SING_6 0b01101111 //A6 + GND (common) as single-ended input
#define SING_7 0b01111111 //A7 + GND (common) as single-ended input
//PGA settings //Input voltage range // Single-ended inputs
#define PGA_1 0b00000000 //± 5 V #define SING_0 0b00001111 // A0 + GND (common) as single-ended input
#define PGA_2 0b00000001 //± 2.5 V #define SING_1 0b00011111 // A1 + GND (common) as single-ended input
#define PGA_4 0b00000010 //± 1.25 V #define SING_2 0b00101111 // A2 + GND (common) as single-ended input
#define PGA_8 0b00000011 //± 625 mV #define SING_3 0b00111111 // A3 + GND (common) as single-ended input
#define PGA_16 0b00000100 //± 312.5 mV #define SING_4 0b01001111 // A4 + GND (common) as single-ended input
#define SING_5 0b01011111 // A5 + GND (common) as single-ended input
#define SING_6 0b01101111 // A6 + GND (common) as single-ended input
#define SING_7 0b01111111 // A7 + GND (common) as single-ended input
// PGA settings //Input voltage range
#define PGA_1 0b00000000 // ± 5 V
#define PGA_2 0b00000001 // ± 2.5 V
#define PGA_4 0b00000010 // ± 1.25 V
#define PGA_8 0b00000011 // ± 625 mV
#define PGA_16 0b00000100 // ± 312.5 mV
#define PGA_32 0b00000101 //+ 156.25 mV #define PGA_32 0b00000101 //+ 156.25 mV
#define PGA_64 0b00000110 //± 78.125 mV #define PGA_64 0b00000110 // ± 78.125 mV
//Datarate //DEC // Datarate //DEC
#define DRATE_30000SPS 0b11110000 //240 #define DRATE_30000SPS 0b11110000 // 240
#define DRATE_15000SPS 0b11100000 //224 #define DRATE_15000SPS 0b11100000 // 224
#define DRATE_7500SPS 0b11010000 //208 #define DRATE_7500SPS 0b11010000 // 208
#define DRATE_3750SPS 0b11000000 //192 #define DRATE_3750SPS 0b11000000 // 192
#define DRATE_2000SPS 0b10110000 //176 #define DRATE_2000SPS 0b10110000 // 176
#define DRATE_1000SPS 0b10100001 //161 #define DRATE_1000SPS 0b10100001 // 161
#define DRATE_500SPS 0b10010010 //146 #define DRATE_500SPS 0b10010010 // 146
#define DRATE_100SPS 0b10000010 //130 #define DRATE_100SPS 0b10000010 // 130
#define DRATE_60SPS 0b01110010 //114 #define DRATE_60SPS 0b01110010 // 114
#define DRATE_50SPS 0b01100011 //99 #define DRATE_50SPS 0b01100011 // 99
#define DRATE_30SPS 0b01010011 //83 #define DRATE_30SPS 0b01010011 // 83
#define DRATE_25SPS 0b01000011 //67 #define DRATE_25SPS 0b01000011 // 67
#define DRATE_15SPS 0b00110011 //51 #define DRATE_15SPS 0b00110011 // 51
#define DRATE_10SPS 0b00100011 //35 #define DRATE_10SPS 0b00100011 // 35
#define DRATE_5SPS 0b00010011 //19 #define DRATE_5SPS 0b00010011 // 19
#define DRATE_2SPS 0b00000011 //3 #define DRATE_2SPS 0b00000011 // 3
//Status register // Status register
#define BITORDER_MSB 0 #define BITORDER_MSB 0
#define BITORDER_LSB 1 #define BITORDER_LSB 1
#define ACAL_DISABLED 0 #define ACAL_DISABLED 0
@@ -66,7 +70,7 @@
#define BUFFER_DISABLED 0 #define BUFFER_DISABLED 0
#define BUFFER_ENABLED 1 #define BUFFER_ENABLED 1
//Register addresses // Register addresses
#define STATUS_REG 0x00 #define STATUS_REG 0x00
#define MUX_REG 0x01 #define MUX_REG 0x01
#define ADCON_REG 0x02 #define ADCON_REG 0x02
@@ -79,7 +83,7 @@
#define FSC1_REG 0x09 #define FSC1_REG 0x09
#define FSC2_REG 0x0A #define FSC2_REG 0x0A
//Command definitions // Command definitions
#define WAKEUP 0b00000000 #define WAKEUP 0b00000000
#define RDATA 0b00000001 #define RDATA 0b00000001
#define RDATAC 0b00000011 #define RDATAC 0b00000011
@@ -96,26 +100,30 @@
#define RESET 0b11111110 #define RESET 0b11111110
//---------------------------------------------------------------- //----------------------------------------------------------------
class ADS1256 class ADS1256
{ {
public: public:
static constexpr int8_t PIN_UNUSED = -1; static constexpr int8_t PIN_UNUSED = -1;
//Constructor // Constructor
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); 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);
~ADS1256()
//Initializing function {
void InitializeADC(); vSemaphoreDelete(m_drdyHigh);
//ADS1256(int drate, int pga, int byteOrder, bool bufen); vSemaphoreDelete(m_drdyLow);
}
//Read a register
// Initializing function
void InitializeADC();
// ADS1256(int drate, int pga, int byteOrder, bool bufen);
// Read a register
long readRegister(uint8_t registerAddress); long readRegister(uint8_t registerAddress);
//Write a register
void writeRegister(uint8_t registerAddress, uint8_t registerValueToWrite);
//Individual methods // Write a register
void writeRegister(uint8_t registerAddress, uint8_t registerValueToWrite);
// Individual methods
void setDRATE(uint8_t drate); void setDRATE(uint8_t drate);
void setPGA(uint8_t pga); void setPGA(uint8_t pga);
uint8_t getPGA(); uint8_t getPGA();
@@ -128,62 +136,80 @@ static constexpr int8_t PIN_UNUSED = -1;
uint8_t getAutoCal(); uint8_t getAutoCal();
void setGPIO(uint8_t dir0, uint8_t dir1, uint8_t dir2, uint8_t dir3); void setGPIO(uint8_t dir0, uint8_t dir1, uint8_t dir2, uint8_t dir3);
void writeGPIO(uint8_t dir0value, uint8_t dir1value, uint8_t dir2value, uint8_t dir3value); void writeGPIO(uint8_t dir0value, uint8_t dir1value, uint8_t dir2value, uint8_t dir3value);
uint8_t readGPIO(uint8_t gpioPin); uint8_t readGPIO(uint8_t gpioPin);
void setCLKOUT(uint8_t clkout); void setCLKOUT(uint8_t clkout);
void setSDCS(uint8_t sdcs); void setSDCS(uint8_t sdcs);
void sendDirectCommand(uint8_t directCommand); void sendDirectCommand(uint8_t directCommand);
//Get a single conversion // Get a single conversion
long readSingle(); long readSingle();
//Single input continuous reading // Single input continuous reading
long readSingleContinuous(); long readSingleContinuous();
//Cycling through the single-ended inputs // Cycling through the single-ended inputs
long cycleSingle(); //Ax + COM long cycleSingle(); // Ax + COM
//Cycling through the differential inputs // Cycling through the differential inputs
long cycleDifferential(); //Ax + Ay long cycleDifferential(); // Ax + Ay
//Converts the reading into a voltage value // Converts the reading into a voltage value
float convertToVoltage(int32_t rawData); float convertToVoltage(int32_t rawData);
//Stop AD // Stop AD
void stopConversion(); void stopConversion();
// functions for callback
inline uint8_t getDRDYpin()
{
return m_DRDY_pin;
}
SemaphoreHandle_t getDRDYsemaphoreHigh()
{
return m_drdyHigh;
}
SemaphoreHandle_t getDRDYsemaphoreLow()
{
return m_drdyLow;
}
private: private:
SPIClass *_spi; // Pointer to an SPIClass object
SPIClass* _spi; //Pointer to an SPIClass object
void waitForLowDRDY(); // Block until DRDY is low void waitForLowDRDY(); // Block until DRDY is low
void waitForHighDRDY(); // Block until DRDY is high void waitForHighDRDY(); // Block until DRDY is high
void updateMUX(uint8_t muxValue); void updateMUX(uint8_t muxValue);
inline void CS_LOW(); inline void CS_LOW();
inline void CS_HIGH(); inline void CS_HIGH();
void updateConversionParameter(); //Refresh the conversion parameter based on the PGA void updateConversionParameter(); // Refresh the conversion parameter based on the PGA
float _VREF = 0; //Value of the reference voltage float m_VREF = 0; // Value of the reference voltage
float conversionParameter = 0; //PGA-dependent multiplier float m_conversionParameter = 0; // PGA-dependent multiplier
//Pins // Pins
int8_t _DRDY_pin; //Pin assigned for DRDY int8_t m_DRDY_pin; // Pin assigned for DRDY
int8_t _RESET_pin; //Pin assigned for RESET int8_t m_RESET_pin; // Pin assigned for RESET
int8_t _SYNC_pin; //Pin assigned for SYNC int8_t m_SYNC_pin; // Pin assigned for SYNC
int8_t _CS_pin; //Pin assigned for CS int8_t m_CS_pin; // Pin assigned for CS
//Register values // Register values
byte _DRATE; //Value of the DRATE register uint8_t m_DRATE; // Value of the DRATE register
byte _ADCON; //Value of the ADCON register uint8_t m_ADCON; // Value of the ADCON register
byte _MUX; //Value of the MUX register uint8_t m_MUX; // Value of the MUX register
byte _PGA; //Value of the PGA (within ADCON) uint8_t m_PGA; // Value of the PGA (within ADCON)
byte _GPIO; //Value of the GPIO register uint8_t m_GPIO; // Value of the GPIO register
byte _STATUS; //Value of the status register uint8_t m_STATUS; // Value of the status register
byte _GPIOvalue; //GPIO value uint8_t m_GPIOvalue; // GPIO value
byte _ByteOrder; //Byte order uint8_t m_ByteOrder; // Byte order
byte _outputBuffer[3]; //3-byte (24-bit) buffer for the fast acquisition - Single-channel, continuous uint8_t m_outputBuffer[3]; // 3-byte (24-bit) buffer for the fast acquisition - Single-channel, continuous
long _outputValue; //Combined value of the _outputBuffer[3] int32_t m_outputValue; // Combined value of the m_outputBuffer[3]
bool _isAcquisitionRunning; //bool that keeps track of the acquisition (running or not) bool m_isAcquisitionRunning; // bool that keeps track of the acquisition (running or not)
uint8_t _cycle; //Tracks the cycles as the MUX is cycling through the input channels uint8_t m_cycle; // Tracks the cycles as the MUX is cycling through the input channels
SemaphoreHandle_t m_drdyHigh;
SemaphoreHandle_t m_drdyLow;
}; };
#endif #endif
+4 -8
View File
@@ -20,7 +20,6 @@ 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/ttyACM1
upload_speed = 921600 upload_speed = 921600
@@ -28,15 +27,14 @@ monitor_port = /dev/ttyACM0
monitor_speed = 921600 monitor_speed = 921600
build_type = release build_type = release
build_flags = build_flags =
-DCORE_DEBUG_LEVEL=5 -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}
@@ -46,7 +44,6 @@ 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/ttyACM1
upload_speed = 921600 upload_speed = 921600
@@ -59,7 +56,7 @@ build_flags =
-O0 -O0
-g3 -g3
-ggdb3 -ggdb3
-DCORE_DEBUG_LEVEL=5 -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
@@ -67,4 +64,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
+3 -7
View File
@@ -1,8 +1,6 @@
#include "datasave.h" #include "datasave.h"
#include <math.h> #include <math.h>
LITTLEFSGuard::LITTLEFSGuard() LITTLEFSGuard::LITTLEFSGuard()
{ {
if (!LittleFS.begin(true, "/littlefs", 10, "littlefs")) if (!LittleFS.begin(true, "/littlefs", 10, "littlefs"))
@@ -12,7 +10,7 @@ LITTLEFSGuard::LITTLEFSGuard()
else else
{ {
LOG_INFO("LittleFS mounted successfully"); LOG_INFO("LittleFS mounted successfully");
LOG_INFO("LittleFS Free KBytes:", (LittleFS.totalBytes() - LittleFS.usedBytes()) /1024); LOG_INFO("LittleFS Free KBytes:", (LittleFS.totalBytes() - LittleFS.usedBytes()) / 1024);
} }
} }
@@ -49,8 +47,7 @@ void ignitionBoxStatusFiltered::update(const ignitionBoxStatus &new_status)
} }
m_count++; m_count++;
// simple moving average calculation // simple moving average calculation
m_last.timestamp = new_status.timestamp; // keep timestamp of latest status 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_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.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.spark_status = new_status.coils12.spark_status; // take latest spark status
@@ -72,7 +69,7 @@ void ignitionBoxStatusFiltered::update(const ignitionBoxStatus &new_status)
filter(m_last.coils34.peak_n_out, new_status.coils34.peak_n_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.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 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 m_last.n_queue_errors = new_status.n_queue_errors;
if (m_count >= m_max_count) if (m_count >= m_max_count)
{ {
@@ -124,4 +121,3 @@ const ArduinoJson::JsonDocument ignitionBoxStatusFiltered::toJson() const
} }
return doc; return doc;
} }
+9 -14
View File
@@ -26,9 +26,9 @@
struct Devices struct Devices
{ {
// Busses // Busses
std::unique_ptr<TwoWire> m_i2c = nullptr; TwoWire *m_i2c = NULL;
std::unique_ptr<SPIClass> m_spi_a = nullptr; SPIClass *m_spi_a = NULL;
std::unique_ptr<SPIClass> m_spi_b = nullptr; SPIClass *m_spi_b = NULL;
// Bus Mutextes // Bus Mutextes
std::mutex m_spi_a_mutex; std::mutex m_spi_a_mutex;
@@ -36,25 +36,20 @@ struct Devices
std::mutex m_i2c_mutex; std::mutex m_i2c_mutex;
// Device Pointers // Device Pointers
std::unique_ptr<AD5292> m_pot_a = nullptr; AD5292 *m_pot_a = NULL;
std::unique_ptr<AD5292> m_pot_b = nullptr; AD5292 *m_pot_b = NULL;
std::unique_ptr<ADS1256> m_adc_a = nullptr; ADS1256 *m_adc_a = NULL;
std::unique_ptr<ADS1256> m_adc_b = nullptr; ADS1256 *m_adc_b = NULL;
std::unique_ptr<ExternalIO> m_ext_io = nullptr;
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 adc->readSingle();
for (int i = 0; i < 5; i++)
{
adc->readSingle();
}
// ora lettura valida a 30kSPS → ~100 µs di settling // ora lettura valida a 30kSPS → ~100 µs di settling
return adc->convertToVoltage(adc->readSingle()); return adc->convertToVoltage(adc->readSingle());
} }
+1 -1
View File
@@ -16,7 +16,7 @@
#define CORE_0 0 #define CORE_0 0
#define CORE_1 1 #define CORE_1 1
#define RT_TASK_STACK 2048 // in words #define RT_TASK_STACK 4096 // in words
#define RT_TASK_PRIORITY (configMAX_PRIORITIES - 5) // highest priority after wifi tasks #define RT_TASK_PRIORITY (configMAX_PRIORITIES - 5) // highest priority after wifi tasks
struct isrParams struct isrParams
+93 -54
View File
@@ -16,23 +16,28 @@
#include <ui.h> #include <ui.h>
#include <led.h> #include <led.h>
// Defines to enable channel B #define CH_A_ENABLE
// #define CH_B_ENABLE #define CH_B_ENABLE
#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 4096 #define PSRAM_MAX 1024
#define QUEUE_MAX 256 #define QUEUE_MAX 32
void setup() void setup()
{ {
Serial.begin(921600); Serial.begin(115200);
delay(250); delay(250);
Serial.setTimeout(5000);
// Setup Logger // Setup Logger
LOG_ATTACH_SERIAL(Serial); LOG_ATTACH_SERIAL(Serial);
LOG_SET_LEVEL(DebugLogLevel::LVL_INFO); LOG_SET_LEVEL(DebugLogLevel::LVL_DEBUG);
// Print Processor Info // Print Processor Info
LOG_DEBUG("ESP32 Chip:", ESP.getChipModel()); LOG_DEBUG("ESP32 Chip:", ESP.getChipModel());
@@ -46,14 +51,15 @@ void setup()
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");
@@ -68,6 +74,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();
@@ -83,7 +90,7 @@ void loop()
led.setBrightness(0.025f); led.setBrightness(0.025f);
led.setStatus(RGBled::LedStatus::INIT); led.setStatus(RGBled::LedStatus::INIT);
std::shared_ptr<Devices> dev = std::make_shared<Devices>(); Devices dev;
bool running = true; bool running = true;
std::mutex fs_mutex; std::mutex fs_mutex;
LITTLEFSGuard fsGuard; LITTLEFSGuard fsGuard;
@@ -91,17 +98,42 @@ void loop()
//////// INIT SPI INTERFACES //////// //////// INIT SPI INTERFACES ////////
bool spiA_ok = true; bool spiA_ok = true;
bool spiB_ok = true; bool spiB_ok = true;
//////// INIT SPI INTERFACES ////////
LOG_DEBUG("Init SPI Interfaces"); LOG_DEBUG("Init SPI Interfaces");
SPIClass SPI_A(FSPI); #ifdef CH_A_ENABLE
LOG_DEBUG("Begin Init SPI_A");
SPIClass SPI_A(HSPI);
spiA_ok = SPI_A.begin(SPI_A_SCK, SPI_A_MISO, SPI_A_MOSI); spiA_ok = SPI_A.begin(SPI_A_SCK, SPI_A_MISO, SPI_A_MOSI);
SPI_A.setDataMode(SPI_MODE1); // ADS1256 requires SPI mode 1 SPI_A.setDataMode(SPI_MODE1); // ADS1256 requires SPI mode 1
LOG_DEBUG("Init SPI A ok"); LOG_DEBUG("Init SPI_A -> OK");
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 #ifdef CH_B_ENABLE
delay(50); LOG_DEBUG("Begin Init SPI_B");
SPIClass SPI_B(HSPI); SPIClass SPI_B(FSPI);
spiB_ok = SPI_B.begin(SPI_B_SCK, SPI_B_MISO, SPI_B_MOSI); spiB_ok = SPI_B.begin(SPI_B_SCK, SPI_B_MISO, SPI_B_MOSI);
SPI_B.setDataMode(SPI_MODE1); // ADS1256 requires SPI mode 1 SPI_B.setDataMode(SPI_MODE1); // ADS1256 requires SPI mode 1
LOG_DEBUG("Init SPI B ok"); 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 #endif
if (!spiA_ok || !spiB_ok) if (!spiA_ok || !spiB_ok)
@@ -111,27 +143,11 @@ void loop()
vTaskDelay(pdMS_TO_TICKS(5000)); vTaskDelay(pdMS_TO_TICKS(5000));
esp_restart(); esp_restart();
} }
dev->m_spi_a.reset(&SPI_A);
#ifdef CH_B_ENABLE
dev->m_spi_b.reset(&SPI_B);
#endif
// Init ADCs
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 CH_B_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);
#endif
// Configure ADCs
dev->m_adc_a->InitializeADC();
dev->m_adc_a->setPGA(PGA_1);
dev->m_adc_a->setDRATE(DRATE_7500SPS);
#ifdef CH_B_ENABLE
dev->m_adc_b->InitializeADC();
dev->m_adc_b->setPGA(PGA_1);
dev->m_adc_b->setDRATE(DRATE_7500SPS);
#endif
LOG_DEBUG("Init SPI OK");
//////// INIT I2C INTERFACES //////// LOG_DEBUG("Init SPI -> OK");
//////// INIT I2C INTERFACES ////////
#ifdef I2C_ENABLE
LOG_DEBUG("Init I2C Interfaces"); LOG_DEBUG("Init I2C Interfaces");
bool i2c_ok = true; bool i2c_ok = true;
i2c_ok = Wire.begin(SDA, SCL, 100000); i2c_ok = Wire.begin(SDA, SCL, 100000);
@@ -142,11 +158,15 @@ void loop()
vTaskDelay(pdMS_TO_TICKS(5000)); vTaskDelay(pdMS_TO_TICKS(5000));
esp_restart(); esp_restart();
} }
LOG_DEBUG("Init I2c ok");
Serial.readStringUntil('\n');
// Init IO Expanders // Init IO Expanders
// dev->m_ext_io = std::make_unique<ExternalIO>(Wire, dev->m_i2c_mutex, EXPANDER_ALL_INTERRUPT); dev->m_ext_io = std::make_unique<ExternalIO>(Wire, dev->m_i2c_mutex, EXPANDER_ALL_INTERRUPT);
#endif
//////// INIT REALTIME TASKS PARAMETERS //////// //////// 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",
@@ -176,8 +196,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",
@@ -207,16 +228,30 @@ 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
//////// SPAWN REALTIME TASKS //////// //////// SPAWN REALTIME TASKS ////////
auto task_A = rtIgnitionTask(taskA_params, PSRAM_MAX, QUEUE_MAX, CORE_0, fs_mutex); bool tasK_A_rt = true;
delay(50); 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); 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("Unable to initialize ISR task");
@@ -224,10 +259,6 @@ void loop()
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);
@@ -240,18 +271,23 @@ void loop()
} }
//////// SPAWN WEBSERVER and WEBSOCKET //////// //////// SPAWN WEBSERVER and WEBSOCKET ////////
AstroWebServer webPage(80, LittleFS);
ArduinoJson::JsonDocument json_data; ArduinoJson::JsonDocument json_data;
bool data_a, data_b; bool data_a = false, data_b = false;
#ifdef WEB_ENABLE
AstroWebServer webPage(80, LittleFS);
delay(1000);
task_A.onMessage([&webPage, &json_data, &data_a](ignitionBoxStatusFiltered sts) 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; });
#ifdef CH_B_RT_ENABLE
task_B.onMessage([&webPage, &json_data, &data_b](ignitionBoxStatusFiltered sts) 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");
@@ -262,12 +298,14 @@ 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)
{ {
clearScreen(); clearScreen();
printRunningTasksMod(Serial); printRunningTasksMod(Serial);
monitor_loop = millis(); monitor_loop = millis();
} }
vTaskDelay(pdMS_TO_TICKS(10));
#ifdef WEB_ENABLE
if ((data_a && data_b) || (this_loop - data_loop > 500)) if ((data_a && data_b) || (this_loop - data_loop > 500))
{ {
webPage.sendWsData(json_data.as<String>()); webPage.sendWsData(json_data.as<String>());
@@ -275,6 +313,7 @@ void loop()
data_a = data_b = false; data_a = data_b = false;
data_loop = millis(); data_loop = millis();
} }
#endif
} //////////////// INNER LOOP ///////////////////// } //////////////// INNER LOOP /////////////////////
} ////////////////////// MAIN LOOP ////////////////////// } ////////////////////// MAIN LOOP //////////////////////
+56 -33
View File
@@ -16,9 +16,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));
} }
} }
@@ -38,16 +45,17 @@ void rtIgnitionTask::rtIgnitionTask_realtime(void *pvParameters)
const rtTaskInterruptParams rt_int = params->rt_int; // copy to avoid external override const rtTaskInterruptParams rt_int = params->rt_int; // copy to avoid external override
const rtTaskIOParams rt_rst = params->rt_io; // copy to avoid external override const rtTaskIOParams rt_rst = params->rt_io; // 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 = params->name == "rtIgnTask_A" ? dev->m_adc_a.get() : dev->m_adc_b.get(); ExternalIO *io = dev->m_ext_io;
std::mutex& spi_mutex = params->name == "rtIgnTask_A" ? dev->m_spi_a_mutex : dev->m_spi_b_mutex; // ADS1256 *adc = params->name == "rtIgnTask_A" ? dev->m_adc_a : dev->m_adc_b;
ExternalIO* io = dev->m_ext_io.get(); 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;
@@ -77,10 +85,6 @@ void rtIgnitionTask::rtIgnitionTask_realtime(void *pvParameters)
.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 = {
@@ -88,7 +92,11 @@ void rtIgnitionTask::rtIgnitionTask_realtime(void *pvParameters)
.arg = (void *)rt_task_info.xHandle, .arg = (void *)rt_task_info.xHandle,
.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);
@@ -98,7 +106,7 @@ 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 [", params->name.c_str(), "]");
// Global rt_task_ptr variables // Global rt_task_ptr variables
bool first_cycle = true; bool first_cycle = true;
@@ -236,18 +244,19 @@ void rtIgnitionTask::rtIgnitionTask_realtime(void *pvParameters)
// 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
{ {
std::lock_guard<std::mutex> lock (spi_mutex); std::lock_guard<std::mutex> lock(spi_mutex);
uint32_t start_adc_read = esp_timer_get_time(); 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(c_adc_time));
@@ -256,10 +265,23 @@ void rtIgnitionTask::rtIgnitionTask_realtime(void *pvParameters)
// outputs on io expander // outputs on io expander
if (io) if (io)
{ {
// [TODO] code to reset sample and hold and arm trigger level detectors // Discharge Pulse
io->extDigitalWrite(rt_rst.sh_disch_12, true);
io->extDigitalWrite(rt_rst.sh_disch_34, true);
delayMicroseconds(250);
io->extDigitalWrite(rt_rst.sh_disch_12, false);
io->extDigitalWrite(rt_rst.sh_disch_34, false);
// Safety delay
delayMicroseconds(500);
// Re-Arm Pulse
io->extDigitalWrite(rt_rst.sh_arm_12, true);
io->extDigitalWrite(rt_rst.sh_arm_34, true);
delayMicroseconds(250);
io->extDigitalWrite(rt_rst.sh_arm_12, false);
io->extDigitalWrite(rt_rst.sh_arm_34, false);
} }
else else
vTaskDelay(pdMS_TO_TICKS(2)); vTaskDelay(pdMS_TO_TICKS(c_io_time));
// 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)
@@ -272,7 +294,7 @@ void rtIgnitionTask::rtIgnitionTask_realtime(void *pvParameters)
} }
// 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("rtTask Ending [", params->name.c_str(), "]");
// 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);
@@ -287,6 +309,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)
@@ -305,12 +328,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,
@@ -349,14 +372,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
@@ -378,15 +402,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
} }
} }
+5 -3
View File
@@ -41,6 +41,7 @@ static const std::map<const uint32_t, const char *> names = {
class rtIgnitionTask class rtIgnitionTask
{ {
using PSHistory = PSRAMVector<ignitionBoxStatus>; using PSHistory = PSRAMVector<ignitionBoxStatus>;
// using PSHistory = std::vector<ignitionBoxStatus>;
public: public:
// RT task Interrupt parameters // RT task Interrupt parameters
@@ -84,7 +85,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 +125,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;
@@ -154,6 +156,6 @@ private:
static const uint32_t c_idle_time = 10000; // in mS static const uint32_t c_idle_time = 10000; // in mS
static const uint32_t c_spark_timeout_max = 500; // uS static const uint32_t c_spark_timeout_max = 500; // uS
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
}; };
+13 -17
View File
@@ -7,7 +7,7 @@
#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"
@@ -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);
+1 -1
View File
@@ -22,7 +22,7 @@ build_type = release
[env:esp32-devtest-debug] [env:esp32-devtest-debug]
board = esp32dev board = esp32dev
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
lib_deps = lib_deps =
hideakitai/DebugLog@^0.8.4 hideakitai/DebugLog@^0.8.4
board_build.flash_size = 4MB board_build.flash_size = 4MB
+12
View File
@@ -0,0 +1,12 @@
#pragma once
// ANSI colors
#define COLOR_RESET "\033[0m"
#define COLOR_RED "\033[31m"
#define COLOR_GREEN "\033[32m"
#define COLOR_BLUE "\033[34m"
#define COLOR_MAGENTA "\033[35m"
#define COLOR_CYAN "\033[36m"
#define COLOR_YELLOW "\033[33m"
#define COLOR_WHITE "\033[37m"
#define COLOR_LBLUE "\033[94m"
+122 -49
View File
@@ -4,6 +4,8 @@
#include <DebugLog.h> #include <DebugLog.h>
#include "timer.h" #include "timer.h"
#include "colors.h"
#include <map> #include <map>
static hw_timer_t *timerA = NULL; static hw_timer_t *timerA = NULL;
@@ -17,6 +19,12 @@ static uint32_t count = 0;
#define SPARK_DLY_MIN 10 #define SPARK_DLY_MIN 10
#define SPARK_DLY_MAX 490 #define SPARK_DLY_MAX 490
#define COIL_PULSE_MIN 100
#define COIL_PULSE_MAX 1000
#define SPARK_PULSE_MIN 10
#define SPARK_PULSE_MAX 500
#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
@@ -30,7 +38,8 @@ void clearScreen()
Serial.flush(); Serial.flush();
} }
static double filtered_rpm = 0; static uint32_t set_rpm = 500;
static uint32_t set_delay = 100;
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"},
@@ -68,7 +77,7 @@ static timerStatus stsB = {
.clock_period_us = (uint32_t)PERIOD_US, .clock_period_us = (uint32_t)PERIOD_US,
.pause_long_us = 10000, .pause_long_us = 10000,
.pause_short_us = 1000, .pause_short_us = 1000,
.coil_pulse_us = 1000, .coil_pulse_us = 500,
.spark_pulse_us = 100, .spark_pulse_us = 100,
.spark_delay_us = 50, .spark_delay_us = 50,
.pins = { .pins = {
@@ -83,11 +92,14 @@ static timerStatus stsB = {
static bool isEnabled_A = false; static bool isEnabled_A = false;
static bool isEnabled_B = false; static bool isEnabled_B = false;
static String last_command;
void setup() void setup()
{ {
Serial.begin(115200); Serial.begin(115200);
delay(1000); delay(1000);
Serial.setTimeout(100);
LOG_ATTACH_SERIAL(Serial); LOG_ATTACH_SERIAL(Serial);
pinMode(PIN_TRIG_A12P, OUTPUT); pinMode(PIN_TRIG_A12P, OUTPUT);
@@ -133,63 +145,124 @@ void setup()
void loop() void loop()
{ {
LOG_INFO("Loop: ", count++); clearScreen();
uint32_t spark_delay = (uint32_t)(map(analogRead(SPARK_DELAY_POT), 0, 4096, SPARK_DLY_MIN, SPARK_DLY_MAX) / PERIOD_US);
stsA.spark_delay_us = spark_delay * PERIOD_US;
if (stsA.spark_delay_us > (SPARK_DLY_MIN + SPARK_DLY_MAX) / 2)
{
stsA.soft_start = true;
stsA.spark_delay_us -= (SPARK_DLY_MIN + SPARK_DLY_MAX) / 2;
}
else
{
stsA.soft_start = false;
}
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)); Serial.printf("\t++++ Loop: %u ++++\n", count++);
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) if (isEnabled_A)
LOG_INFO("==== System A is ENABLED ===="); Serial.println("==== System A is" COLOR_GREEN " ENABLED" COLOR_RESET " ====");
else else
LOG_INFO("==== System A is DISABLED ===="); Serial.println("==== System A is" COLOR_RED " DISABLED" COLOR_RESET " ====");
if (isEnabled_B) if (isEnabled_B)
LOG_INFO("==== System B is ENABLED ===="); Serial.println("==== System B is" COLOR_GREEN " ENABLED" COLOR_RESET " ====");
else else
LOG_INFO("==== System B is DISABLED ===="); Serial.println("==== System B is" COLOR_RED " DISABLED" COLOR_RESET " ====");
LOG_INFO("Spark Delay uS: ", stsA.spark_delay_us, "\tSoft Start: ", stsA.soft_start ? "TRUE" : "FALSE"); Serial.printf("Spark Delay uS: %u\n", stsA.spark_delay_us);
LOG_INFO("Engine Rpm: ", (uint32_t)(filtered_rpm)); Serial.printf("Soft Start: %s\n", stsA.soft_start ? "ENABLED" : "DISABLED");
LOG_INFO("Coil Pulse: ", stsA.coil_pulse_us, "us"); Serial.printf("Engine Rpm: %u\n", (uint32_t)(set_rpm));
LOG_INFO("Spark Pulse: ", stsA.spark_pulse_us, "us"); Serial.printf("Coil Pulse: %u uS\n", stsA.coil_pulse_us);
Serial.printf("Spark Pulse: %u uS\n", stsA.spark_pulse_us);
Serial.println(COLOR_CYAN "-------------------------------------");
Serial.println("E[a/b] > Enable Box a/b | D[a/b] > Disable a/b");
Serial.println("S[ddd] > Spark Delay | R[dddd] > Engine RPM");
Serial.println("C[ddd] > Spark Pulse | P[ddd] > Coil Pulse");
Serial.println("-------------------------------------" COLOR_RESET);
Serial.printf("Last Command: %s\n", last_command.c_str());
if (digitalRead(ENABLE_PIN_A) == LOW && !isEnabled_A) auto str = Serial.readStringUntil('\n');
if (!str.isEmpty())
{ {
timerStart(timerA); last_command = str;
isEnabled_A = true; const auto cmd = str.charAt(0);
} char c;
else if (digitalRead(ENABLE_PIN_A) == HIGH && isEnabled_A) switch (cmd)
{ {
timerStop(timerA); case 'E':
isEnabled_A = false; {
char box;
sscanf(str.c_str(), "%c%c\n", &c, &box);
if (box == 'a' && !isEnabled_A)
{
timerStart(timerA);
isEnabled_A = true;
}
else if (box == 'b' && !isEnabled_B)
{
timerStart(timerB);
isEnabled_B = true;
}
break;
}
case 'D':
{
char c;
char box;
sscanf(str.c_str(), "%c%c\n", &c, &box);
if (box == 'a' && isEnabled_A)
{
timerStop(timerA);
isEnabled_A = false;
}
else if (box == 'b' && isEnabled_B)
{
timerStop(timerB);
isEnabled_B = false;
}
break;
}
case 'R':
{
int new_rpm;
sscanf(str.c_str(), "%c%d\n", &c, &new_rpm);
new_rpm = min(RPM_MAX, max(RPM_MIN, new_rpm));
stsA.pause_long_us = (uint32_t)(60000000.0f / (float)new_rpm / 2.0f);
stsB.pause_long_us = stsA.pause_long_us;
set_rpm = (uint32_t)new_rpm;
break;
}
case 'S':
{
int new_delay;
sscanf(str.c_str(), "%c%d\n", &c, &new_delay);
new_delay = min(SPARK_DLY_MAX, max(SPARK_DLY_MIN, new_delay));
stsA.spark_delay_us = (uint32_t)(new_delay);
if (stsA.spark_delay_us > (SPARK_DLY_MIN + SPARK_DLY_MAX) / 2)
{
stsA.soft_start = true;
stsA.spark_delay_us -= (SPARK_DLY_MIN + SPARK_DLY_MAX) / 2;
}
else
{
stsA.soft_start = false;
}
stsB.soft_start = stsA.soft_start;
stsB.spark_delay_us = stsA.spark_delay_us;
break;
}
case 'P':
{
int new_pulse;
sscanf(str.c_str(), "%c%d\n", &c, &new_pulse);
new_pulse = min(COIL_PULSE_MAX, max(COIL_PULSE_MIN, new_pulse));
stsA.coil_pulse_us = stsB.coil_pulse_us = (uint32_t)new_pulse;
break;
}
case 'C':
{
int new_pulse;
sscanf(str.c_str(), "%c%d\n", &c, &new_pulse);
new_pulse = min(SPARK_PULSE_MAX, max(SPARK_PULSE_MIN, new_pulse));
stsA.spark_pulse_us = stsB.spark_pulse_us = (uint32_t)new_pulse;
break;
}
default:
break;
}
Serial.read();
} }
if (digitalRead(ENABLE_PIN_B) == LOW && !isEnabled_B) str.clear();
{ delay(1000);
timerStart(timerB);
isEnabled_B = true;
}
else if (digitalRead(ENABLE_PIN_B) == HIGH && isEnabled_B)
{
timerStop(timerB);
isEnabled_B = false;
}
delay(100);
clearScreen();
} }