ardupilot/libraries/AP_ICEngine/AP_ICEngine_TCA9554.cpp

102 lines
2.7 KiB
C++

#include "AP_ICEngine_config.h"
/*
support for TCA9554 for starter control on I2C
*/
#if AP_ICENGINE_TCA9554_STARTER_ENABLED
#include "AP_ICEngine.h"
extern const AP_HAL::HAL& hal;
/*
* TCA9554 output register mapping for PMB Rev E
* P0 = PMU_EN - PMU output ON/OFF (CN6 pin 2)
* P1 = ECU_EN - Unused (previously Engine Kill Switch)
* P2 = I2C_P2 - Unused
* P3 = LED (active low)
* P4 = PMU_START - Crank Direction (CN6 pin 5)
* P5 = PMU_ARM - Crank Signal (CN6 pin 6)
* P6 = PMU_STAT_IN - Unused
* P7 = PMU_STAT - Unused
*/
#define TCA9554_I2C_BUS 1
#define TCA9554_I2C_ADDR 0x20
#define TCA9554_OUTPUT 0x01 // Output Port register address. Outgoing logic levels
#define TCA9554_OUT_DEFAULT 0x30 // 0011 0000
#define TCA9554_CONF 0x03 // Configuration Port register address [0 = Output]
#define TCA9554_PINS 0xC2 // Set all used ports to outputs = 1100 0010
/*
initialise TCA9554
*/
bool AP_ICEngine_TCA9554::TCA9554_init()
{
dev_TCA9554 = std::move(hal.i2c_mgr->get_device(TCA9554_I2C_BUS, TCA9554_I2C_ADDR));
if (!dev_TCA9554) {
return false;
}
WITH_SEMAPHORE(dev_TCA9554->get_semaphore());
// setup 1 checked registers
dev_TCA9554->setup_checked_registers(1);
dev_TCA9554->set_retries(10);
// set outputs
bool ret = dev_TCA9554->write_register(TCA9554_OUTPUT, TCA9554_OUT_DEFAULT);
if (!ret) {
return false;
}
ret = dev_TCA9554->write_register(TCA9554_CONF, TCA9554_PINS, true);
if (!ret) {
return false;
}
dev_TCA9554->set_retries(1);
return true;
}
/*
set the state of the i2c controller
*/
void AP_ICEngine_TCA9554::TCA9554_set(TCA9554_state_t value)
{
const uint32_t now_ms = AP_HAL::millis();
if (now_ms - last_reg_check_ms > 100) {
/*
register checking at 10Hz allows us to cope with the i2c
device being power cycled after boot
*/
last_reg_check_ms = now_ms;
WITH_SEMAPHORE(dev_TCA9554->get_semaphore());
dev_TCA9554->check_next_register();
}
if (value != last_state) {
WITH_SEMAPHORE(dev_TCA9554->get_semaphore());
// set outputs and status leds
if (dev_TCA9554->write_register(TCA9554_OUTPUT, (~(value<<2) & 0x0C) | value)) {
last_state = value;
}
}
}
void AP_ICEngine_TCA9554::set_starter(bool on, bool crank_dir_reverse)
{
if (!initialised) {
initialised = TCA9554_init();
if (!initialised) {
// waiting for power to PMU
return;
}
}
if (!crank_dir_reverse) {
TCA9554_set(on? STARTER_FORWARD : STARTER_OFF);
} else {
TCA9554_set(on? STARTER_REVERSE : STARTER_OFF);
}
}
#endif // AP_ICENGINE_TCA9554_STARTER_ENABLED