Basic trigger scope implementation (#4885)
* big buffer * mostly hooked up big buffer * bad merge * s * sneak preview of trigger scope * s * constness * channel limits * s * unnecessary * efilib * TcpServerSandbox * includes fix * binary format * tooth logger uses big buffer * dead config * config * implement basic trigger scope * good behavior * enable on other alphax * flag to enable second channel * use 8 bit mode on the ADC for less memory use * changelog
This commit is contained in:
parent
872595f302
commit
9d8bfb834e
|
@ -30,6 +30,7 @@ Release template (copy/paste this for new release):
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Electronic throttle supply voltage compensation, giving more consistent behavior as battery voltage changes #4838
|
- Electronic throttle supply voltage compensation, giving more consistent behavior as battery voltage changes #4838
|
||||||
|
- VR trigger input oscilloscope for boards with "discrete VR" hardware (AlphaX ECUs, some Hellen) #4885
|
||||||
|
|
||||||
## December 2022 Release - "Day 289"
|
## December 2022 Release - "Day 289"
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@ BOARDINC = $(BOARDS_DIR)/hellen/alphax-2chan
|
||||||
|
|
||||||
DDEFS += -DEFI_MAIN_RELAY_CONTROL=TRUE
|
DDEFS += -DEFI_MAIN_RELAY_CONTROL=TRUE
|
||||||
|
|
||||||
|
# This board has trigger scope hardware!
|
||||||
|
DDEFS += -DTRIGGER_SCOPE
|
||||||
|
|
||||||
# Add them all together
|
# Add them all together
|
||||||
DDEFS += -DFIRMWARE_ID=\"AlphaX-2chan\"
|
DDEFS += -DFIRMWARE_ID=\"AlphaX-2chan\"
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
#define TRIGGER_SCOPE_ADC ADCD3
|
||||||
|
|
||||||
|
#define TRIGGER_SCOPE_SAMPLE_TIME ADC_SAMPLE_144
|
||||||
|
|
||||||
|
// RES3
|
||||||
|
#define TRIGGER_SCOPE_PIN_CH1 Gpio::F8
|
||||||
|
#define TRIGGER_SCOPE_ADC_CH1 ADC_CHANNEL_IN6
|
||||||
|
|
||||||
|
#define TRIGGER_SCOPE_HAS_CH2 true
|
||||||
|
#define TRIGGER_SCOPE_PIN_CH2 Gpio::F8
|
||||||
|
#define TRIGGER_SCOPE_ADC_CH2 ADC_CHANNEL_IN6
|
|
@ -6,7 +6,8 @@ BOARDINC = $(BOARDS_DIR)/hellen/alphax-4chan
|
||||||
|
|
||||||
DDEFS += -DEFI_MAIN_RELAY_CONTROL=TRUE
|
DDEFS += -DEFI_MAIN_RELAY_CONTROL=TRUE
|
||||||
|
|
||||||
|
# This board has trigger scope hardware!
|
||||||
|
DDEFS += -DTRIGGER_SCOPE
|
||||||
|
|
||||||
# Add them all together
|
# Add them all together
|
||||||
DDEFS += -DFIRMWARE_ID=\"AlphaX-4chan\"
|
DDEFS += -DFIRMWARE_ID=\"AlphaX-4chan\"
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#define TRIGGER_SCOPE_ADC ADCD3
|
||||||
|
|
||||||
|
#define TRIGGER_SCOPE_SAMPLE_TIME ADC_SAMPLE_144
|
||||||
|
|
||||||
|
// RES3
|
||||||
|
#define TRIGGER_SCOPE_PIN_CH1 Gpio::F8
|
||||||
|
#define TRIGGER_SCOPE_ADC_CH1 ADC_CHANNEL_IN6
|
||||||
|
|
||||||
|
// RES2
|
||||||
|
#define TRIGGER_SCOPE_HAS_CH2 true
|
||||||
|
#define TRIGGER_SCOPE_PIN_CH2 Gpio::F10
|
||||||
|
#define TRIGGER_SCOPE_ADC_CH2 ADC_CHANNEL_IN8
|
|
@ -6,7 +6,8 @@ BOARDINC = $(BOARDS_DIR)/hellen/alphax-8chan
|
||||||
|
|
||||||
DDEFS += -DEFI_MAIN_RELAY_CONTROL=TRUE
|
DDEFS += -DEFI_MAIN_RELAY_CONTROL=TRUE
|
||||||
|
|
||||||
|
# This board has trigger scope hardware!
|
||||||
|
DDEFS += -DTRIGGER_SCOPE
|
||||||
|
|
||||||
# Add them all together
|
# Add them all together
|
||||||
DDEFS += -DFIRMWARE_ID=\"AlphaX-8chan\"
|
DDEFS += -DFIRMWARE_ID=\"AlphaX-8chan\"
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#define TRIGGER_SCOPE_ADC ADCD3
|
||||||
|
|
||||||
|
#define TRIGGER_SCOPE_SAMPLE_TIME ADC_SAMPLE_144
|
||||||
|
|
||||||
|
// RES3
|
||||||
|
#define TRIGGER_SCOPE_PIN_CH1 Gpio::F8
|
||||||
|
#define TRIGGER_SCOPE_ADC_CH1 ADC_CHANNEL_IN6
|
||||||
|
|
||||||
|
// RES2
|
||||||
|
#define TRIGGER_SCOPE_HAS_CH2 true
|
||||||
|
#define TRIGGER_SCOPE_PIN_CH2 Gpio::F10
|
||||||
|
#define TRIGGER_SCOPE_ADC_CH2 ADC_CHANNEL_IN8
|
|
@ -1,19 +1,82 @@
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
|
|
||||||
|
#ifdef TRIGGER_SCOPE
|
||||||
|
|
||||||
#include "trigger_scope.h"
|
#include "trigger_scope.h"
|
||||||
|
#include "trigger_scope_config.h"
|
||||||
|
|
||||||
static BigBufferHandle buffer;
|
static BigBufferHandle buffer;
|
||||||
|
|
||||||
static bool isRunning = false;
|
static bool isRunning = false;
|
||||||
|
|
||||||
|
static void completionCallback(ADCDriver* adcp) {
|
||||||
|
if (isRunning && adcp->state == ADC_COMPLETE) {
|
||||||
|
engine->outputChannels.triggerScopeReady = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint32_t smpr1 =
|
||||||
|
ADC_SMPR1_SMP_AN10(TRIGGER_SCOPE_SAMPLE_TIME) |
|
||||||
|
ADC_SMPR1_SMP_AN11(TRIGGER_SCOPE_SAMPLE_TIME) |
|
||||||
|
ADC_SMPR1_SMP_AN12(TRIGGER_SCOPE_SAMPLE_TIME) |
|
||||||
|
ADC_SMPR1_SMP_AN13(TRIGGER_SCOPE_SAMPLE_TIME) |
|
||||||
|
ADC_SMPR1_SMP_AN14(TRIGGER_SCOPE_SAMPLE_TIME) |
|
||||||
|
ADC_SMPR1_SMP_AN15(TRIGGER_SCOPE_SAMPLE_TIME);
|
||||||
|
|
||||||
|
static const uint32_t smpr2 =
|
||||||
|
ADC_SMPR2_SMP_AN0(TRIGGER_SCOPE_SAMPLE_TIME) |
|
||||||
|
ADC_SMPR2_SMP_AN1(TRIGGER_SCOPE_SAMPLE_TIME) |
|
||||||
|
ADC_SMPR2_SMP_AN2(TRIGGER_SCOPE_SAMPLE_TIME) |
|
||||||
|
ADC_SMPR2_SMP_AN3(TRIGGER_SCOPE_SAMPLE_TIME) |
|
||||||
|
ADC_SMPR2_SMP_AN4(TRIGGER_SCOPE_SAMPLE_TIME) |
|
||||||
|
ADC_SMPR2_SMP_AN5(TRIGGER_SCOPE_SAMPLE_TIME) |
|
||||||
|
ADC_SMPR2_SMP_AN6(TRIGGER_SCOPE_SAMPLE_TIME) |
|
||||||
|
ADC_SMPR2_SMP_AN7(TRIGGER_SCOPE_SAMPLE_TIME) |
|
||||||
|
ADC_SMPR2_SMP_AN8(TRIGGER_SCOPE_SAMPLE_TIME) |
|
||||||
|
ADC_SMPR2_SMP_AN9(TRIGGER_SCOPE_SAMPLE_TIME);
|
||||||
|
|
||||||
|
static const ADCConversionGroup adcConvGroupCh1 = { FALSE, 2, &completionCallback, nullptr,
|
||||||
|
ADC_CR1_RES_1, // Sample in 8-bit mode
|
||||||
|
ADC_CR2_SWSTART,
|
||||||
|
// sample times for channels 10...18
|
||||||
|
smpr1,
|
||||||
|
// sample times for channels 0...9
|
||||||
|
smpr2,
|
||||||
|
|
||||||
|
0, // htr
|
||||||
|
0, // ltr
|
||||||
|
|
||||||
|
0, // sqr1
|
||||||
|
0, // sqr2
|
||||||
|
ADC_SQR3_SQ1_N(TRIGGER_SCOPE_ADC_CH1) | ADC_SQR3_SQ2_N(TRIGGER_SCOPE_ADC_CH2)
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr size_t sampleCount = 1000;
|
||||||
|
static_assert(2 * sizeof(uint8_t) * sampleCount < BIG_BUFFER_SIZE);
|
||||||
|
|
||||||
|
static void startSampling(void* = nullptr) {
|
||||||
|
chibios_rt::CriticalSectionLocker csl;
|
||||||
|
|
||||||
|
if (buffer && !engineConfiguration->enableSoftwareKnock) {
|
||||||
|
// Cancel if ADC isn't ready
|
||||||
|
if (!((TRIGGER_SCOPE_ADC.state == ADC_READY) ||
|
||||||
|
(TRIGGER_SCOPE_ADC.state == ADC_COMPLETE) ||
|
||||||
|
(TRIGGER_SCOPE_ADC.state == ADC_ERROR))) {
|
||||||
|
triggerScopeDisable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
adcStartConversionI(&TRIGGER_SCOPE_ADC, &adcConvGroupCh1, buffer.get<adcsample_t>(), sampleCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Enable one buffer's worth of perf tracing, and retrieve the buffer size in bytes
|
// Enable one buffer's worth of perf tracing, and retrieve the buffer size in bytes
|
||||||
void triggerScopeEnable() {
|
void triggerScopeEnable() {
|
||||||
buffer = getBigBuffer(BigBufferUser::TriggerScope);
|
buffer = getBigBuffer(BigBufferUser::TriggerScope);
|
||||||
|
|
||||||
// TODO: trigger ADC
|
|
||||||
|
|
||||||
isRunning = true;
|
isRunning = true;
|
||||||
engine->outputChannels.triggerScopeReady = true;
|
|
||||||
|
startSampling();
|
||||||
}
|
}
|
||||||
|
|
||||||
void triggerScopeDisable() {
|
void triggerScopeDisable() {
|
||||||
|
@ -24,19 +87,35 @@ void triggerScopeDisable() {
|
||||||
engine->outputChannels.triggerScopeReady = false;
|
engine->outputChannels.triggerScopeReady = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int theta = 0;
|
static scheduling_s restartTimer;
|
||||||
|
|
||||||
// Retrieve the trace buffer
|
// Retrieve the trace buffer
|
||||||
const BigBufferHandle& triggerScopeGetBuffer() {
|
const BigBufferHandle& triggerScopeGetBuffer() {
|
||||||
if (buffer) {
|
engine->outputChannels.triggerScopeReady = false;
|
||||||
for (size_t i = 0; i < buffer.size(); i++)
|
|
||||||
{
|
|
||||||
buffer.get<uint8_t>()[i] = 128 + 100 * sin((float)theta / 50);
|
|
||||||
theta++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// engine->outputChannels.triggerScopeReady = false;
|
// Start the next sample once we've read out this one
|
||||||
|
if (isRunning) {
|
||||||
|
engine->executor.scheduleByTimestampNt("trigger scope", &restartTimer, getTimeNowNt() + MS2NT(10), startSampling);
|
||||||
|
}
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void initTriggerScope() {
|
||||||
|
// Trigger scope and knock currently mutually exclusive
|
||||||
|
if (!engineConfiguration->enableSoftwareKnock) {
|
||||||
|
adcStart(&TRIGGER_SCOPE_ADC, nullptr);
|
||||||
|
|
||||||
|
// Manually set ADC DMA to byte mode, as we'll be taking 8 bit samples
|
||||||
|
// Defaults are to sample at 12 bits, and DMA 16-bit words
|
||||||
|
ADCD3.dmamode &= ~(STM32_DMA_CR_PSIZE_MASK | STM32_DMA_CR_MSIZE_MASK);
|
||||||
|
ADCD3.dmamode |= STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;
|
||||||
|
|
||||||
|
efiSetPadMode("knock ch1", TRIGGER_SCOPE_PIN_CH1, PAL_MODE_INPUT_ANALOG);
|
||||||
|
#if TRIGGER_SCOPE_HAS_CH2
|
||||||
|
efiSetPadMode("knock ch2", TRIGGER_SCOPE_PIN_CH2, PAL_MODE_INPUT_ANALOG);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // TRIGGER_SCOPE
|
||||||
|
|
|
@ -3,3 +3,5 @@
|
||||||
void triggerScopeEnable();
|
void triggerScopeEnable();
|
||||||
void triggerScopeDisable();
|
void triggerScopeDisable();
|
||||||
const BigBufferHandle& triggerScopeGetBuffer();
|
const BigBufferHandle& triggerScopeGetBuffer();
|
||||||
|
|
||||||
|
void initTriggerScope();
|
||||||
|
|
|
@ -759,6 +759,7 @@ int TunerStudio::handleCrcCommand(TsChannelBase* tsChannel, char *data, int inco
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
#ifdef TRIGGER_SCOPE
|
||||||
case TS_TRIGGER_SCOPE_ENABLE:
|
case TS_TRIGGER_SCOPE_ENABLE:
|
||||||
triggerScopeEnable();
|
triggerScopeEnable();
|
||||||
break;
|
break;
|
||||||
|
@ -777,6 +778,7 @@ int TunerStudio::handleCrcCommand(TsChannelBase* tsChannel, char *data, int inco
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
#endif // TRIGGER_SCOPE
|
||||||
default:
|
default:
|
||||||
// dunno what that was, send NAK
|
// dunno what that was, send NAK
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "trigger_emulator_algo.h"
|
#include "trigger_emulator_algo.h"
|
||||||
#include "boost_control.h"
|
#include "boost_control.h"
|
||||||
#include "software_knock.h"
|
#include "software_knock.h"
|
||||||
|
#include "trigger_scope.h"
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#if EFI_MC33816
|
#if EFI_MC33816
|
||||||
#include "mc33816.h"
|
#include "mc33816.h"
|
||||||
|
@ -525,6 +526,10 @@ void initHardware() {
|
||||||
initSoftwareKnock();
|
initSoftwareKnock();
|
||||||
#endif /* EFI_SOFTWARE_KNOCK */
|
#endif /* EFI_SOFTWARE_KNOCK */
|
||||||
|
|
||||||
|
#ifdef TRIGGER_SCOPE
|
||||||
|
initTriggerScope();
|
||||||
|
#endif // TRIGGER_SCOPE
|
||||||
|
|
||||||
#if HAL_USE_SPI
|
#if HAL_USE_SPI
|
||||||
initSpiModules(engineConfiguration);
|
initSpiModules(engineConfiguration);
|
||||||
#endif /* HAL_USE_SPI */
|
#endif /* HAL_USE_SPI */
|
||||||
|
|
|
@ -141,13 +141,9 @@ enable2ndByteCanID = false
|
||||||
dataReadyCondition = { triggerScopeReady }
|
dataReadyCondition = { triggerScopeReady }
|
||||||
continuousRead = true
|
continuousRead = true
|
||||||
|
|
||||||
recordDef = 0, 0, 4
|
recordDef = 0, 0, 2
|
||||||
recordField = lowBits1, "low", 0, 8, 1, "" , hidden
|
recordField = channel1, "Channel 1", 0, 8, {6.6 / 255}, "v"
|
||||||
recordField = highBits1, "high", 8, 8, 1, "" , hidden
|
recordField = channel2, "Channel 2", 8, 8, {6.6 / 255}, "v"
|
||||||
calcField = channel1, "Channel 1", "v", { 6.6 / 4096 * ( lowBits1 * 256 + highBits1 ) }
|
|
||||||
recordField = lowBits2, "low2", 16, 8, 1, "" , hidden
|
|
||||||
recordField = highBits2, "high2", 24, 8, 1, "" , hidden
|
|
||||||
calcField = channel2, "Channel 2", "v", { 6.6 / 4096 * ( lowBits2 * 256 + highBits2 ) }
|
|
||||||
|
|
||||||
[VeAnalyze]
|
[VeAnalyze]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue