28#if EFI_PROD_CODE && (BOARD_MC33810_COUNT > 0)
42#define DRIVER_NAME "mc33810"
57#define MC_CMD_READ_REG(reg) (0x0a00 | (((reg) & 0x0f) << 4))
58#define MC_CMD_SPI_CHECK (0x0f00)
59#define MC_CMD_MODE_SELECT(mode) (0x1000 | ((mode) & 0x0fff))
63#define MC_CMD_DRIVER_EN(en) (0x3000 | ((en) & 0x00ff))
64#define MC_CMD_SPARK(spark) (0x4000 | ((spark) & 0x0fff))
68#define MC_CMD_DAC(dac) (0x6000 | ((dac) & 0x0fff))
74#define MC_CMD_PWM(pwm) (0xa000 | ((pwm) & 0x0fff))
79#define MC_CMD_INVALID (0xf000)
82#define TX_GET_CMD(v) (((v) >> 12) & 0x000f)
85#define REG_ALL_STAT (0x0)
86#define REG_OUT10_FAULT (0x1)
87#define REG_OUT32_FAULT (0x2)
88#define REG_GPGD_FAULT (0x3)
89#define REG_IGN_FAULT (0x4)
90#define REG_MODE_CMD (0x5)
91#define REG_LSD_FAULT_CMD (0x6)
92#define REG_DRIVER_EN (0x7)
93#define REG_SPARK_CMD (0x8)
94#define REG_END_SPARK_FILTER (0x9)
95#define REG_DAC_CMD (0xa)
96#define REG_GPGD_SHORT_THRES (0xb)
97#define REG_GPGD_SHORT_TIMER (0xc)
98#define REG_GPGD_FAULT_OP (0xd)
103#define SPI_CHECK_ACK (0x0d0a)
105#define REP_FLAG_RESET BIT(15)
107#define REP_FLAG_COR BIT(14)
109#define REP_FLAG_SOR BIT(13)
111#define REP_FLAG_OV BIT(13)
113#define REP_FLAG_LV BIT(12)
115#define REP_FLAG_NMF BIT(12)
139 void debug()
override;
143 int spi_rw(uint16_t tx, uint16_t* rx);
144 int spi_rw_array(
const uint16_t *tx, uint16_t *rx,
int n);
145 int update_output_and_diag();
150 void ign_event(
size_t pin,
int value);
151 void on_spkdur(efitick_t now);
153 int chip_init_data();
158 uint8_t o_state_cached;
162 uint8_t o_direct_mask;
167 bool all_status_updated;
168 uint16_t all_status_value;
171 uint16_t out_fault[2];
186 uint8_t active_coil_idx;
187 uint8_t spark_fault_mask;
188 efitick_t spartStart[MC33810_IGN_OUTPUTS];
200 bool hadSuccessfulInit =
false;
203static Mc33810
chips[BOARD_MC33810_COUNT];
206 "mc33810.OUT1",
"mc33810.OUT2",
"mc33810.OUT3",
"mc33810.OUT4",
207 "mc33810.GD0",
"mc33810.GD1",
"mc33810.GD2",
"mc33810.GD3",
215 return rx & REP_FLAG_COR;
225int Mc33810::spi_unselect()
228 SPIDriver *spi = cfg->spi_bus;
235 while (palReadPad(cfg->sck.port, cfg->sck.pad) && (++retry < 1000)) {
247 efiPrintf(DRIVER_NAME
"failed wait for SCK = 0");
259int Mc33810::spi_rw(uint16_t tx, uint16_t *rx_ptr)
262 SPIDriver *spi = cfg->spi_bus;
267 spiStart(spi, &cfg->spi_config);
273 rx = spiPolledExchange(spi, tx);
282 if (recentTx != MC_CMD_INVALID) {
284 if (rx & REP_FLAG_RESET)
289 if (((TX_GET_CMD(recentTx) >= 0x1) && (TX_GET_CMD(recentTx) <= 0xa)) ||
290 (recentTx == MC_CMD_READ_REG(REG_ALL_STAT))) {
292 all_status_value = rx;
293 all_status_updated =
true;
295 if (rx & REP_FLAG_SOR)
300 if (rx & REP_FLAG_OV)
302 if (rx & REP_FLAG_LV)
310 efiPrintf(DRIVER_NAME
"SPI [%x][%x]", tx, rx);
319int Mc33810::spi_rw_array(
const uint16_t *tx, uint16_t *rx,
int n)
322 SPIDriver *spi = cfg->spi_bus;
331 spiStart(spi, &cfg->spi_config);
333 for (
int i = 0; i < n; i++) {
337 uint16_t rxdata = spiPolledExchange(spi, tx[i]);
344 if (recentTx != MC_CMD_INVALID) {
346 if (rxdata & REP_FLAG_RESET)
351 if (((TX_GET_CMD(recentTx) >= 0x1) && (TX_GET_CMD(recentTx) <= 0xa)) ||
352 (recentTx == MC_CMD_READ_REG(REG_ALL_STAT))) {
354 all_status_value = rxdata;
355 all_status_updated =
true;
357 if (rxdata & REP_FLAG_SOR)
362 if (rxdata & REP_FLAG_OV)
364 if (rxdata & REP_FLAG_LV)
373 recentTx = MC_CMD_INVALID;
390int Mc33810::update_output_and_diag()
394 uint16_t out_data = o_state & (~o_direct_mask);
395 const uint16_t tx[] = {
399 (uint16_t)MC_CMD_DRIVER_EN(out_data),
400 MC_CMD_READ_REG(REG_OUT10_FAULT),
401 MC_CMD_READ_REG(REG_OUT32_FAULT),
402 MC_CMD_READ_REG(REG_GPGD_FAULT),
403 MC_CMD_READ_REG(REG_IGN_FAULT),
404 MC_CMD_READ_REG(REG_ALL_STAT)
406 uint16_t rx[efi::size(tx)];
409 all_status_updated =
false;
411 ret = spi_rw_array(tx, rx, efi::size(tx));
418 out_fault[0] = rx[1 + 1];
419 out_fault[1] = rx[2 + 1];
420 gp_fault = rx[3 + 1];
421 ign_fault = rx[4 + 1];
430int Mc33810::chip_init_data()
439 palSetPadMode(cfg->en.port, cfg->en.pad, PAL_MODE_OUTPUT_PUSHPULL);
440 palSetPort(cfg->en.port, PAL_PORT_BIT(cfg->en.pad));
443 for (
int n = 0; n < MC33810_DIRECT_OUTPUTS; n++) {
444 if (cfg->direct_io[n].port) {
445 ret |=
gpio_pin_markUsed(cfg->direct_io[n].port, cfg->direct_io[n].pad, DRIVER_NAME
" DIRECT IO");
446 palSetPadMode(cfg->direct_io[n].port, cfg->direct_io[n].pad, PAL_MODE_OUTPUT_PUSHPULL);
447 palClearPort(cfg->direct_io[n].port, PAL_PORT_BIT(cfg->direct_io[n].pad));
453 efiPrintf(DRIVER_NAME
" error binding pin(s)");
460 reinterpret_cast<void*
>(
this));
462 efiPrintf(DRIVER_NAME
" error requesting SPKDUR input IRQ: %d", ret);
467 spkdur.port =
getHwPort(DRIVER_NAME, cfg->spkdur);
468 spkdur.pad =
getHwPin(DRIVER_NAME, cfg->spkdur);
470 spkdur.port =
nullptr;
478#if SMART_CHIPS_UNMARK_ON_FAIL
481 palSetPort(cfg->en.port,
482 PAL_PORT_BIT(cfg->en.pad));
486 for (
int n = 0; n < MC33810_DIRECT_OUTPUTS; n++) {
487 if (cfg->direct_io[n].port) {
502int Mc33810::chip_init()
512 recentTx = MC_CMD_INVALID;
517 ret = spi_rw(MC_CMD_SPI_CHECK, &rxSpiCheck);
519 ret |= spi_rw(MC_CMD_READ_REG(REG_REV), &rx);
522 efiPrintf(DRIVER_NAME
" first SPI RX failed");
525 if (rx != SPI_CHECK_ACK) {
527 static Timer needBatteryMessage;
529 if (vBatt > 6 || needBatteryMessage.getElapsedSeconds() > 7) {
530 needBatteryMessage.reset();
534 }
else if (
isCor(rx)) {
539 efiPrintf(DRIVER_NAME
" spi loopback test failed [first 0x%04x][spi check 0x%04x][%s] vBatt=%f count=%d", rxSpiCheck, rx, msg, vBatt,
547 ret = spi_rw(MC_CMD_READ_REG(REG_ALL_STAT), &rx);
550 efiPrintf(DRIVER_NAME
" revision failed");
554 efiPrintf(DRIVER_NAME
" spi COR status");
573 ret = spi_rw(MC_CMD_SPARK(spark_cmd), NULL);
575 efiPrintf(DRIVER_NAME
" cmd spark");
579 uint16_t nomi_current = 0x0a;
581 if ((nomi >= 3.0) && (nomi <= 10.75)) {
582 nomi_current = (nomi - 3.0) / 0.25;
585 uint16_t maxi_current = 0x08;
587 if ((maxi >= 6.0) && (maxi <= 21.0)) {
588 maxi_current = maxi - 6.0;
592 ((nomi_current & 0x1f) << 0) |
596 ((maxi_current & 0xf) << 8) |
598 ret = spi_rw(MC_CMD_DAC(dac_cmd), NULL);
600 efiPrintf(DRIVER_NAME
" cmd dac");
611 uint16_t mode_select_cmd =
613 ((o_gpgd_mask & 0xf0) << 4) |
617 ret = spi_rw(MC_CMD_MODE_SELECT(mode_select_cmd) , NULL);
619 efiPrintf(DRIVER_NAME
" cmd mode select");
626 palClearPort(cfg->en.port,
627 PAL_PORT_BIT(cfg->en.pad));
630 if (!hadSuccessfulInit) {
631 efiPrintf(DRIVER_NAME
" Successful Init");
632 hadSuccessfulInit =
true;
647void Mc33810::wake_driver()
650 chibios_rt::CriticalSectionLocker csl;
651 chSemSignalI(&mc33810_wake);
652 if (!port_is_isr_context()) {
666void Mc33810::on_spkdur(efitick_t now)
673 bool edge = palReadPad(spkdur.port, spkdur.pad);
678 spartStart[active_coil_idx] = now;
682 sparkDuration[active_coil_idx] = USF2MS(NT2USF(now - spartStart[active_coil_idx]));
684 spark_fault_mask &= ~BIT(MC33810_INJ_OUTPUTS + active_coil_idx);
689 sparkDuration[active_coil_idx] = 0;
690 spark_fault_mask |= BIT(MC33810_INJ_OUTPUTS + active_coil_idx);
700void Mc33810::ign_event(
size_t pin,
int value)
703 if (spkdur.port ==
nullptr) {
707 uint8_t pin_mask = BIT(
pin);
708 uint8_t new_o_state = o_state;
711 new_o_state |= pin_mask;
713 new_o_state &= ~pin_mask;
717 if (o_state == new_o_state)
724 size_t idx =
pin - MC33810_INJ_OUTPUTS;
729 spark_fault_mask |= BIT(MC33810_INJ_OUTPUTS + active_coil_idx);
730 sparkDuration[active_coil_idx] = 0;
733 active_coil_idx = idx;
745 chRegSetThreadName(DRIVER_NAME);
747 chThdSleepMilliseconds(2);
751 msg_t msg = chSemWaitTimeout(&mc33810_wake, TIME_MS2I(MC33810_POLL_INTERVAL_MS));
756 for (
int i = 0; i < BOARD_MC33810_COUNT; i++) {
757 auto chip = &
chips[i];
764 if (chip->need_init) {
765 int ret = chip->chip_init();
768 chip->need_init =
false;
772 if ((chip->cfg == NULL) ||
775 chip->need_init =
true;
780 int ret = chip->update_output_and_diag();
794 Mc33810 *chip = (Mc33810 *)ptr;
796 chip->on_spkdur(now);
803int Mc33810::writePad(
size_t pin,
int value) {
804 uint8_t pin_mask = BIT(
pin);
806 if (
pin >= MC33810_OUTPUTS) {
812 chibios_rt::CriticalSectionLocker csl;
814 if (pin_mask & IGN_MASK) {
815 ign_event(
pin, value);
821 o_state &= ~pin_mask;
826 if (o_direct_mask & pin_mask) {
829 int pad = PAL_PORT_BIT(cfg->direct_io[
pin].pad);
830 efiPrintf(DRIVER_NAME
"writePad pad %d",
pad);
833 palSetPort(cfg->direct_io[
pin].port,
834 PAL_PORT_BIT(cfg->direct_io[
pin].pad));
836 palClearPort(cfg->direct_io[
pin].port,
837 PAL_PORT_BIT(cfg->direct_io[
pin].pad));
851 if (
pin >= MC33810_DIRECT_OUTPUTS)
854 if (
pin < MC33810_INJ_OUTPUTS) {
856 val = out_fault[(pin < 2) ? 0 : 1] >> (4 * (
pin & 0x01));
865 diag |= PIN_SHORT_TO_BAT;
867 diag |= PIN_DRIVER_OVERTEMP;
870 val = gp_fault >> (2 * (
pin - 4));
875 diag |= PIN_SHORT_TO_GND;
878 if ((o_gpgd_mask & BIT(
pin)) == 0) {
879 val = ign_fault >> (3 * (
pin - 4));
886 diag |= PIN_OVERLOAD;
889 diag |= PIN_OVERLOAD;
892 if (spark_fault_mask & BIT(
pin))
897 if (sparkDuration[
pin - MC33810_IGN_OUTPUTS] < 0.150)
905void Mc33810::debug() {
906 efiPrintf(
"rst_cnt %d cor_cnt %d sor_cnt %d ov_cnt %d lv_cnt %d\n",
907 rst_cnt, cor_cnt, sor_cnt, ov_cnt, lv_cnt);
909 for (
size_t i = 0; i < MC33810_IGN_OUTPUTS; i++) {
910 efiPrintf(
"Ign %d spark fault %d last duration %f mS\n",
911 i, !!(spark_fault_mask & BIT(MC33810_INJ_OUTPUTS + i)),
923 ret = chip_init_data();
934 mc33810_thread = chThdCreateStatic(mc33810_thread_wa,
sizeof(mc33810_thread_wa),
935 PRIO_GPIOCHIP, mc33810_driver_thread,
nullptr);
949 if ((!cfg) || (!cfg->
spi_bus) || (index >= BOARD_MC33810_COUNT))
957 Mc33810& chip =
chips[index];
960 if (chip.cfg != NULL)
965 chip.o_state_cached = 0;
966 chip.o_direct_mask = 0;
967 for (
int i = 0; i < MC33810_DIRECT_OUTPUTS; i++) {
969 chip.o_direct_mask |= BIT(i);
974 if ((chip.o_direct_mask & 0xf0) != 0xf0)
996 for (i = 0; i < BOARD_MC33810_COUNT; i++) {
997 auto& chip =
chips[i];
999 chip.need_init =
true;
1022 if (idx >= BOARD_MC33810_COUNT)
1031 (void)base; (void)index; (void)cfg;
TunerStudioOutputChannels outputChannels
static float getOrZero(SensorType type)
int gpiochip_register(brain_pin_e base, const char *name, GpioChip &gpioChip, size_t size)
Register gpiochip.
int gpiochips_setPinNames(brain_pin_e base, const char **names)
Set pins names for registered gpiochip.
ioportid_t getHwPort(const char *msg, brain_pin_e brainPin)
ioportmask_t getHwPin(const char *msg, brain_pin_e brainPin)
static EngineAccessor engine
static constexpr engine_configuration_s * engineConfiguration
GPIO_TypeDef * ioportid_t
Port Identifier.
static void mc33810_spkdur_cb(void *ptr, efitick_t now)
static Mc33810 chips[BOARD_MC33810_COUNT]
static THD_FUNCTION(mc33810_driver_thread, p)
static const char * mc33810_pin_names[MC33810_OUTPUTS]
int getMc33810maxDwellTimer(mc33810maxDwellTimer_e value)
const mc33810_state_s * mc33810getLiveData(size_t idx)
static THD_WORKING_AREA(mc33810_thread_wa, 256)
int mc33810_add(brain_pin_e base, unsigned int index, const mc33810_config *cfg)
MC33810 driver add.
static thread_t * mc33810_thread
SEMAPHORE_DECL(mc33810_wake, 10)
void gpio_pin_markUnused(ioportid_t port, ioportmask_t pin)
bool brain_pin_is_onchip(brain_pin_e brainPin)
bool isBrainPinValid(brain_pin_e brainPin)
bool gpio_pin_markUsed(ioportid_t port, ioportmask_t pin, const char *msg)
virtual brain_pin_diag_e getDiag(size_t)
virtual int writePad(size_t, int)
mc33810maxDwellTimer_e mc33810maxDwellTimer
scaled_channel< uint8_t, 4, 1 > mc33810Nomi
bool mc33810DisableRecoveryMode
int8_t smartChipAliveCounter
int8_t smartChipRestartCounter
struct mc33810_config::@36 direct_io[MC33810_DIRECT_OUTPUTS]
uint16_t mc33810spiErrorCounter