Gpio diagnostic (#1100)

* enums: add brain_pin_diag_e enum for pin diagnostic

* gpio core: add pin diagnostic call

* gpio: mc33810: add diagnostic support

* gpio: mc33972: add diagnostic support

* gpio: tle6240: add diagnostic

* pin_repository: output diagnostic data for gpio chips

* enums: kinetis: add brain_pin_diag_e enum for pin diagnostic
This commit is contained in:
dron0gus 2020-01-12 18:20:10 +03:00 committed by rusefi
parent 113fc4be36
commit 618d6f5a5e
9 changed files with 229 additions and 26 deletions

View File

@ -145,6 +145,20 @@ typedef enum __attribute__ ((__packed__)) {
/* Plase keep updating this define */
#define BRAIN_PIN_LAST_ONCHIP GPIOE_17
/* diagnostic for brain pins
* can be combination of few bits
* defined as bit mask */
typedef enum __attribute__ ((__packed__))
{
PIN_OK = 0,
PIN_OPEN = 0x01,
PIN_SHORT_TO_GND = 0x02,
PIN_SHORT_TO_BAT = 0x04,
PIN_OVERLOAD = 0x08,
PIN_DRIVER_OVERTEMP = 0x10,
PIN_INVALID = 0x80
} brain_pin_diag_e;
typedef enum __attribute__ ((__packed__)) {
EFI_ADC_0 = 0,
EFI_ADC_1 = 1,

View File

@ -219,6 +219,20 @@ typedef enum __attribute__ ((__packed__)) {
/* Plase keep updating this define */
#define BRAIN_PIN_LAST_ONCHIP GPIOH_15
/* diagnostic for brain pins
* can be combination of few bits
* defined as bit mask */
typedef enum __attribute__ ((__packed__))
{
PIN_OK = 0,
PIN_OPEN = 0x01,
PIN_SHORT_TO_GND = 0x02,
PIN_SHORT_TO_BAT = 0x04,
PIN_OVERLOAD = 0x08,
PIN_DRIVER_OVERTEMP = 0x10,
PIN_INVALID = 0x80
} brain_pin_diag_e;
/**
* Frankenso analog #1 PC2 ADC12
* Frankenso analog #2 PC1 ADC11

View File

@ -282,6 +282,27 @@ int gpiochips_readPad(brain_pin_e pin)
return -1;
}
/**
* @brief Get diagnostic for given gpio
* @details actual output value depent on gpiochip capabilities
* returns -1 in case of pin not belong to any gpio chip
* returns PIN_OK in case of chip does not support getting diagnostic
* else return brain_pin_diag_e from gpiochip driver;
*/
brain_pin_diag_e gpiochips_getDiag(brain_pin_e pin)
{
struct gpiochip *chip = gpiochip_find(pin);
if (!chip)
return PIN_INVALID;
if (chip->ops->getDiag)
return chip->ops->getDiag(chip->priv, pin - chip->base);
return PIN_OK;
}
/**
* @brief Get total pin count allocated for external gpio chips.
* @details Will also include unused pins for chips that was registered

View File

@ -30,7 +30,7 @@ struct gpiochip_ops {
int (*setPadMode)(void *data, unsigned int pin, int mode);
int (*writePad)(void *data, unsigned int pin, int value);
int (*readPad)(void *data, unsigned int pin);
int (*getDiag)(void *data, unsigned int pin);
brain_pin_diag_e (*getDiag)(void *data, unsigned int pin);
int (*init)(void *data);
int (*deinit)(void *data);
};
@ -53,6 +53,7 @@ int gpiochips_init(void);
int gpiochips_setPadMode(brain_pin_e pin, int mode);
int gpiochips_writePad(brain_pin_e pin, int value);
int gpiochips_readPad(brain_pin_e pin);
brain_pin_diag_e gpiochips_getDiag(brain_pin_e pin);
/* return total number of external gpios */
int gpiochips_get_total_pins(void);

View File

@ -52,6 +52,9 @@ typedef enum {
#define CMD_PWM(pwm) (0xa000 | ((pwm) & 0x0fff))
#define CMD_CLK_CALIB (0xe000)
/* get command code from TX value */
#define TX_GET_CMD(v) (((v) >> 12) & 0x000f)
/* enum? */
#define REG_ALL_STAT (0x0)
#define REG_OUT10_FAULT (0x1)
@ -95,6 +98,18 @@ struct mc33810_priv {
/* direct driven output mask */
uint8_t o_direct_mask;
/* ALL STATUS RESPONSE value and flags */
bool all_status_requested;
bool all_status_updated;
uint16_t all_status_value;
/* OUTx fault registers */
uint16_t out_fault[2];
/* GPGD mode fault register */
uint16_t gpgd_fault;
/* IGN mode fault register */
uint16_t ign_fault;
mc33810_drv_state drv_state;
};
@ -144,6 +159,17 @@ static int mc33810_spi_rw(struct mc33810_priv *chip, uint16_t tx, uint16_t *rx)
if (rx)
*rx = rxb;
/* if reply on previous command is ALL STATUS RESPONSE */
if (chip->all_status_requested) {
chip->all_status_value = rxb;
chip->all_status_updated = true;
}
/* if next reply will be ALL STATUS RESPONSE */
chip->all_status_requested =
(((TX_GET_CMD(tx) >= 0x1) && (TX_GET_CMD(tx) <= 0xa)) ||
(tx == CMD_READ_REG(REG_ALL_STAT)));
/* no errors for now */
return 0;
}
@ -153,13 +179,77 @@ static int mc33810_spi_rw(struct mc33810_priv *chip, uint16_t tx, uint16_t *rx)
* @details Sends ORed data to register, also receive diagnostic.
*/
static int mc33810_update_output(struct mc33810_priv *chip)
static int mc33810_update_output_and_diag(struct mc33810_priv *chip)
{
int ret = 0;
/* TODO: lock? */
chip->o_state_cached = chip->o_state;
/* we need to get updates status */
chip->all_status_updated = false;
/* if any pin is driven over SPI */
if (chip->o_direct_mask != 0xff) {
uint16_t out_data;
out_data = chip->o_state & (~chip->o_direct_mask);
ret = mc33810_spi_rw(chip, CMD_DRIVER_EN(out_data), NULL);
if (ret)
return ret;
chip->o_state_cached = chip->o_state;
}
/* this comlicated logic to save few spi transfers in case we will receive status as reply on other command */
if (!chip->all_status_requested) {
ret = mc33810_spi_rw(chip, CMD_READ_REG(REG_ALL_STAT), NULL);
if (ret)
return ret;
}
/* get reply */
if (!chip->all_status_updated) {
ret = mc33810_spi_rw(chip, CMD_READ_REG(REG_ALL_STAT), NULL);
if (ret)
return ret;
}
/* now we have updated ALL STATUS register in chip data */
/* check OUT (injectors) first */
if (chip->all_status_value & 0x000f) {
/* request diagnostic of OUT0 and OUT1 */
ret = mc33810_spi_rw(chip, CMD_READ_REG(REG_OUT10_FAULT), NULL);
if (ret)
return ret;
/* get diagnostic for OUT0 and OUT1 and request diagnostic for OUT2 and OUT3 */
ret = mc33810_spi_rw(chip, CMD_READ_REG(REG_OUT32_FAULT), &chip->out_fault[0]);
if (ret)
return ret;
/* get diagnostic for OUT2 and OUT2 and requset ALL STATUS */
ret = mc33810_spi_rw(chip, CMD_READ_REG(REG_ALL_STAT), &chip->out_fault[1]);
if (ret)
return ret;
}
/* check GPGD - mode not supported yet */
if (chip->all_status_value & 0x00f0) {
/* request diagnostic of GPGD */
ret = mc33810_spi_rw(chip, CMD_READ_REG(REG_GPGD_FAULT), NULL);
if (ret)
return ret;
/* get diagnostic for GPGD and requset ALL STATUS */
ret = mc33810_spi_rw(chip, CMD_READ_REG(REG_ALL_STAT), &chip->gpgd_fault);
if (ret)
return ret;
}
/* check IGN */
if (chip->all_status_value & 0x0f00) {
/* request diagnostic of IGN */
ret = mc33810_spi_rw(chip, CMD_READ_REG(REG_IGN_FAULT), NULL);
if (ret)
return ret;
/* get diagnostic for IGN and requset ALL STATUS */
ret = mc33810_spi_rw(chip, CMD_READ_REG(REG_ALL_STAT), &chip->ign_fault);
if (ret)
return ret;
}
/* TODO: unlock? */
@ -300,7 +390,7 @@ static THD_FUNCTION(mc33810_driver_thread, p)
continue;
/* TODO: implemet indirect driven gpios */
ret = mc33810_update_output(chip);
ret = mc33810_update_output_and_diag(chip);
if (ret) {
/* set state to MC33810_FAILED? */
}
@ -349,16 +439,45 @@ int mc33810_writePad(void *data, unsigned int pin, int value)
return 0;
}
int mc33810_getDiag(void *data, unsigned int pin)
brain_pin_diag_e mc33810_getDiag(void *data, unsigned int pin)
{
int diag;
int val;
struct mc33810_priv *chip;
brain_pin_diag_e diag = PIN_OK;
if ((pin >= MC33810_DIRECT_OUTPUTS) || (data == NULL))
return -1;
return PIN_INVALID;
/* TODO: implement */
diag = 0;
chip = (struct mc33810_priv *)data;
if (pin < 4) {
/* OUT drivers */
val = chip->out_fault[pin < 2 ? 0 : 1] >> (4 * (pin & 0x01));
/* ON open fault */
if (val & BIT(0))
diag |= PIN_OPEN;
/* OFF open fault */
if (val & BIT(1))
diag |= PIN_OPEN;
if (val & BIT(2))
diag |= PIN_SHORT_TO_BAT;
if (val & BIT(3))
diag |= PIN_DRIVER_OVERTEMP;
} else {
/* INJ drivers, GPGD mode is not supported */
val = chip->ign_fault >> (3 * (pin - 4));
/* open load */
if (val & BIT(0))
diag |= PIN_OPEN;
/* max Dwell fault - too long coil charge time */
if (val & BIT(1))
diag |= PIN_OVERLOAD;
/* MAXI fault - too high coil current */
if (val & BIT(2))
diag |= PIN_OVERLOAD;
}
/* convert to some common enum? */
return diag;
}
@ -437,14 +556,21 @@ int mc33810_add(unsigned int index, const struct mc33810_config *cfg)
chip->o_direct_mask |= (1 << i);
}
chip->drv_state = MC33810_WAIT_INIT;
/* GPGD mode is not supported yet, ignition mode does not support spi on/off commands
* so ignition signals should be directly driven */
if ((chip->o_direct_mask & 0xf0) != 0xf0)
return -1;
/* register, return gpio chip base */
ret = gpiochip_register(DRIVER_NAME, &mc33810_ops, MC33810_OUTPUTS, chip);
if (ret < 0)
return ret;
/* set default pin names, board init code can rewrite */
gpiochips_setPinNames(ret, mc33810_pin_names);
chip->drv_state = MC33810_WAIT_INIT;
return ret;
}

View File

@ -25,6 +25,7 @@
struct mc33810_config {
SPIDriver *spi_bus;
SPIConfig spi_config;
/* First 4 is injector drivers, then 4 ignition pre-drivers */
struct {
ioportid_t port;
uint_fast8_t pad;

View File

@ -273,19 +273,19 @@ int mc33972_readPad(void *data, unsigned int pin) {
return !!(chip->i_state & FLAG_PIN(pin));
}
int mc33972_getDiag(void *data, unsigned int pin) {
int diag;
brain_pin_diag_e mc33972_getDiag(void *data, unsigned int pin) {
brain_pin_diag_e diag = PIN_OK;
struct mc33972_priv *chip;
if ((pin >= MC33972_INPUTS) || (data == NULL))
return -1;
return PIN_INVALID;
chip = (struct mc33972_priv *)data;
/* one diag for all pins */
diag = !!(chip->i_state & FLAG_THERM);
/* one diag bit for all pins */
if (chip->i_state & FLAG_THERM)
diag = PIN_DRIVER_OVERTEMP;
/* convert to some common enum? */
return diag;
}

View File

@ -409,19 +409,28 @@ int tle6240_writePad(void *data, unsigned int pin, int value)
return 0;
}
int tle6240_getDiag(void *data, unsigned int pin)
brain_pin_diag_e tle6240_getDiag(void *data, unsigned int pin)
{
int diag;
int val;
brain_pin_diag_e diag;
struct tle6240_priv *chip;
if ((pin >= TLE6240_DIRECT_OUTPUTS) || (data == NULL))
return -1;
if ((pin >= TLE6240_OUTPUTS) || (data == NULL))
return PIN_INVALID;
chip = (struct tle6240_priv *)data;
diag = (chip->diag[(pin > 7) ? 1 : 0] >> ((pin % 8) * 2)) & 0x03;
val = (chip->diag[(pin > 7) ? 1 : 0] >> ((pin % 8) * 2)) & 0x03;
if (val == 0x3)
diag = PIN_OK;
else if (val == 0x2)
/* Overload, shorted load or overtemperature */
diag = PIN_OVERLOAD | PIN_DRIVER_OVERTEMP;
else if (val == 0x1)
diag = PIN_OPEN;
else if (val == 0x0)
diag = PIN_SHORT_TO_GND;
/* convert to some common enum? */
return diag;
}

View File

@ -68,24 +68,41 @@ static void reportPins(void) {
#if (BOARD_EXT_GPIOCHIPS > 0)
for (unsigned int i = getNumBrainPins() ; i < getNumBrainPins() + BOARD_EXT_PINREPOPINS /* gpiochips_get_total_pins()*/ ; i++) {
static char pin_error[64];
const char *pin_name;
const char *pin_user;
brain_pin_diag_e pin_diag;
brain_pin_e brainPin = index_to_brainPin(i);
pin_name = gpiochips_getPinName(brainPin);
pin_user = getBrainUsedPin(i);
pin_diag = gpiochips_getDiag(brainPin);
/* use autogeneraged helpers here? */
if (pin_diag == PIN_OK) {
snprintf(pin_error, sizeof(pin_error), "Ok");
} else if (pin_diag != PIN_INVALID) {
snprintf(pin_error, sizeof(pin_error), "%s%s%s%s%s",
pin_diag & PIN_OPEN ? "open_load " : "",
pin_diag & PIN_SHORT_TO_GND ? "short_to_gnd " : "",
pin_diag & PIN_SHORT_TO_BAT ? "short_to_bat " : "",
pin_diag & PIN_OVERLOAD ? "overload " : "",
pin_diag & PIN_DRIVER_OVERTEMP ? "overtemp": "");
} else {
snprintf(pin_error, sizeof(pin_error), "INVALID");
}
/* here show all pins, unused too */
if (pin_name != NULL) {
// this probably uses a lot of output buffer!
scheduleMsg(&logger, "ext %s: %s",
pin_name, pin_user ? pin_user : "free");
scheduleMsg(&logger, "ext %s: %s diagnostic: %s",
pin_name, pin_user ? pin_user : "free", pin_error);
} else {
const char *chip_name = gpiochips_getChipName(brainPin);
/* if chip exist */
if (chip_name != NULL) {
scheduleMsg(&logger, "ext %s.%d: %s",
chip_name, gpiochips_getPinOffset(brainPin), pin_user ? pin_user : "free");
scheduleMsg(&logger, "ext %s.%d: %s diagnostic: %s",
chip_name, gpiochips_getPinOffset(brainPin), pin_user ? pin_user : "free", pin_error);
}
}
}