fast exti interrupt handoff (#3497)

* fast exti

* test code snuck in

* full interrupt disable :(

* do it the old fashioned way

* enable interrupt

* consume stored timestamp

* dead

* h7 maybe

* guard maybe

* non-stm32

* exti 16 wrong on f4/f7

* CORTEX_MAXIMUM_PRIORITY

* safer but uglier

* s

* chibios

* no const

* initializers

Co-authored-by: Matthew Kennedy <makenne@microsoft.com>
This commit is contained in:
Matthew Kennedy 2021-11-19 03:37:52 -08:00 committed by GitHub
parent f76054c0b3
commit 29613ec403
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 171 additions and 47 deletions

@ -1 +1 @@
Subproject commit 8bae576fdde4e2220bfdc577ca71920bcf1043b2
Subproject commit e19494fd2323c21337fc0fc8377d967175d36898

View File

@ -9,9 +9,8 @@
#include "digital_input_exti.h"
// Callback adapter since we can't pass a member function to a callback
static void freqSensorExtiCallback(void* arg) {
auto inst = reinterpret_cast<FrequencySensor*>(arg);
inst->onEdge(getTimeNowNt());
static void freqSensorExtiCallback(void* arg, efitick_t nowNt) {
reinterpret_cast<FrequencySensor*>(arg)->onEdge(nowNt);
}
void FrequencySensor::init(brain_pin_e pin) {

View File

@ -18,16 +18,25 @@
* because pin '0' would be used on two different ports
*/
static ioportmask_t ext_used = 0;
static const char *EXT_USED[16];
#ifdef STM32_I2C_I2C1_IRQ_PRIORITY
void efiExtiInit() {
memset(EXT_USED, 0, sizeof(EXT_USED));
nvicEnableVector(I2C1_EV_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY);
}
// EXT is not able to give you the front direction but you could read the pin in the callback.
void efiExtiEnablePin(const char *msg, brain_pin_e brainPin, uint32_t mode, palcallback_t cb, void *cb_data) {
struct ExtiChannel
{
ExtiCallback Callback = nullptr;
void* CallbackData;
efitick_t Timestamp = 0;
const char* Name = nullptr;
};
static ExtiChannel channels[16];
// EXT is not able to give you the front direction but you could read the pin in the callback.
void efiExtiEnablePin(const char *msg, brain_pin_e brainPin, uint32_t mode, ExtiCallback cb, void *cb_data) {
/* paranoid check, in case of GPIO_UNASSIGNED getHwPort will return NULL
* and we will fail on next check */
if (!isBrainPinValid(brainPin)) {
@ -47,23 +56,24 @@ void efiExtiEnablePin(const char *msg, brain_pin_e brainPin, uint32_t mode, palc
int index = getHwPin(msg, brainPin);
auto& channel = channels[index];
/* is this index already used? */
if (ext_used & PAL_PORT_BIT(index)) {
if (channel.Callback) {
firmwareError(CUSTOM_ERR_PIN_ALREADY_USED_2, "%s: pin %s/index %d: exti index already used by %s",
msg,
hwPortname(brainPin),
index,
EXT_USED[index]);
channel.Name);
return;
}
ioline_t line = PAL_LINE(port, index);
palEnableLineEvent(line, mode);
palSetLineCallback(line, cb, cb_data);
/* mark used */
ext_used |= PAL_PORT_BIT(index);
EXT_USED[index] = msg;
channel.Name = msg;
channel.Callback = cb;
channel.CallbackData = cb_data;
}
void efiExtiDisablePin(brain_pin_e brainPin)
@ -80,8 +90,10 @@ void efiExtiDisablePin(brain_pin_e brainPin)
int index = getHwPin("exti", brainPin);
auto& channel = channels[index];
/* is this index was used? */
if (!(ext_used & PAL_PORT_BIT(index))) {
if (!channel.Callback) {
return;
}
@ -89,8 +101,9 @@ void efiExtiDisablePin(brain_pin_e brainPin)
palDisableLineEvent(line);
/* mark unused */
ext_used &= ~PAL_PORT_BIT(index);
EXT_USED[index] = nullptr;
channel.Name = nullptr;
channel.Callback = nullptr;
channel.CallbackData = nullptr;
}
digital_input_s* startDigitalCaptureExti(const char *msg, brain_pin_e brainPin) {
@ -103,9 +116,96 @@ digital_input_s* startDigitalCapture(const char *msg, brain_pin_e brainPin) {
}
#endif // EFI_ICU_INPUTS
static inline void triggerInterrupt() {
// Manually fire the I2C1_EV interrupt, it will be queued after this interrupt returns
NVIC->STIR = I2C1_EV_IRQn;
}
CH_IRQ_HANDLER(STM32_I2C1_EVENT_HANDLER) {
OSAL_IRQ_PROLOGUE();
for (size_t i = 0; i < 16; i++) {
auto& channel = channels[i];
// get the timestamp out under lock
// todo: lock freeeeee!
__disable_irq();
auto timestamp = channel.Timestamp;
channel.Timestamp = 0;
__enable_irq();
if (timestamp != 0) {
channel.Callback(channel.CallbackData, timestamp);
}
}
OSAL_IRQ_EPILOGUE();
}
void handleExtiIsr(uint8_t index) {
// No need to lock anything, we're already the highest-pri interrupt!
uint32_t pr;
extiGetAndClearGroup1(1U << index, pr);
if (pr & (1 << index)) {
auto& timestamp = channels[index].Timestamp;
if (timestamp == 0) {
timestamp = getTimeNowNt();
}
triggerInterrupt();
}
}
CH_FAST_IRQ_HANDLER(Vector58) {
handleExtiIsr(0);
}
CH_FAST_IRQ_HANDLER(Vector5C) {
handleExtiIsr(1);
}
CH_FAST_IRQ_HANDLER(Vector60) {
handleExtiIsr(2);
}
CH_FAST_IRQ_HANDLER(Vector64) {
handleExtiIsr(3);
}
CH_FAST_IRQ_HANDLER(Vector68) {
handleExtiIsr(4);
}
CH_FAST_IRQ_HANDLER(Vector9C) {
handleExtiIsr(5);
handleExtiIsr(6);
handleExtiIsr(7);
handleExtiIsr(8);
handleExtiIsr(9);
}
CH_FAST_IRQ_HANDLER(VectorE0) {
handleExtiIsr(10);
handleExtiIsr(11);
handleExtiIsr(12);
handleExtiIsr(13);
handleExtiIsr(14);
handleExtiIsr(15);
}
#else // not STM32
// TODO: non-stm32 exti
void efiExtiInit() {
firmwareError(OBD_PCM_Processor_Fault, "exti not supported");
}
void efiExtiEnablePin(const char *, brain_pin_e, uint32_t, ExtiCallback, void *) { }
void efiExtiDisablePin(brain_pin_e) { }
#endif
#endif /* HAL_USE_PAL && EFI_PROD_CODE */

View File

@ -10,7 +10,10 @@
#include "digital_input.h"
#if HAL_USE_PAL
using ExtiCallback = void(*)(void*, efitick_t);
void efiExtiInit();
void efiExtiEnablePin(const char *msg, brain_pin_e pin, uint32_t mode, palcallback_t cb, void *cb_data);
void efiExtiEnablePin(const char *msg, brain_pin_e pin, uint32_t mode, ExtiCallback cb, void *cb_data);
void efiExtiDisablePin(brain_pin_e brainPin);
#endif /* HAL_USE_PAL */

View File

@ -24,9 +24,8 @@
static ioline_t shaftLines[TRIGGER_SUPPORTED_CHANNELS];
static ioline_t camLines[CAM_INPUTS_COUNT];
static void shaft_callback(void *arg) {
static void shaft_callback(void *arg, efitick_t stamp) {
// do the time sensitive things as early as possible!
efitick_t stamp = getTimeNowNt();
TRIGGER_BAIL_IF_DISABLED
//#if HW_CHECK_MODE
// TRIGGER_BAIL_IF_SELF_STIM
@ -42,8 +41,7 @@ static void shaft_callback(void *arg) {
hwHandleShaftSignal(index, rise, stamp);
}
static void cam_callback(void *arg) {
efitick_t stamp = getTimeNowNt();
static void cam_callback(void *arg, efitick_t stamp) {
TRIGGER_BAIL_IF_DISABLED
//#if HW_CHECK_MODE
// TRIGGER_BAIL_IF_SELF_STIM

View File

@ -89,7 +89,19 @@
/*
* EXT driver system settings.
*/
#define STM32_IRQ_EXTI_PRIORITY ICU_PRIORITY
#define STM32_DISABLE_EXTI0_HANDLER
#define STM32_DISABLE_EXTI1_HANDLER
#define STM32_DISABLE_EXTI2_HANDLER
#define STM32_DISABLE_EXTI3_HANDLER
#define STM32_DISABLE_EXTI4_HANDLER
#define STM32_DISABLE_EXTI5_9_HANDLER
#define STM32_DISABLE_EXTI10_15_HANDLER
// we hijack this interrupt handler as the EXTI chained handler, see digital_input_exti.cpp
#define STM32_I2C_I2C1_IRQ_PRIORITY ICU_PRIORITY
#define STM32_IRQ_EXTI_PRIORITY CORTEX_MAXIMUM_PRIORITY
#define STM32_IRQ_EXTI0_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI1_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI2_PRIORITY STM32_IRQ_EXTI_PRIORITY
@ -97,14 +109,14 @@
#define STM32_IRQ_EXTI4_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI5_9_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI10_15_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI16_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI16_PRIORITY 15
#define STM32_IRQ_EXTI17_PRIORITY 15 /* why? */
#define STM32_IRQ_EXTI18_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI19_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI20_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI18_PRIORITY 15
#define STM32_IRQ_EXTI19_PRIORITY 15
#define STM32_IRQ_EXTI20_PRIORITY 15
#define STM32_IRQ_EXTI21_PRIORITY 15 /* why? */
#define STM32_IRQ_EXTI22_PRIORITY 15 /* why? */
#define STM32_IRQ_EXTI23_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI23_PRIORITY 15
/*
* GPT driver system settings.
@ -138,7 +150,6 @@
#define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
#define STM32_I2C_I2C4_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
#define STM32_I2C_I2C4_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
#define STM32_I2C_I2C1_IRQ_PRIORITY 5
#define STM32_I2C_I2C2_IRQ_PRIORITY 5
#define STM32_I2C_I2C3_IRQ_PRIORITY 5
#define STM32_I2C_I2C4_IRQ_PRIORITY 5

View File

@ -175,13 +175,27 @@
/*
* IRQ system settings.
*/
#define STM32_IRQ_EXTI0_PRIORITY 6
#define STM32_IRQ_EXTI1_PRIORITY 6
#define STM32_IRQ_EXTI2_PRIORITY 6
#define STM32_IRQ_EXTI3_PRIORITY 6
#define STM32_IRQ_EXTI4_PRIORITY 6
#define STM32_IRQ_EXTI5_9_PRIORITY 6
#define STM32_IRQ_EXTI10_15_PRIORITY 6
#define STM32_DISABLE_EXTI0_HANDLER
#define STM32_DISABLE_EXTI1_HANDLER
#define STM32_DISABLE_EXTI2_HANDLER
#define STM32_DISABLE_EXTI3_HANDLER
#define STM32_DISABLE_EXTI4_HANDLER
#define STM32_DISABLE_EXTI5_9_HANDLER
#define STM32_DISABLE_EXTI10_15_HANDLER
// we hijack this interrupt handler as the EXTI chained handler, see digital_input_exti.cpp
#define STM32_I2C_I2C1_IRQ_PRIORITY 6
#define STM32_IRQ_EXTI_PRIORITY CORTEX_MAXIMUM_PRIORITY
#define STM32_IRQ_EXTI0_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI1_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI2_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI3_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI4_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI5_9_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI10_15_PRIORITY STM32_IRQ_EXTI_PRIORITY
#define STM32_IRQ_EXTI16_PRIORITY 6
#define STM32_IRQ_EXTI17_PRIORITY 6
#define STM32_IRQ_EXTI18_PRIORITY 6
@ -293,7 +307,7 @@
#define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY
#define STM32_I2C_I2C4_RX_BDMA_STREAM STM32_BDMA_STREAM_ID_ANY
#define STM32_I2C_I2C4_TX_BDMA_STREAM STM32_BDMA_STREAM_ID_ANY
#define STM32_I2C_I2C1_IRQ_PRIORITY 5
// STM32_I2C_I2C1_IRQ_PRIORITY is defined above, reused for fast EXTI handoff
#define STM32_I2C_I2C2_IRQ_PRIORITY 5
#define STM32_I2C_I2C3_IRQ_PRIORITY 5
#define STM32_I2C_I2C4_IRQ_PRIORITY 5

View File

@ -115,13 +115,12 @@ static void onTriggerChanged(efitick_t stamp, bool isPrimary, bool isRising) {
}
static void shaft_callback(void *arg) {
static void shaft_callback(void *arg, efitick_t stamp) {
if (curAdcMode != TRIGGER_EXTI) {
return;
}
// do the time sensitive things as early as possible!
efitick_t stamp = getTimeNowNt();
ioline_t pal_line = (ioline_t)arg;
bool rise = (palReadLine(pal_line) == PAL_HIGH);
@ -148,7 +147,7 @@ static void shaft_callback(void *arg) {
prevStamp = stamp;
}
static void cam_callback(void *) {
static void cam_callback(void *, efitick_t) {
}
// todo: add cam support?