TLE9201 SPI diag support https://github.com/rusefi/rusefi/issues/5058 (#7049)
This commit is contained in:
parent
0a0ff11d5a
commit
7bd44fbfa3
|
@ -253,6 +253,10 @@
|
|||
#define BOARD_TLE9104_COUNT 0
|
||||
#endif
|
||||
|
||||
#ifndef BOARD_TLE9201_COUNT
|
||||
#define BOARD_TLE9201_COUNT 0
|
||||
#endif
|
||||
|
||||
#define EFI_ANALOG_SENSORS TRUE
|
||||
|
||||
#ifndef EFI_MAX_31855
|
||||
|
|
|
@ -31,6 +31,7 @@ HW_LAYER_DRIVERS_CPP = \
|
|||
$(DRIVERS_DIR)/gpio/mc33810.cpp \
|
||||
$(DRIVERS_DIR)/gpio/drv8860.cpp \
|
||||
$(DRIVERS_DIR)/gpio/tle9104.cpp \
|
||||
$(DRIVERS_DIR)/gpio/tle9201.cpp \
|
||||
$(DRIVERS_DIR)/gpio/l9779.cpp \
|
||||
$(DRIVERS_DIR)/gpio/protected_gpio.cpp \
|
||||
$(DRIVERS_DIR)/sent/sent_hw_icu.cpp \
|
||||
|
|
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* tle9201.c
|
||||
*
|
||||
* TLE9201 H-Bridge with SPI
|
||||
*
|
||||
* @date Nov 1, 2024
|
||||
*
|
||||
* @author andreika, (c) 2024
|
||||
* @author Andrey Belomutskiy, (c) 2012-2024
|
||||
*/
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include "gpio/gpio_ext.h"
|
||||
#include "gpio/tle9201.h"
|
||||
|
||||
#if EFI_PROD_CODE && (BOARD_TLE9201_COUNT > 0)
|
||||
|
||||
/*==========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*==========================================================================*/
|
||||
|
||||
#define DRIVER_NAME "tle9201"
|
||||
|
||||
#define TLE9201_REG_RD_DIA 0x00 // read diagnosis register
|
||||
#define TLE9201_REG_RES_DIA 0x80 // reset diagnosis register
|
||||
#define TLE9201_REG_RD_REV 0x20 // read device revision number
|
||||
#define TLE9201_REG_RD_CTRL 0x60 // read control register
|
||||
#define TLE9201_REG_WR_CTRL 0xE0 // write control register
|
||||
#define TLE9201_REG_WR_CTRL_RD_DIA 0xC0 // write control and read diagnosis
|
||||
|
||||
#define TLE9201_REV_MAJOR_MASK 0xF0
|
||||
#define TLE9201_REV_MAJOR 0x20
|
||||
|
||||
#define TLE9201_DIAG_CL (1<<4) // over current
|
||||
#define TLE9201_DIAG_TV (1<<5) // transmission validation
|
||||
#define TLE9201_DIAG_OT (1<<6) // over temperature
|
||||
#define TLE9201_DIAG_EN (1<<7) // outputs enabled
|
||||
#define TLE9201_DIAG_OUT_MASK 0xf // bits 0..3
|
||||
|
||||
#define TLE9201_GET_VAL(rx) ((rx) & 0xff)
|
||||
|
||||
static bool drv_task_ready = false;
|
||||
|
||||
typedef enum {
|
||||
TLE9201_DISABLED = 0,
|
||||
TLE9201_READY,
|
||||
TLE9201_FAILED
|
||||
} tle9201_drv_state;
|
||||
|
||||
/*==========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*==========================================================================*/
|
||||
|
||||
/*==========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*==========================================================================*/
|
||||
|
||||
// Output states
|
||||
static const char *diagDiaOut[16] = { "?", "?", "?",
|
||||
"VS Undervoltage", // 0x3
|
||||
"?",
|
||||
"Short to Bat at OUT1 and OUT2", // 0x5
|
||||
"Short to GND at OUT1, short to Bat at OUT2", // 0x6
|
||||
"Short to Bat at OUT2", // 0x7
|
||||
"?",
|
||||
"Short to Bat at OUT1, short to GND at OUT2", // 0x9
|
||||
"Short to GND at OUT1 and OUT2", // 0xA
|
||||
"Short to GND at OUT2", // 0xB
|
||||
"Open Load", // 0xC
|
||||
"Short to Bat at OUT1", // 0xD
|
||||
"Short to GND at OUT1", // 0xE
|
||||
"No failure" // 0xF
|
||||
};
|
||||
|
||||
/* OS */
|
||||
SEMAPHORE_DECL(tle9201_wake, 10 /* or BOARD_TLE9201_COUNT ? */);
|
||||
static THD_WORKING_AREA(tle9201_thread_1_wa, 256);
|
||||
|
||||
/* Driver */
|
||||
struct Tle9201 {
|
||||
int init(int i);
|
||||
|
||||
int spi_rw(uint16_t tx, uint16_t *rx);
|
||||
int read_reg(uint8_t addr, uint8_t *val);
|
||||
|
||||
bool get_diag_and_rev(uint8_t *diag, uint8_t *rev);
|
||||
void process_diag_and_rev(uint8_t diag, uint8_t rev);
|
||||
|
||||
const tle9201_config *cfg = NULL;
|
||||
|
||||
tle9201_drv_state drv_state;
|
||||
int idx;
|
||||
int detectedRev = 0;
|
||||
uint8_t savedDiag = 0;
|
||||
char name[10];
|
||||
};
|
||||
|
||||
static Tle9201 chips[BOARD_TLE9201_COUNT];
|
||||
|
||||
/*==========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*==========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief TLE9201 send+receive routine.
|
||||
*/
|
||||
|
||||
int Tle9201::spi_rw(uint16_t tx, uint16_t *rx) {
|
||||
SPIDriver *spi = cfg->spi_bus;
|
||||
|
||||
/* Acquire ownership of the bus. */
|
||||
spiAcquireBus(spi);
|
||||
/* Setup transfer parameters. */
|
||||
spiStart(spi, &cfg->spi_config);
|
||||
/* Slave Select assertion. */
|
||||
spiSelect(spi);
|
||||
/* Atomic transfer operations. */
|
||||
uint16_t rxd = spiPolledExchange(spi, tx);
|
||||
/* Slave Select de-assertion. */
|
||||
spiUnselect(spi);
|
||||
/* Ownership release. */
|
||||
spiReleaseBus(spi);
|
||||
|
||||
// return data
|
||||
if (rx) {
|
||||
*rx = rxd;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Tle9201::read_reg(uint8_t addr, uint8_t *val) {
|
||||
int ret;
|
||||
|
||||
ret = spi_rw(addr, nullptr);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t rxd;
|
||||
ret = spi_rw(addr, &rxd);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (val) {
|
||||
*val = TLE9201_GET_VAL(rxd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Tle9201::get_diag_and_rev(uint8_t *diag, uint8_t *rev) {
|
||||
int retDiag = read_reg(TLE9201_REG_RD_DIA, diag);
|
||||
int retRev = read_reg(TLE9201_REG_RD_REV, rev);
|
||||
return (retDiag == 0 && retRev == 0);
|
||||
}
|
||||
|
||||
void Tle9201::process_diag_and_rev(uint8_t diag, uint8_t rev) {
|
||||
// react on revision change
|
||||
if (rev != detectedRev) {
|
||||
if ((rev & TLE9201_REV_MAJOR_MASK) == TLE9201_REV_MAJOR) {
|
||||
efiPrintf("%s Detected! (rev=%08x)", name, rev);
|
||||
} else {
|
||||
efiPrintf("%s ERROR: Unknown revision (%08x)!", name, rev);
|
||||
}
|
||||
|
||||
detectedRev = rev;
|
||||
}
|
||||
|
||||
// react on diagnosis byte change
|
||||
if (diag != savedDiag) {
|
||||
efiPrintf("%s Diag (%08x):", name, diag);
|
||||
// this bit should be always 0
|
||||
if (diag & TLE9201_DIAG_TV) {
|
||||
efiPrintf("* Diag status incorrect!");
|
||||
}
|
||||
// these bits are 0 if something happened
|
||||
if (!(diag & TLE9201_DIAG_CL)) {
|
||||
efiPrintf("* Overcurrent shutdown!");
|
||||
}
|
||||
if (!(diag & TLE9201_DIAG_OT)) {
|
||||
efiPrintf("* Overtemperature shutdown!");
|
||||
}
|
||||
if (!(diag & TLE9201_DIAG_EN)) {
|
||||
efiPrintf("* Outputs disabled.");
|
||||
}
|
||||
// print the status of the outputs
|
||||
efiPrintf("* %s", diagDiaOut[diag & TLE9201_DIAG_OUT_MASK]);
|
||||
|
||||
savedDiag = diag;
|
||||
}
|
||||
}
|
||||
|
||||
/*==========================================================================*/
|
||||
/* Driver thread. */
|
||||
/*==========================================================================*/
|
||||
|
||||
static THD_FUNCTION(tle9201_driver_thread, p) {
|
||||
int i;
|
||||
bool wasSpiFailure = false;
|
||||
|
||||
(void)p;
|
||||
|
||||
chRegSetThreadName(DRIVER_NAME);
|
||||
|
||||
while (1) {
|
||||
chThdSleepMilliseconds(TLE9201_POLL_INTERVAL_MS);
|
||||
|
||||
for (i = 0; i < BOARD_TLE9201_COUNT; i++) {
|
||||
auto chip = &chips[i];
|
||||
if ((chip->cfg == NULL) ||
|
||||
(chip->drv_state == TLE9201_DISABLED) ||
|
||||
(chip->drv_state == TLE9201_FAILED))
|
||||
continue;
|
||||
|
||||
uint8_t diag, rev;
|
||||
// get diagnosis and revision bytes
|
||||
if (!chip->get_diag_and_rev(&diag, &rev)) {
|
||||
if (!wasSpiFailure) {
|
||||
efiPrintf("%s ERROR: SPI failure!", chip->name);
|
||||
wasSpiFailure = true;
|
||||
}
|
||||
} else {
|
||||
wasSpiFailure = false;
|
||||
}
|
||||
|
||||
chip->process_diag_and_rev(diag, rev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*==========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*==========================================================================*/
|
||||
|
||||
/*==========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*==========================================================================*/
|
||||
|
||||
int Tle9201::init(int i) {
|
||||
drv_state = TLE9201_READY;
|
||||
idx = i;
|
||||
sprintf(name, "TLE9201[%d]", idx);
|
||||
|
||||
if (!drv_task_ready) {
|
||||
chThdCreateStatic(tle9201_thread_1_wa, sizeof(tle9201_thread_1_wa),
|
||||
PRIO_GPIOCHIP, tle9201_driver_thread, NULL);
|
||||
drv_task_ready = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TLE9201 driver add.
|
||||
* @details Checks for valid config
|
||||
*/
|
||||
|
||||
int tle9201_add(unsigned int index, const tle9201_config *cfg) {
|
||||
/* no config or no such chip */
|
||||
if ((!cfg) || (!cfg->spi_bus) || (index >= BOARD_TLE9201_COUNT))
|
||||
return -1;
|
||||
|
||||
/* check for valid cs.
|
||||
* TODO: remove this check? CS can be driven by SPI */
|
||||
//if (cfg->spi_config.ssport == NULL)
|
||||
// return -1;
|
||||
|
||||
auto& chip = chips[index];
|
||||
|
||||
/* already initted? */
|
||||
if (chip.cfg != NULL)
|
||||
return -1;
|
||||
|
||||
chip.cfg = cfg;
|
||||
chip.init(index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* BOARD_TLE9201_COUNT > 0 */
|
||||
|
||||
int tle9201_add(unsigned int index, const tle9201_config *cfg) {
|
||||
(void)index; (void)cfg;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* BOARD_TLE9201_COUNT */
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* tle9201.h
|
||||
*
|
||||
* TLE9201 H-Bridge with SPI
|
||||
*
|
||||
* @date Nov 1, 2024
|
||||
*
|
||||
* @author andreika, (c) 2024
|
||||
* @author Andrey Belomutskiy, (c) 2012-2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "efifeatures.h"
|
||||
#include <hal.h>
|
||||
|
||||
// 10 Hz
|
||||
#define TLE9201_POLL_INTERVAL_MS 100
|
||||
|
||||
// used by tle9201_config.spi_config.cr1 & .cr2
|
||||
#define TLE9201_CONFIG_CR1 (\
|
||||
SPI_CR1_8BIT_MODE | \
|
||||
SPI_CR1_SSM | \
|
||||
SPI_CR1_SSI | \
|
||||
((0b110 << SPI_CR1_BR_Pos) & SPI_CR1_BR) | \
|
||||
SPI_CR1_MSTR | \
|
||||
SPI_CR1_CPHA)
|
||||
#define TLE9201_CONFIG_CR2 (SPI_CR2_8BIT_MODE)
|
||||
|
||||
struct tle9201_config {
|
||||
#if HAL_USE_SPI
|
||||
SPIDriver *spi_bus;
|
||||
SPIConfig spi_config;
|
||||
#endif
|
||||
};
|
||||
|
||||
int tle9201_add(unsigned int index, const struct tle9201_config *cfg);
|
|
@ -12,6 +12,7 @@
|
|||
#include "drivers/gpio/tle6240.h"
|
||||
#include "drivers/gpio/mc33972.h"
|
||||
#include "drivers/gpio/tle8888.h"
|
||||
#include "drivers/gpio/tle9201.h"
|
||||
#include "drivers/gpio/drv8860.h"
|
||||
#include "drivers/gpio/can_gpio_msiobox.h"
|
||||
// we seem OK without L9779 here do we need those includes at all?
|
||||
|
|
Loading…
Reference in New Issue