From 85fab40d2155e773e9ddaa257e7ee20b6c046fe9 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Tue, 9 Feb 2021 19:04:36 -0800 Subject: [PATCH] get mcu temperature within port (#2326) * remove EFI_ADC_TEMP_SENSOR * implement * comment * s * switch adc_inputs over * header * s * I think aligned-on-stack should work ok * num channels * cache safety * move adc init too * don't compile that file for the h7 * cypress & kinetis * ports * guard against bootloader Co-authored-by: Matthew Kennedy --- .../ports/Cypress/S6E2CxAH/cypress_stm32.h | 2 - .../hal/ports/KINETIS/KE1xF/kinetis_stm32.h | 2 - .../controllers/algo/auto_generated_enums.cpp | 2 - .../boards/subaru_eg33/rusefi_hw_enums.h | 4 +- .../controllers/algo/auto_generated_enums.cpp | 2 - firmware/controllers/algo/rusefi_hw_enums.h | 4 +- firmware/hw_layer/adc/adc_inputs.cpp | 57 ++------- firmware/hw_layer/ports/cypress/mpu_util.cpp | 13 ++ firmware/hw_layer/ports/kinetis/mpu_util.cpp | 13 ++ firmware/hw_layer/ports/mpu_util.h | 5 + .../hw_layer/ports/stm32/stm32_adc_v2.cpp | 113 ++++++++++++++++++ .../hw_layer/ports/stm32/stm32f4/hw_ports.mk | 3 +- .../hw_layer/ports/stm32/stm32f7/hw_ports.mk | 3 +- 13 files changed, 157 insertions(+), 66 deletions(-) create mode 100644 firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp diff --git a/firmware/config/boards/hellen/cypress/OS/os/hal/ports/Cypress/S6E2CxAH/cypress_stm32.h b/firmware/config/boards/hellen/cypress/OS/os/hal/ports/Cypress/S6E2CxAH/cypress_stm32.h index ddd9c0521c..63e635aa78 100644 --- a/firmware/config/boards/hellen/cypress/OS/os/hal/ports/Cypress/S6E2CxAH/cypress_stm32.h +++ b/firmware/config/boards/hellen/cypress/OS/os/hal/ports/Cypress/S6E2CxAH/cypress_stm32.h @@ -99,6 +99,4 @@ #define STM32_HAS_GPIOJ TRUE #define STM32_HAS_GPIOK TRUE -#define adcSTM32EnableTSVREFE() - #endif /* CYPRESS_STM32_H_ */ diff --git a/firmware/config/boards/kinetis/OS/os/hal/ports/KINETIS/KE1xF/kinetis_stm32.h b/firmware/config/boards/kinetis/OS/os/hal/ports/KINETIS/KE1xF/kinetis_stm32.h index 231a6fc5a3..f11e28b4d2 100644 --- a/firmware/config/boards/kinetis/OS/os/hal/ports/KINETIS/KE1xF/kinetis_stm32.h +++ b/firmware/config/boards/kinetis/OS/os/hal/ports/KINETIS/KE1xF/kinetis_stm32.h @@ -98,6 +98,4 @@ #define STM32_HAS_GPIOG KINETIS_HAS_GPIOG #define STM32_HAS_GPIOH KINETIS_HAS_GPIOH -#define adcSTM32EnableTSVREFE() - #endif /* KINETIS_STM32_H_ */ diff --git a/firmware/config/boards/subaru_eg33/config/controllers/algo/auto_generated_enums.cpp b/firmware/config/boards/subaru_eg33/config/controllers/algo/auto_generated_enums.cpp index fee4e3481c..3e0fe89207 100644 --- a/firmware/config/boards/subaru_eg33/config/controllers/algo/auto_generated_enums.cpp +++ b/firmware/config/boards/subaru_eg33/config/controllers/algo/auto_generated_enums.cpp @@ -92,8 +92,6 @@ case EFI_ADC_LAST_CHANNEL: return "EFI_ADC_LAST_CHANNEL"; case EFI_ADC_NONE: return "EFI_ADC_NONE"; -case EFI_ADC_TEMP_SENSOR: - return "EFI_ADC_TEMP_SENSOR"; } return NULL; } diff --git a/firmware/config/boards/subaru_eg33/rusefi_hw_enums.h b/firmware/config/boards/subaru_eg33/rusefi_hw_enums.h index a3012705d3..ef3ef3a7d6 100644 --- a/firmware/config/boards/subaru_eg33/rusefi_hw_enums.h +++ b/firmware/config/boards/subaru_eg33/rusefi_hw_enums.h @@ -286,9 +286,7 @@ typedef enum __attribute__ ((__packed__)) { EFI_ADC3_14 = 23, // PF4 EFI_ADC3_15 = 24, // PF5 - EFI_ADC_TEMP_SENSOR = 25, // Internal temp sensor - - EFI_ADC_LAST_CHANNEL = 26, // Please keep this in sync with the last valid channel index! + EFI_ADC_LAST_CHANNEL = 25, // Please keep this in sync with the last valid channel index! EFI_ADC_ERROR = 50, } adc_channel_e; diff --git a/firmware/controllers/algo/auto_generated_enums.cpp b/firmware/controllers/algo/auto_generated_enums.cpp index aea8cc8652..542d4a1791 100644 --- a/firmware/controllers/algo/auto_generated_enums.cpp +++ b/firmware/controllers/algo/auto_generated_enums.cpp @@ -76,8 +76,6 @@ case EFI_ADC_LAST_CHANNEL: return "EFI_ADC_LAST_CHANNEL"; case EFI_ADC_NONE: return "EFI_ADC_NONE"; -case EFI_ADC_TEMP_SENSOR: - return "EFI_ADC_TEMP_SENSOR"; } return NULL; } diff --git a/firmware/controllers/algo/rusefi_hw_enums.h b/firmware/controllers/algo/rusefi_hw_enums.h index f013e36a7d..d50498f483 100644 --- a/firmware/controllers/algo/rusefi_hw_enums.h +++ b/firmware/controllers/algo/rusefi_hw_enums.h @@ -289,9 +289,7 @@ typedef enum __attribute__ ((__packed__)) { EFI_ADC_14 = 15, // PC4 EFI_ADC_15 = 16, // PC5 - EFI_ADC_TEMP_SENSOR = 17, // Internal temp sensor - - EFI_ADC_LAST_CHANNEL = 18, // Please keep this in sync with the last valid channel index! + EFI_ADC_LAST_CHANNEL = 17, // Please keep this in sync with the last valid channel index! EFI_ADC_ERROR = 50, } adc_channel_e; diff --git a/firmware/hw_layer/adc/adc_inputs.cpp b/firmware/hw_layer/adc/adc_inputs.cpp index 6976d0944f..ea23b9d082 100644 --- a/firmware/hw_layer/adc/adc_inputs.cpp +++ b/firmware/hw_layer/adc/adc_inputs.cpp @@ -249,22 +249,10 @@ static void fast_adc_callback(GPTDriver*) { } #endif /* HAL_USE_GPT */ +static float mcuTemperature; + float getMCUInternalTemperature() { -#if defined(ADC_CHANNEL_SENSOR) - float TemperatureValue = adcToVolts(slowAdc.getAdcValueByHwChannel(EFI_ADC_TEMP_SENSOR)); - TemperatureValue -= 0.760f; // Subtract the reference voltage at 25 deg C - TemperatureValue /= 0.0025f; // Divide by slope 2.5mV - - TemperatureValue += 25.0; // Add the 25 deg C - - if (TemperatureValue > 150.0f || TemperatureValue < -50.0f) { - firmwareError(OBD_PCM_Processor_Fault, "Invalid CPU temperature measured %f", TemperatureValue); - } - - return TemperatureValue; -#else - return 0; -#endif /* ADC_CHANNEL_SENSOR */ + return mcuTemperature; } int getInternalAdcValue(const char *msg, adc_channel_e hwChannel) { @@ -360,11 +348,6 @@ void AdcDevice::enableChannel(adc_channel_e hwChannel) { int logicChannel = channelCount++; size_t channelAdcIndex = hwChannel - 1; -#if defined(STM32F7XX) - /* the temperature sensor is internally connected to ADC1_IN18 */ - if (hwChannel == EFI_ADC_TEMP_SENSOR) - channelAdcIndex = 18; -#endif internalAdcIndexByHardwareIndex[hwChannel] = logicChannel; hardwareIndexByIndernalAdcIndex[logicChannel] = hwChannel; @@ -492,6 +475,9 @@ public: void proteusAdcHack(); proteusAdcHack(); #endif + + // Ask the port to sample the MCU temperature + mcuTemperature = getMcuTemperature(); } { @@ -608,36 +594,7 @@ void initAdcInputs() { addConsoleActionI("adcdebug", &setAdcDebugReporting); #if EFI_INTERNAL_ADC - /* - * Initializes the ADC driver. - */ - adcStart(&ADC_SLOW_DEVICE, NULL); - adcStart(&ADC_FAST_DEVICE, NULL); - adcSTM32EnableTSVREFE(); // Internal temperature sensor -#if defined(STM32F7XX) - /* the temperature sensor is internally - * connected to the same input channel as VBAT. Only one conversion, - * temperature sensor or VBAT, must be selected at a time. */ - adcSTM32DisableVBATE(); -#endif - - /* Enable this code only when you absolutly sure - * that there is no possible errors from ADC */ -#if 0 - /* All ADC use DMA and DMA calls end_cb from its IRQ - * If none of ADC users need error callback - we can disable - * shared ADC IRQ and save some CPU ticks */ - if ((adcgrpcfgSlow.error_cb == NULL) && - (adcgrpcfgFast.error_cb == NULL) - /* TODO: Add ADC3? */) { - nvicDisableVector(STM32_ADC_NUMBER); - } -#endif - -#if defined(ADC_CHANNEL_SENSOR) - // Internal temperature sensor, Available on ADC1 only - slowAdc.enableChannel(EFI_ADC_TEMP_SENSOR); -#endif /* ADC_CHANNEL_SENSOR */ + portInitAdc(); slowAdc.init(); diff --git a/firmware/hw_layer/ports/cypress/mpu_util.cpp b/firmware/hw_layer/ports/cypress/mpu_util.cpp index 030eb1dcf3..3d83200b6f 100644 --- a/firmware/hw_layer/ports/cypress/mpu_util.cpp +++ b/firmware/hw_layer/ports/cypress/mpu_util.cpp @@ -257,4 +257,17 @@ uintptr_t getFlashAddrSecondCopy() { return FLASH_ADDR_SECOND_COPY; } +void portInitAdc() { + // Init slow ADC + adcStart(&ADCD1, NULL); + + // Init fast ADC (MAP sensor) + adcStart(&ADCD2, NULL); +} + +float getMcuTemperature() { + // TODO: implement me! + return 0; +} + #endif /* EFI_PROD_CODE */ diff --git a/firmware/hw_layer/ports/kinetis/mpu_util.cpp b/firmware/hw_layer/ports/kinetis/mpu_util.cpp index c078074443..a473465562 100644 --- a/firmware/hw_layer/ports/kinetis/mpu_util.cpp +++ b/firmware/hw_layer/ports/kinetis/mpu_util.cpp @@ -262,4 +262,17 @@ uintptr_t getFlashAddrSecondCopy() { return nullptr; } +void portInitAdc() { + // Init slow ADC + adcStart(&ADCD1, NULL); + + // Init fast ADC (MAP sensor) + adcStart(&ADCD2, NULL); +} + +float getMcuTemperature() { + // TODO: implement me! + return 0; +} + #endif /* EFI_PROD_CODE */ diff --git a/firmware/hw_layer/ports/mpu_util.h b/firmware/hw_layer/ports/mpu_util.h index fe53703dea..92f1791af0 100644 --- a/firmware/hw_layer/ports/mpu_util.h +++ b/firmware/hw_layer/ports/mpu_util.h @@ -10,6 +10,11 @@ void baseMCUInit(void); void jump_to_bootloader(); +// ADC +void portInitAdc(); +float getMcuTemperature(); + + // CAN bus #if HAL_USE_CAN bool isValidCanTxPin(brain_pin_e pin); diff --git a/firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp b/firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp new file mode 100644 index 0000000000..0a35ad82c5 --- /dev/null +++ b/firmware/hw_layer/ports/stm32/stm32_adc_v2.cpp @@ -0,0 +1,113 @@ +/** + * @file stm32_adc_v2.cpp + * @brief Port implementation for the STM32 "v2" ADC found on the STM32F4 and STM32F7 + * + * @date February 9, 2021 + * @author Matthew Kennedy, (c) 2021 + */ + +#include "engine_ptr.h" +#include "persistent_configuration.h" + +#if HAL_USE_ADC + +EXTERN_CONFIG; + +void portInitAdc() { + // Init slow ADC + adcStart(&ADCD1, NULL); + + // Init fast ADC (MAP sensor) + adcStart(&ADCD2, NULL); + + // Enable internal temperature reference + adcSTM32EnableTSVREFE(); // Internal temperature sensor + +#if defined(STM32F7XX) + /* the temperature sensor is internally + * connected to the same input channel as VBAT. Only one conversion, + * temperature sensor or VBAT, must be selected at a time. */ + adcSTM32DisableVBATE(); +#endif + + /* Enable this code only when you absolutly sure + * that there is no possible errors from ADC */ +#if 0 + /* All ADC use DMA and DMA calls end_cb from its IRQ + * If none of ADC users need error callback - we can disable + * shared ADC IRQ and save some CPU ticks */ + if ((adcgrpcfgSlow.error_cb == NULL) && + (adcgrpcfgFast.error_cb == NULL) + /* TODO: Add ADC3? */) { + nvicDisableVector(STM32_ADC_NUMBER); + } +#endif +} + +/* + * ADC conversion group. + */ +static const ADCConversionGroup tempSensorConvGroup = { + .circular = FALSE, + .num_channels = 1, + .end_cb = nullptr, + .error_cb = nullptr, + /* HW dependent part below */ + .cr1 = 0, + .cr2 = ADC_CR2_SWSTART, + // sample times for channels 10...18 + .smpr1 = + ADC_SMPR1_SMP_VBAT(ADC_SAMPLE_144) | /* input18 - temperature and vbat input on some STM32F7xx */ + ADC_SMPR1_SMP_SENSOR(ADC_SAMPLE_144), /* input16 - temperature sensor input on STM32F4xx */ + .smpr2 = 0, + .htr = 0, .ltr = 0, + .sqr1 = 0, + .sqr2 = 0, +#if defined(STM32F4XX) + .sqr3 = ADC_SQR3_SQ1_N(16), +#endif +#if defined(STM32F7XX) + .sqr3 = ADC_SQR3_SQ1_N(18), +#endif +}; + +float getMcuTemperature() { + // 4x oversample is plenty + constexpr int oversample = 4; + + // Buffer is a full 32 bytes to occupy a full cache line + __ALIGNED(32) adcsample_t samples[16]; + + // Temperature sensor is only physically wired to ADC1 + adcConvert(&ADCD1, &tempSensorConvGroup, samples, oversample); + +#if CORTEX_MODEL == 7 + // The STM32F7xx/STM32H7xx has a data cache + // DMA operations DO NOT invalidate cache lines, since the ARM m7 doesn't have + // anything like a CCI that maintains coherency across multiple bus masters. + // As a result, we have to manually invalidate the D-cache any time we (the CPU) + // would like to read something that somebody else wrote (ADC via DMA, in this case) + SCB_InvalidateDCache_by_Addr(reinterpret_cast(samples), sizeof(samples)); +#endif /* CORTEX_MODEL == 7 */ + + uint32_t sum = 0; + for (size_t i = 0; i < oversample; i++) { + sum += samples[i]; + } + + float volts = (float)sum / (4096 * oversample); + volts *= CONFIG(adcVcc); + + volts -= 0.760f; // Subtract the reference voltage at 25 deg C + float degrees = volts / 0.0025f; // Divide by slope 2.5mV + + degrees += 25.0; // Add the 25 deg C + + if (degrees > 150.0f || degrees < -50.0f) { + firmwareError(OBD_PCM_Processor_Fault, "Invalid CPU temperature measured %f", degrees); + } + + return degrees; +} + +#endif // HAL_USE_ADC diff --git a/firmware/hw_layer/ports/stm32/stm32f4/hw_ports.mk b/firmware/hw_layer/ports/stm32/stm32f4/hw_ports.mk index f9698d8c37..9d926704c2 100644 --- a/firmware/hw_layer/ports/stm32/stm32f4/hw_ports.mk +++ b/firmware/hw_layer/ports/stm32/stm32f4/hw_ports.mk @@ -3,7 +3,8 @@ include $(PROJECT_DIR)/hw_layer/ports/stm32/stm32_common.mk HW_LAYER_EMS += $(PROJECT_DIR)/hw_layer/ports/stm32/stm32f4/stm32f4xx_hal_flash.c \ $(PROJECT_DIR)/hw_layer/ports/stm32/stm32f4/stm32f4xx_hal_flash_ex.c \ -HW_LAYER_EMS_CPP += $(PROJECT_DIR)/hw_layer/ports/stm32/stm32f4/mpu_util.cpp +HW_LAYER_EMS_CPP += $(PROJECT_DIR)/hw_layer/ports/stm32/stm32f4/mpu_util.cpp \ + $(PROJECT_DIR)/hw_layer/ports/stm32/stm32_adc_v2.cpp \ DDEFS += -DSTM32F407xx LDSCRIPT = $(PROJECT_DIR)/hw_layer/ports/stm32/stm32f4/STM32F405xG.ld diff --git a/firmware/hw_layer/ports/stm32/stm32f7/hw_ports.mk b/firmware/hw_layer/ports/stm32/stm32f7/hw_ports.mk index 30f2111bff..b8ba1f1d45 100644 --- a/firmware/hw_layer/ports/stm32/stm32f7/hw_ports.mk +++ b/firmware/hw_layer/ports/stm32/stm32f7/hw_ports.mk @@ -3,7 +3,8 @@ include $(PROJECT_DIR)/hw_layer/ports/stm32/stm32_common.mk HW_LAYER_EMS += $(PROJECT_DIR)/hw_layer/ports/stm32/stm32f7/stm32f7xx_hal_flash.c \ $(PROJECT_DIR)/hw_layer/ports/stm32/stm32f7/stm32f7xx_hal_flash_ex.c -HW_LAYER_EMS_CPP += $(PROJECT_DIR)/hw_layer/ports/stm32/stm32f7/mpu_util.cpp +HW_LAYER_EMS_CPP += $(PROJECT_DIR)/hw_layer/ports/stm32/stm32f7/mpu_util.cpp \ + $(PROJECT_DIR)/hw_layer/ports/stm32/stm32_adc_v2.cpp \ DDEFS += -DSTM32F767xx LDSCRIPT = $(PROJECT_DIR)/hw_layer/ports/stm32/stm32f7/STM32F76xxI.ld