From bdc6915ae37b8bad6e7b8dda7af77e61577ede4d Mon Sep 17 00:00:00 2001 From: andreika-git Date: Sat, 27 Jul 2019 16:52:01 +0300 Subject: [PATCH] Kinetis files (pre-alpha) (#890) --- firmware/hw_layer/ports/kinetis/flash.c | 205 +++++++++++++++ firmware/hw_layer/ports/kinetis/hw_ports.mk | 11 + .../hw_layer/ports/kinetis/kinetis_common.cpp | 126 +++++++++ .../hw_layer/ports/kinetis/kinetis_pins.cpp | 147 +++++++++++ firmware/hw_layer/ports/kinetis/mpu_util.cpp | 246 ++++++++++++++++++ firmware/hw_layer/ports/kinetis/mpu_util.h | 88 +++++++ firmware/hw_layer/trigger_input_comp.cpp | 135 ++++++++++ 7 files changed, 958 insertions(+) create mode 100644 firmware/hw_layer/ports/kinetis/flash.c create mode 100644 firmware/hw_layer/ports/kinetis/hw_ports.mk create mode 100644 firmware/hw_layer/ports/kinetis/kinetis_common.cpp create mode 100644 firmware/hw_layer/ports/kinetis/kinetis_pins.cpp create mode 100644 firmware/hw_layer/ports/kinetis/mpu_util.cpp create mode 100644 firmware/hw_layer/ports/kinetis/mpu_util.h create mode 100644 firmware/hw_layer/trigger_input_comp.cpp diff --git a/firmware/hw_layer/ports/kinetis/flash.c b/firmware/hw_layer/ports/kinetis/flash.c new file mode 100644 index 0000000000..1e9d908aaf --- /dev/null +++ b/firmware/hw_layer/ports/kinetis/flash.c @@ -0,0 +1,205 @@ +/** + * + * @file flash.c + * @brief Lower-level code for Kinetis related to internal flash memory + * @author andreika + */ + +#include "global.h" + +#if EFI_INTERNAL_FLASH + +#include "flash.h" +#include "fsl_ftfx_flexnvm.h" +#include + + +//#define KINETIS_FLASH_DEBUG + +typedef uint32_t flashdata_t; + +static bool wasInit = false; +static bool isLocked = true; +static bool isInitializing = false; +static flexnvm_config_t flashCfg; + +static status_t initStatus = -1; +static status_t protectStatus = -1; +static status_t securityStatus = -1; +static uint8_t protectValue = 0; +static ftfx_security_state_t sstate; + +static kinetis_clock_type_e savedClockType = KINETIS_DEFAULT_CLK; + +#ifdef KINETIS_FLASH_DEBUG +void flashPrintStatus(void) { + debugLog("* flashInit status=%d\r\n", initStatus); + debugLog("* FLEXNVM_DflashGetProtection status=%d prot=%d\r\n", protectStatus, protectValue); + debugLog("* FLEXNVM_GetSecurityState status=%d security=0x%08x\r\n", securityStatus, sstate); + + uint32_t dflashBlockBase = 0; + uint32_t dflashTotalSize = 0; + uint32_t dflashSectorSize = 0; + + /* Get flash properties*/ + FLEXNVM_GetProperty(&flashCfg, kFLEXNVM_PropertyDflashBlockBaseAddr, &dflashBlockBase); + FLEXNVM_GetProperty(&flashCfg, kFLEXNVM_PropertyDflashTotalSize, &dflashTotalSize); + FLEXNVM_GetProperty(&flashCfg, kFLEXNVM_PropertyDflashSectorSize, &dflashSectorSize); + + debugLog("Data Flash Base Address: (0x%x)\r\n", dflashBlockBase); + debugLog("Data Flash Total Size:\t%d KB, Hex: (0x%x)\r\n", (dflashTotalSize / 1024), dflashTotalSize); + debugLog("Data Flash Sector Size:\t%d KB, Hex: (0x%x)\r\n", (dflashSectorSize / 1024), dflashSectorSize); +} +#endif /* KINETIS_FLASH_DEBUG */ + +// should be called only from flashUnlock() +static bool flashInit(void) { + isInitializing = true; + + memset(&flashCfg, 0, sizeof(flashCfg)); + initStatus = FLEXNVM_Init(&flashCfg); + protectStatus = FLEXNVM_DflashGetProtection(&flashCfg, &protectValue); + securityStatus = FLEXNVM_GetSecurityState(&flashCfg, &sstate); + + wasInit = true; + isInitializing = false; + +#ifdef KINETIS_FLASH_DEBUG + flashPrintStatus(); +#endif /* KINETIS_FLASH_DEBUG */ + + return (initStatus == kStatus_FTFx_Success); +} + +bool flashUnlock(void) { +// chSysUnconditionalLock(); + // this is strictly non-reentrant function! + if (!isLocked) { +// chSysUnconditionalUnlock(); + return false; // already unlocked + } + isLocked = false; + + savedClockType = ke1xf_clock_get_current_type(); + // flash commands won't work in HSRUN clock mode + // we set a lower frequency clock + ke1xf_clock_init(kinetis_clock_int_osc_run); + + // before any flash access function, we should have called init() first (but not from init() itself) + if (!isInitializing && !wasInit) { + flashInit(); + } + + return true; +} + +bool flashLock(void) { + // this is strictly non-reentrant function! + if (isLocked) { + return false; // already locked + } + + // restore clock + ke1xf_clock_init(savedClockType); + + isLocked = true; +// chSysUnconditionalUnlock(); + + return true; +} + +static int alignToWord(int v) { + return (v + FSL_FEATURE_FLASH_FLEX_NVM_SECTOR_CMD_ADDRESS_ALIGMENT - 1) & ~(FSL_FEATURE_FLASH_FLEX_NVM_SECTOR_CMD_ADDRESS_ALIGMENT - 1); +} + +int flashErase(flashaddr_t address, size_t size) { + if (!flashUnlock()) + return FLASH_RETURN_NO_PERMISSION; + + flashaddr_t sizeAligned = alignToWord(size); + status_t status = FLEXNVM_DflashErase(&flashCfg, address, sizeAligned, kFTFx_ApiEraseKey); + + flashLock(); + +#ifdef KINETIS_FLASH_DEBUG + debugLog("* flashErase(addr=%08x siz=%d sizeAligned=%d)=%d\r\n", address, size, sizeAligned, status); +#endif /* KINETIS_FLASH_DEBUG */ + + if (status == kStatus_FTFx_Success) + return FLASH_RETURN_SUCCESS; + return -(int)status; +} + +int flashWrite(flashaddr_t address, const char* buffer, size_t size) { + if (!flashUnlock()) + return FLASH_RETURN_NO_PERMISSION; + + //FLEXNVM_DflashSetProtection(&flashCfg, 0xff); + + flashaddr_t sizeAligned = alignToWord(size); + status_t status = FLEXNVM_DflashProgram(&flashCfg, address, (uint8_t *)buffer, sizeAligned); + + flashLock(); + +#ifdef KINETIS_FLASH_DEBUG + debugLog("* flashWrite(addr=%08x siz=%d sizeAligned=%d)=%d\r\n", address, size, sizeAligned, status); +#endif /* KINETIS_FLASH_DEBUG */ + + if (status == kStatus_FTFx_Success) + return FLASH_RETURN_SUCCESS; + return -(int)status; +} + +bool flashIsErased(flashaddr_t address, size_t size) { + /* Check for default set bits in the flash memory + * For efficiency, compare flashdata_t values as much as possible, + * then, fallback to byte per byte comparison. */ + while (size >= sizeof(flashdata_t)) { + if (*(volatile flashdata_t*) address != (flashdata_t) (-1)) // flashdata_t being unsigned, -1 is 0xFF..FF + return false; + address += sizeof(flashdata_t); + size -= sizeof(flashdata_t); + } + while (size > 0) { + if (*(char*) address != 0xFF) + return false; + ++address; + --size; + } + + return TRUE; +} + +bool flashCompare(flashaddr_t address, const char* buffer, size_t size) { +#if 0 + uint32_t failAddr = 0, failDat = 0; + status_t status = FLEXNVM_DflashVerifyProgram(&flashCfg, address, size, (const uint8_t *)buffer, + kFTFx_MarginValueUser, &failAddr, &failDat); + return (status == kStatus_FTFx_Success); +#endif + /* For efficiency, compare flashdata_t values as much as possible, + * then, fallback to byte per byte comparison. */ + while (size >= sizeof(flashdata_t)) { + if (*(volatile flashdata_t*) address != *(flashdata_t*) buffer) + return FALSE; + address += sizeof(flashdata_t); + buffer += sizeof(flashdata_t); + size -= sizeof(flashdata_t); + } + while (size > 0) { + if (*(volatile char*) address != *buffer) + return FALSE; + ++address; + ++buffer; + --size; + } + + return TRUE; +} + +int flashRead(flashaddr_t address, char* buffer, size_t size) { + memcpy(buffer, (char*) address, size); + return FLASH_RETURN_SUCCESS; +} + +#endif /* EFI_INTERNAL_FLASH */ diff --git a/firmware/hw_layer/ports/kinetis/hw_ports.mk b/firmware/hw_layer/ports/kinetis/hw_ports.mk new file mode 100644 index 0000000000..29245349f7 --- /dev/null +++ b/firmware/hw_layer/ports/kinetis/hw_ports.mk @@ -0,0 +1,11 @@ +ifeq ($(KINETIS_CONTRIB),) + KINETIS_CONTRIB = $(CHIBIOS_CONTRIB) +endif + +HW_LAYER_EMS += $(PROJECT_DIR)/hw_layer/ports/kinetis/flash.c \ + $(KINETIS_CONTRIB)/os/hal/ports/KINETIS/KE1xF/fsl/fsl_ftfx_flexnvm.c \ + $(KINETIS_CONTRIB)/os/hal/ports/KINETIS/KE1xF/fsl/fsl_ftfx_controller.c + +HW_LAYER_EMS_CPP += $(PROJECT_DIR)/hw_layer/ports/kinetis/mpu_util.cpp \ + $(PROJECT_DIR)/hw_layer/ports/kinetis/kinetis_pins.cpp \ + $(PROJECT_DIR)/hw_layer/ports/kinetis/kinetis_common.cpp diff --git a/firmware/hw_layer/ports/kinetis/kinetis_common.cpp b/firmware/hw_layer/ports/kinetis/kinetis_common.cpp new file mode 100644 index 0000000000..aad392ff2d --- /dev/null +++ b/firmware/hw_layer/ports/kinetis/kinetis_common.cpp @@ -0,0 +1,126 @@ +/** + * @file kinetis_common.cpp + * @brief Low level common Kinetis code + * + * @date Mar 28, 2019 + * @author andreika + */ + +#include "global.h" +#include "engine.h" +#include "pin_repository.h" + +extern ioportid_t PORTS[]; + +ioportid_t PORTS[] = { GPIOA, GPIOB, GPIOC, GPIOD, GPIOE}; + +#if HAL_USE_ADC || defined(__DOXYGEN__) + +// ADC_CHANNEL_IN0 // PA2 (def=VIGN) +// ADC_CHANNEL_IN1 // PA3 (def=MAP4) +// ADC_CHANNEL_IN2 // x +// ADC_CHANNEL_IN3 // PD3 (def=MAP3) +// ADC_CHANNEL_IN4 // x +// ADC_CHANNEL_IN5 // x +// ADC_CHANNEL_IN6 // x +// ADC_CHANNEL_IN7 // PB12 (def=MAP2) +// ADC_CHANNEL_IN8 // PB13 (def=MAP1) +// ADC_CHANNEL_IN9 // x +// ADC_CHANNEL_IN10 // PE2 (def=O2S2) +// ADC_CHANNEL_IN11 // x +// ADC_CHANNEL_IN12 // PC14 (def=O2S) +// ADC_CHANNEL_IN13 // PC15 (def=TPS) +// ADC_CHANNEL_IN14 // PC16 (def=CLT) +// ADC_CHANNEL_IN15 // PC17 (def=IAT) + +brain_pin_e getAdcChannelBrainPin(const char *msg, adc_channel_e hwChannel) { + // todo: replace this with an array :) + switch (hwChannel) { + case EFI_ADC_0: + return GPIOA_2; + case EFI_ADC_1: + return GPIOA_3; + case EFI_ADC_2: + return GPIO_INVALID; + case EFI_ADC_3: + return GPIOD_3; + case EFI_ADC_4: + return GPIO_INVALID; + case EFI_ADC_5: + return GPIO_INVALID; + case EFI_ADC_6: + return GPIO_INVALID; + case EFI_ADC_7: + return GPIOB_12; + case EFI_ADC_8: + return GPIOB_13; + case EFI_ADC_9: + return GPIO_INVALID; + case EFI_ADC_10: + return GPIOE_2; + case EFI_ADC_11: + return GPIO_INVALID; + case EFI_ADC_12: + return GPIOC_14; + case EFI_ADC_13: + return GPIOC_15; + case EFI_ADC_14: + return GPIOC_16; + case EFI_ADC_15: + return GPIOC_17; + default: + firmwareError(CUSTOM_ERR_ADC_UNKNOWN_CHANNEL, "Unknown hw channel %d [%s]", hwChannel, msg); + return GPIO_INVALID; + } +} + +adc_channel_e getAdcChannel(brain_pin_e pin) { + switch (pin) { + case GPIOA_2: + return EFI_ADC_0; + case GPIOA_3: + return EFI_ADC_1; + //case GPIOA_2: + // return EFI_ADC_2; + case GPIOD_3: + return EFI_ADC_3; + //case GPIOA_4: + // return EFI_ADC_4; + //case GPIOA_5: + // return EFI_ADC_5; + //case GPIOA_6: + // return EFI_ADC_6; + case GPIOB_12: + return EFI_ADC_7; + case GPIOB_13: + return EFI_ADC_8; + //case GPIOB_1: + // return EFI_ADC_9; + case GPIOE_2: + return EFI_ADC_10; + //case GPIOC_1: + // return EFI_ADC_11; + case GPIOC_14: + return EFI_ADC_12; + case GPIOC_15: + return EFI_ADC_13; + case GPIOC_16: + return EFI_ADC_14; + case GPIOC_17: + return EFI_ADC_15; + default: + return EFI_ADC_ERROR; + } +} + +// deprecated - migrate to 'getAdcChannelBrainPin' +ioportid_t getAdcChannelPort(const char *msg, adc_channel_e hwChannel) { + return getHwPort(msg, getAdcChannelBrainPin(msg, hwChannel)); +} + +// deprecated - migrate to 'getAdcChannelBrainPin' +int getAdcChannelPin(adc_channel_e hwChannel) { + return getHwPin("get_pin", getAdcChannelBrainPin("get_pin", hwChannel)); +} + +#endif /* HAL_USE_ADC */ diff --git a/firmware/hw_layer/ports/kinetis/kinetis_pins.cpp b/firmware/hw_layer/ports/kinetis/kinetis_pins.cpp new file mode 100644 index 0000000000..118e5def6b --- /dev/null +++ b/firmware/hw_layer/ports/kinetis/kinetis_pins.cpp @@ -0,0 +1,147 @@ +/** + * @file kinetis_pins.cpp + * @brief Kinetis-compatible GPIO code + * + * @date Jun 02, 2019 + * @author Andrey Belomutskiy, (c) 2012-2019 + * @author andreika + */ + +#include "global.h" +#include "engine.h" +#include "efi_gpio.h" + +#if EFI_GPIO_HARDWARE + +// This is the radical departure from STM32 +#define PORT_SIZE 18 + +static ioportid_t ports[] = {GPIOA, + GPIOB, + GPIOC, + GPIOD, + GPIOE, + nullptr, + nullptr, + nullptr, +}; + +#define PIN_REPO_SIZE (sizeof(ports) / sizeof(ports[0])) * PORT_SIZE +// todo: move this into PinRepository class +static const char *PIN_USED[PIN_REPO_SIZE + BOARD_EXT_PINREPOPINS]; + +#include "pin_repository.h" +#include "io_pins.h" + +extern ioportid_t PORTS[]; + +/** + * @deprecated - use hwPortname() instead + */ +const char *portname(ioportid_t GPIOx) { + if (GPIOx == GPIOA) + return "PA"; + if (GPIOx == GPIOB) + return "PB"; + if (GPIOx == GPIOC) + return "PC"; + if (GPIOx == GPIOD) + return "PD"; + if (GPIOx == GPIOE) + return "PE"; + return "unknown"; +} + +static int getPortIndex(ioportid_t port) { + efiAssert(CUSTOM_ERR_ASSERT, port != NULL, "null port", -1); + if (port == GPIOA) + return 0; + if (port == GPIOB) + return 1; + if (port == GPIOC) + return 2; + if (port == GPIOD) + return 3; + if (port == GPIOE) + return 4; + firmwareError(CUSTOM_ERR_UNKNOWN_PORT, "unknown port"); + return -1; +} + +ioportid_t getBrainPort(brain_pin_e brainPin) { + return ports[(brainPin - GPIOA_0) / PORT_SIZE]; +} + +int getBrainPinIndex(brain_pin_e brainPin) { + return (brainPin - GPIOA_0) % PORT_SIZE; +} + +int getBrainIndex(ioportid_t port, ioportmask_t pin) { + int portIndex = getPortIndex(port); + return portIndex * PORT_SIZE + pin; +} + +ioportid_t getHwPort(const char *msg, brain_pin_e brainPin) { + if (brainPin == GPIO_UNASSIGNED || brainPin == GPIO_INVALID) + return GPIO_NULL; + if (brainPin < GPIOA_0 || brainPin > BRAIN_PIN_LAST_ONCHIP) { + firmwareError(CUSTOM_ERR_INVALID_PIN, "%s: Invalid brain_pin_e: %d", msg, brainPin); + return GPIO_NULL; + } + return PORTS[(brainPin - GPIOA_0) / PORT_SIZE]; +} + +/** + * this method returns the numeric part of pin name. For instance, for PC13 this would return '13' + */ +ioportmask_t getHwPin(const char *msg, brain_pin_e brainPin) +{ + if (brainPin == GPIO_UNASSIGNED || brainPin == GPIO_INVALID) + return EFI_ERROR_CODE; + + if (brain_pin_is_onchip(brainPin)) + return getBrainPinIndex(brainPin); + + firmwareError(CUSTOM_ERR_INVALID_PIN, "%s: Invalid on-chip brain_pin_e: %d", msg, brainPin); + return EFI_ERROR_CODE; +} + +/** + * Parse string representation of physical pin into brain_pin_e ordinal. + * + * @return GPIO_UNASSIGNED for "none", GPIO_INVALID for invalid entry + */ +brain_pin_e parseBrainPin(const char *str) { + if (strEqual(str, "none")) + return GPIO_UNASSIGNED; + // todo: create method toLowerCase? + if (str[0] != 'p' && str[0] != 'P') { + return GPIO_INVALID; + } + char port = str[1]; + brain_pin_e basePin; + if (port >= 'a' && port <= 'z') { + basePin = (brain_pin_e) ((int) GPIOA_0 + PORT_SIZE * (port - 'a')); + } else if (port >= 'A' && port <= 'Z') { + basePin = (brain_pin_e) ((int) GPIOA_0 + PORT_SIZE * (port - 'A')); + } else { + return GPIO_INVALID; + } + const char *pinStr = str + 2; + int pin = atoi(pinStr); + return (brain_pin_e)(basePin + pin); +} + +unsigned int getNumBrainPins(void) { + return PIN_REPO_SIZE; +} + +void initBrainUsedPins(void) { + memset(PIN_USED, 0, sizeof(PIN_USED)); +} + +const char* & getBrainUsedPin(unsigned int idx) { + return PIN_USED[idx]; +} + +#endif /* EFI_GPIO_HARDWARE */ diff --git a/firmware/hw_layer/ports/kinetis/mpu_util.cpp b/firmware/hw_layer/ports/kinetis/mpu_util.cpp new file mode 100644 index 0000000000..efb53fea43 --- /dev/null +++ b/firmware/hw_layer/ports/kinetis/mpu_util.cpp @@ -0,0 +1,246 @@ +/** + * @file mpu_util.cpp + * + * @date Jul 27, 2014 + * @author Andrey Belomutskiy, (c) 2012-2018 + * @author andreika + */ + +#include "global.h" + +#if EFI_PROD_CODE + +#include "mpu_util.h" +#include "flash.h" +#include "error_handling.h" +#include "engine.h" +#include "pin_repository.h" +#include "os_util.h" + +EXTERN_ENGINE; + +void baseHardwareInit(void) { +} + +void _unhandled_exception(void) { +/*lint -restore*/ + + chDbgPanic3("_unhandled_exception", __FILE__, __LINE__); + while (true) { + } +} + +void DebugMonitorVector(void) { + chDbgPanic3("DebugMonitorVector", __FILE__, __LINE__); + while (TRUE) + ; +} + +void UsageFaultVector(void) { + chDbgPanic3("UsageFaultVector", __FILE__, __LINE__); + while (TRUE) + ; +} + +void BusFaultVector(void) { + chDbgPanic3("BusFaultVector", __FILE__, __LINE__); + while (TRUE) { + } +} + +void HardFaultVector(void) { + while (TRUE) { + } +} + +#if HAL_USE_SPI || defined(__DOXYGEN__) +bool isSpiInitialized[5] = { false, false, false, false, false }; + +static int getSpiAf(SPIDriver *driver) { +#if STM32_SPI_USE_SPI1 + if (driver == &SPID1) { + return EFI_SPI1_AF; + } +#endif +#if STM32_SPI_USE_SPI2 + if (driver == &SPID2) { + return EFI_SPI2_AF; + } +#endif +#if STM32_SPI_USE_SPI3 + if (driver == &SPID3) { + return EFI_SPI3_AF; + } +#endif + return -1; +} + +brain_pin_e getMisoPin(spi_device_e device) { + switch(device) { + case SPI_DEVICE_1: + return CONFIGB(spi1misoPin); + case SPI_DEVICE_2: + return CONFIGB(spi2misoPin); + case SPI_DEVICE_3: + return CONFIGB(spi3misoPin); + default: + break; + } + return GPIO_UNASSIGNED; +} + +brain_pin_e getMosiPin(spi_device_e device) { + switch(device) { + case SPI_DEVICE_1: + return CONFIGB(spi1mosiPin); + case SPI_DEVICE_2: + return CONFIGB(spi2mosiPin); + case SPI_DEVICE_3: + return CONFIGB(spi3mosiPin); + default: + break; + } + return GPIO_UNASSIGNED; +} + +brain_pin_e getSckPin(spi_device_e device) { + switch(device) { + case SPI_DEVICE_1: + return CONFIGB(spi1sckPin); + case SPI_DEVICE_2: + return CONFIGB(spi2sckPin); + case SPI_DEVICE_3: + return CONFIGB(spi3sckPin); + default: + break; + } + return GPIO_UNASSIGNED; +} + +void turnOnSpi(spi_device_e device) { + if (isSpiInitialized[device]) + return; // already initialized + isSpiInitialized[device] = true; + if (device == SPI_DEVICE_1) { +// todo: introduce a nice structure with all fields for same SPI +#if STM32_SPI_USE_SPI1 +// scheduleMsg(&logging, "Turning on SPI1 pins"); + initSpiModule(&SPID1, getSckPin(device), + getMisoPin(device), + getMosiPin(device), + engineConfiguration->spi1SckMode, + engineConfiguration->spi1MosiMode, + engineConfiguration->spi1MisoMode); +#endif /* STM32_SPI_USE_SPI1 */ + } + if (device == SPI_DEVICE_2) { +#if STM32_SPI_USE_SPI2 +// scheduleMsg(&logging, "Turning on SPI2 pins"); + initSpiModule(&SPID2, getSckPin(device), + getMisoPin(device), + getMosiPin(device), + engineConfiguration->spi2SckMode, + engineConfiguration->spi2MosiMode, + engineConfiguration->spi2MisoMode); +#endif /* STM32_SPI_USE_SPI2 */ + } + if (device == SPI_DEVICE_3) { +#if STM32_SPI_USE_SPI3 +// scheduleMsg(&logging, "Turning on SPI3 pins"); + initSpiModule(&SPID3, getSckPin(device), + getMisoPin(device), + getMosiPin(device), + engineConfiguration->spi3SckMode, + engineConfiguration->spi3MosiMode, + engineConfiguration->spi3MisoMode); +#endif /* STM32_SPI_USE_SPI3 */ + } +} + +void initSpiModule(SPIDriver *driver, brain_pin_e sck, brain_pin_e miso, + brain_pin_e mosi, + int sckMode, + int mosiMode, + int misoMode) { + + /** + * See https://github.com/rusefi/rusefi/pull/664/ + * + * Info on the silicon defect can be found in this document, section 2.5.2: + * https://www.st.com/content/ccc/resource/technical/document/errata_sheet/0a/98/58/84/86/b6/47/a2/DM00037591.pdf/files/DM00037591.pdf/jcr:content/translations/en.DM00037591.pdf + */ + efiSetPadMode("SPI clock", sck, PAL_MODE_ALTERNATE(getSpiAf(driver)) | sckMode | PAL_STM32_OSPEED_HIGHEST); + + efiSetPadMode("SPI master out", mosi, PAL_MODE_ALTERNATE(getSpiAf(driver)) | mosiMode | PAL_STM32_OSPEED_HIGHEST); + efiSetPadMode("SPI master in ", miso, PAL_MODE_ALTERNATE(getSpiAf(driver)) | misoMode | PAL_STM32_OSPEED_HIGHEST); +} + +void initSpiCs(SPIConfig *spiConfig, brain_pin_e csPin) { + spiConfig->end_cb = NULL; + ioportid_t port = getHwPort("spi", csPin); + ioportmask_t pin = getHwPin("spi", csPin); + spiConfig->ssport = port; + spiConfig->sspad = pin; + // todo: we use hardware CS control? + //efiSetPadMode("chip select", csPin, PAL_MODE_OUTPUT_OPENDRAIN); +} + +#endif /* HAL_USE_SPI */ + +BOR_Level_t BOR_Get(void) { + return BOR_Level_None; +} + +BOR_Result_t BOR_Set(BOR_Level_t BORValue) { + return BOR_Result_Ok; +} + +#if EFI_CAN_SUPPORT || defined(__DOXYGEN__) + +static bool isValidCan1RxPin(brain_pin_e pin) { + return pin == GPIOA_11 || pin == GPIOB_8 || pin == GPIOD_0; +} + +static bool isValidCan1TxPin(brain_pin_e pin) { + return pin == GPIOA_12 || pin == GPIOB_9 || pin == GPIOD_1; +} + +static bool isValidCan2RxPin(brain_pin_e pin) { + return pin == GPIOB_5 || pin == GPIOB_12; +} + +static bool isValidCan2TxPin(brain_pin_e pin) { + return pin == GPIOB_6 || pin == GPIOB_13; +} + +bool isValidCanTxPin(brain_pin_e pin) { + return isValidCan1TxPin(pin) || isValidCan2TxPin(pin); +} + +bool isValidCanRxPin(brain_pin_e pin) { + return isValidCan1RxPin(pin) || isValidCan2RxPin(pin); +} + +CANDriver * detectCanDevice(brain_pin_e pinRx, brain_pin_e pinTx) { + if (isValidCan1RxPin(pinRx) && isValidCan1TxPin(pinTx)) + return &CAND1; + if (isValidCan2RxPin(pinRx) && isValidCan2TxPin(pinTx)) + return &CAND2; + return NULL; +} + +#endif /* EFI_CAN_SUPPORT */ + +size_t flashSectorSize(flashsector_t sector) { + // sectors 0..11 are the 1st memory bank (1Mb), and 12..23 are the 2nd (the same structure). + if (sector <= 3 || (sector >= 12 && sector <= 15)) + return 16 * 1024; + else if (sector == 4 || sector == 16) + return 64 * 1024; + else if ((sector >= 5 && sector <= 11) || (sector >= 17 && sector <= 23)) + return 128 * 1024; + return 0; +} + +#endif /* EFI_PROD_CODE */ + diff --git a/firmware/hw_layer/ports/kinetis/mpu_util.h b/firmware/hw_layer/ports/kinetis/mpu_util.h new file mode 100644 index 0000000000..5554ac8898 --- /dev/null +++ b/firmware/hw_layer/ports/kinetis/mpu_util.h @@ -0,0 +1,88 @@ +/** + * @file mpu_util.h + * + * @date Jul 27, 2014 + * @author Andrey Belomutskiy, (c) 2012-2017 + * @author andreika + */ + +#ifndef MPU_UTIL_H_ +#define MPU_UTIL_H_ + +// we are lucky - all CAN pins use the same AF +#define EFI_CAN_RX_AF 9 +#define EFI_CAN_TX_AF 9 + +// burnout or 'Burn Out' +typedef enum { + BOR_Level_None = 0, + BOR_Level_1 = 1, + BOR_Level_2 = 2, + BOR_Level_3 = 3 +} BOR_Level_t; + +typedef enum { + BOR_Result_Ok = 0x00, + BOR_Result_Error +} BOR_Result_t; + +BOR_Level_t BOR_Get(void); +BOR_Result_t BOR_Set(BOR_Level_t BORValue); + +#ifndef ADC_TwoSamplingDelay_5Cycles +#define ADC_TwoSamplingDelay_5Cycles ((uint32_t)0x00000000) +#endif + +#ifndef ADC_TwoSamplingDelay_20Cycles +#define ADC_TwoSamplingDelay_20Cycles ((uint32_t)0x00000F00) +#endif + +#ifndef ADC_CR2_SWSTART +#define ADC_CR2_SWSTART ((uint32_t)0x40000000) +#endif + +#define SPI_CR1_16BIT_MODE SPI_CR1_DFF +#define SPI_CR2_16BIT_MODE 0 + +// TODO +#define SPI_CR1_24BIT_MODE 0 +#define SPI_CR2_24BIT_MODE 0 + +void baseHardwareInit(void); +void turnOnSpi(spi_device_e device); + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +// these need to be declared C style for the linker magic to work + +void DebugMonitorVector(void); +void UsageFaultVector(void); +void BusFaultVector(void); +void HardFaultVector(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#if HAL_USE_SPI +void initSpiModule(SPIDriver *driver, brain_pin_e sck, brain_pin_e miso, + brain_pin_e mosi, + int sckMode, + int mosiMode, + int misoMode); +/** + * @see getSpiDevice + */ +void initSpiCs(SPIConfig *spiConfig, brain_pin_e csPin); +#endif /* HAL_USE_SPI */ + +bool isValidCanTxPin(brain_pin_e pin); +bool isValidCanRxPin(brain_pin_e pin); +#if HAL_USE_CAN +CANDriver * detectCanDevice(brain_pin_e pinRx, brain_pin_e pinTx); +#endif /* HAL_USE_CAN */ + +#endif /* MPU_UTIL_H_ */ diff --git a/firmware/hw_layer/trigger_input_comp.cpp b/firmware/hw_layer/trigger_input_comp.cpp new file mode 100644 index 0000000000..d3783f609a --- /dev/null +++ b/firmware/hw_layer/trigger_input_comp.cpp @@ -0,0 +1,135 @@ +/** + * @file trigger_input_comp.cpp + * @brief Position sensor hardware layer, Using hardware comparator + * + * @date Apr 13, 2019 + * @author Andrey Belomutskiy, (c) 2012-2019 + * @author andreika + */ + +#include "global.h" + +#if (EFI_SHAFT_POSITION_INPUT && HAL_USE_COMP) || defined(__DOXYGEN__) + +#include "hal_comp.h" + +#include "trigger_input.h" +#include "digital_input_hw.h" +#include "pin_repository.h" +#include "trigger_structure.h" +#include "trigger_central.h" +#include "engine_configuration.h" + +#define TRIGGER_SUPPORTED_CHANNELS 2 + +extern bool hasFirmwareErrorFlag; + +EXTERN_ENGINE +; +static Logging *logger; + +int vvtEventRiseCounter = 0; +int vvtEventFallCounter = 0; + +static void comp_shaft_callback(COMPDriver *comp) { + bool isRising = (comp_lld_get_status(comp) & COMP_IRQ_RISING) != 0; + int isPrimary = (comp == EFI_COMP_PRIMARY_DEVICE); + if (!isPrimary && !TRIGGER_SHAPE(needSecondTriggerInput)) { + return; + } + trigger_event_e signal; + if (isRising) { + signal = isPrimary ? (engineConfiguration->invertPrimaryTriggerSignal ? SHAFT_PRIMARY_FALLING : SHAFT_PRIMARY_RISING) : + (engineConfiguration->invertSecondaryTriggerSignal ? SHAFT_SECONDARY_FALLING : SHAFT_SECONDARY_RISING); + } else { + signal = isPrimary ? (engineConfiguration->invertPrimaryTriggerSignal ? SHAFT_PRIMARY_RISING : SHAFT_PRIMARY_FALLING) : + (engineConfiguration->invertSecondaryTriggerSignal ? SHAFT_SECONDARY_RISING : SHAFT_SECONDARY_FALLING); + } + hwHandleShaftSignal(signal); + +#ifdef EFI_TRIGGER_DEBUG_BLINK + __blink(1); +#endif +} + +// todo: add cam support? +#if 0 +static void comp_cam_callback(COMPDriver *comp) { + if (isRising) { + vvtEventRiseCounter++; + hwHandleVvtCamSignal(TV_RISE); + } else { + vvtEventFallCounter++; + hwHandleVvtCamSignal(TV_FALL); + } +} +#endif + +static COMPConfig comp_shaft_cfg = { + COMP_OUTPUT_NORMAL, COMP_IRQ_BOTH, + comp_shaft_callback, + 0 +}; + +static bool isCompEnabled = false; + +void turnOnTriggerInputPins(Logging *sharedLogger) { + logger = sharedLogger; + compInit(); + compStart(EFI_COMP_PRIMARY_DEVICE, &comp_shaft_cfg); + + applyNewTriggerInputPins(); +} + +void startTriggerInputPins(void) { + //efiAssertVoid(CUSTOM_ERR_, !isCompEnabled, "isCompEnabled"); + + const float vRef = 5.0f; + const float vSensorRef = 2.5f; // 2.5V resistor divider + // when VR sensor is silent, there's still some noise around vRef, so we need a small threshold to avoid false triggering + const float noSignalThreshold = 0.05f; + + const int maxDacValue = 255; + const int vDac = (int)(int)efiRound(maxDacValue * (vSensorRef - noSignalThreshold) / vRef, 1.0f); + + int channel = EFI_COMP_TRIGGER_CHANNEL; // todo: use getInputCaptureChannel(hwPin); + + // todo: set pin mode to default (analog/comparator) + //palSetPadMode(comp_channel_port[channel], comp_channel_pad[channel], PAL_MODE_INPUT_ANALOG); + + // no generic hal support for extended COMP configuration, so we use hal_lld layer... + osalSysLock(); + comp_lld_set_dac_value(EFI_COMP_PRIMARY_DEVICE, vDac); + comp_lld_channel_enable(EFI_COMP_PRIMARY_DEVICE, channel); + osalSysUnlock(); + + compEnable(EFI_COMP_PRIMARY_DEVICE); + isCompEnabled = true; +} + +void stopTriggerInputPins(void) { + if (!isCompEnabled) + return; + compDisable(EFI_COMP_PRIMARY_DEVICE); + isCompEnabled = false; +#if 0 + for (int i = 0; i < TRIGGER_SUPPORTED_CHANNELS; i++) { + if (CONFIGB(triggerInputPins)[i] + != activeConfiguration.bc.triggerInputPins[i]) { + turnOffTriggerInputPin(activeConfiguration.bc.triggerInputPins[i]); + } + } + if (engineConfiguration->camInput != activeConfiguration.camInput) { + turnOffTriggerInputPin(activeConfiguration.camInput); + } +#endif +} + +void applyNewTriggerInputPins(void) { + // first we will turn off all the changed pins + stopTriggerInputPins(); + // then we will enable all the changed pins + startTriggerInputPins(); +} + +#endif /* EFI_SHAFT_POSITION_INPUT && HAL_USE_COMP */