rusefi/firmware/hw_layer/mc33816.cpp

297 lines
7.0 KiB
C++

/*
* @file mc33816.cpp
*
* TL,DR: GDI
*
* The NXP MC33816 is a programmable gate driver IC for precision solenoid control applications.
*
*
* Useful wires:
* 5v, 3(3.3v), Gnd, 12v, VccIO(3v) SPI, DRVEN, RSTB
*
* For MC33816 vs PT2000 differences see
* https://www.nxp.com/docs/en/application-note/AN5203.pdf
*
* @date May 3, 2019
* @author Andrey Belomutskiy, (c) 2012-2020
*/
#include "pch.h"
#if EFI_MC33816
#include "hardware.h"
#include "mpu_util.h"
#include "ignition_controller.h"
static SPIConfig spiCfg = {
.circular = false,
#ifdef _CHIBIOS_RT_CONF_VER_6_1_
.end_cb = NULL,
#else
.slave = false,
.data_cb = NULL,
.error_cb = NULL,
#endif
.ssport = nullptr,
.sspad = 0,
.cr1 =
SPI_CR1_MSTR |
SPI_CR1_SSM | // Software Slave Management, the SSI bit will be internal reference
SPI_CR1_SSI | // Internal Slave Select (active low) set High
SPI_CR1_CPHA |
//SPI_CR1_BR_1 // 5MHz
SPI_CR1_BR_0 | SPI_CR1_BR_1 | SPI_CR1_BR_2 |
SPI_CR1_SPE,
.cr2 = SPI_CR2_SSOE |
SPI_CR2_16BIT_MODE
};
class Pt2001 : public Pt2001Base {
public:
bool init();
void initIfNeeded();
protected:
void acquireBus() override {
criticalAssertVoid(driver != nullptr, "mc33816");
spiAcquireBus(driver);
}
void releaseBus() override {
spiReleaseBus(driver);
}
void select() override {
criticalAssertVoid(driver != nullptr, "mc33816");
// revive MC33816 driver, also support bus sharing #6781
// should be somewhere but not here spiStart(driver, &spiCfg);
// efiPrintf("mc select %s", hwOnChipPhysicalPinName(driver->config->ssport, driver->config->sspad));
spiSelect(driver);
//chris - "no implementation on stm32"
chipSelect.setValue(0);
}
void deselect() override {
spiUnselect(driver);
//chris - "no implementation on stm32"
chipSelect.setValue(1);
}
uint16_t sendRecv(uint16_t tx) override {
return spiPolledExchange(driver, tx);
}
// Send `count` number of 16 bit words from `data`
void sendLarge(const uint16_t* data, size_t count) override {
spiSend(driver, count, data);
}
// GPIO reset and enable pins
void setResetB(bool state) override {
resetB.setValue(state);
}
void setDriveEN(bool state) override {
driven.setValue(state);
}
// GPIO inputs for various pins we need
bool readFlag0() const override {
return efiReadPin(engineConfiguration->mc33816_flag0);
}
// Get battery voltage - only try to init chip when powered
float getVbatt() const override {
// reminder that we do not have sensor subsystem right away
return Sensor::get(SensorType::BatteryVoltage).value_or(0);
}
// CONFIGURATIONS: currents, timings, voltages
float getBoostVoltage() const override {
return engineConfiguration->mc33_hvolt;
}
// Currents in amps
float getBoostCurrent() const override {
return engineConfiguration->mc33_i_boost;
}
float getPeakCurrent() const override {
return engineConfiguration->mc33_i_peak;
}
float getHoldCurrent() const override {
return engineConfiguration->mc33_i_hold;
}
float getPumpPeakCurrent() const override {
return engineConfiguration->mc33_hpfp_i_peak;
}
float getPumpHoldCurrent() const override {
return engineConfiguration->mc33_hpfp_i_hold;
}
// Timings in microseconds
uint16_t getTpeakOff() const override {
return engineConfiguration->mc33_t_peak_off;
}
uint16_t getTpeakTot() const override {
return engineConfiguration->mc33_t_peak_tot;
}
uint16_t getTbypass() const override {
return engineConfiguration->mc33_t_bypass;
}
uint16_t getTholdOff() const override {
return engineConfiguration->mc33_t_hold_off;
}
uint16_t getTHoldTot() const override {
return engineConfiguration->mc33_t_hold_tot;
}
uint16_t getTBoostMin() const override {
return engineConfiguration->mc33_t_min_boost;
}
uint16_t getTBoostMax() const override {
return engineConfiguration->mc33_t_max_boost;
}
uint16_t getPumpTholdOff() const override {
return engineConfiguration->mc33_hpfp_i_hold_off;
}
uint16_t getPumpTholdTot() const override {
return engineConfiguration->mc33_hpfp_max_hold;
}
// Print out an error message
void onError(const char* why) override {
efiPrintf("PT2001 error: %s", why);
}
bool errorOnUnexpectedFlag() override {
efiPrintf("****** unexpected mc33 flag state ******");
return false;
}
void sleepMs(size_t ms) override {
chThdSleepMilliseconds(ms);
}
private:
SPIDriver* driver;
OutputPin resetB;
OutputPin driven;
OutputPin chipSelect;
};
static Pt2001 pt;
/**
* returns true if chip has configuration
*/
bool Pt2001::init() {
//
// see setTest33816EngineConfiguration for default configuration
// Pins
if (!isBrainPinValid(engineConfiguration->mc33816_cs) ||
!isBrainPinValid(engineConfiguration->mc33816_rstb) ||
!isBrainPinValid(engineConfiguration->mc33816_driven)) {
return false;
}
if (isBrainPinValid(engineConfiguration->mc33816_flag0)) {
efiSetPadMode("mc33816 flag0", engineConfiguration->mc33816_flag0, getInputMode(PI_DEFAULT));
}
chipSelect.initPin("mc33 CS", engineConfiguration->mc33816_cs /*, &engineConfiguration->csPinMode*/);
chipSelect.setValue(1);
// Initialize the chip via ResetB
resetB.initPin("mc33 RESTB", engineConfiguration->mc33816_rstb);
// High Voltage via DRIVEN
driven.initPin("mc33 DRIVEN", engineConfiguration->mc33816_driven);
spiCfg.ssport = getHwPort("mc33816", engineConfiguration->mc33816_cs);
spiCfg.sspad = getHwPin("mc33816", engineConfiguration->mc33816_cs);
#if HW_MICRO_RUSEFI
// hard-coded for now, just resolve the conflict with SD card!
engineConfiguration->mc33816spiDevice = SPI_DEVICE_3;
#endif
if (engineConfiguration->mc33816spiDevice == SPI_NONE) {
criticalError("mc33816 needs SPI selection");
}
driver = getSpiDevice(engineConfiguration->mc33816spiDevice);
if (driver == nullptr) {
// error already reported
return false;
}
spiStart(driver, &spiCfg);
efiPrintf("mc33 started SPI");
// addConsoleAction("mc33_stats", showStats);
addConsoleAction("mc33_restart", [](){
pt.initIfNeeded();
});
// todo: too soon to read voltage, it has to fail, right?!
initIfNeeded();
return true;
}
static bool isInitialized = false;
void Pt2001::initIfNeeded() {
if (!isIgnVoltage()) {
isInitialized = false;
efiPrintf("unhappy mc33 due to battery voltage");
} else {
if (!isInitialized) {
isInitialized = restart();
if (isInitialized) {
efiPrintf("happy mc33/PT2001!");
} else {
efiPrintf("unhappy mc33 fault=%d %s", (int)fault, mcFaultToString(fault));
}
}
}
}
static THD_WORKING_AREA(mc33_thread_wa, 256);
static THD_FUNCTION(mc33_driver_thread, p) {
(void)p;
while (true) {
if (!isIgnVoltage()) {
if (isInitialized) {
efiPrintf("Power loss? Would have to re-init mc33/PT2001?");
isInitialized = false;
}
chThdSleepMilliseconds(100);
continue;
}
pt.initIfNeeded();
chThdSleepMilliseconds(100);
}
}
void initMc33816() {
bool isConfigured = pt.init();
if (isConfigured) {
chThdCreateStatic(mc33_thread_wa, sizeof(mc33_thread_wa), PRIO_GPIOCHIP, mc33_driver_thread, nullptr);
}
}
#endif /* EFI_MC33816 */