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:
Matthew Kennedy 2022-12-10 20:00:12 -08:00 committed by GitHub
parent 872595f302
commit 9d8bfb834e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 145 additions and 22 deletions

View File

@ -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"

View File

@ -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\"

View File

@ -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

View File

@ -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\"

View File

@ -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

View File

@ -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\"

View File

@ -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

View File

@ -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

View File

@ -3,3 +3,5 @@
void triggerScopeEnable();
void triggerScopeDisable();
const BigBufferHandle& triggerScopeGetBuffer();
void initTriggerScope();

View File

@ -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;

View File

@ -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 */

View File

@ -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]