[kp18058] fix reported formatting issues

This commit is contained in:
NewoPL 2024-10-30 20:29:48 +01:00
parent dca6fd8407
commit a92a2e0378
5 changed files with 138 additions and 158 deletions

View file

@ -6,9 +6,9 @@ namespace kp18058 {
static const char *const TAG = "kp18058"; static const char *const TAG = "kp18058";
static const uint8_t I2C_MAX_RETRY = 3; static const uint8_t I2C_MAX_RETRY = 3;
#define BIT_CHECK(PIN, N) !!((PIN & (1 << N))) #define BIT_CHECK(PIN, N) !!(((PIN) & (1 << (N))))
uint8_t GetParityBit(uint8_t b) { uint8_t get_parity_bit(uint8_t b) {
uint8_t sum = 0; uint8_t sum = 0;
for (int i = 1; i < 8; i++) { for (int i = 1; i < 8; i++) {
if (BIT_CHECK(b, i)) { if (BIT_CHECK(b, i)) {
@ -18,9 +18,9 @@ uint8_t GetParityBit(uint8_t b) {
return sum % 2; // 0 for even, 1 for odd return sum % 2; // 0 for even, 1 for odd
} }
kp18058::kp18058() : i2c_ready_(false), max_cw_current_(0), max_rgb_current_(0) { kp18058::kp18058() : max_cw_current_(0), max_rgb_current_(0), i2c_ready_(false) {
for (int i = 0; i < 5; ++i) { for (auto &channel : channels_) {
channels_[i] = nullptr; channel = nullptr;
} }
} }
@ -33,13 +33,12 @@ void kp18058::dump_config() {
ESP_LOGCONFIG(TAG, "KP18058 LED Driver:"); ESP_LOGCONFIG(TAG, "KP18058 LED Driver:");
LOG_PIN(" Data Pin: ", i2c_.get_data_pin()); LOG_PIN(" Data Pin: ", i2c_.get_data_pin());
LOG_PIN(" Clock Pin: ", i2c_.get_clock_pin()); LOG_PIN(" Clock Pin: ", i2c_.get_clock_pin());
ESP_LOGCONFIG(TAG, " I2C Communication %s", i2c_ready_ ? "Initialized": "FAILED"); ESP_LOGCONFIG(TAG, " I2C Communication %s", i2c_ready_ ? "Initialized" : "FAILED");
ESP_LOGCONFIG(TAG, " CW max current: %.1f", this->max_cw_current_); ESP_LOGCONFIG(TAG, " CW max current: %.1f", this->max_cw_current_);
ESP_LOGCONFIG(TAG, " RGB max current: %.1f", this->max_rgb_current_); ESP_LOGCONFIG(TAG, " RGB max current: %.1f", this->max_rgb_current_);
} }
void kp18058::program_led_driver() { void kp18058::program_led_driver() {
if (!i2c_ready_) { if (!i2c_ready_) {
ESP_LOGI(TAG, "Reestablishing communication with KP18058."); ESP_LOGI(TAG, "Reestablishing communication with KP18058.");
i2c_ready_ = i2c_.reset(); i2c_ready_ = i2c_.reset();
@ -49,10 +48,10 @@ void kp18058::program_led_driver() {
} }
} }
// returns true if All channels are zero or nullptr // Returns true if all channels are zero or nullptr
auto areAllChannelsZero = [this]() { auto all_channels_zero = [this]() {
for (int i = 0; i < 5; ++i) { for (auto *channel : channels_) {
if (channels_[i] != nullptr && channels_[i]->get_value() > 0) { if (channel != nullptr && channel->get_value() > 0) {
// If any channel is non-zero, return false // If any channel is non-zero, return false
return false; return false;
} }
@ -64,7 +63,7 @@ void kp18058::program_led_driver() {
KP18058_Settings settings{}; KP18058_Settings settings{};
settings.address_identification = 1; settings.address_identification = 1;
settings.working_mode = areAllChannelsZero() ? STANDBY_MODE : RGBCW_MODE; settings.working_mode = all_channels_zero() ? STANDBY_MODE : RGBCW_MODE;
// Set byte address start. valid values are 0 - 13 // Set byte address start. valid values are 0 - 13
// In this message always all bytes are transmited (starting from 0) // In this message always all bytes are transmited (starting from 0)
settings.start_byte_address = 0x00; settings.start_byte_address = 0x00;
@ -76,8 +75,8 @@ void kp18058::program_led_driver() {
settings.rc_filter_enable = RC_FILTER_DISABLE; settings.rc_filter_enable = RC_FILTER_DISABLE;
// Set max current values // Set max current values
settings.max_current_out4_5 = static_cast<uint8_t>(max_cw_current_/2.5) & 0x1F; settings.max_current_out4_5 = static_cast<uint8_t>(max_cw_current_ / 2.5) & 0x1F;
settings.max_current_out1_3 = static_cast<uint8_t>(max_rgb_current_/2.5) & 0x1F; settings.max_current_out1_3 = static_cast<uint8_t>(max_rgb_current_ / 2.5) & 0x1F;
// set dimming method for RGB channels and chop dimming frequency // set dimming method for RGB channels and chop dimming frequency
settings.chop_dimming_out1_3 = ANALOG_DIMMING; settings.chop_dimming_out1_3 = ANALOG_DIMMING;
@ -85,14 +84,14 @@ void kp18058::program_led_driver() {
// Set grayscale values for each output channel // Set grayscale values for each output channel
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
uint16_t useVal = (channels_[i] != nullptr) ? channels_[i]->get_value() : 0; uint16_t use_val = (channels_[i] != nullptr) ? channels_[i]->get_value() : 0;
settings.channels[i].upper_grayscale = (useVal >> 5) & 0x1F; settings.channels[i].upper_grayscale = (use_val >> 5) & 0x1F;
settings.channels[i].lower_grayscale = useVal & 0x1F; settings.channels[i].lower_grayscale = use_val & 0x1F;
} }
// Calculate parity bits for each byte // Calculate parity bits for each byte
for (int i = 0; i < sizeof(KP18058_Settings); ++i) { for (int i = 0; i < sizeof(KP18058_Settings); ++i) {
settings.bytes[i] |= GetParityBit(settings.bytes[i]); settings.bytes[i] |= get_parity_bit(settings.bytes[i]);
} }
// Send the I2C message // Send the I2C message
@ -102,7 +101,8 @@ void kp18058::program_led_driver() {
bool write_succeeded; bool write_succeeded;
for (int attempt = 0; attempt < I2C_MAX_RETRY; attempt++) { for (int attempt = 0; attempt < I2C_MAX_RETRY; attempt++) {
write_succeeded = i2c_.write_byte(settings.bytes[i]); write_succeeded = i2c_.write_byte(settings.bytes[i]);
if (write_succeeded) break; if (write_succeeded)
break;
} }
// if all tries failed break and stop sending the rest of the frame bytes // if all tries failed break and stop sending the rest of the frame bytes
if (!write_succeeded) { if (!write_succeeded) {
@ -112,7 +112,6 @@ void kp18058::program_led_driver() {
} }
} }
i2c_.stop(); i2c_.stop();
return;
} }
} // namespace kp18058 } // namespace kp18058

View file

@ -114,7 +114,6 @@ class kp18058_output : public output::FloatOutput {
// 10-bit grayscale value representing intensity (0-1023) of the output. // 10-bit grayscale value representing intensity (0-1023) of the output.
uint16_t value_; uint16_t value_;
// Pointer to the parent kp18058 driver class for this output channel. // Pointer to the parent kp18058 driver class for this output channel.
kp18058 *parent_; kp18058 *parent_;
}; };

View file

@ -6,24 +6,16 @@ namespace kp18058 {
/** /**
* @brief Enumeration for device working modes. * @brief Enumeration for device working modes.
*/ */
typedef enum { enum WorkingMode { STANDBY_MODE = 0b00, RGB_MODE = 0b01, CW_MODE = 0b10, RGBCW_MODE = 0b11 };
STANDBY_MODE = 0b00,
RGB_MODE = 0b01,
CW_MODE = 0b10,
RGBCW_MODE = 0b11
} WorkingMode;
/** /**
* @brief Enumeration for Line Compensation Mode. * @brief Enumeration for Line Compensation Mode.
* *
* Controls whether line compensation is enabled or disabled. * Controls whether line compensation is enabled or disabled.
* When the input voltage exceeds the voltage threshold * When the input voltage exceeds the voltage threshold
* the Line compensation decreases the current linearly with the defined slope * the Line compensation decreases the current linearly with the defined slope.
*/ */
typedef enum { enum LCMode { LC_DISABLE = 0b0, LC_ENABLE = 0b1 };
LC_DISABLE = 0b0,
LC_ENABLE = 0b1
} LCMode;
/** /**
* @brief Enumeration for Line Compensation Start Threshold. * @brief Enumeration for Line Compensation Start Threshold.
@ -33,119 +25,115 @@ typedef enum {
* - For low thresholds (140V to 175V): Compensation slope parameter is defined for 15V increment. * - For low thresholds (140V to 175V): Compensation slope parameter is defined for 15V increment.
* - For high thresholds (260V to 330V): Compensation slope parameter is defined for 30V increment. * - For high thresholds (260V to 330V): Compensation slope parameter is defined for 30V increment.
*/ */
typedef enum { enum LCThreshold : uint8_t {
// Low voltage thresholds (15V increments) // Low voltage thresholds (15V increments)
LC_THRESHOLD_140V = 0b0000, LC_THRESHOLD_140V = 0b0000,
LC_THRESHOLD_145V = 0b0001, LC_THRESHOLD_145V = 0b0001,
LC_THRESHOLD_150V = 0b0010, LC_THRESHOLD_150V = 0b0010,
LC_THRESHOLD_155V = 0b0011, LC_THRESHOLD_155V = 0b0011,
LC_THRESHOLD_160V = 0b0100, LC_THRESHOLD_160V = 0b0100,
LC_THRESHOLD_165V = 0b0101, LC_THRESHOLD_165V = 0b0101,
LC_THRESHOLD_170V = 0b0110, LC_THRESHOLD_170V = 0b0110,
LC_THRESHOLD_175V = 0b0111, LC_THRESHOLD_175V = 0b0111,
// High voltage thresholds (30V increments) // High voltage thresholds (30V increments)
LC_THRESHOLD_260V = 0b1000, LC_THRESHOLD_260V = 0b1000,
LC_THRESHOLD_270V = 0b1001, LC_THRESHOLD_270V = 0b1001,
LC_THRESHOLD_280V = 0b1010, LC_THRESHOLD_280V = 0b1010,
LC_THRESHOLD_290V = 0b1011, LC_THRESHOLD_290V = 0b1011,
LC_THRESHOLD_300V = 0b1100, LC_THRESHOLD_300V = 0b1100,
LC_THRESHOLD_310V = 0b1101, LC_THRESHOLD_310V = 0b1101,
LC_THRESHOLD_320V = 0b1110, LC_THRESHOLD_320V = 0b1110,
LC_THRESHOLD_330V = 0b1111 LC_THRESHOLD_330V = 0b1111
} LCThreshold; };
/** /**
* @brief Enumeration for Line Compensation Slope Settings * @brief Enumeration for Line Compensation Slope Settings.
* *
* Defines the slope used to decrease the current when line compensation is enabled. * Defines the slope used to decrease the current when line compensation is enabled.
*/ */
typedef enum { enum LCSlope {
LC_SLOPE_7_5_PERCENT = 0b00, /**< current decreases 7.5% */ LC_SLOPE_7_5_PERCENT = 0b00, /**< current decreases 7.5% */
LC_SLOPE_10_PERCENT = 0b01, /**< current decreases 10% */ LC_SLOPE_10_PERCENT = 0b01, /**< current decreases 10% */
LC_SLOPE_12_5_PERCENT = 0b10, /**< current decreases 12.5% */ LC_SLOPE_12_5_PERCENT = 0b10, /**< current decreases 12.5% */
LC_SLOPE_15_PERCENT = 0b11 /**< current decreases 15% */ LC_SLOPE_15_PERCENT = 0b11 /**< current decreases 15% */
} LCSlope; };
/** /**
* #brief Enumeration for RC Filter Settings * @brief Enumeration for RC Filter Settings.
* *
* Controls whether RC filtering is enabled for line compensation calculations. * Controls whether RC filtering is enabled for line compensation calculations.
* When enabled, it takes an average input voltage; otherwise, it uses the instantaneous input value. * When enabled, it takes an average input voltage; otherwise, it uses the instantaneous input value.
*/ */
typedef enum { enum RCFilter { RC_FILTER_ENABLE = 0b0, RC_FILTER_DISABLE = 0b1 };
RC_FILTER_ENABLE = 0b0,
RC_FILTER_DISABLE = 0b1
} RCFilter;
/** /**
* @brief Enumeration for Dimming Modes for RGB Channels (1-3) * @brief Enumeration for Dimming Modes for RGB Channels (1-3).
* *
* Specifies whether analog dimming or chop dimming is used for RGB channels. * Specifies whether analog dimming or chop dimming is used for RGB channels.
*/ */
typedef enum { enum DimmingMode {
ANALOG_DIMMING = 0b0, /**< Analog dimming mode, adjusts LED current amplitude. */ ANALOG_DIMMING = 0b0, /**< Analog dimming mode, adjusts LED current amplitude. */
CHOP_DIMMING = 0b1 /**< Chop dimming mode, adjusts LED current duty cycle. */ CHOP_DIMMING = 0b1 /**< Chop dimming mode, adjusts LED current duty cycle. */
} DimmingMode; };
/** /**
* Enumeration for Chop Dimming Frequency Settings * @brief Enumeration for Chop Dimming Frequency Settings.
* Defines the frequency used for chop dimming mode. */ *
typedef enum { * Defines the frequency used for chop dimming mode.
CD_FREQUENCY_4KHZ = 0b00, */
CD_FREQUENCY_2KHZ = 0b01, enum CDFrequency : uint8_t {
CD_FREQUENCY_1KHZ = 0b10, CD_FREQUENCY_4KHZ = 0b00,
CD_FREQUENCY_500HZ = 0b11 CD_FREQUENCY_2KHZ = 0b01,
} CDFrequency; CD_FREQUENCY_1KHZ = 0b10,
CD_FREQUENCY_500HZ = 0b11
};
#pragma pack(push, 1) #pragma pack(push, 1)
/** /**
* Union representing the structure of the I2C message * @brief Union representing the structure of the I2C message for configuring the KP18058 LED driver settings.
* for configuring the KP18058 LED driver settings.
*/ */
typedef union { typedef union {
// Access the settings as a structure
struct {
// Byte 0
uint8_t byte0_parity_bit : 1;
uint8_t start_byte_address : 4;
WorkingMode working_mode : 2;
uint8_t address_identification : 1;
// Access the settings as a structure // Byte 1
uint8_t byte1_parity_bit : 1;
LCSlope line_comp_slope : 2;
LCThreshold line_comp_threshold : 4;
LCMode line_compensation_enable : 1;
// Byte 2
uint8_t byte2_parity_bit : 1;
uint8_t max_current_out1_3 : 5;
CDFrequency chop_dimming_frequency : 2;
// Byte 3
uint8_t byte3_parity_bit : 1;
uint8_t max_current_out4_5 : 5;
RCFilter rc_filter_enable : 1;
DimmingMode chop_dimming_out1_3 : 1;
// Channel array for OUT1 to OUT5 grayscale data
struct { struct {
// Byte 0 uint8_t upper_parity : 1;
uint8_t byte0_parity_bit : 1; uint8_t upper_grayscale : 5; /**< upper 5 bits of the channel value */
uint8_t start_byte_address : 4; uint8_t upper_reserved : 2;
WorkingMode working_mode : 2;
uint8_t address_identification : 1;
// Byte 1 uint8_t lower_parity : 1;
uint8_t byte1_parity_bit : 1; uint8_t lower_grayscale : 5; /**< lower 5 bits of the channel value */
LCSlope line_comp_slope : 2; uint8_t lower_reserved : 2;
LCThreshold line_comp_threshold : 4; } channels[5];
LCMode line_compensation_enable : 1; };
// Byte 2
uint8_t byte2_parity_bit : 1;
uint8_t max_current_out1_3 : 5;
CDFrequency chop_dimming_frequency : 2;
// Byte 3
uint8_t byte3_parity_bit : 1;
uint8_t max_current_out4_5 : 5;
RCFilter rc_filter_enable : 1;
DimmingMode chop_dimming_out1_3 : 1;
// Channel array for OUT1 to OUT5 grayscale data
struct {
uint8_t upper_parity : 1;
uint8_t upper_grayscale : 5; /**< upper 5 bits of the channel value */
uint8_t upper_reserved : 2;
uint8_t lower_parity : 1;
uint8_t lower_grayscale : 5; /**< lower 5 bits of the channel value */
uint8_t lower_reserved : 2;
} channels[5];
};
// Access the settings as a byte array
uint8_t bytes[14];
// Access the settings as a byte array
uint8_t bytes[14];
} KP18058_Settings; } KP18058_Settings;
#pragma pack(pop) #pragma pack(pop)

View file

@ -45,8 +45,7 @@ bool softI2C::reset() {
} }
bool softI2C::write_byte(uint8_t value) { bool softI2C::write_byte(uint8_t value) {
ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
ns_sleep(SOFT_I2C_CLOCK_TIME/2);
for (uint8_t curr = 0x80; curr != 0; curr >>= 1) { for (uint8_t curr = 0x80; curr != 0; curr >>= 1) {
if (curr & value) { if (curr & value) {
@ -60,7 +59,7 @@ bool softI2C::write_byte(uint8_t value) {
// Data is written to the register on the falling edge of SCL // Data is written to the register on the falling edge of SCL
// it needs to be valid through at least HOLD TIME // it needs to be valid through at least HOLD TIME
// waiting half a cycle assuming it is longer than HOLD_TIME // waiting half a cycle assuming it is longer than HOLD_TIME
ns_sleep(SOFT_I2C_CLOCK_TIME/2); ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
} }
// Every time the transmission of 8bit data (one byte) // Every time the transmission of 8bit data (one byte)
@ -69,9 +68,9 @@ bool softI2C::write_byte(uint8_t value) {
bool ack_received; bool ack_received;
set_high(data_pin_); set_high(data_pin_);
set_high(clock_pin_); set_high(clock_pin_);
ns_sleep(SOFT_I2C_CLOCK_TIME/2); ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
ack_received = !data_pin_->digital_read(); ack_received = !data_pin_->digital_read();
ns_sleep(SOFT_I2C_CLOCK_TIME/2); ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
set_low(clock_pin_); set_low(clock_pin_);
return ack_received; return ack_received;
@ -81,19 +80,18 @@ void softI2C::start() {
set_low(data_pin_); set_low(data_pin_);
// It needs to be valid through at least HOLD TIME // It needs to be valid through at least HOLD TIME
// Waiting half a cycle. Assuming it is longer than HOLD_TIME // Waiting half a cycle. Assuming it is longer than HOLD_TIME
ns_sleep(SOFT_I2C_CLOCK_TIME/2); ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
set_low(clock_pin_); set_low(clock_pin_);
return;
} }
void softI2C::stop() { void softI2C::stop() {
ns_sleep(SOFT_I2C_CLOCK_TIME/2); ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
set_low(data_pin_); set_low(data_pin_);
// It needs to be valid through at least HOLD TIME // It needs to be valid through at least HOLD TIME
// Waiting half a cycle. Assuming it is longer than HOLD_TIME // Waiting half a cycle. Assuming it is longer than HOLD_TIME
ns_sleep(SOFT_I2C_CLOCK_TIME/2); ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
set_high(clock_pin_); set_high(clock_pin_);
ns_sleep(SOFT_I2C_CLOCK_TIME/2); ns_sleep(SOFT_I2C_CLOCK_TIME / 2);
set_high(data_pin_); set_high(data_pin_);
} }

View file

@ -44,14 +44,14 @@ class softI2C {
* *
* @return Pointer to the GPIOPin object for the data line (SDA). * @return Pointer to the GPIOPin object for the data line (SDA).
*/ */
GPIOPin* get_data_pin() const { return data_pin_; } GPIOPin *get_data_pin() const { return data_pin_; }
/** /**
* @brief Gets the clock pin associated with this I2C instance. * @brief Gets the clock pin associated with this I2C instance.
* *
* @return Pointer to the GPIOPin object for the clock line (SCL). * @return Pointer to the GPIOPin object for the clock line (SCL).
*/ */
GPIOPin* get_clock_pin() const { return clock_pin_; } GPIOPin *get_clock_pin() const { return clock_pin_; }
/** /**
* @brief Resets the I2C bus and checks for device readiness. * @brief Resets the I2C bus and checks for device readiness.
@ -94,7 +94,6 @@ class softI2C {
bool write_byte(uint8_t value); bool write_byte(uint8_t value);
private: private:
/** /**
* @brief Sets the specified GPIO pin low. * @brief Sets the specified GPIO pin low.
* *
@ -114,13 +113,10 @@ class softI2C {
* *
* @param pin Pointer to the GPIOPin object representing the pin to set high. * @param pin Pointer to the GPIOPin object representing the pin to set high.
*/ */
void set_high(GPIOPin *pin) { pin->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); }
void set_high(GPIOPin *pin) { GPIOPin *data_pin_; ///< Pointer to the GPIOPin object for the data line (SDA).
pin->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); GPIOPin *clock_pin_; ///< Pointer to the GPIOPin object for the clock line (SCL).
}
GPIOPin *data_pin_; ///< Pointer to the GPIOPin object for the data line (SDA).
GPIOPin *clock_pin_; ///< Pointer to the GPIOPin object for the clock line (SCL).
}; };
} // namespace kp18058 } // namespace kp18058