gpio: core: support HW PWM on gpiochip outputs

This commit is contained in:
Andrey Gusakov 2024-04-30 16:06:47 +03:00
parent 13b530ca86
commit b6ac22e7d0
3 changed files with 88 additions and 3 deletions

View File

@ -2168,4 +2168,8 @@ enum class ObdCode : uint16_t {
* Commanded fuel exceeds your fuel injector flow
*/
CUSTOM_TOO_LONG_FUEL_INJECTION = 9013,
/**
* GPIO chip errors
*/
CUSTOM_GPIO_CHIP_FAILED_PWM = 9014,
};

View File

@ -28,7 +28,7 @@
/* Local variables and types. */
/*==========================================================================*/
/* TODO: chnage array to list? */
/* TODO: change array to list? */
struct gpiochip {
brain_pin_e base;
size_t size;
@ -40,6 +40,47 @@ struct gpiochip {
static gpiochip chips[BOARD_EXT_GPIOCHIPS];
/* TODO: move inside gpio chip driver? */
class external_hardware_pwm : public hardware_pwm {
public:
bool hasInit() const {
return m_chip != nullptr;
}
int start(const char* msg, gpiochip* chip, size_t pin, float frequency, float duty) {
int ret;
ret = chip->chip->setPadPWM(pin, frequency, duty);
if (ret >= 0) {
m_chip = chip;
m_pin = pin;
m_frequency = frequency;
} else {
/* This is not an error, will fallback to SW PWM */
//firmwareError(ObdCode::CUSTOM_GPIO_CHIP_FAILED_PWM, "Faield to enable PWM mode for chip %s on pin \"%s\"", msg, chip->name, pin);
return -1;
}
return 0;
}
void setDuty(float duty) override {
if (!m_chip) {
criticalError("Attempted to set duty on null external PWM device");
return;
}
m_chip->chip->setPadPWM(m_pin, m_frequency, duty);
}
private:
gpiochip* m_chip = nullptr;
size_t m_pin = 0;
float m_frequency = 0;
};
/* TODO: is 5 enought? */
static external_hardware_pwm extPwms[5];
/*==========================================================================*/
/* Local functions. */
/*==========================================================================*/
@ -59,6 +100,17 @@ static gpiochip *gpiochip_find(brain_pin_e pin)
return nullptr;
}
static external_hardware_pwm* gpiochip_getNextPwmDevice() {
for (size_t i = 0; i < efi::size(extPwms); i++) {
if (!extPwms[i].hasInit()) {
return &extPwms[i];
}
}
criticalError("Run out of gpiochip PWM devices!");
return nullptr;
}
/*==========================================================================*/
/* Exported functions. */
/*==========================================================================*/
@ -276,8 +328,8 @@ int gpiochips_writePad(brain_pin_e pin, int value) {
gpiochip *chip = gpiochip_find(pin);
if (!chip) {
// todo: make readPad fail in a similar way?
criticalError("gpiochip not found for pin %d", pin);
// todo: make readPad fail in a similar way?
criticalError("gpiochip not found for pin %d", pin);
return -108;
}
@ -302,6 +354,33 @@ int gpiochips_readPad(brain_pin_e pin)
return chip->chip->readPad(pin - chip->base);
}
/**
* @brief Try to init PWM on given pin
* @details success of call depends on chip capabilities
* returns nullptr in case there is no chip for given pin
* returns nullptr in case of pin is not PWM capable
* returns nullptr in case all extPwms are already used
* returns hardware_pwm if succes, later user can call ->setDuty to change duty
*/
hardware_pwm* gpiochip_tryInitPwm(const char* msg, brain_pin_e pin, float frequency, float duty)
{
gpiochip *chip = gpiochip_find(pin);
if (!chip) {
return nullptr;
}
/* TODO: implement reintialization of same pin with different settings reusing same external_hardware_pwm */
if (external_hardware_pwm *device = gpiochip_getNextPwmDevice()) {
if (device->start(msg, chip, pin - chip->base, frequency, duty) >= 0) {
return device;
}
}
return nullptr;
}
/**
* @brief Get diagnostic for given gpio
* @details actual output value depend on gpiochip capabilities

View File

@ -27,6 +27,7 @@ struct GpioChip {
virtual int setPadMode(size_t /*pin*/, iomode_t /*mode*/) { return -1; }
virtual int writePad(size_t /*pin*/, int /*value*/) { return -1; }
virtual int readPad(size_t /*pin*/) { return -1; }
virtual int setPadPWM(size_t /*pin*/, float /*frequency*/, float /*duty*/) { return -1; }
virtual brain_pin_diag_e getDiag(size_t /*pin*/) { return PIN_OK; }
virtual int deinit() { return 0; }
@ -54,6 +55,7 @@ int gpiochips_init(void);
int gpiochips_setPadMode(brain_pin_e pin, iomode_t mode);
int gpiochips_writePad(brain_pin_e pin, int value);
int gpiochips_readPad(brain_pin_e pin);
hardware_pwm* gpiochip_tryInitPwm(const char* msg, brain_pin_e pin, float frequency, float duty);
brain_pin_diag_e gpiochips_getDiag(brain_pin_e pin);
/* return total number of external gpios */