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
|
||||
- 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"
|
||||
|
||||
|
|
|
@ -6,7 +6,8 @@ BOARDINC = $(BOARDS_DIR)/hellen/alphax-2chan
|
|||
|
||||
DDEFS += -DEFI_MAIN_RELAY_CONTROL=TRUE
|
||||
|
||||
|
||||
# This board has trigger scope hardware!
|
||||
DDEFS += -DTRIGGER_SCOPE
|
||||
|
||||
# Add them all together
|
||||
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
|
||||
|
||||
|
||||
# This board has trigger scope hardware!
|
||||
DDEFS += -DTRIGGER_SCOPE
|
||||
|
||||
# Add them all together
|
||||
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
|
||||
|
||||
|
||||
# This board has trigger scope hardware!
|
||||
DDEFS += -DTRIGGER_SCOPE
|
||||
|
||||
# Add them all together
|
||||
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"
|
||||
|
||||
#ifdef TRIGGER_SCOPE
|
||||
|
||||
#include "trigger_scope.h"
|
||||
#include "trigger_scope_config.h"
|
||||
|
||||
static BigBufferHandle buffer;
|
||||
|
||||
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
|
||||
void triggerScopeEnable() {
|
||||
buffer = getBigBuffer(BigBufferUser::TriggerScope);
|
||||
|
||||
// TODO: trigger ADC
|
||||
|
||||
isRunning = true;
|
||||
engine->outputChannels.triggerScopeReady = true;
|
||||
|
||||
startSampling();
|
||||
}
|
||||
|
||||
void triggerScopeDisable() {
|
||||
|
@ -24,19 +87,35 @@ void triggerScopeDisable() {
|
|||
engine->outputChannels.triggerScopeReady = false;
|
||||
}
|
||||
|
||||
static int theta = 0;
|
||||
static scheduling_s restartTimer;
|
||||
|
||||
// Retrieve the trace buffer
|
||||
const BigBufferHandle& triggerScopeGetBuffer() {
|
||||
if (buffer) {
|
||||
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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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 triggerScopeDisable();
|
||||
const BigBufferHandle& triggerScopeGetBuffer();
|
||||
|
||||
void initTriggerScope();
|
||||
|
|
|
@ -759,6 +759,7 @@ int TunerStudio::handleCrcCommand(TsChannelBase* tsChannel, char *data, int inco
|
|||
}
|
||||
}
|
||||
break;
|
||||
#ifdef TRIGGER_SCOPE
|
||||
case TS_TRIGGER_SCOPE_ENABLE:
|
||||
triggerScopeEnable();
|
||||
break;
|
||||
|
@ -777,6 +778,7 @@ int TunerStudio::handleCrcCommand(TsChannelBase* tsChannel, char *data, int inco
|
|||
}
|
||||
}
|
||||
break;
|
||||
#endif // TRIGGER_SCOPE
|
||||
default:
|
||||
// dunno what that was, send NAK
|
||||
return false;
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "trigger_emulator_algo.h"
|
||||
#include "boost_control.h"
|
||||
#include "software_knock.h"
|
||||
#include "trigger_scope.h"
|
||||
#include "init.h"
|
||||
#if EFI_MC33816
|
||||
#include "mc33816.h"
|
||||
|
@ -525,6 +526,10 @@ void initHardware() {
|
|||
initSoftwareKnock();
|
||||
#endif /* EFI_SOFTWARE_KNOCK */
|
||||
|
||||
#ifdef TRIGGER_SCOPE
|
||||
initTriggerScope();
|
||||
#endif // TRIGGER_SCOPE
|
||||
|
||||
#if HAL_USE_SPI
|
||||
initSpiModules(engineConfiguration);
|
||||
#endif /* HAL_USE_SPI */
|
||||
|
|
|
@ -141,13 +141,9 @@ enable2ndByteCanID = false
|
|||
dataReadyCondition = { triggerScopeReady }
|
||||
continuousRead = true
|
||||
|
||||
recordDef = 0, 0, 4
|
||||
recordField = lowBits1, "low", 0, 8, 1, "" , hidden
|
||||
recordField = highBits1, "high", 8, 8, 1, "" , hidden
|
||||
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 ) }
|
||||
recordDef = 0, 0, 2
|
||||
recordField = channel1, "Channel 1", 0, 8, {6.6 / 255}, "v"
|
||||
recordField = channel2, "Channel 2", 8, 8, {6.6 / 255}, "v"
|
||||
|
||||
[VeAnalyze]
|
||||
|
||||
|
|
Loading…
Reference in New Issue