/** * rgb_led.c * * Low level control of the AWINIC AW2033 RGB LED over I2C. * * Copyright (c) 2022 Bigscreen, Inc. */ #include "asf.h" #include "rgb_led.h" #include RGB_Color_t currently_set_color = {.r = 0, .b = 0, .g = 0}; uint8_t current_dimming_value = 0x80; // Max is 0x80 = full brightness static uint8_t compute_dimmed_color(uint8_t color, uint8_t dim) { uint16_t temp = (uint16_t) color; temp = temp * ((uint16_t)dim); return (uint8_t) (temp >> 7); } void rgb_led_init(I2C_Handle* hi2c) { I2C_Transaction_Request i2ctxn; uint8_t dummy_byte; // Initialize AW2033 chip i2ctxn.cb = NULL; // no callback needed i2ctxn.dev_addr = RGB_LED_I2C_ADDR; i2ctxn.shift = I2C_Unshifted; i2ctxn.len = 1; i2ctxn.data = &dummy_byte; i2c_lock(hi2c); // Apply reset dummy_byte = RGB_RESET_CODE; i2ctxn.internal_addr = RGB_RESET_REG; i2ctxn.ttype = I2C_INT_ADDR_WRITE; i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME); // Enable chip and disable the auto-charge feature dummy_byte = RGB_GCR1_CHIPEN + RGB_GCR1_CHRGDIS; i2ctxn.internal_addr = RGB_GCR1_REG; i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME); // Set global maximum current (30mA) dummy_byte = RGB_GCR2_IMAX_30MA; i2ctxn.internal_addr = RGB_GCR2_REG; i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME); // Enable LED outputs dummy_byte = RGB_LCTR_LED0_EN + RGB_LCTR_LED1_EN + RGB_LCTR_LED2_EN; i2ctxn.internal_addr = RGB_LCTR_REG; i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME); // Set LED0 max current dummy_byte = RGB_LCFGX_CUR_MAX; i2ctxn.internal_addr = RGB_LCFG0_REG; i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME); // Set LED1 max current dummy_byte = RGB_LCFGX_CUR_MAX; i2ctxn.internal_addr = RGB_LCFG1_REG; i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME); // Set LED2 max current dummy_byte = RGB_LCFGX_CUR_MAX; i2ctxn.internal_addr = RGB_LCFG2_REG; i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME); i2c_unlock(hi2c); } static void rgb_led_set_output(I2C_Handle* hi2c, const RGB_Color_t* color) { uint8_t dummy_byte; I2C_Transaction_Request i2ctxn; i2c_lock(hi2c); i2ctxn.cb = NULL; i2ctxn.dev_addr = RGB_LED_I2C_ADDR; i2ctxn.shift = I2C_Unshifted; i2ctxn.len = 1; i2ctxn.data = &dummy_byte; i2ctxn.internal_addr = RGB_PWM0_REG; i2ctxn.ttype = I2C_INT_ADDR_WRITE; dummy_byte = color->r; i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME); // For some reason red doesn't play nice. Do it again i2ctxn.internal_addr = RGB_PWM0_REG; dummy_byte = color->r; i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME); // Third time's the charm? i2ctxn.internal_addr = RGB_PWM0_REG; dummy_byte = color->r; i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME); i2ctxn.internal_addr = RGB_PWM1_REG; dummy_byte = color->g; i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME); i2ctxn.internal_addr = RGB_PWM2_REG; dummy_byte = color->b; i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME); i2c_unlock(hi2c); } void rgb_led_set_color(I2C_Handle* hi2c, const RGB_Color_t* color) { memcpy(¤tly_set_color, color, sizeof(RGB_Color_t)); rgb_led_set_dimming(hi2c, current_dimming_value); } void rgb_led_set_dimming(I2C_Handle* hi2c, uint8_t dimval) { if(dimval > 0x80) dimval = 0x80; // maximum at 0x80 = full brightness current_dimming_value = dimval; RGB_Color_t temp_color; #if 1 temp_color.r = compute_dimmed_color(currently_set_color.r, dimval); temp_color.g = compute_dimmed_color(currently_set_color.g, dimval); temp_color.b = compute_dimmed_color(currently_set_color.b, dimval); #else temp_color.r = 0xFF; temp_color.g = 0x00; temp_color.b = 0xFF; #endif rgb_led_set_output(hi2c, &temp_color); }