rusefi/firmware/hw_layer/smart_gpio.cpp

390 lines
11 KiB
C++
Raw Normal View History

2019-04-13 07:58:52 -07:00
/*
* @file smart_gpio.cpp
*
* @date Apr 13, 2019
2020-01-07 21:02:40 -08:00
* @author Andrey Belomutskiy, (c) 2012-2020
2019-04-13 07:58:52 -07:00
*/
#include "pch.h"
2019-04-13 08:22:40 -07:00
2019-04-13 07:58:52 -07:00
#include "smart_gpio.h"
#include "hardware.h"
2019-04-13 07:58:52 -07:00
#include "gpio_ext.h"
#include "drivers/gpio/tle6240.h"
#include "drivers/gpio/mc33972.h"
#include "drivers/gpio/mc33810.h"
2019-04-13 07:58:52 -07:00
#include "drivers/gpio/tle8888.h"
2020-09-09 14:16:51 -07:00
#include "drivers/gpio/drv8860.h"
2022-01-10 16:15:04 -08:00
#include "drivers/gpio/l9779.h"
#include "drivers/gpio/tle9104.h"
2023-03-04 19:11:45 -08:00
#include "drivers/gpio/can_gpio.h"
2019-04-13 07:58:52 -07:00
2024-03-15 17:30:09 -07:00
#if EFI_PROD_CODE
#if (BOARD_TLE6240_COUNT > 0)
// todo: migrate to TS or board config
#ifndef TLE6240_RESET_PORT
#define TLE6240_RESET_PORT GPIOG
#endif /* TLE6240_RESET_PORT */
#ifndef TLE6240_RESET_PAD
#define TLE6240_RESET_PAD 3U
#endif /* TLE6240_RESET_PAD */
#ifndef TLE6240_DIRECT_IO
#define TLE6240_DIRECT_IO \
/* IN1 - D_TACH_OUT */ \
[0] = {.port = GPIOG, .pad = 2}, \
/* IN2..4 grounded */ \
[1] = {.port = NULL, .pad = 0}, \
[2] = {.port = NULL, .pad = 0}, \
[3] = {.port = NULL, .pad = 0}, \
/* IN9 - D_INJ_5 */ \
[4] = {.port = GPIOD, .pad = 15}, \
/* IN10 - D_WASTGATE */ \
[5] = {.port = GPIOD, .pad = 14}, \
/* IN11 - D_IDLE_OPEN */ \
[6] = {.port = GPIOC, .pad = 6}, \
/* IN12 - D_IDLE_CLOSE */ \
[7] = {.port = GPIOC, .pad = 7},
#endif /* TLE6240_DIRECT_IO */
static OutputPin tle6240Cs;
struct tle6240_config tle6240 = {
.spi_bus = NULL,
2019-04-13 07:58:52 -07:00
.spi_config = {
.circular = false,
.end_cb = NULL,
.ssport = NULL,
.sspad = 0,
2019-04-13 07:58:52 -07:00
.cr1 =
SPI_CR1_16BIT_MODE |
2019-04-13 07:58:52 -07:00
SPI_CR1_SSM |
SPI_CR1_SSI |
/* SPI_CR1_LSBFIRST | */
((3 << SPI_CR1_BR_Pos) & SPI_CR1_BR) | /* div = 16 */
SPI_CR1_MSTR |
/* SPI_CR1_CPOL | */ // = 0
SPI_CR1_CPHA | // = 1
0,
.cr2 = SPI_CR2_16BIT_MODE
},
.direct_io = {
TLE6240_DIRECT_IO
2019-04-13 07:58:52 -07:00
},
.reset = {.port = TLE6240_RESET_PORT, .pad = TLE6240_RESET_PAD}
2019-04-13 07:58:52 -07:00
};
2019-04-13 08:22:40 -07:00
#endif /* (BOARD_TLE6240_COUNT > 0) */
2019-04-13 07:58:52 -07:00
2019-04-13 08:22:40 -07:00
#if (BOARD_MC33972_COUNT > 0)
static OutputPin mc33972Cs;
struct mc33972_config mc33972 = {
.spi_bus = NULL,
2019-04-13 07:58:52 -07:00
.spi_config = {
.circular = false,
.end_cb = NULL,
.ssport = NULL,
.sspad = 0,
2019-04-13 07:58:52 -07:00
.cr1 =
SPI_CR1_8BIT_MODE |
2019-04-13 07:58:52 -07:00
SPI_CR1_SSM |
SPI_CR1_SSI |
/* SPI_CR1_LSBFIRST | */
((3 << SPI_CR1_BR_Pos) & SPI_CR1_BR) | /* div = 16 */
SPI_CR1_MSTR |
/* SPI_CR1_CPOL | */ /* = 0 */
SPI_CR1_CPHA | /* = 1 */
0,
.cr2 = SPI_CR2_8BIT_MODE
2019-04-13 07:58:52 -07:00
},
};
2019-04-13 08:22:40 -07:00
#endif /* (BOARD_MC33972_COUNT > 0) */
2019-04-13 07:58:52 -07:00
2022-01-10 16:15:04 -08:00
#if (BOARD_L9779_COUNT > 0)
static OutputPin l9779Cs;
struct l9779_config l9779_cfg = {
.spi_bus = NULL,
.spi_config = {
.circular = false,
.end_cb = NULL,
.ssport = NULL,
.sspad = 0,
.cr1 =
SPI_CR1_16BIT_MODE |
SPI_CR1_SSM |
SPI_CR1_SSI |
//SPI_CR1_LSBFIRST | //MSB first
((3 << SPI_CR1_BR_Pos) & SPI_CR1_BR) | // div = 16, up to 8 MHz
SPI_CR1_MSTR |
SPI_CR1_CPHA |
0,
.cr2 = SPI_CR2_16BIT_MODE
},
.direct_gpio = {
/* IGNI1..IGNI4 */
[0] = {.port = NULL, .pad = 0},
[1] = {.port = NULL, .pad = 0},
[2] = {.port = NULL, .pad = 0},
[3] = {.port = NULL, .pad = 0},
/* IN1..IN7 */
[4] = {.port = NULL, .pad = 0},
[5] = {.port = NULL, .pad = 0},
[6] = {.port = NULL, .pad = 0},
[7] = {.port = NULL, .pad = 0},
[8] = {.port = NULL, .pad = 0},
[9] = {.port = NULL, .pad = 0},
[10] = {.port = NULL, .pad = 0},
},
/* PWM (IN8) */
.pwm_gpio = {.port = NULL, .pad = 0},
2022-01-10 16:15:04 -08:00
};
#endif /* (BOARD_L9779_COUNT > 0) */
#if (BOARD_TLE8888_COUNT > 0)
static OutputPin tle8888Cs;
struct tle8888_config tle8888_cfg = {
.spi_bus = NULL,
.spi_config = {
.circular = false,
.end_cb = NULL,
.ssport = NULL,
.sspad = 0,
.cr1 =
SPI_CR1_16BIT_MODE |
SPI_CR1_SSM |
SPI_CR1_SSI |
SPI_CR1_LSBFIRST | //LSB first
((3 << SPI_CR1_BR_Pos) & SPI_CR1_BR) | // div = 16
SPI_CR1_MSTR |
SPI_CR1_CPHA |
0,
.cr2 = SPI_CR2_16BIT_MODE
},
.reset = {.port = NULL, .pad = 0},
Tle8888 big update 1 (#1892) * smart gpio: fix tle8888 direct pin mapping for MRE * MRE: use TLE8888 pins instead of MCU gpios that drives TLE8888 * TLE8888: cleanup * TLE8888: do not reset driver private data on WD/undervoltage reset * TLE8888: diagnostic updates * TLE8888 driver: BIG driver rework * TLE8888: check SPI answers for abnormal states Reply with other than requested register can be a sign of: -Power-On-Reset, then OpStat0 will be replyed -WatchDog reset, then FWDStat1 will be replyed -Invalid communication frame, then Diag0 will be replyed Keep tracking last accessed register and check with the next reply. * TLE8888: debug clean-up * TLE8888: implement spi array write This reduce CS inactive state time between two consequent accesses from 8.8 uS to 1.4 uS * TLE8888: fix PP outputs in OD mode * TLE8888: cleanup register definitions * TLE8888: run separate driver thread for each chip instance Calculating poll interval for few chips become more complex, avoid this running thread for each device. * TLE8888: fix cypress and kinetic compilation Both platforms define its own MAX and cause redifination error if common.h is included in driver. * MRE: update mapping.yaml and fix direct pin mapping for TLE8888 * TLE8888: diagnnostic: disable switch off in case of overcurrent For all output, use current limiting instead * TLE8888: check for overvoltage on OUT8..OUT13 * TLE8888: add TODO note about how to recover from failure condition Currently TLE8888 automaticly recovers only from overcurrent and (may be) overtemperature conditions. Short to bat cause output disable (bit in OECONFIG is reset) and needs driver/host intervention. * TLE8888: save few bytes of RAM * TLE8888: Lada Kalina is test mule for IDLE stepper on TLE8888 Don't forget to enable PP mode for TLE8888 outputs 21..24: uncomment line 1087 in tle8888.c * TLE8888: reorder code, cleanup * TLE8888: mode all debug/statisctic to per-chip struct * TLE8888: rework poll interval calculation * MRE: use TLE8888 pins instead of MCU gpios that drives TLE8888 #2
2020-10-23 09:25:30 -07:00
.direct_gpio = {
/* IN1..4 -> OUT1..OUT4 (Injectors) */
[0] = {.port = GPIOE, .pad = 14},
[1] = {.port = GPIOE, .pad = 13},
[2] = {.port = GPIOE, .pad = 12},
[3] = {.port = GPIOE, .pad = 11},
/* IN5..8 -> IGN1..IGN4 (Ignitors) */
Tle8888 big update 1 (#1892) * smart gpio: fix tle8888 direct pin mapping for MRE * MRE: use TLE8888 pins instead of MCU gpios that drives TLE8888 * TLE8888: cleanup * TLE8888: do not reset driver private data on WD/undervoltage reset * TLE8888: diagnostic updates * TLE8888 driver: BIG driver rework * TLE8888: check SPI answers for abnormal states Reply with other than requested register can be a sign of: -Power-On-Reset, then OpStat0 will be replyed -WatchDog reset, then FWDStat1 will be replyed -Invalid communication frame, then Diag0 will be replyed Keep tracking last accessed register and check with the next reply. * TLE8888: debug clean-up * TLE8888: implement spi array write This reduce CS inactive state time between two consequent accesses from 8.8 uS to 1.4 uS * TLE8888: fix PP outputs in OD mode * TLE8888: cleanup register definitions * TLE8888: run separate driver thread for each chip instance Calculating poll interval for few chips become more complex, avoid this running thread for each device. * TLE8888: fix cypress and kinetic compilation Both platforms define its own MAX and cause redifination error if common.h is included in driver. * MRE: update mapping.yaml and fix direct pin mapping for TLE8888 * TLE8888: diagnnostic: disable switch off in case of overcurrent For all output, use current limiting instead * TLE8888: check for overvoltage on OUT8..OUT13 * TLE8888: add TODO note about how to recover from failure condition Currently TLE8888 automaticly recovers only from overcurrent and (may be) overtemperature conditions. Short to bat cause output disable (bit in OECONFIG is reset) and needs driver/host intervention. * TLE8888: save few bytes of RAM * TLE8888: Lada Kalina is test mule for IDLE stepper on TLE8888 Don't forget to enable PP mode for TLE8888 outputs 21..24: uncomment line 1087 in tle8888.c * TLE8888: reorder code, cleanup * TLE8888: mode all debug/statisctic to per-chip struct * TLE8888: rework poll interval calculation * MRE: use TLE8888 pins instead of MCU gpios that drives TLE8888 #2
2020-10-23 09:25:30 -07:00
/* Not used */
[4] = {.port = NULL, .pad = 0},
[5] = {.port = NULL, .pad = 0},
[6] = {.port = NULL, .pad = 0},
[7] = {.port = NULL, .pad = 0},
/* Remapable IN9..12 */
[8] = {.port = GPIOE, .pad = 10},
[9] = {.port = GPIOE, .pad = 9},
[10] = {.port = GPIOE, .pad = 8},
[11] = {.port = GPIOE, .pad = 7},
},
.direct_maps = {
[0] = {.output = 5}, /* MRE: LS2 */
[1] = {.output = 6}, /* MRE: LS1 */
[2] = {.output = 21}, /* MRE: GP1 - not used when stepper = true */
[3] = {.output = 22}, /* MRE: GP2 - not used when stepper = true */
},
.ign_en = {.port = GPIOD, .pad = 10},
.inj_en = {.port = GPIOD, .pad = 11},
2020-04-23 16:49:22 -07:00
.mode = TL_AUTO,
.stepper = false
};
#endif
#if (BOARD_MC33810_COUNT > 0)
static OutputPin mc33810Cs[C_MC33810_COUNT];
#endif /* (BOARD_MC33810_COUNT > 0) */
2020-09-09 14:16:51 -07:00
#if (BOARD_DRV8860_COUNT > 0)
static OutputPin drv8860Cs;
2020-09-09 14:16:51 -07:00
struct drv8860_config drv8860 = {
.spi_bus = NULL,
2020-09-09 14:16:51 -07:00
.spi_config = {
.circular = false,
.end_cb = NULL,
.ssport = NULL,
.sspad = 0,
.cr1 =
SPI_CR1_16BIT_MODE |
SPI_CR1_SSM |
SPI_CR1_SSI |
((7 << SPI_CR1_BR_Pos) & SPI_CR1_BR) | /* div = 32 */
SPI_CR1_MSTR |
SPI_CR1_CPOL |
0,
.cr2 = SPI_CR2_16BIT_MODE
},
.reset = {.port = DRV8860_RESET_PORT, .pad = DRV8860_RESET_PAD}
};
#endif /* (BOARD_DRV8860_COUNT > 0) */
2024-03-15 17:30:09 -07:00
#endif // EFI_PROD_CODE
2019-04-13 07:58:52 -07:00
void initSmartGpio() {
startSmartCsPins();
2024-03-15 17:30:09 -07:00
#if EFI_PROD_CODE
2019-04-13 07:58:52 -07:00
#if (BOARD_TLE6240_COUNT > 0)
if (isBrainPinValid(engineConfiguration->tle6240_cs)) {
tle6240.spi_config.ssport = getHwPort("tle6240 CS", engineConfiguration->tle6240_cs);
tle6240.spi_config.sspad = getHwPin("tle6240 CS", engineConfiguration->tle6240_cs);
tle6240.spi_bus = getSpiDevice(engineConfiguration->tle6240spiDevice);
int ret = tle6240_add(Gpio::TLE6240_PIN_1, 0, &tle6240);
criticalAssertVoid(ret == (int)Gpio::TLE6240_PIN_1, "tle6240");
}
2020-09-09 14:16:51 -07:00
#endif /* (BOARD_TLE6240_COUNT > 0) */
2019-04-13 07:58:52 -07:00
#if (BOARD_MC33972_COUNT > 0)
if (isBrainPinValid(engineConfiguration->mc33972_cs)) {
// todo: reuse initSpiCs method?
mc33972.spi_config.ssport = getHwPort("mc33972 CS", engineConfiguration->mc33972_cs);
mc33972.spi_config.sspad = getHwPin("mc33972 CS", engineConfiguration->mc33972_cs);
mc33972.spi_bus = getSpiDevice(engineConfiguration->mc33972spiDevice);
// todo: propogate 'basePinOffset' parameter
int ret = mc33972_add(Gpio::MC33972_PIN_1, 0, &mc33972);
criticalAssertVoid(ret == (int)Gpio::MC33972_PIN_1, "mc33972");
}
2020-09-09 14:16:51 -07:00
#endif /* (BOARD_MC33972_COUNT > 0) */
2019-04-13 07:58:52 -07:00
#if (BOARD_L9779_COUNT > 0)
if (isBrainPinValid(engineConfiguration->l9779_cs)) {
// todo: reuse initSpiCs method?
l9779_cfg.spi_config.ssport = getHwPort("l9779 CS", engineConfiguration->l9779_cs);
l9779_cfg.spi_config.sspad = getHwPin("l9779 CS", engineConfiguration->l9779_cs);
l9779_cfg.spi_bus = getSpiDevice(engineConfiguration->l9779spiDevice);
// todo: propogate 'basePinOffset' parameter
int ret = l9779_add(Gpio::L9779_IGN_1, 0, &l9779_cfg);
criticalAssertVoid(ret == (int)Gpio::L9779_IGN_1, "l9779");
}
#endif /* (BOARD_L9779_COUNT > 0) */
2019-04-13 09:02:34 -07:00
#if (BOARD_TLE8888_COUNT > 0)
if (isBrainPinValid(engineConfiguration->tle8888_cs)) {
// todo: reuse initSpiCs method?
tle8888_cfg.spi_config.ssport = getHwPort("tle8888 CS", engineConfiguration->tle8888_cs);
tle8888_cfg.spi_config.sspad = getHwPin("tle8888 CS", engineConfiguration->tle8888_cs);
tle8888_cfg.spi_bus = getSpiDevice(engineConfiguration->tle8888spiDevice);
2020-04-23 13:57:37 -07:00
tle8888_cfg.mode = engineConfiguration->tle8888mode;
tle8888_cfg.stepper = engineConfiguration->useTLE8888_stepper;
/* spi_bus == null checked in _add function */
int ret = tle8888_add(Gpio::TLE8888_PIN_1, 0, &tle8888_cfg);
criticalAssertVoid(ret == (int)Gpio::TLE8888_PIN_1, "tle8888");
}
2020-09-09 14:16:51 -07:00
#endif /* (BOARD_TLE8888_COUNT > 0) */
2024-03-15 21:26:36 -07:00
#if EFI_PROD_CODE && (BOARD_DRV8860_COUNT > 0)
if (isBrainPinValid(engineConfiguration->drv8860_cs)) {
2020-09-09 14:16:51 -07:00
drv8860.spi_config.ssport = getHwPort("drv8860 CS", engineConfiguration->drv8860_cs);
drv8860.spi_config.sspad = getHwPin("drv8860 CS", engineConfiguration->drv8860_cs);
drv8860.spi_bus = getSpiDevice(engineConfiguration->drv8860spiDevice);
int ret = drv8860_add(Gpio::DRV8860_PIN_1, 0, &drv8860);
2020-09-09 14:16:51 -07:00
criticalAssertVoid(ret == (int)Gpio::DRV8860_PIN_1, "drv8860");
2020-09-09 14:16:51 -07:00
}
#endif /* (BOARD_DRV8860_COUNT > 0) */
2023-03-04 19:11:45 -08:00
#if EFI_CAN_GPIO
initCanGpio();
#endif // EFI_CAN_GPIO
#if (BOARD_MC33810_COUNT > 0)
/* none of official boards has this IC */
#endif /* (BOARD_MC33810_COUNT > 0) */
#if (BOARD_TLE9104_COUNT > 0)
// No official boards have this IC
#endif
2024-03-15 17:30:09 -07:00
#endif // EFI_PROD_CODE
/* external chip init */
gpiochips_init();
}
void tle8888startup() {
2024-03-15 17:30:09 -07:00
#if EFI_PROD_CODE && (BOARD_TLE8888_COUNT > 0)
static efitick_t tle8888CrankingResetTime = 0;
if (engineConfiguration->useTLE8888_cranking_hack && engine->rpmCalculator.isCranking()) {
efitick_t nowNt = getTimeNowNt();
if (nowNt - tle8888CrankingResetTime > MS2NT(300)) {
tle8888_req_init();
// let's reset TLE8888 every 300ms while cranking since that's the best we can do to deal with undervoltage reset
// PS: oh yes, it's a horrible design! Please suggest something better!
tle8888CrankingResetTime = nowNt;
}
}
2023-03-05 06:27:06 -08:00
#endif /* BOARD_TLE8888_COUNT */
}
void stopSmartCsPins() {
2024-03-15 17:30:09 -07:00
#if EFI_PROD_CODE
#if (BOARD_TLE8888_COUNT > 0)
efiSetPadUnused(activeConfiguration.tle8888_cs);
#endif /* BOARD_TLE8888_COUNT */
#if (BOARD_TLE6240_COUNT > 0)
efiSetPadUnused(activeConfiguration.tle6240_cs);
#endif /* BOARD_TLE6240_COUNT */
#if (BOARD_MC33972_COUNT > 0)
efiSetPadUnused(activeConfiguration.mc33972_cs);
#endif /* BOARD_MC33972_COUNT */
2020-09-09 14:16:51 -07:00
#if (BOARD_DRV8860_COUNT > 0)
2020-09-09 14:16:51 -07:00
#endif /* BOARD_DRV8860_COUNT */
#if (BOARD_MC33810_COUNT > 0)
for (size_t i = 0;i<C_MC33810_COUNT;i++) {
efiSetPadUnused(engineConfiguration->mc33810_cs[i]);
}
#endif /* (BOARD_MC33810_COUNT > 0) */
#if (BOARD_TLE9104_COUNT > 0)
// No official boards have this IC
#endif
2024-03-15 17:30:09 -07:00
#endif // EFI_PROD_CODE
}
void startSmartCsPins() {
2024-03-15 17:30:09 -07:00
#if EFI_PROD_CODE
#if (BOARD_TLE8888_COUNT > 0)
tle8888Cs.initPin("tle8888 CS", engineConfiguration->tle8888_cs,
2023-02-25 00:31:12 -08:00
engineConfiguration->tle8888_csPinMode);
tle8888Cs.setValue(true);
#endif /* BOARD_TLE8888_COUNT */
#if (BOARD_TLE6240_COUNT > 0)
2023-03-04 17:34:43 -08:00
// todo: any way to reduce copy-paste? some convention between pin property name and pin mode property name?
tle6240Cs.initPin("tle6240 CS", engineConfiguration->tle6240_cs,
2023-02-25 00:31:12 -08:00
engineConfiguration->tle6240_csPinMode);
tle6240Cs.setValue(true);
#endif /* BOARD_TLE6240_COUNT */
#if (BOARD_MC33972_COUNT > 0)
2023-03-04 17:34:43 -08:00
// todo: any way to reduce copy-paste? some convention between pin property name and pin mode property name?
mc33972Cs.initPin("mc33972 CS", engineConfiguration->mc33972_cs,
2023-02-25 00:31:12 -08:00
engineConfiguration->mc33972_csPinMode);
mc33972Cs.setValue(true);
#endif /* BOARD_MC33972_COUNT */
2020-09-09 14:16:51 -07:00
#if (BOARD_DRV8860_COUNT > 0)
2023-03-04 17:34:43 -08:00
// todo: any way to reduce copy-paste? some convention between pin property name and pin mode property name?
2020-09-09 14:16:51 -07:00
drv8860Cs.initPin("drv8860 CS", engineConfiguration->drv8860_cs,
2023-02-25 00:31:12 -08:00
engineConfiguration->drv8860_csPinMode);
2020-09-09 14:16:51 -07:00
drv8860Cs.setValue(true);
#endif /* BOARD_DRV8860_COUNT */
#if (BOARD_MC33810_COUNT > 0)
for (size_t i = 0;i<C_MC33810_COUNT;i++) {
mc33810Cs[i].initPin("mc33810 CS", engineConfiguration->mc33810_cs[i],
engineConfiguration->mc33810_csPinMode);
mc33810Cs[i].setValue(true);
}
#endif /* (BOARD_MC33810_COUNT > 0) */
#if (BOARD_TLE9104_COUNT > 0)
2023-03-04 17:32:22 -08:00
// todo: no official boards have this IC yet
#endif
#if (BOARD_L9779_COUNT > 0)
// todo: use existing l9779_cs and l9779_csPinMode settings
2023-03-04 17:32:22 -08:00
// todo: no official boards have this IC yet
#endif
2024-03-15 17:30:09 -07:00
#endif // EFI_PROD_CODE
2019-04-13 07:58:52 -07:00
}