diff options
author | Nick Brassel <[email protected]> | 2023-08-29 21:24:43 +1000 |
---|---|---|
committer | Nick Brassel <[email protected]> | 2023-08-29 21:24:43 +1000 |
commit | 31a91add168c956655ace8ec4cf9750db1e2cfc6 (patch) | |
tree | 12cea9b5f8e769f9611a31cbaede9537edad71cc /drivers | |
parent | f07490bc092e365ba03dc685b3fc30ad0bf0b752 (diff) | |
parent | edaf8a87ef3164f8986b0a8eb171d4879b45414c (diff) | |
download | qmk_firmware-31a91add168c956655ace8ec4cf9750db1e2cfc6.tar.gz qmk_firmware-31a91add168c956655ace8ec4cf9750db1e2cfc6.zip |
Merge branch 'develop'0.22.0
Diffstat (limited to 'drivers')
33 files changed, 1014 insertions, 951 deletions
diff --git a/drivers/backlight/backlight_software.c b/drivers/backlight/backlight_software.c new file mode 100644 index 0000000000..f2af3e918e --- /dev/null +++ b/drivers/backlight/backlight_software.c @@ -0,0 +1,54 @@ +#include "backlight.h" +#include "backlight_driver_common.h" +#include "util.h" + +#ifdef BACKLIGHT_BREATHING +# error "Backlight breathing is not available for software PWM. Please disable." +#endif + +static uint16_t s_duty_pattern = 0; + +// clang-format off + +/** \brief PWM duty patterns + * + * We scale the current backlight level to an index within this array. This allows + * backlight_task to focus on just switching LEDs on/off, and we can predict the duty pattern + */ +static const uint16_t backlight_duty_table[] = { + 0b0000000000000000, + 0b1000000000000000, + 0b1000000010000000, + 0b1000001000010000, + 0b1000100010001000, + 0b1001001001001000, + 0b1010101010101010, + 0b1110111011101110, + 0b1111111111111111, +}; +#define backlight_duty_table_size ARRAY_SIZE(backlight_duty_table) + +// clang-format on + +static uint8_t scale_backlight(uint8_t v) { + return v * (backlight_duty_table_size - 1) / BACKLIGHT_LEVELS; +} + +void backlight_init_ports(void) { + backlight_pins_init(); +} + +void backlight_set(uint8_t level) { + s_duty_pattern = backlight_duty_table[scale_backlight(level)]; +} + +void backlight_task(void) { + static uint8_t backlight_tick = 0; + + if (s_duty_pattern & ((uint16_t)1 << backlight_tick)) { + backlight_pins_on(); + } else { + backlight_pins_off(); + } + backlight_tick = (backlight_tick + 1) % 16; +} diff --git a/drivers/haptic/DRV2605L.c b/drivers/haptic/DRV2605L.c deleted file mode 100644 index 5a1d2ca0af..0000000000 --- a/drivers/haptic/DRV2605L.c +++ /dev/null @@ -1,122 +0,0 @@ -/* Copyright 2018 ishtob - * Driver for DRV2605L written for QMK - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "DRV2605L.h" -#include "print.h" -#include <stdlib.h> -#include <stdio.h> -#include <math.h> - -uint8_t DRV2605L_transfer_buffer[2]; -uint8_t DRV2605L_read_register; - -void DRV_write(uint8_t drv_register, uint8_t settings) { - DRV2605L_transfer_buffer[0] = drv_register; - DRV2605L_transfer_buffer[1] = settings; - i2c_transmit(DRV2605L_BASE_ADDRESS << 1, DRV2605L_transfer_buffer, 2, 100); -} - -uint8_t DRV_read(uint8_t regaddress) { - i2c_readReg(DRV2605L_BASE_ADDRESS << 1, regaddress, &DRV2605L_read_register, 1, 100); - - return DRV2605L_read_register; -} - -void DRV_init(void) { - i2c_init(); - /* 0x07 sets DRV2605 into calibration mode */ - DRV_write(DRV_MODE, 0x07); - - // DRV_write(DRV_FEEDBACK_CTRL,0xB6); - -#if FB_ERM_LRA == 0 - /* ERM settings */ - DRV_write(DRV_RATED_VOLT, (RATED_VOLTAGE / 21.33) * 1000); -# if ERM_OPEN_LOOP == 0 - DRV_write(DRV_OVERDRIVE_CLAMP_VOLT, (((V_PEAK * (DRIVE_TIME + BLANKING_TIME + IDISS_TIME)) / 0.02133) / (DRIVE_TIME - 0.0003))); -# elif ERM_OPEN_LOOP == 1 - DRV_write(DRV_OVERDRIVE_CLAMP_VOLT, (V_PEAK / 0.02196)); -# endif -#elif FB_ERM_LRA == 1 - DRV_write(DRV_RATED_VOLT, ((V_RMS * sqrt(1 - ((4 * ((150 + (SAMPLE_TIME * 50)) * 0.000001)) + 0.0003) * F_LRA) / 0.02071))); -# if LRA_OPEN_LOOP == 0 - DRV_write(DRV_OVERDRIVE_CLAMP_VOLT, ((V_PEAK / sqrt(1 - (F_LRA * 0.0008)) / 0.02133))); -# elif LRA_OPEN_LOOP == 1 - DRV_write(DRV_OVERDRIVE_CLAMP_VOLT, (V_PEAK / 0.02196)); -# endif -#endif - - DRVREG_FBR FB_SET; - FB_SET.Bits.ERM_LRA = FB_ERM_LRA; - FB_SET.Bits.BRAKE_FACTOR = FB_BRAKEFACTOR; - FB_SET.Bits.LOOP_GAIN = FB_LOOPGAIN; - FB_SET.Bits.BEMF_GAIN = 0; /* auto-calibration populates this field*/ - DRV_write(DRV_FEEDBACK_CTRL, (uint8_t)FB_SET.Byte); - DRVREG_CTRL1 C1_SET; - C1_SET.Bits.C1_DRIVE_TIME = DRIVE_TIME; - C1_SET.Bits.C1_AC_COUPLE = AC_COUPLE; - C1_SET.Bits.C1_STARTUP_BOOST = STARTUP_BOOST; - DRV_write(DRV_CTRL_1, (uint8_t)C1_SET.Byte); - DRVREG_CTRL2 C2_SET; - C2_SET.Bits.C2_BIDIR_INPUT = BIDIR_INPUT; - C2_SET.Bits.C2_BRAKE_STAB = BRAKE_STAB; - C2_SET.Bits.C2_SAMPLE_TIME = SAMPLE_TIME; - C2_SET.Bits.C2_BLANKING_TIME = BLANKING_TIME; - C2_SET.Bits.C2_IDISS_TIME = IDISS_TIME; - DRV_write(DRV_CTRL_2, (uint8_t)C2_SET.Byte); - DRVREG_CTRL3 C3_SET; - C3_SET.Bits.C3_LRA_OPEN_LOOP = LRA_OPEN_LOOP; - C3_SET.Bits.C3_N_PWM_ANALOG = N_PWM_ANALOG; - C3_SET.Bits.C3_LRA_DRIVE_MODE = LRA_DRIVE_MODE; - C3_SET.Bits.C3_DATA_FORMAT_RTO = DATA_FORMAT_RTO; - C3_SET.Bits.C3_SUPPLY_COMP_DIS = SUPPLY_COMP_DIS; - C3_SET.Bits.C3_ERM_OPEN_LOOP = ERM_OPEN_LOOP; - C3_SET.Bits.C3_NG_THRESH = NG_THRESH; - DRV_write(DRV_CTRL_3, (uint8_t)C3_SET.Byte); - DRVREG_CTRL4 C4_SET; - C4_SET.Bits.C4_ZC_DET_TIME = ZC_DET_TIME; - C4_SET.Bits.C4_AUTO_CAL_TIME = AUTO_CAL_TIME; - DRV_write(DRV_CTRL_4, (uint8_t)C4_SET.Byte); - DRV_write(DRV_LIB_SELECTION, LIB_SELECTION); - - DRV_write(DRV_GO, 0x01); - - /* 0x00 sets DRV2605 out of standby and to use internal trigger - * 0x01 sets DRV2605 out of standby and to use external trigger */ - DRV_write(DRV_MODE, 0x00); - - // Play greeting sequence - DRV_write(DRV_GO, 0x00); - DRV_write(DRV_WAVEFORM_SEQ_1, DRV_GREETING); - DRV_write(DRV_GO, 0x01); -} - -void DRV_rtp_init(void) { - DRV_write(DRV_GO, 0x00); - DRV_write(DRV_RTP_INPUT, 20); // 20 is the lowest value I've found where haptics can still be felt. - DRV_write(DRV_MODE, 0x05); - DRV_write(DRV_GO, 0x01); -} - -void DRV_amplitude(uint8_t amplitude) { - DRV_write(DRV_RTP_INPUT, amplitude); -} - -void DRV_pulse(uint8_t sequence) { - DRV_write(DRV_GO, 0x00); - DRV_write(DRV_WAVEFORM_SEQ_1, sequence); - DRV_write(DRV_GO, 0x01); -} diff --git a/drivers/haptic/DRV2605L.h b/drivers/haptic/DRV2605L.h deleted file mode 100644 index 8b8eae38b8..0000000000 --- a/drivers/haptic/DRV2605L.h +++ /dev/null @@ -1,406 +0,0 @@ -/* Copyright 2018 ishtob - * Driver for DRV2605L written for QMK - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once -#include "i2c_master.h" - -/* Initialization settings - - * Feedback Control Settings */ -#ifndef FB_ERM_LRA -# define FB_ERM_LRA 1 /* For ERM:0 or LRA:1*/ -#endif -#ifndef FB_BRAKEFACTOR -# define FB_BRAKEFACTOR 3 /* For 1x:0, 2x:1, 3x:2, 4x:3, 6x:4, 8x:5, 16x:6, Disable Braking:7 */ -#endif -#ifndef FB_LOOPGAIN -# define FB_LOOPGAIN 1 /* For Low:0, Medium:1, High:2, Very High:3 */ -#endif - -/* LRA specific settings */ -#if FB_ERM_LRA == 1 -# ifndef V_RMS -# define V_RMS 2.0 -# endif -# ifndef V_PEAK -# define V_PEAK 2.1 -# endif -# ifndef F_LRA -# define F_LRA 205 -# endif -# ifndef RATED_VOLTAGE -# define RATED_VOLTAGE 2 /* 2v as safe range in case device voltage is not set */ -# endif -#endif - -#ifndef RATED_VOLTAGE -# define RATED_VOLTAGE 2 /* 2v as safe range in case device voltage is not set */ -#endif -#ifndef V_PEAK -# define V_PEAK 2.8 -#endif - -/* Library Selection */ -#ifndef LIB_SELECTION -# if FB_ERM_LRA == 1 -# define LIB_SELECTION 6 /* For Empty:0' TS2200 library A to D:1-5, LRA Library: 6 */ -# else -# define LIB_SELECTION 1 -# endif -#endif - -#ifndef DRV_GREETING -# define DRV_GREETING alert_750ms -#endif -#ifndef DRV_MODE_DEFAULT -# define DRV_MODE_DEFAULT strong_click1 -#endif - -/* Control 1 register settings */ -#ifndef DRIVE_TIME -# define DRIVE_TIME 25 -#endif -#ifndef AC_COUPLE -# define AC_COUPLE 0 -#endif -#ifndef STARTUP_BOOST -# define STARTUP_BOOST 1 -#endif - -/* Control 2 Settings */ -#ifndef BIDIR_INPUT -# define BIDIR_INPUT 1 -#endif -#ifndef BRAKE_STAB -# define BRAKE_STAB 1 /* Loopgain is reduced when braking is almost complete to improve stability */ -#endif -#ifndef SAMPLE_TIME -# define SAMPLE_TIME 3 -#endif -#ifndef BLANKING_TIME -# define BLANKING_TIME 1 -#endif -#ifndef IDISS_TIME -# define IDISS_TIME 1 -#endif - -/* Control 3 settings */ -#ifndef NG_THRESH -# define NG_THRESH 2 -#endif -#ifndef ERM_OPEN_LOOP -# define ERM_OPEN_LOOP 1 -#endif -#ifndef SUPPLY_COMP_DIS -# define SUPPLY_COMP_DIS 0 -#endif -#ifndef DATA_FORMAT_RTO -# define DATA_FORMAT_RTO 0 -#endif -#ifndef LRA_DRIVE_MODE -# define LRA_DRIVE_MODE 0 -#endif -#ifndef N_PWM_ANALOG -# define N_PWM_ANALOG 0 -#endif -#ifndef LRA_OPEN_LOOP -# define LRA_OPEN_LOOP 0 -#endif - -/* Control 4 settings */ -#ifndef ZC_DET_TIME -# define ZC_DET_TIME 0 -#endif -#ifndef AUTO_CAL_TIME -# define AUTO_CAL_TIME 3 -#endif - -/* register defines -------------------------------------------------------- */ -#define DRV2605L_BASE_ADDRESS 0x5A /* DRV2605L Base address */ -#define DRV_STATUS 0x00 -#define DRV_MODE 0x01 -#define DRV_RTP_INPUT 0x02 -#define DRV_LIB_SELECTION 0x03 -#define DRV_WAVEFORM_SEQ_1 0x04 -#define DRV_WAVEFORM_SEQ_2 0x05 -#define DRV_WAVEFORM_SEQ_3 0x06 -#define DRV_WAVEFORM_SEQ_4 0x07 -#define DRV_WAVEFORM_SEQ_5 0x08 -#define DRV_WAVEFORM_SEQ_6 0x09 -#define DRV_WAVEFORM_SEQ_7 0x0A -#define DRV_WAVEFORM_SEQ_8 0x0B -#define DRV_GO 0x0C -#define DRV_OVERDRIVE_TIME_OFFSET 0x0D -#define DRV_SUSTAIN_TIME_OFFSET_P 0x0E -#define DRV_SUSTAIN_TIME_OFFSET_N 0x0F -#define DRV_BRAKE_TIME_OFFSET 0x10 -#define DRV_AUDIO_2_VIBE_CTRL 0x11 -#define DRV_AUDIO_2_VIBE_MIN_IN 0x12 -#define DRV_AUDIO_2_VIBE_MAX_IN 0x13 -#define DRV_AUDIO_2_VIBE_MIN_OUTDRV 0x14 -#define DRV_AUDIO_2_VIBE_MAX_OUTDRV 0x15 -#define DRV_RATED_VOLT 0x16 -#define DRV_OVERDRIVE_CLAMP_VOLT 0x17 -#define DRV_AUTO_CALIB_COMP_RESULT 0x18 -#define DRV_AUTO_CALIB_BEMF_RESULT 0x19 -#define DRV_FEEDBACK_CTRL 0x1A -#define DRV_CTRL_1 0x1B -#define DRV_CTRL_2 0x1C -#define DRV_CTRL_3 0x1D -#define DRV_CTRL_4 0x1E -#define DRV_CTRL_5 0x1F -#define DRV_OPEN_LOOP_PERIOD 0x20 -#define DRV_VBAT_VOLT_MONITOR 0x21 -#define DRV_LRA_RESONANCE_PERIOD 0x22 - -void DRV_init(void); -void DRV_write(const uint8_t drv_register, const uint8_t settings); -uint8_t DRV_read(const uint8_t regaddress); -void DRV_rtp_init(void); -void DRV_amplitude(const uint8_t amplitude); -void DRV_pulse(const uint8_t sequence); - -typedef enum DRV_EFFECT { - clear_sequence = 0, - strong_click = 1, - strong_click_60 = 2, - strong_click_30 = 3, - sharp_click = 4, - sharp_click_60 = 5, - sharp_click_30 = 6, - soft_bump = 7, - soft_bump_60 = 8, - soft_bump_30 = 9, - dbl_click = 10, - dbl_click_60 = 11, - trp_click = 12, - soft_fuzz = 13, - strong_buzz = 14, - alert_750ms = 15, - alert_1000ms = 16, - strong_click1 = 17, - strong_click2_80 = 18, - strong_click3_60 = 19, - strong_click4_30 = 20, - medium_click1 = 21, - medium_click2_80 = 22, - medium_click3_60 = 23, - sharp_tick1 = 24, - sharp_tick2_80 = 25, - sharp_tick3_60 = 26, - sh_dblclick_str = 27, - sh_dblclick_str_80 = 28, - sh_dblclick_str_60 = 29, - sh_dblclick_str_30 = 30, - sh_dblclick_med = 31, - sh_dblclick_med_80 = 32, - sh_dblclick_med_60 = 33, - sh_dblsharp_tick = 34, - sh_dblsharp_tick_80 = 35, - sh_dblsharp_tick_60 = 36, - lg_dblclick_str = 37, - lg_dblclick_str_80 = 38, - lg_dblclick_str_60 = 39, - lg_dblclick_str_30 = 40, - lg_dblclick_med = 41, - lg_dblclick_med_80 = 42, - lg_dblclick_med_60 = 43, - lg_dblsharp_tick = 44, - lg_dblsharp_tick_80 = 45, - lg_dblsharp_tick_60 = 46, - buzz = 47, - buzz_80 = 48, - buzz_60 = 49, - buzz_40 = 50, - buzz_20 = 51, - pulsing_strong = 52, - pulsing_strong_80 = 53, - pulsing_medium = 54, - pulsing_medium_80 = 55, - pulsing_sharp = 56, - pulsing_sharp_80 = 57, - transition_click = 58, - transition_click_80 = 59, - transition_click_60 = 60, - transition_click_40 = 61, - transition_click_20 = 62, - transition_click_10 = 63, - transition_hum = 64, - transition_hum_80 = 65, - transition_hum_60 = 66, - transition_hum_40 = 67, - transition_hum_20 = 68, - transition_hum_10 = 69, - transition_rampdown_long_smooth1 = 70, - transition_rampdown_long_smooth2 = 71, - transition_rampdown_med_smooth1 = 72, - transition_rampdown_med_smooth2 = 73, - transition_rampdown_short_smooth1 = 74, - transition_rampdown_short_smooth2 = 75, - transition_rampdown_long_sharp1 = 76, - transition_rampdown_long_sharp2 = 77, - transition_rampdown_med_sharp1 = 78, - transition_rampdown_med_sharp2 = 79, - transition_rampdown_short_sharp1 = 80, - transition_rampdown_short_sharp2 = 81, - transition_rampup_long_smooth1 = 82, - transition_rampup_long_smooth2 = 83, - transition_rampup_med_smooth1 = 84, - transition_rampup_med_smooth2 = 85, - transition_rampup_short_smooth1 = 86, - transition_rampup_short_smooth2 = 87, - transition_rampup_long_sharp1 = 88, - transition_rampup_long_sharp2 = 89, - transition_rampup_med_sharp1 = 90, - transition_rampup_med_sharp2 = 91, - transition_rampup_short_sharp1 = 92, - transition_rampup_short_sharp2 = 93, - transition_rampdown_long_smooth1_50 = 94, - transition_rampdown_long_smooth2_50 = 95, - transition_rampdown_med_smooth1_50 = 96, - transition_rampdown_med_smooth2_50 = 97, - transition_rampdown_short_smooth1_50 = 98, - transition_rampdown_short_smooth2_50 = 99, - transition_rampdown_long_sharp1_50 = 100, - transition_rampdown_long_sharp2_50 = 101, - transition_rampdown_med_sharp1_50 = 102, - transition_rampdown_med_sharp2_50 = 103, - transition_rampdown_short_sharp1_50 = 104, - transition_rampdown_short_sharp2_50 = 105, - transition_rampup_long_smooth1_50 = 106, - transition_rampup_long_smooth2_50 = 107, - transition_rampup_med_smooth1_50 = 108, - transition_rampup_med_smooth2_50 = 109, - transition_rampup_short_smooth1_50 = 110, - transition_rampup_short_smooth2_50 = 111, - transition_rampup_long_sharp1_50 = 112, - transition_rampup_long_sharp2_50 = 113, - transition_rampup_med_sharp1_50 = 114, - transition_rampup_med_sharp2_50 = 115, - transition_rampup_short_sharp1_50 = 116, - transition_rampup_short_sharp2_50 = 117, - long_buzz_for_programmatic_stopping = 118, - smooth_hum1_50 = 119, - smooth_hum2_40 = 120, - smooth_hum3_30 = 121, - smooth_hum4_20 = 122, - smooth_hum5_10 = 123, - drv_effect_max = 124, -} DRV_EFFECT; - -/* Register bit array unions */ - -typedef union DRVREG_STATUS { /* register 0x00 */ - uint8_t Byte; - struct { - uint8_t OC_DETECT : 1; /* set to 1 when overcurrent event is detected */ - uint8_t OVER_TEMP : 1; /* set to 1 when device exceeds temp threshold */ - uint8_t FB_STS : 1; /* set to 1 when feedback controller has timed out */ - /* auto-calibration routine and diagnostic result - * result | auto-calibation | diagnostic | - * 0 | passed | actuator func normal | - * 1 | failed | actuator func fault* | - * * actuator is not present or is shorted, timing out, or giving out–of-range back-EMF */ - uint8_t DIAG_RESULT : 1; - uint8_t : 1; - uint8_t DEVICE_ID : 3; /* Device IDs 3: DRV2605 4: DRV2604 5: DRV2604L 6: DRV2605L */ - } Bits; -} DRVREG_STATUS; - -typedef union DRVREG_MODE { /* register 0x01 */ - uint8_t Byte; - struct { - uint8_t MODE : 3; /* Mode setting */ - uint8_t : 3; - uint8_t STANDBY : 1; /* 0:standby 1:ready */ - } Bits; -} DRVREG_MODE; - -typedef union DRVREG_WAIT { - uint8_t Byte; - struct { - uint8_t WAIT_MODE : 1; /* Set to 1 to interpret as wait for next 7 bits x10ms */ - uint8_t WAIT_TIME : 7; - } Bits; -} DRVREG_WAIT; - -typedef union DRVREG_FBR { /* register 0x1A */ - uint8_t Byte; - struct { - uint8_t BEMF_GAIN : 2; - uint8_t LOOP_GAIN : 2; - uint8_t BRAKE_FACTOR : 3; - uint8_t ERM_LRA : 1; - } Bits; -} DRVREG_FBR; - -typedef union DRVREG_CTRL1 { /* register 0x1B */ - uint8_t Byte; - struct { - uint8_t C1_DRIVE_TIME : 5; - uint8_t C1_AC_COUPLE : 1; - uint8_t : 1; - uint8_t C1_STARTUP_BOOST : 1; - } Bits; -} DRVREG_CTRL1; - -typedef union DRVREG_CTRL2 { /* register 0x1C */ - uint8_t Byte; - struct { - uint8_t C2_IDISS_TIME : 2; - uint8_t C2_BLANKING_TIME : 2; - uint8_t C2_SAMPLE_TIME : 2; - uint8_t C2_BRAKE_STAB : 1; - uint8_t C2_BIDIR_INPUT : 1; - } Bits; -} DRVREG_CTRL2; - -typedef union DRVREG_CTRL3 { /* register 0x1D */ - uint8_t Byte; - struct { - uint8_t C3_LRA_OPEN_LOOP : 1; - uint8_t C3_N_PWM_ANALOG : 1; - uint8_t C3_LRA_DRIVE_MODE : 1; - uint8_t C3_DATA_FORMAT_RTO : 1; - uint8_t C3_SUPPLY_COMP_DIS : 1; - uint8_t C3_ERM_OPEN_LOOP : 1; - uint8_t C3_NG_THRESH : 2; - } Bits; -} DRVREG_CTRL3; - -typedef union DRVREG_CTRL4 { /* register 0x1E */ - uint8_t Byte; - struct { - uint8_t C4_OTP_PROGRAM : 1; - uint8_t : 1; - uint8_t C4_OTP_STATUS : 1; - uint8_t : 1; - uint8_t C4_AUTO_CAL_TIME : 2; - uint8_t C4_ZC_DET_TIME : 2; - } Bits; -} DRVREG_CTRL4; - -typedef union DRVREG_CTRL5 { /* register 0x1F */ - uint8_t Byte; - struct { - uint8_t C5_IDISS_TIME : 2; - uint8_t C5_BLANKING_TIME : 2; - uint8_t C5_PLAYBACK_INTERVAL : 1; - uint8_t C5_LRA_AUTO_OPEN_LOOP : 1; - uint8_t C5_AUTO_OL_CNT : 2; - } Bits; -} DRVREG_CTRL5; diff --git a/drivers/haptic/drv2605l.c b/drivers/haptic/drv2605l.c new file mode 100644 index 0000000000..1ad2ad385f --- /dev/null +++ b/drivers/haptic/drv2605l.c @@ -0,0 +1,126 @@ +/* Copyright 2018 ishtob + * Driver for DRV2605L written for QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "drv2605l.h" +#include "i2c_master.h" +#include <math.h> + +uint8_t drv2605l_write_buffer[2]; +uint8_t drv2605l_read_buffer; + +void drv2605l_write(uint8_t reg_addr, uint8_t data) { + drv2605l_write_buffer[0] = reg_addr; + drv2605l_write_buffer[1] = data; + i2c_transmit(DRV2605L_I2C_ADDRESS << 1, drv2605l_write_buffer, 2, 100); +} + +uint8_t drv2605l_read(uint8_t reg_addr) { + i2c_readReg(DRV2605L_I2C_ADDRESS << 1, reg_addr, &drv2605l_read_buffer, 1, 100); + + return drv2605l_read_buffer; +} + +void drv2605l_init(void) { + i2c_init(); + /* 0x07 sets DRV2605 into calibration mode */ + drv2605l_write(DRV2605L_REG_MODE, 0x07); + + // drv2605l_write(DRV2605L_REG_FEEDBACK_CTRL,0xB6); + +#if DRV2605L_FB_ERM_LRA == 0 + /* ERM settings */ + drv2605l_write(DRV2605L_REG_RATED_VOLTAGE, (DRV2605L_RATED_VOLTAGE / 21.33) * 1000); +# if DRV2605L_ERM_OPEN_LOOP == 0 + drv2605l_write(DRV2605L_REG_OVERDRIVE_CLAMP_VOLTAGE, (((DRV2605L_V_PEAK * (DRV2605L_DRIVE_TIME + DRV2605L_BLANKING_TIME + DRV2605L_IDISS_TIME)) / 0.02133) / (DRV2605L_DRIVE_TIME - 0.0003))); +# elif DRV2605L_ERM_OPEN_LOOP == 1 + drv2605l_write(DRV2605L_REG_OVERDRIVE_CLAMP_VOLTAGE, (DRV2605L_V_PEAK / 0.02196)); +# endif +#elif DRV2605L_FB_ERM_LRA == 1 + drv2605l_write(DRV2605L_REG_RATED_VOLTAGE, ((DRV2605L_V_RMS * sqrt(1 - ((4 * ((150 + (DRV2605L_SAMPLE_TIME * 50)) * 0.000001)) + 0.0003) * DRV2605L_F_LRA) / 0.02071))); +# if DRV2605L_LRA_OPEN_LOOP == 0 + drv2605l_write(DRV2605L_REG_OVERDRIVE_CLAMP_VOLTAGE, ((DRV2605L_V_PEAK / sqrt(1 - (DRV2605L_F_LRA * 0.0008)) / 0.02133))); +# elif DRV2605L_LRA_OPEN_LOOP == 1 + drv2605l_write(DRV2605L_REG_OVERDRIVE_CLAMP_VOLTAGE, (DRV2605L_V_PEAK / 0.02196)); +# endif +#endif + + drv2605l_reg_feedback_ctrl_t reg_feedback_ctrl; + reg_feedback_ctrl.bits.ERM_LRA = DRV2605L_FB_ERM_LRA; + reg_feedback_ctrl.bits.BRAKE_FACTOR = DRV2605L_FB_BRAKEFACTOR; + reg_feedback_ctrl.bits.LOOP_GAIN = DRV2605L_FB_LOOPGAIN; + reg_feedback_ctrl.bits.BEMF_GAIN = 0; /* auto-calibration populates this field*/ + drv2605l_write(DRV2605L_REG_FEEDBACK_CTRL, (uint8_t)reg_feedback_ctrl.raw); + + drv2605l_reg_ctrl1_t reg_ctrl1; + reg_ctrl1.bits.C1_DRIVE_TIME = DRV2605L_DRIVE_TIME; + reg_ctrl1.bits.C1_AC_COUPLE = DRV2605L_AC_COUPLE; + reg_ctrl1.bits.C1_STARTUP_BOOST = DRV2605L_STARTUP_BOOST; + drv2605l_write(DRV2605L_REG_CTRL1, (uint8_t)reg_ctrl1.raw); + + drv2605l_reg_ctrl2_t reg_ctrl2; + reg_ctrl2.bits.C2_BIDIR_INPUT = DRV2605L_BIDIR_INPUT; + reg_ctrl2.bits.C2_BRAKE_STAB = DRV2605L_BRAKE_STAB; + reg_ctrl2.bits.C2_SAMPLE_TIME = DRV2605L_SAMPLE_TIME; + reg_ctrl2.bits.C2_BLANKING_TIME = DRV2605L_BLANKING_TIME; + reg_ctrl2.bits.C2_IDISS_TIME = DRV2605L_IDISS_TIME; + drv2605l_write(DRV2605L_REG_CTRL2, (uint8_t)reg_ctrl2.raw); + + drv2605l_reg_ctrl3_t reg_ctrl3; + reg_ctrl3.bits.C3_LRA_OPEN_LOOP = DRV2605L_LRA_OPEN_LOOP; + reg_ctrl3.bits.C3_N_PWM_ANALOG = DRV2605L_N_PWM_ANALOG; + reg_ctrl3.bits.C3_LRA_DRIVE_MODE = DRV2605L_LRA_DRIVE_MODE; + reg_ctrl3.bits.C3_DATA_FORMAT_RTO = DRV2605L_DATA_FORMAT_RTO; + reg_ctrl3.bits.C3_SUPPLY_COMP_DIS = DRV2605L_SUPPLY_COMP_DIS; + reg_ctrl3.bits.C3_ERM_OPEN_LOOP = DRV2605L_ERM_OPEN_LOOP; + reg_ctrl3.bits.C3_NG_THRESH = DRV2605L_NG_THRESH; + drv2605l_write(DRV2605L_REG_CTRL3, (uint8_t)reg_ctrl3.raw); + + drv2605l_reg_ctrl4_t reg_ctrl4; + reg_ctrl4.bits.C4_ZC_DET_TIME = DRV2605L_ZC_DET_TIME; + reg_ctrl4.bits.C4_AUTO_CAL_TIME = DRV2605L_AUTO_CAL_TIME; + drv2605l_write(DRV2605L_REG_CTRL4, (uint8_t)reg_ctrl4.raw); + + drv2605l_write(DRV2605L_REG_LIBRARY_SELECTION, DRV2605L_LIBRARY); + + drv2605l_write(DRV2605L_REG_GO, 0x01); + + /* 0x00 sets DRV2605 out of standby and to use internal trigger + * 0x01 sets DRV2605 out of standby and to use external trigger */ + drv2605l_write(DRV2605L_REG_MODE, 0x00); + + // Play greeting sequence + drv2605l_write(DRV2605L_REG_GO, 0x00); + drv2605l_write(DRV2605L_REG_WAVEFORM_SEQUENCER_1, DRV2605L_GREETING); + drv2605l_write(DRV2605L_REG_GO, 0x01); +} + +void drv2605l_rtp_init(void) { + drv2605l_write(DRV2605L_REG_GO, 0x00); + drv2605l_write(DRV2605L_REG_RTP_INPUT, 20); // 20 is the lowest value I've found where haptics can still be felt. + drv2605l_write(DRV2605L_REG_MODE, 0x05); + drv2605l_write(DRV2605L_REG_GO, 0x01); +} + +void drv2605l_amplitude(uint8_t amplitude) { + drv2605l_write(DRV2605L_REG_RTP_INPUT, amplitude); +} + +void drv2605l_pulse(uint8_t sequence) { + drv2605l_write(DRV2605L_REG_GO, 0x00); + drv2605l_write(DRV2605L_REG_WAVEFORM_SEQUENCER_1, sequence); + drv2605l_write(DRV2605L_REG_GO, 0x01); +} diff --git a/drivers/haptic/drv2605l.h b/drivers/haptic/drv2605l.h new file mode 100644 index 0000000000..a7cf856a86 --- /dev/null +++ b/drivers/haptic/drv2605l.h @@ -0,0 +1,362 @@ +/* Copyright 2018 ishtob + * Driver for DRV2605L written for QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <stdint.h> + +/* Initialization settings + + * Feedback Control Settings */ +#ifndef DRV2605L_FB_ERM_LRA +# define DRV2605L_FB_ERM_LRA 1 /* For ERM:0 or LRA:1*/ +#endif +#ifndef DRV2605L_FB_BRAKEFACTOR +# define DRV2605L_FB_BRAKEFACTOR 3 /* For 1x:0, 2x:1, 3x:2, 4x:3, 6x:4, 8x:5, 16x:6, Disable Braking:7 */ +#endif +#ifndef DRV2605L_FB_LOOPGAIN +# define DRV2605L_FB_LOOPGAIN 1 /* For Low:0, Medium:1, High:2, Very High:3 */ +#endif + +/* LRA specific settings */ +#if DRV2605L_FB_ERM_LRA == 1 +# ifndef DRV2605L_V_RMS +# define DRV2605L_V_RMS 2.0 +# endif +# ifndef DRV2605L_V_PEAK +# define DRV2605L_V_PEAK 2.1 +# endif +# ifndef DRV2605L_F_LRA +# define DRV2605L_F_LRA 205 +# endif +# ifndef DRV2605L_RATED_VOLTAGE +# define DRV2605L_RATED_VOLTAGE 2 /* 2v as safe range in case device voltage is not set */ +# endif +#endif + +#ifndef DRV2605L_RATED_VOLTAGE +# define DRV2605L_RATED_VOLTAGE 2 /* 2v as safe range in case device voltage is not set */ +#endif +#ifndef DRV2605L_V_PEAK +# define DRV2605L_V_PEAK 2.8 +#endif + +/* Library Selection */ +#ifndef DRV2605L_LIBRARY +# if DRV2605L_FB_ERM_LRA == 1 +# define DRV2605L_LIBRARY 6 /* For Empty:0' TS2200 library A to D:1-5, LRA Library: 6 */ +# else +# define DRV2605L_LIBRARY 1 +# endif +#endif + +#ifndef DRV2605L_GREETING +# define DRV2605L_GREETING DRV2605L_EFFECT_750_MS_ALERT_100 +#endif +#ifndef DRV2605L_DEFAULT_MODE +# define DRV2605L_DEFAULT_MODE DRV2605L_EFFECT_STRONG_CLICK_1_100 +#endif + +/* Control 1 register settings */ +#ifndef DRV2605L_DRIVE_TIME +# define DRV2605L_DRIVE_TIME 25 +#endif +#ifndef DRV2605L_AC_COUPLE +# define DRV2605L_AC_COUPLE 0 +#endif +#ifndef DRV2605L_STARTUP_BOOST +# define DRV2605L_STARTUP_BOOST 1 +#endif + +/* Control 2 Settings */ +#ifndef DRV2605L_BIDIR_INPUT +# define DRV2605L_BIDIR_INPUT 1 +#endif +#ifndef DRV2605L_BRAKE_STAB +# define DRV2605L_BRAKE_STAB 1 /* Loopgain is reduced when braking is almost complete to improve stability */ +#endif +#ifndef DRV2605L_SAMPLE_TIME +# define DRV2605L_SAMPLE_TIME 3 +#endif +#ifndef DRV2605L_BLANKING_TIME +# define DRV2605L_BLANKING_TIME 1 +#endif +#ifndef DRV2605L_IDISS_TIME +# define DRV2605L_IDISS_TIME 1 +#endif + +/* Control 3 settings */ +#ifndef DRV2605L_NG_THRESH +# define DRV2605L_NG_THRESH 2 +#endif +#ifndef DRV2605L_ERM_OPEN_LOOP +# define DRV2605L_ERM_OPEN_LOOP 1 +#endif +#ifndef DRV2605L_SUPPLY_COMP_DIS +# define DRV2605L_SUPPLY_COMP_DIS 0 +#endif +#ifndef DRV2605L_DATA_FORMAT_RTO +# define DRV2605L_DATA_FORMAT_RTO 0 +#endif +#ifndef DRV2605L_LRA_DRIVE_MODE +# define DRV2605L_LRA_DRIVE_MODE 0 +#endif +#ifndef DRV2605L_N_PWM_ANALOG +# define DRV2605L_N_PWM_ANALOG 0 +#endif +#ifndef DRV2605L_LRA_OPEN_LOOP +# define DRV2605L_LRA_OPEN_LOOP 0 +#endif + +/* Control 4 settings */ +#ifndef DRV2605L_ZC_DET_TIME +# define DRV2605L_ZC_DET_TIME 0 +#endif +#ifndef DRV2605L_AUTO_CAL_TIME +# define DRV2605L_AUTO_CAL_TIME 3 +#endif + +#define DRV2605L_I2C_ADDRESS 0x5A + +#define DRV2605L_REG_STATUS 0x00 +#define DRV2605L_REG_MODE 0x01 +#define DRV2605L_REG_RTP_INPUT 0x02 +#define DRV2605L_REG_LIBRARY_SELECTION 0x03 +#define DRV2605L_REG_WAVEFORM_SEQUENCER_1 0x04 +#define DRV2605L_REG_WAVEFORM_SEQUENCER_2 0x05 +#define DRV2605L_REG_WAVEFORM_SEQUENCER_3 0x06 +#define DRV2605L_REG_WAVEFORM_SEQUENCER_4 0x07 +#define DRV2605L_REG_WAVEFORM_SEQUENCER_5 0x08 +#define DRV2605L_REG_WAVEFORM_SEQUENCER_6 0x09 +#define DRV2605L_REG_WAVEFORM_SEQUENCER_7 0x0A +#define DRV2605L_REG_WAVEFORM_SEQUENCER_8 0x0B +#define DRV2605L_REG_GO 0x0C +#define DRV2605L_REG_OVERDRIVE_TIME_OFFSET 0x0D +#define DRV2605L_REG_SUSTAIN_TIME_OFFSET_P 0x0E +#define DRV2605L_REG_SUSTAIN_TIME_OFFSET_N 0x0F +#define DRV2605L_REG_BRAKE_TIME_OFFSET 0x10 +#define DRV2605L_REG_AUDIO_TO_VIBE_CTRL 0x11 +#define DRV2605L_REG_AUDIO_TO_VIBE_MIN_INPUT 0x12 +#define DRV2605L_REG_AUDIO_TO_VIBE_MAX_INPUT 0x13 +#define DRV2605L_REG_AUDIO_TO_VIBE_MIN_OUTPUT_DRIVE 0x14 +#define DRV2605L_REG_AUDIO_TO_VIBE_MAX_OUTPUT_DRIVE 0x15 +#define DRV2605L_REG_RATED_VOLTAGE 0x16 +#define DRV2605L_REG_OVERDRIVE_CLAMP_VOLTAGE 0x17 +#define DRV2605L_REG_AUTO_CALIBRATION_COMPENSATION_RESULT 0x18 +#define DRV2605L_REG_AUTO_CALIBRATION_BACK_EMF_RESULT 0x19 +#define DRV2605L_REG_FEEDBACK_CTRL 0x1A +#define DRV2605L_REG_CTRL1 0x1B +#define DRV2605L_REG_CTRL2 0x1C +#define DRV2605L_REG_CTRL3 0x1D +#define DRV2605L_REG_CTRL4 0x1E +#define DRV2605L_REG_CTRL5 0x1F +#define DRV2605L_REG_LRA_OPEN_LOOP_PERIOD 0x20 +#define DRV2605L_REG_VBAT_VOLTAGE_MONITOR 0x21 +#define DRV2605L_REG_LRA_RESONANCE_PERIOD 0x22 + +void drv2605l_init(void); +void drv2605l_write(const uint8_t reg_addr, const uint8_t data); +uint8_t drv2605l_read(const uint8_t reg_addr); +void drv2605l_rtp_init(void); +void drv2605l_amplitude(const uint8_t amplitude); +void drv2605l_pulse(const uint8_t sequence); + +typedef enum drv2605l_effect_t { + DRV2605L_EFFECT_CLEAR_SEQUENCE, + DRV2605L_EFFECT_STRONG_CLICK_100, + DRV2605L_EFFECT_STRONG_CLICK_60, + DRV2605L_EFFECT_STRONG_CLICK_30, + DRV2605L_EFFECT_SHARP_CLICK_100, + DRV2605L_EFFECT_SHARP_CLICK_60, + DRV2605L_EFFECT_SHARP_CLICK_30, + DRV2605L_EFFECT_SOFT_BUMP_100, + DRV2605L_EFFECT_SOFT_BUMP_60, + DRV2605L_EFFECT_SOFT_BUMP_30, + DRV2605L_EFFECT_DOUBLE_CLICK_100, + DRV2605L_EFFECT_DOUBLE_CLICK_60, + DRV2605L_EFFECT_TRIPLE_CLICK_100, + DRV2605L_EFFECT_SOFT_FUZZ_60, + DRV2605L_EFFECT_STRONG_BUZZ_100, + DRV2605L_EFFECT_750_MS_ALERT_100, + DRV2605L_EFFECT_1000_MS_ALERT_100, + DRV2605L_EFFECT_STRONG_CLICK_1_100, + DRV2605L_EFFECT_STRONG_CLICK_2_80, + DRV2605L_EFFECT_STRONG_CLICK_3_60, + DRV2605L_EFFECT_STRONG_CLICK_4_30, + DRV2605L_EFFECT_MEDIUM_CLICK_1_100, + DRV2605L_EFFECT_MEDIUM_CLICK_2_80, + DRV2605L_EFFECT_MEDIUM_CLICK_3_60, + DRV2605L_EFFECT_SHARP_TICK_1_100, + DRV2605L_EFFECT_SHARP_TICK_2_80, + DRV2605L_EFFECT_SHARP_TICK_3_60, + DRV2605L_EFFECT_SHORT_DOUBLE_CLICK_STRONG_1_100, + DRV2605L_EFFECT_SHORT_DOUBLE_CLICK_STRONG_2_80, + DRV2605L_EFFECT_SHORT_DOUBLE_CLICK_STRONG_3_60, + DRV2605L_EFFECT_SHORT_DOUBLE_CLICK_STRONG_4_30, + DRV2605L_EFFECT_SHORT_DOUBLE_CLICK_MEDIUM_1_100, + DRV2605L_EFFECT_SHORT_DOUBLE_CLICK_MEDIUM_2_80, + DRV2605L_EFFECT_SHORT_DOUBLE_CLICK_MEDIUM_3_60, + DRV2605L_EFFECT_SHORT_DOUBLE_SHARP_TICK_1_100, + DRV2605L_EFFECT_SHORT_DOUBLE_SHARP_TICK_2_80, + DRV2605L_EFFECT_SHORT_DOUBLE_SHARP_TICK_3_60, + DRV2605L_EFFECT_LONG_DOUBLE_SHARP_CLICK_STRONG_1_100, + DRV2605L_EFFECT_LONG_DOUBLE_SHARP_CLICK_STRONG_2_80, + DRV2605L_EFFECT_LONG_DOUBLE_SHARP_CLICK_STRONG_3_60, + DRV2605L_EFFECT_LONG_DOUBLE_SHARP_CLICK_STRONG_4_30, + DRV2605L_EFFECT_LONG_DOUBLE_SHARP_CLICK_MEDIUM_1_100, + DRV2605L_EFFECT_LONG_DOUBLE_SHARP_CLICK_MEDIUM_2_80, + DRV2605L_EFFECT_LONG_DOUBLE_SHARP_CLICK_MEDIUM_3_60, + DRV2605L_EFFECT_LONG_DOUBLE_SHARP_TICK_1_100, + DRV2605L_EFFECT_LONG_DOUBLE_SHARP_TICK_2_80, + DRV2605L_EFFECT_LONG_DOUBLE_SHARP_TICK_3_60, + DRV2605L_EFFECT_BUZZ_1_100, + DRV2605L_EFFECT_BUZZ_2_80, + DRV2605L_EFFECT_BUZZ_3_60, + DRV2605L_EFFECT_BUZZ_4_40, + DRV2605L_EFFECT_BUZZ_5_20, + DRV2605L_EFFECT_PULSING_STRONG_1_100, + DRV2605L_EFFECT_PULSING_STRONG_2_60, + DRV2605L_EFFECT_PULSING_MEDIUM_1_100, + DRV2605L_EFFECT_PULSING_MEDIUM_2_60, + DRV2605L_EFFECT_PULSING_SHARP_1_100, + DRV2605L_EFFECT_PULSING_SHARP_2_60, + DRV2605L_EFFECT_TRANSITION_CLICK_1_100, + DRV2605L_EFFECT_TRANSITION_CLICK_2_80, + DRV2605L_EFFECT_TRANSITION_CLICK_3_60, + DRV2605L_EFFECT_TRANSITION_CLICK_4_40, + DRV2605L_EFFECT_TRANSITION_CLICK_5_20, + DRV2605L_EFFECT_TRANSITION_CLICK_6_10, + DRV2605L_EFFECT_TRANSITION_HUM_1_100, + DRV2605L_EFFECT_TRANSITION_HUM_2_80, + DRV2605L_EFFECT_TRANSITION_HUM_3_60, + DRV2605L_EFFECT_TRANSITION_HUM_4_40, + DRV2605L_EFFECT_TRANSITION_HUM_5_20, + DRV2605L_EFFECT_TRANSITION_HUM_6_10, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_LONG_SMOOTH_1_100, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_LONG_SMOOTH_2_100, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_MEDIUM_SMOOTH_1_100, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_MEDIUM_SMOOTH_2_100, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_SHORT_SMOOTH_1_100, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_SHORT_SMOOTH_2_100, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_LONG_SHARP_1_100, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_LONG_SHARP_2_100, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_MEDIUM_SHARP_1_100, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_MEDIUM_SHARP_2_100, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_SHORT_SHARP_1_100, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_SHORT_SHARP_2_100, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_LONG_SMOOTH_1_100, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_LONG_SMOOTH_2_100, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_MEDIUM_SMOOTH_1_100, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_MEDIUM_SMOOTH_2_100, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_SHORT_SMOOTH_1_100, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_SHORT_SMOOTH_2_100, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_LONG_SHARP_1_100, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_LONG_SHARP_2_100, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_MEDIUM_SHARP_1_100, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_MEDIUM_SHARP_2_100, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_SHORT_SHARP_1_100, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_SHORT_SHARP_2_100, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_LONG_SMOOTH_1_50, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_LONG_SMOOTH_2_50, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_MEDIUM_SMOOTH_1_50, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_MEDIUM_SMOOTH_2_50, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_SHORT_SMOOTH_1_50, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_SHORT_SMOOTH_2_50, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_LONG_SHARP_1_50, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_LONG_SHARP_2_50, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_MEDIUM_SHARP_1_50, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_MEDIUM_SHARP_2_50, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_SHORT_SHARP_1_50, + DRV2605L_EFFECT_TRANSITION_RAMP_DOWN_SHORT_SHARP_2_50, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_LONG_SMOOTH_1_50, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_LONG_SMOOTH_2_50, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_MEDIUM_SMOOTH_1_50, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_MEDIUM_SMOOTH_2_50, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_SHORT_SMOOTH_1_50, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_SHORT_SMOOTH_2_50, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_LONG_SHARP_1_50, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_LONG_SHARP_2_50, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_MEDIUM_SHARP_1_50, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_MEDIUM_SHARP_2_50, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_SHORT_SHARP_1_50, + DRV2605L_EFFECT_TRANSITION_RAMP_UP_SHORT_SHARP_2_50, + DRV2605L_EFFECT_LONG_BUZZ_FOR_PROGRAMMATIC_STOPPING, + DRV2605L_EFFECT_SMOOTH_HUM_1_50, + DRV2605L_EFFECT_SMOOTH_HUM_2_40, + DRV2605L_EFFECT_SMOOTH_HUM_3_30, + DRV2605L_EFFECT_SMOOTH_HUM_4_20, + DRV2605L_EFFECT_SMOOTH_HUM_5_10, + DRV2605L_EFFECT_COUNT +} drv2605l_effect_t; + +/* Register bit array unions */ + +typedef union { /* register 0x1A */ + uint8_t raw; + struct { + uint8_t BEMF_GAIN : 2; + uint8_t LOOP_GAIN : 2; + uint8_t BRAKE_FACTOR : 3; + uint8_t ERM_LRA : 1; + } bits; +} drv2605l_reg_feedback_ctrl_t; + +typedef union { /* register 0x1B */ + uint8_t raw; + struct { + uint8_t C1_DRIVE_TIME : 5; + uint8_t C1_AC_COUPLE : 1; + uint8_t : 1; + uint8_t C1_STARTUP_BOOST : 1; + } bits; +} drv2605l_reg_ctrl1_t; + +typedef union { /* register 0x1C */ + uint8_t raw; + struct { + uint8_t C2_IDISS_TIME : 2; + uint8_t C2_BLANKING_TIME : 2; + uint8_t C2_SAMPLE_TIME : 2; + uint8_t C2_BRAKE_STAB : 1; + uint8_t C2_BIDIR_INPUT : 1; + } bits; +} drv2605l_reg_ctrl2_t; + +typedef union { /* register 0x1D */ + uint8_t raw; + struct { + uint8_t C3_LRA_OPEN_LOOP : 1; + uint8_t C3_N_PWM_ANALOG : 1; + uint8_t C3_LRA_DRIVE_MODE : 1; + uint8_t C3_DATA_FORMAT_RTO : 1; + uint8_t C3_SUPPLY_COMP_DIS : 1; + uint8_t C3_ERM_OPEN_LOOP : 1; + uint8_t C3_NG_THRESH : 2; + } bits; +} drv2605l_reg_ctrl3_t; + +typedef union { /* register 0x1E */ + uint8_t raw; + struct { + uint8_t C4_OTP_PROGRAM : 1; + uint8_t : 1; + uint8_t C4_OTP_STATUS : 1; + uint8_t : 1; + uint8_t C4_AUTO_CAL_TIME : 2; + uint8_t C4_ZC_DET_TIME : 2; + } bits; +} drv2605l_reg_ctrl4_t; diff --git a/drivers/led/apa102.c b/drivers/led/apa102.c index 40fc68e4f1..766d8cd2eb 100644 --- a/drivers/led/apa102.c +++ b/drivers/led/apa102.c @@ -16,14 +16,14 @@ */ #include "apa102.h" -#include "quantum.h" +#include "gpio.h" #ifndef APA102_NOPS # if defined(__AVR__) # define APA102_NOPS 0 // AVR at 16 MHz already spends 62.5 ns per clock, so no extra delay is needed # elif defined(PROTOCOL_CHIBIOS) - # include "hal.h" +# include "chibios_config.h" # if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) || defined(GD32VF103) # define APA102_NOPS (100 / (1000000000L / (CPU_CLOCK / 4))) // This calculates how many loops of 4 nops to run to delay 100 ns # else diff --git a/drivers/led/aw20216.c b/drivers/led/aw20216.c index 7895f1497b..479643add4 100644 --- a/drivers/led/aw20216.c +++ b/drivers/led/aw20216.c @@ -71,7 +71,7 @@ uint8_t g_pwm_buffer[DRIVER_COUNT][AW_PWM_REGISTER_COUNT]; bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; -bool AW20216_write(pin_t cs_pin, uint8_t page, uint8_t reg, uint8_t* data, uint8_t len) { +bool aw20216_write(pin_t cs_pin, uint8_t page, uint8_t reg, uint8_t* data, uint8_t len) { static uint8_t s_spi_transfer_buffer[2] = {0}; if (!spi_start(cs_pin, false, AW_SPI_MODE, AW_SPI_DIVISOR)) { @@ -96,70 +96,73 @@ bool AW20216_write(pin_t cs_pin, uint8_t page, uint8_t reg, uint8_t* data, uint8 return true; } -static inline bool AW20216_write_register(pin_t cs_pin, uint8_t page, uint8_t reg, uint8_t value) { +static inline bool aw20216_write_register(pin_t cs_pin, uint8_t page, uint8_t reg, uint8_t value) { // Little wrapper so callers need not care about sending a buffer - return AW20216_write(cs_pin, page, reg, &value, 1); + return aw20216_write(cs_pin, page, reg, &value, 1); } -void AW20216_soft_reset(pin_t cs_pin) { - AW20216_write_register(cs_pin, AW_PAGE_FUNCTION, AW_REG_RESET, AW_RESET_CMD); +void aw20216_soft_reset(pin_t cs_pin) { + aw20216_write_register(cs_pin, AW_PAGE_FUNCTION, AW_REG_RESET, AW_RESET_CMD); } -static void AW20216_init_scaling(pin_t cs_pin) { +static void aw20216_init_scaling(pin_t cs_pin) { // Set constant current to the max, control brightness with PWM for (uint8_t i = 0; i < AW_PWM_REGISTER_COUNT; i++) { - AW20216_write_register(cs_pin, AW_PAGE_SCALING, i, AW_SCALING_MAX); + aw20216_write_register(cs_pin, AW_PAGE_SCALING, i, AW_SCALING_MAX); } } -static inline void AW20216_init_current_limit(pin_t cs_pin) { +static inline void aw20216_init_current_limit(pin_t cs_pin) { // Push config - AW20216_write_register(cs_pin, AW_PAGE_FUNCTION, AW_REG_GLOBALCURRENT, AW_GLOBAL_CURRENT_MAX); + aw20216_write_register(cs_pin, AW_PAGE_FUNCTION, AW_REG_GLOBALCURRENT, AW_GLOBAL_CURRENT_MAX); } -static inline void AW20216_soft_enable(pin_t cs_pin) { +static inline void aw20216_soft_enable(pin_t cs_pin) { // Push config - AW20216_write_register(cs_pin, AW_PAGE_FUNCTION, AW_REG_CONFIGURATION, AW_CONFIG_DEFAULT | AW_CHIPEN); + aw20216_write_register(cs_pin, AW_PAGE_FUNCTION, AW_REG_CONFIGURATION, AW_CONFIG_DEFAULT | AW_CHIPEN); } -static inline void AW20216_auto_lowpower(pin_t cs_pin) { - AW20216_write_register(cs_pin, AW_PAGE_FUNCTION, AW_REG_MIXFUNCTION, AW_MIXCR_DEFAULT | AW_LPEN); +static inline void aw20216_auto_lowpower(pin_t cs_pin) { + aw20216_write_register(cs_pin, AW_PAGE_FUNCTION, AW_REG_MIXFUNCTION, AW_MIXCR_DEFAULT | AW_LPEN); } -void AW20216_init(pin_t cs_pin, pin_t en_pin) { +void aw20216_init(pin_t cs_pin, pin_t en_pin) { setPinOutput(en_pin); writePinHigh(en_pin); - AW20216_soft_reset(cs_pin); + aw20216_soft_reset(cs_pin); wait_ms(2); // Drivers should start with all scaling and PWM registers as off - AW20216_init_current_limit(cs_pin); - AW20216_init_scaling(cs_pin); + aw20216_init_current_limit(cs_pin); + aw20216_init_scaling(cs_pin); - AW20216_soft_enable(cs_pin); - AW20216_auto_lowpower(cs_pin); + aw20216_soft_enable(cs_pin); + aw20216_auto_lowpower(cs_pin); } -void AW20216_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { +void aw20216_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { aw_led led; memcpy_P(&led, (&g_aw_leds[index]), sizeof(led)); + if (g_pwm_buffer[led.driver][led.r] == red && g_pwm_buffer[led.driver][led.g] == green && g_pwm_buffer[led.driver][led.b] == blue) { + return; + } g_pwm_buffer[led.driver][led.r] = red; g_pwm_buffer[led.driver][led.g] = green; g_pwm_buffer[led.driver][led.b] = blue; g_pwm_buffer_update_required[led.driver] = true; } -void AW20216_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { +void aw20216_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { for (uint8_t i = 0; i < RGB_MATRIX_LED_COUNT; i++) { - AW20216_set_color(i, red, green, blue); + aw20216_set_color(i, red, green, blue); } } -void AW20216_update_pwm_buffers(pin_t cs_pin, uint8_t index) { +void aw20216_update_pwm_buffers(pin_t cs_pin, uint8_t index) { if (g_pwm_buffer_update_required[index]) { - AW20216_write(cs_pin, AW_PAGE_PWM, 0, g_pwm_buffer[index], AW_PWM_REGISTER_COUNT); + aw20216_write(cs_pin, AW_PAGE_PWM, 0, g_pwm_buffer[index], AW_PWM_REGISTER_COUNT); } g_pwm_buffer_update_required[index] = false; } diff --git a/drivers/led/aw20216.h b/drivers/led/aw20216.h index c6e71b4b4e..e342cb6bac 100644 --- a/drivers/led/aw20216.h +++ b/drivers/led/aw20216.h @@ -30,10 +30,10 @@ typedef struct aw_led { extern const aw_led PROGMEM g_aw_leds[RGB_MATRIX_LED_COUNT]; -void AW20216_init(pin_t cs_pin, pin_t en_pin); -void AW20216_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); -void AW20216_set_color_all(uint8_t red, uint8_t green, uint8_t blue); -void AW20216_update_pwm_buffers(pin_t cs_pin, uint8_t index); +void aw20216_init(pin_t cs_pin, pin_t en_pin); +void aw20216_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); +void aw20216_set_color_all(uint8_t red, uint8_t green, uint8_t blue); +void aw20216_update_pwm_buffers(pin_t cs_pin, uint8_t index); #define CS1_SW1 0x00 #define CS2_SW1 0x01 diff --git a/drivers/led/ckled2001-simple.c b/drivers/led/ckled2001-simple.c index 6c4ffd398e..c4d4c0a4cc 100644 --- a/drivers/led/ckled2001-simple.c +++ b/drivers/led/ckled2001-simple.c @@ -42,7 +42,7 @@ uint8_t g_twi_transfer_buffer[20]; // The control buffers match the PG0 LED On/Off registers. // Storing them like this is optimal for I2C transfers to the registers. // We could optimize this and take out the unused registers from these -// buffers and the transfers in CKLED2001_write_pwm_buffer() but it's +// buffers and the transfers in ckled2001_write_pwm_buffer() but it's // probably not worth the extra complexity. uint8_t g_pwm_buffer[DRIVER_COUNT][192]; bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; @@ -50,7 +50,7 @@ bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; uint8_t g_led_control_registers[DRIVER_COUNT][24] = {0}; bool g_led_control_registers_update_required[DRIVER_COUNT] = {false}; -bool CKLED2001_write_register(uint8_t addr, uint8_t reg, uint8_t data) { +bool ckled2001_write_register(uint8_t addr, uint8_t reg, uint8_t data) { // If the transaction fails function returns false. g_twi_transfer_buffer[0] = reg; g_twi_transfer_buffer[1] = data; @@ -69,7 +69,7 @@ bool CKLED2001_write_register(uint8_t addr, uint8_t reg, uint8_t data) { return true; } -bool CKLED2001_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { +bool ckled2001_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { // Assumes PG1 is already selected. // If any of the transactions fails function returns false. // Transmit PWM registers in 12 transfers of 16 bytes. @@ -100,69 +100,72 @@ bool CKLED2001_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { return true; } -void CKLED2001_init(uint8_t addr) { +void ckled2001_init(uint8_t addr) { // Select to function page - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); // Setting LED driver to shutdown mode - CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_SHUT_DOWN_MODE); + ckled2001_write_register(addr, CONFIGURATION_REG, MSKSW_SHUT_DOWN_MODE); // Setting internal channel pulldown/pullup - CKLED2001_write_register(addr, PDU_REG, MSKSET_CA_CB_CHANNEL); + ckled2001_write_register(addr, PDU_REG, MSKSET_CA_CB_CHANNEL); // Select number of scan phase - CKLED2001_write_register(addr, SCAN_PHASE_REG, PHASE_CHANNEL); + ckled2001_write_register(addr, SCAN_PHASE_REG, PHASE_CHANNEL); // Setting PWM Delay Phase - CKLED2001_write_register(addr, SLEW_RATE_CONTROL_MODE1_REG, MSKPWM_DELAY_PHASE_ENABLE); + ckled2001_write_register(addr, SLEW_RATE_CONTROL_MODE1_REG, MSKPWM_DELAY_PHASE_ENABLE); // Setting Driving/Sinking Channel Slew Rate - CKLED2001_write_register(addr, SLEW_RATE_CONTROL_MODE2_REG, MSKDRIVING_SINKING_CHHANNEL_SLEWRATE_ENABLE); + ckled2001_write_register(addr, SLEW_RATE_CONTROL_MODE2_REG, MSKDRIVING_SINKING_CHHANNEL_SLEWRATE_ENABLE); // Setting Iref - CKLED2001_write_register(addr, SOFTWARE_SLEEP_REG, MSKSLEEP_DISABLE); + ckled2001_write_register(addr, SOFTWARE_SLEEP_REG, MSKSLEEP_DISABLE); // Set LED CONTROL PAGE (Page 0) - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE); for (int i = 0; i < LED_CONTROL_ON_OFF_LENGTH; i++) { - CKLED2001_write_register(addr, i, 0x00); + ckled2001_write_register(addr, i, 0x00); } // Set PWM PAGE (Page 1) - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_PWM_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_PWM_PAGE); for (int i = 0; i < LED_CURRENT_TUNE_LENGTH; i++) { - CKLED2001_write_register(addr, i, 0x00); + ckled2001_write_register(addr, i, 0x00); } // Set CURRENT PAGE (Page 4) uint8_t current_tuen_reg_list[LED_CURRENT_TUNE_LENGTH] = CKLED2001_CURRENT_TUNE; - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, CURRENT_TUNE_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, CURRENT_TUNE_PAGE); for (int i = 0; i < LED_CURRENT_TUNE_LENGTH; i++) { - CKLED2001_write_register(addr, i, current_tuen_reg_list[i]); + ckled2001_write_register(addr, i, current_tuen_reg_list[i]); } // Enable LEDs ON/OFF - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE); for (int i = 0; i < LED_CONTROL_ON_OFF_LENGTH; i++) { - CKLED2001_write_register(addr, i, 0xFF); + ckled2001_write_register(addr, i, 0xFF); } // Select to function page - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); // Setting LED driver to normal mode - CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_NORMAL_MODE); + ckled2001_write_register(addr, CONFIGURATION_REG, MSKSW_NORMAL_MODE); } -void CKLED2001_set_value(int index, uint8_t value) { +void ckled2001_set_value(int index, uint8_t value) { ckled2001_led led; if (index >= 0 && index < LED_MATRIX_LED_COUNT) { memcpy_P(&led, (&g_ckled2001_leds[index]), sizeof(led)); + if (g_pwm_buffer[led.driver][led.v] == value) { + return; + } g_pwm_buffer[led.driver][led.v] = value; g_pwm_buffer_update_required[led.driver] = true; } } -void CKLED2001_set_value_all(uint8_t value) { +void ckled2001_set_value_all(uint8_t value) { for (int i = 0; i < LED_MATRIX_LED_COUNT; i++) { - CKLED2001_set_value(i, value); + ckled2001_set_value(i, value); } } -void CKLED2001_set_led_control_register(uint8_t index, bool value) { +void ckled2001_set_led_control_register(uint8_t index, bool value) { ckled2001_led led; memcpy_P(&led, (&g_ckled2001_leds[index]), sizeof(led)); @@ -178,41 +181,41 @@ void CKLED2001_set_led_control_register(uint8_t index, bool value) { g_led_control_registers_update_required[led.driver] = true; } -void CKLED2001_update_pwm_buffers(uint8_t addr, uint8_t index) { +void ckled2001_update_pwm_buffers(uint8_t addr, uint8_t index) { if (g_pwm_buffer_update_required[index]) { - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_PWM_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_PWM_PAGE); // If any of the transactions fail we risk writing dirty PG0, // refresh page 0 just in case. - if (!CKLED2001_write_pwm_buffer(addr, g_pwm_buffer[index])) { + if (!ckled2001_write_pwm_buffer(addr, g_pwm_buffer[index])) { g_led_control_registers_update_required[index] = true; } } g_pwm_buffer_update_required[index] = false; } -void CKLED2001_update_led_control_registers(uint8_t addr, uint8_t index) { +void ckled2001_update_led_control_registers(uint8_t addr, uint8_t index) { if (g_led_control_registers_update_required[index]) { - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE); for (int i = 0; i < 24; i++) { - CKLED2001_write_register(addr, i, g_led_control_registers[index][i]); + ckled2001_write_register(addr, i, g_led_control_registers[index][i]); } } g_led_control_registers_update_required[index] = false; } -void CKLED2001_sw_return_normal(uint8_t addr) { +void ckled2001_sw_return_normal(uint8_t addr) { // Select to function page - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); // Setting LED driver to normal mode - CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_NORMAL_MODE); + ckled2001_write_register(addr, CONFIGURATION_REG, MSKSW_NORMAL_MODE); } -void CKLED2001_sw_shutdown(uint8_t addr) { +void ckled2001_sw_shutdown(uint8_t addr) { // Select to function page - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); // Setting LED driver to shutdown mode - CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_SHUT_DOWN_MODE); + ckled2001_write_register(addr, CONFIGURATION_REG, MSKSW_SHUT_DOWN_MODE); // Write SW Sleep Register - CKLED2001_write_register(addr, SOFTWARE_SLEEP_REG, MSKSLEEP_ENABLE); + ckled2001_write_register(addr, SOFTWARE_SLEEP_REG, MSKSLEEP_ENABLE); } diff --git a/drivers/led/ckled2001-simple.h b/drivers/led/ckled2001-simple.h index a56cad3461..c94df62dd2 100644 --- a/drivers/led/ckled2001-simple.h +++ b/drivers/led/ckled2001-simple.h @@ -27,24 +27,24 @@ typedef struct ckled2001_led { extern const ckled2001_led PROGMEM g_ckled2001_leds[LED_MATRIX_LED_COUNT]; -void CKLED2001_init(uint8_t addr); -bool CKLED2001_write_register(uint8_t addr, uint8_t reg, uint8_t data); -bool CKLED2001_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); +void ckled2001_init(uint8_t addr); +bool ckled2001_write_register(uint8_t addr, uint8_t reg, uint8_t data); +bool ckled2001_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); -void CKLED2001_set_value(int index, uint8_t value); -void CKLED2001_set_value_all(uint8_t value); +void ckled2001_set_value(int index, uint8_t value); +void ckled2001_set_value_all(uint8_t value); -void CKLED2001_set_led_control_register(uint8_t index, bool value); +void ckled2001_set_led_control_register(uint8_t index, bool value); // This should not be called from an interrupt // (eg. from a timer interrupt). // Call this while idle (in between matrix scans). // If the buffer is dirty, it will update the driver with the buffer. -void CKLED2001_update_pwm_buffers(uint8_t addr, uint8_t index); -void CKLED2001_update_led_control_registers(uint8_t addr, uint8_t index); +void ckled2001_update_pwm_buffers(uint8_t addr, uint8_t index); +void ckled2001_update_led_control_registers(uint8_t addr, uint8_t index); -void CKLED2001_sw_return_normal(uint8_t addr); -void CKLED2001_sw_shutdown(uint8_t addr); +void ckled2001_sw_return_normal(uint8_t addr); +void ckled2001_sw_shutdown(uint8_t addr); // Registers Page Define #define CONFIGURE_CMD_PAGE 0xFD diff --git a/drivers/led/ckled2001.c b/drivers/led/ckled2001.c index a99b479d1c..6ababf55e9 100644 --- a/drivers/led/ckled2001.c +++ b/drivers/led/ckled2001.c @@ -42,7 +42,7 @@ uint8_t g_twi_transfer_buffer[65]; // The control buffers match the PG0 LED On/Off registers. // Storing them like this is optimal for I2C transfers to the registers. // We could optimize this and take out the unused registers from these -// buffers and the transfers in CKLED2001_write_pwm_buffer() but it's +// buffers and the transfers in ckled2001_write_pwm_buffer() but it's // probably not worth the extra complexity. uint8_t g_pwm_buffer[DRIVER_COUNT][192]; bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; @@ -50,7 +50,7 @@ bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; uint8_t g_led_control_registers[DRIVER_COUNT][24] = {0}; bool g_led_control_registers_update_required[DRIVER_COUNT] = {false}; -bool CKLED2001_write_register(uint8_t addr, uint8_t reg, uint8_t data) { +bool ckled2001_write_register(uint8_t addr, uint8_t reg, uint8_t data) { // If the transaction fails function returns false. g_twi_transfer_buffer[0] = reg; g_twi_transfer_buffer[1] = data; @@ -69,7 +69,7 @@ bool CKLED2001_write_register(uint8_t addr, uint8_t reg, uint8_t data) { return true; } -bool CKLED2001_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { +bool ckled2001_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { // Assumes PG1 is already selected. // If any of the transactions fails function returns false. // Transmit PWM registers in 3 transfers of 64 bytes. @@ -99,57 +99,60 @@ bool CKLED2001_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { return true; } -void CKLED2001_init(uint8_t addr) { +void ckled2001_init(uint8_t addr) { // Select to function page - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); // Setting LED driver to shutdown mode - CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_SHUT_DOWN_MODE); + ckled2001_write_register(addr, CONFIGURATION_REG, MSKSW_SHUT_DOWN_MODE); // Setting internal channel pulldown/pullup - CKLED2001_write_register(addr, PDU_REG, MSKSET_CA_CB_CHANNEL); + ckled2001_write_register(addr, PDU_REG, MSKSET_CA_CB_CHANNEL); // Select number of scan phase - CKLED2001_write_register(addr, SCAN_PHASE_REG, PHASE_CHANNEL); + ckled2001_write_register(addr, SCAN_PHASE_REG, PHASE_CHANNEL); // Setting PWM Delay Phase - CKLED2001_write_register(addr, SLEW_RATE_CONTROL_MODE1_REG, MSKPWM_DELAY_PHASE_ENABLE); + ckled2001_write_register(addr, SLEW_RATE_CONTROL_MODE1_REG, MSKPWM_DELAY_PHASE_ENABLE); // Setting Driving/Sinking Channel Slew Rate - CKLED2001_write_register(addr, SLEW_RATE_CONTROL_MODE2_REG, MSKDRIVING_SINKING_CHHANNEL_SLEWRATE_ENABLE); + ckled2001_write_register(addr, SLEW_RATE_CONTROL_MODE2_REG, MSKDRIVING_SINKING_CHHANNEL_SLEWRATE_ENABLE); // Setting Iref - CKLED2001_write_register(addr, SOFTWARE_SLEEP_REG, MSKSLEEP_DISABLE); + ckled2001_write_register(addr, SOFTWARE_SLEEP_REG, MSKSLEEP_DISABLE); // Set LED CONTROL PAGE (Page 0) - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE); for (int i = 0; i < LED_CONTROL_ON_OFF_LENGTH; i++) { - CKLED2001_write_register(addr, i, 0x00); + ckled2001_write_register(addr, i, 0x00); } // Set PWM PAGE (Page 1) - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_PWM_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_PWM_PAGE); for (int i = 0; i < LED_CURRENT_TUNE_LENGTH; i++) { - CKLED2001_write_register(addr, i, 0x00); + ckled2001_write_register(addr, i, 0x00); } // Set CURRENT PAGE (Page 4) uint8_t current_tuen_reg_list[LED_CURRENT_TUNE_LENGTH] = CKLED2001_CURRENT_TUNE; - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, CURRENT_TUNE_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, CURRENT_TUNE_PAGE); for (int i = 0; i < LED_CURRENT_TUNE_LENGTH; i++) { - CKLED2001_write_register(addr, i, current_tuen_reg_list[i]); + ckled2001_write_register(addr, i, current_tuen_reg_list[i]); } // Enable LEDs ON/OFF - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE); for (int i = 0; i < LED_CONTROL_ON_OFF_LENGTH; i++) { - CKLED2001_write_register(addr, i, 0xFF); + ckled2001_write_register(addr, i, 0xFF); } // Select to function page - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); // Setting LED driver to normal mode - CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_NORMAL_MODE); + ckled2001_write_register(addr, CONFIGURATION_REG, MSKSW_NORMAL_MODE); } -void CKLED2001_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { +void ckled2001_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { ckled2001_led led; if (index >= 0 && index < RGB_MATRIX_LED_COUNT) { memcpy_P(&led, (&g_ckled2001_leds[index]), sizeof(led)); + if (g_pwm_buffer[led.driver][led.r] == red && g_pwm_buffer[led.driver][led.g] == green && g_pwm_buffer[led.driver][led.b] == blue) { + return; + } g_pwm_buffer[led.driver][led.r] = red; g_pwm_buffer[led.driver][led.g] = green; g_pwm_buffer[led.driver][led.b] = blue; @@ -157,13 +160,13 @@ void CKLED2001_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { } } -void CKLED2001_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { +void ckled2001_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { for (int i = 0; i < RGB_MATRIX_LED_COUNT; i++) { - CKLED2001_set_color(i, red, green, blue); + ckled2001_set_color(i, red, green, blue); } } -void CKLED2001_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { +void ckled2001_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { ckled2001_led led; memcpy_P(&led, (&g_ckled2001_leds[index]), sizeof(led)); @@ -193,41 +196,41 @@ void CKLED2001_set_led_control_register(uint8_t index, bool red, bool green, boo g_led_control_registers_update_required[led.driver] = true; } -void CKLED2001_update_pwm_buffers(uint8_t addr, uint8_t index) { +void ckled2001_update_pwm_buffers(uint8_t addr, uint8_t index) { if (g_pwm_buffer_update_required[index]) { - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_PWM_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_PWM_PAGE); // If any of the transactions fail we risk writing dirty PG0, // refresh page 0 just in case. - if (!CKLED2001_write_pwm_buffer(addr, g_pwm_buffer[index])) { + if (!ckled2001_write_pwm_buffer(addr, g_pwm_buffer[index])) { g_led_control_registers_update_required[index] = true; } } g_pwm_buffer_update_required[index] = false; } -void CKLED2001_update_led_control_registers(uint8_t addr, uint8_t index) { +void ckled2001_update_led_control_registers(uint8_t addr, uint8_t index) { if (g_led_control_registers_update_required[index]) { - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, LED_CONTROL_PAGE); for (int i = 0; i < 24; i++) { - CKLED2001_write_register(addr, i, g_led_control_registers[index][i]); + ckled2001_write_register(addr, i, g_led_control_registers[index][i]); } } g_led_control_registers_update_required[index] = false; } -void CKLED2001_sw_return_normal(uint8_t addr) { +void ckled2001_sw_return_normal(uint8_t addr) { // Select to function page - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); // Setting LED driver to normal mode - CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_NORMAL_MODE); + ckled2001_write_register(addr, CONFIGURATION_REG, MSKSW_NORMAL_MODE); } -void CKLED2001_sw_shutdown(uint8_t addr) { +void ckled2001_sw_shutdown(uint8_t addr) { // Select to function page - CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); + ckled2001_write_register(addr, CONFIGURE_CMD_PAGE, FUNCTION_PAGE); // Setting LED driver to shutdown mode - CKLED2001_write_register(addr, CONFIGURATION_REG, MSKSW_SHUT_DOWN_MODE); + ckled2001_write_register(addr, CONFIGURATION_REG, MSKSW_SHUT_DOWN_MODE); // Write SW Sleep Register - CKLED2001_write_register(addr, SOFTWARE_SLEEP_REG, MSKSLEEP_ENABLE); + ckled2001_write_register(addr, SOFTWARE_SLEEP_REG, MSKSLEEP_ENABLE); } diff --git a/drivers/led/ckled2001.h b/drivers/led/ckled2001.h index aa70a0623f..32da137fb7 100644 --- a/drivers/led/ckled2001.h +++ b/drivers/led/ckled2001.h @@ -29,24 +29,24 @@ typedef struct ckled2001_led { extern const ckled2001_led PROGMEM g_ckled2001_leds[RGB_MATRIX_LED_COUNT]; -void CKLED2001_init(uint8_t addr); -bool CKLED2001_write_register(uint8_t addr, uint8_t reg, uint8_t data); -bool CKLED2001_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); +void ckled2001_init(uint8_t addr); +bool ckled2001_write_register(uint8_t addr, uint8_t reg, uint8_t data); +bool ckled2001_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); -void CKLED2001_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); -void CKLED2001_set_color_all(uint8_t red, uint8_t green, uint8_t blue); +void ckled2001_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); +void ckled2001_set_color_all(uint8_t red, uint8_t green, uint8_t blue); -void CKLED2001_set_led_control_register(uint8_t index, bool red, bool green, bool blue); +void ckled2001_set_led_control_register(uint8_t index, bool red, bool green, bool blue); // This should not be called from an interrupt // (eg. from a timer interrupt). // Call this while idle (in between matrix scans). // If the buffer is dirty, it will update the driver with the buffer. -void CKLED2001_update_pwm_buffers(uint8_t addr, uint8_t index); -void CKLED2001_update_led_control_registers(uint8_t addr, uint8_t index); +void ckled2001_update_pwm_buffers(uint8_t addr, uint8_t index); +void ckled2001_update_led_control_registers(uint8_t addr, uint8_t index); -void CKLED2001_sw_return_normal(uint8_t addr); -void CKLED2001_sw_shutdown(uint8_t addr); +void ckled2001_sw_return_normal(uint8_t addr); +void ckled2001_sw_shutdown(uint8_t addr); // Registers Page Define #define CONFIGURE_CMD_PAGE 0xFD diff --git a/drivers/led/issi/is31fl3218.c b/drivers/led/issi/is31fl3218.c index c2300ebe89..970e9a0be9 100644 --- a/drivers/led/issi/is31fl3218.c +++ b/drivers/led/issi/is31fl3218.c @@ -37,58 +37,61 @@ uint8_t g_twi_transfer_buffer[20]; uint8_t g_pwm_buffer[18]; bool g_pwm_buffer_update_required = false; -void IS31FL3218_write_register(uint8_t reg, uint8_t data) { +void is31fl3218_write_register(uint8_t reg, uint8_t data) { g_twi_transfer_buffer[0] = reg; g_twi_transfer_buffer[1] = data; i2c_transmit(ISSI_ADDRESS, g_twi_transfer_buffer, 2, ISSI_TIMEOUT); } -void IS31FL3218_write_pwm_buffer(uint8_t *pwm_buffer) { +void is31fl3218_write_pwm_buffer(uint8_t *pwm_buffer) { g_twi_transfer_buffer[0] = ISSI_REG_PWM; memcpy(g_twi_transfer_buffer + 1, pwm_buffer, 18); i2c_transmit(ISSI_ADDRESS, g_twi_transfer_buffer, 19, ISSI_TIMEOUT); } -void IS31FL3218_init(void) { +void is31fl3218_init(void) { // In case we ever want to reinitialize (?) - IS31FL3218_write_register(ISSI_REG_RESET, 0x00); + is31fl3218_write_register(ISSI_REG_RESET, 0x00); // Turn off software shutdown - IS31FL3218_write_register(ISSI_REG_SHUTDOWN, 0x01); + is31fl3218_write_register(ISSI_REG_SHUTDOWN, 0x01); // Set all PWM values to zero for (uint8_t i = 0; i < 18; i++) { - IS31FL3218_write_register(ISSI_REG_PWM + i, 0x00); + is31fl3218_write_register(ISSI_REG_PWM + i, 0x00); } // Enable all channels for (uint8_t i = 0; i < 3; i++) { - IS31FL3218_write_register(ISSI_REG_CONTROL + i, 0b00111111); + is31fl3218_write_register(ISSI_REG_CONTROL + i, 0b00111111); } // Load PWM registers and LED Control register data - IS31FL3218_write_register(ISSI_REG_UPDATE, 0x01); + is31fl3218_write_register(ISSI_REG_UPDATE, 0x01); } -void IS31FL3218_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { +void is31fl3218_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { + if (g_pwm_buffer[index * 3 + 0] == red && g_pwm_buffer[index * 3 + 1] == green && g_pwm_buffer[index * 3 + 2] == blue) { + return; + } g_pwm_buffer[index * 3 + 0] = red; g_pwm_buffer[index * 3 + 1] = green; g_pwm_buffer[index * 3 + 2] = blue; g_pwm_buffer_update_required = true; } -void IS31FL3218_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { +void is31fl3218_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { for (int i = 0; i < 6; i++) { - IS31FL3218_set_color(i, red, green, blue); + is31fl3218_set_color(i, red, green, blue); } } -void IS31FL3218_update_pwm_buffers(void) { +void is31fl3218_update_pwm_buffers(void) { if (g_pwm_buffer_update_required) { - IS31FL3218_write_pwm_buffer(g_pwm_buffer); + is31fl3218_write_pwm_buffer(g_pwm_buffer); // Load PWM registers and LED Control register data - IS31FL3218_write_register(ISSI_REG_UPDATE, 0x01); + is31fl3218_write_register(ISSI_REG_UPDATE, 0x01); } g_pwm_buffer_update_required = false; } diff --git a/drivers/led/issi/is31fl3218.h b/drivers/led/issi/is31fl3218.h index 26bb01a014..2fe3768432 100644 --- a/drivers/led/issi/is31fl3218.h +++ b/drivers/led/issi/is31fl3218.h @@ -20,7 +20,7 @@ #include <stdbool.h> #include <string.h> -void IS31FL3218_init(void); -void IS31FL3218_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); -void IS31FL3218_set_color_all(uint8_t red, uint8_t green, uint8_t blue); -void IS31FL3218_update_pwm_buffers(void); +void is31fl3218_init(void); +void is31fl3218_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); +void is31fl3218_set_color_all(uint8_t red, uint8_t green, uint8_t blue); +void is31fl3218_update_pwm_buffers(void); diff --git a/drivers/led/issi/is31fl3731-simple.c b/drivers/led/issi/is31fl3731-simple.c index a62b21cc6b..f7f6980a3b 100644 --- a/drivers/led/issi/is31fl3731-simple.c +++ b/drivers/led/issi/is31fl3731-simple.c @@ -64,7 +64,7 @@ uint8_t g_twi_transfer_buffer[20]; // These buffers match the IS31FL3731 PWM registers 0x24-0xB3. // Storing them like this is optimal for I2C transfers to the registers. // We could optimize this and take out the unused registers from these -// buffers and the transfers in IS31FL3731_write_pwm_buffer() but it's +// buffers and the transfers in is31fl3731_write_pwm_buffer() but it's // probably not worth the extra complexity. uint8_t g_pwm_buffer[LED_DRIVER_COUNT][144]; bool g_pwm_buffer_update_required[LED_DRIVER_COUNT] = {false}; @@ -95,7 +95,7 @@ bool g_led_control_registers_update_required[LED_DRIVER_COUNT] = {false}; // 0x0E - R17,G15,G14,G13,G12,G11,G10,G09 // 0x10 - R16,R15,R14,R13,R12,R11,R10,R09 -void IS31FL3731_write_register(uint8_t addr, uint8_t reg, uint8_t data) { +void is31fl3731_write_register(uint8_t addr, uint8_t reg, uint8_t data) { g_twi_transfer_buffer[0] = reg; g_twi_transfer_buffer[1] = data; @@ -110,7 +110,7 @@ void IS31FL3731_write_register(uint8_t addr, uint8_t reg, uint8_t data) { #endif } -void IS31FL3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { +void is31fl3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { // assumes bank is already selected // transmit PWM registers in 9 transfers of 16 bytes @@ -135,79 +135,83 @@ void IS31FL3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { } } -void IS31FL3731_init(uint8_t addr) { +void is31fl3731_init(uint8_t addr) { // In order to avoid the LEDs being driven with garbage data // in the LED driver's PWM registers, first enable software shutdown, // then set up the mode and other settings, clear the PWM registers, // then disable software shutdown. // select "function register" bank - IS31FL3731_write_register(addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG); + is31fl3731_write_register(addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG); // enable software shutdown - IS31FL3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x00); + is31fl3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x00); #ifdef ISSI_3731_DEGHOST // set to enable de-ghosting of the array - IS31FL3731_write_register(addr, ISSI_REG_GHOST_IMAGE_PREVENTION, 0x10); + is31fl3731_write_register(addr, ISSI_REG_GHOST_IMAGE_PREVENTION, 0x10); #endif // this delay was copied from other drivers, might not be needed wait_ms(10); // picture mode - IS31FL3731_write_register(addr, ISSI_REG_CONFIG, ISSI_REG_CONFIG_PICTUREMODE); + is31fl3731_write_register(addr, ISSI_REG_CONFIG, ISSI_REG_CONFIG_PICTUREMODE); // display frame 0 - IS31FL3731_write_register(addr, ISSI_REG_PICTUREFRAME, 0x00); + is31fl3731_write_register(addr, ISSI_REG_PICTUREFRAME, 0x00); // audio sync off - IS31FL3731_write_register(addr, ISSI_REG_AUDIOSYNC, 0x00); + is31fl3731_write_register(addr, ISSI_REG_AUDIOSYNC, 0x00); // select bank 0 - IS31FL3731_write_register(addr, ISSI_COMMANDREGISTER, 0); + is31fl3731_write_register(addr, ISSI_COMMANDREGISTER, 0); // turn off all LEDs in the LED control register for (int i = 0x00; i <= 0x11; i++) { - IS31FL3731_write_register(addr, i, 0x00); + is31fl3731_write_register(addr, i, 0x00); } // turn off all LEDs in the blink control register (not really needed) for (int i = 0x12; i <= 0x23; i++) { - IS31FL3731_write_register(addr, i, 0x00); + is31fl3731_write_register(addr, i, 0x00); } // set PWM on all LEDs to 0 for (int i = 0x24; i <= 0xB3; i++) { - IS31FL3731_write_register(addr, i, 0x00); + is31fl3731_write_register(addr, i, 0x00); } // select "function register" bank - IS31FL3731_write_register(addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG); + is31fl3731_write_register(addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG); // disable software shutdown - IS31FL3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x01); + is31fl3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x01); // select bank 0 and leave it selected. // most usage after initialization is just writing PWM buffers in bank 0 // as there's not much point in double-buffering - IS31FL3731_write_register(addr, ISSI_COMMANDREGISTER, 0); + is31fl3731_write_register(addr, ISSI_COMMANDREGISTER, 0); } -void IS31FL3731_set_value(int index, uint8_t value) { +void is31fl3731_set_value(int index, uint8_t value) { is31_led led; if (index >= 0 && index < LED_MATRIX_LED_COUNT) { memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); // Subtract 0x24 to get the second index of g_pwm_buffer + + if (g_pwm_buffer[led.driver][led.v - 0x24] == value) { + return; + } g_pwm_buffer[led.driver][led.v - 0x24] = value; g_pwm_buffer_update_required[led.driver] = true; } } -void IS31FL3731_set_value_all(uint8_t value) { +void is31fl3731_set_value_all(uint8_t value) { for (int i = 0; i < LED_MATRIX_LED_COUNT; i++) { - IS31FL3731_set_value(i, value); + is31fl3731_set_value(i, value); } } -void IS31FL3731_set_led_control_register(uint8_t index, bool value) { +void is31fl3731_set_led_control_register(uint8_t index, bool value) { is31_led led; memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); @@ -223,17 +227,17 @@ void IS31FL3731_set_led_control_register(uint8_t index, bool value) { g_led_control_registers_update_required[led.driver] = true; } -void IS31FL3731_update_pwm_buffers(uint8_t addr, uint8_t index) { +void is31fl3731_update_pwm_buffers(uint8_t addr, uint8_t index) { if (g_pwm_buffer_update_required[index]) { - IS31FL3731_write_pwm_buffer(addr, g_pwm_buffer[index]); + is31fl3731_write_pwm_buffer(addr, g_pwm_buffer[index]); g_pwm_buffer_update_required[index] = false; } } -void IS31FL3731_update_led_control_registers(uint8_t addr, uint8_t index) { +void is31fl3731_update_led_control_registers(uint8_t addr, uint8_t index) { if (g_led_control_registers_update_required[index]) { for (int i = 0; i < 18; i++) { - IS31FL3731_write_register(addr, i, g_led_control_registers[index][i]); + is31fl3731_write_register(addr, i, g_led_control_registers[index][i]); } g_led_control_registers_update_required[index] = false; } diff --git a/drivers/led/issi/is31fl3731-simple.h b/drivers/led/issi/is31fl3731-simple.h index 7834766b94..69fba14a0b 100644 --- a/drivers/led/issi/is31fl3731-simple.h +++ b/drivers/led/issi/is31fl3731-simple.h @@ -30,21 +30,21 @@ typedef struct is31_led { extern const is31_led PROGMEM g_is31_leds[LED_MATRIX_LED_COUNT]; -void IS31FL3731_init(uint8_t addr); -void IS31FL3731_write_register(uint8_t addr, uint8_t reg, uint8_t data); -void IS31FL3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); +void is31fl3731_init(uint8_t addr); +void is31fl3731_write_register(uint8_t addr, uint8_t reg, uint8_t data); +void is31fl3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); -void IS31FL3731_set_value(int index, uint8_t value); -void IS31FL3731_set_value_all(uint8_t value); +void is31fl3731_set_value(int index, uint8_t value); +void is31fl3731_set_value_all(uint8_t value); -void IS31FL3731_set_led_control_register(uint8_t index, bool value); +void is31fl3731_set_led_control_register(uint8_t index, bool value); // This should not be called from an interrupt // (eg. from a timer interrupt). // Call this while idle (in between matrix scans). // If the buffer is dirty, it will update the driver with the buffer. -void IS31FL3731_update_pwm_buffers(uint8_t addr, uint8_t index); -void IS31FL3731_update_led_control_registers(uint8_t addr, uint8_t index); +void is31fl3731_update_pwm_buffers(uint8_t addr, uint8_t index); +void is31fl3731_update_led_control_registers(uint8_t addr, uint8_t index); #define C1_1 0x24 #define C1_2 0x25 diff --git a/drivers/led/issi/is31fl3731.c b/drivers/led/issi/is31fl3731.c index 80344ca721..15a01b6d75 100644 --- a/drivers/led/issi/is31fl3731.c +++ b/drivers/led/issi/is31fl3731.c @@ -63,7 +63,7 @@ uint8_t g_twi_transfer_buffer[20]; // These buffers match the IS31FL3731 PWM registers 0x24-0xB3. // Storing them like this is optimal for I2C transfers to the registers. // We could optimize this and take out the unused registers from these -// buffers and the transfers in IS31FL3731_write_pwm_buffer() but it's +// buffers and the transfers in is31fl3731_write_pwm_buffer() but it's // probably not worth the extra complexity. uint8_t g_pwm_buffer[DRIVER_COUNT][144]; bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; @@ -85,7 +85,7 @@ bool g_led_control_registers_update_required[DRIVER_COUNT] = {false}; // 0x0E - R17,G15,G14,G13,G12,G11,G10,G09 // 0x10 - R16,R15,R14,R13,R12,R11,R10,R09 -void IS31FL3731_write_register(uint8_t addr, uint8_t reg, uint8_t data) { +void is31fl3731_write_register(uint8_t addr, uint8_t reg, uint8_t data) { g_twi_transfer_buffer[0] = reg; g_twi_transfer_buffer[1] = data; @@ -98,7 +98,7 @@ void IS31FL3731_write_register(uint8_t addr, uint8_t reg, uint8_t data) { #endif } -void IS31FL3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { +void is31fl3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { // assumes bank is already selected // transmit PWM registers in 9 transfers of 16 bytes @@ -123,67 +123,70 @@ void IS31FL3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { } } -void IS31FL3731_init(uint8_t addr) { +void is31fl3731_init(uint8_t addr) { // In order to avoid the LEDs being driven with garbage data // in the LED driver's PWM registers, first enable software shutdown, // then set up the mode and other settings, clear the PWM registers, // then disable software shutdown. // select "function register" bank - IS31FL3731_write_register(addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG); + is31fl3731_write_register(addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG); // enable software shutdown - IS31FL3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x00); + is31fl3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x00); #ifdef ISSI_3731_DEGHOST // set to enable de-ghosting of the array - IS31FL3731_write_register(addr, ISSI_REG_GHOST_IMAGE_PREVENTION, 0x10); + is31fl3731_write_register(addr, ISSI_REG_GHOST_IMAGE_PREVENTION, 0x10); #endif // this delay was copied from other drivers, might not be needed wait_ms(10); // picture mode - IS31FL3731_write_register(addr, ISSI_REG_CONFIG, ISSI_REG_CONFIG_PICTUREMODE); + is31fl3731_write_register(addr, ISSI_REG_CONFIG, ISSI_REG_CONFIG_PICTUREMODE); // display frame 0 - IS31FL3731_write_register(addr, ISSI_REG_PICTUREFRAME, 0x00); + is31fl3731_write_register(addr, ISSI_REG_PICTUREFRAME, 0x00); // audio sync off - IS31FL3731_write_register(addr, ISSI_REG_AUDIOSYNC, 0x00); + is31fl3731_write_register(addr, ISSI_REG_AUDIOSYNC, 0x00); // select bank 0 - IS31FL3731_write_register(addr, ISSI_COMMANDREGISTER, 0); + is31fl3731_write_register(addr, ISSI_COMMANDREGISTER, 0); // turn off all LEDs in the LED control register for (int i = 0x00; i <= 0x11; i++) { - IS31FL3731_write_register(addr, i, 0x00); + is31fl3731_write_register(addr, i, 0x00); } // turn off all LEDs in the blink control register (not really needed) for (int i = 0x12; i <= 0x23; i++) { - IS31FL3731_write_register(addr, i, 0x00); + is31fl3731_write_register(addr, i, 0x00); } // set PWM on all LEDs to 0 for (int i = 0x24; i <= 0xB3; i++) { - IS31FL3731_write_register(addr, i, 0x00); + is31fl3731_write_register(addr, i, 0x00); } // select "function register" bank - IS31FL3731_write_register(addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG); + is31fl3731_write_register(addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG); // disable software shutdown - IS31FL3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x01); + is31fl3731_write_register(addr, ISSI_REG_SHUTDOWN, 0x01); // select bank 0 and leave it selected. // most usage after initialization is just writing PWM buffers in bank 0 // as there's not much point in double-buffering - IS31FL3731_write_register(addr, ISSI_COMMANDREGISTER, 0); + is31fl3731_write_register(addr, ISSI_COMMANDREGISTER, 0); } -void IS31FL3731_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { +void is31fl3731_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { is31_led led; if (index >= 0 && index < RGB_MATRIX_LED_COUNT) { memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); // Subtract 0x24 to get the second index of g_pwm_buffer + if (g_pwm_buffer[led.driver][led.r - 0x24] == red && g_pwm_buffer[led.driver][led.g - 0x24] == green && g_pwm_buffer[led.driver][led.b - 0x24] == blue) { + return; + } g_pwm_buffer[led.driver][led.r - 0x24] = red; g_pwm_buffer[led.driver][led.g - 0x24] = green; g_pwm_buffer[led.driver][led.b - 0x24] = blue; @@ -191,13 +194,13 @@ void IS31FL3731_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { } } -void IS31FL3731_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { +void is31fl3731_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { for (int i = 0; i < RGB_MATRIX_LED_COUNT; i++) { - IS31FL3731_set_color(i, red, green, blue); + is31fl3731_set_color(i, red, green, blue); } } -void IS31FL3731_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { +void is31fl3731_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { is31_led led; memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); @@ -227,17 +230,17 @@ void IS31FL3731_set_led_control_register(uint8_t index, bool red, bool green, bo g_led_control_registers_update_required[led.driver] = true; } -void IS31FL3731_update_pwm_buffers(uint8_t addr, uint8_t index) { +void is31fl3731_update_pwm_buffers(uint8_t addr, uint8_t index) { if (g_pwm_buffer_update_required[index]) { - IS31FL3731_write_pwm_buffer(addr, g_pwm_buffer[index]); + is31fl3731_write_pwm_buffer(addr, g_pwm_buffer[index]); } g_pwm_buffer_update_required[index] = false; } -void IS31FL3731_update_led_control_registers(uint8_t addr, uint8_t index) { +void is31fl3731_update_led_control_registers(uint8_t addr, uint8_t index) { if (g_led_control_registers_update_required[index]) { for (int i = 0; i < 18; i++) { - IS31FL3731_write_register(addr, i, g_led_control_registers[index][i]); + is31fl3731_write_register(addr, i, g_led_control_registers[index][i]); } } g_led_control_registers_update_required[index] = false; diff --git a/drivers/led/issi/is31fl3731.h b/drivers/led/issi/is31fl3731.h index 4c79cb8146..bdf03de1ee 100644 --- a/drivers/led/issi/is31fl3731.h +++ b/drivers/led/issi/is31fl3731.h @@ -31,21 +31,21 @@ typedef struct is31_led { extern const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT]; -void IS31FL3731_init(uint8_t addr); -void IS31FL3731_write_register(uint8_t addr, uint8_t reg, uint8_t data); -void IS31FL3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); +void is31fl3731_init(uint8_t addr); +void is31fl3731_write_register(uint8_t addr, uint8_t reg, uint8_t data); +void is31fl3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); -void IS31FL3731_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); -void IS31FL3731_set_color_all(uint8_t red, uint8_t green, uint8_t blue); +void is31fl3731_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); +void is31fl3731_set_color_all(uint8_t red, uint8_t green, uint8_t blue); -void IS31FL3731_set_led_control_register(uint8_t index, bool red, bool green, bool blue); +void is31fl3731_set_led_control_register(uint8_t index, bool red, bool green, bool blue); // This should not be called from an interrupt // (eg. from a timer interrupt). // Call this while idle (in between matrix scans). // If the buffer is dirty, it will update the driver with the buffer. -void IS31FL3731_update_pwm_buffers(uint8_t addr, uint8_t index); -void IS31FL3731_update_led_control_registers(uint8_t addr, uint8_t index); +void is31fl3731_update_pwm_buffers(uint8_t addr, uint8_t index); +void is31fl3731_update_led_control_registers(uint8_t addr, uint8_t index); #define C1_1 0x24 #define C1_2 0x25 diff --git a/drivers/led/issi/is31fl3733-simple.c b/drivers/led/issi/is31fl3733-simple.c index 21138c6e05..f9a0a271a8 100644 --- a/drivers/led/issi/is31fl3733-simple.c +++ b/drivers/led/issi/is31fl3733-simple.c @@ -81,7 +81,7 @@ uint8_t g_twi_transfer_buffer[20]; // The control buffers match the PG0 LED On/Off registers. // Storing them like this is optimal for I2C transfers to the registers. // We could optimize this and take out the unused registers from these -// buffers and the transfers in IS31FL3733_write_pwm_buffer() but it's +// buffers and the transfers in is31fl3733_write_pwm_buffer() but it's // probably not worth the extra complexity. uint8_t g_pwm_buffer[LED_DRIVER_COUNT][192]; bool g_pwm_buffer_update_required[LED_DRIVER_COUNT] = {false}; @@ -98,7 +98,7 @@ uint8_t g_led_control_registers[LED_DRIVER_COUNT][24] = {{0}, {0}, {0}, {0}}; #endif bool g_led_control_registers_update_required[LED_DRIVER_COUNT] = {false}; -bool IS31FL3733_write_register(uint8_t addr, uint8_t reg, uint8_t data) { +bool is31fl3733_write_register(uint8_t addr, uint8_t reg, uint8_t data) { // If the transaction fails function returns false. g_twi_transfer_buffer[0] = reg; g_twi_transfer_buffer[1] = data; @@ -117,7 +117,7 @@ bool IS31FL3733_write_register(uint8_t addr, uint8_t reg, uint8_t data) { return true; } -bool IS31FL3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { +bool is31fl3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { // Assumes PG1 is already selected. // If any of the transactions fails function returns false. // Transmit PWM registers in 12 transfers of 16 bytes. @@ -146,7 +146,7 @@ bool IS31FL3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { return true; } -void IS31FL3733_init(uint8_t addr, uint8_t sync) { +void is31fl3733_init(uint8_t addr, uint8_t sync) { // In order to avoid the LEDs being driven with garbage data // in the LED driver's PWM registers, shutdown is enabled last. // Set up the mode and other settings, clear the PWM registers, @@ -154,61 +154,66 @@ void IS31FL3733_init(uint8_t addr, uint8_t sync) { // Sync is passed so set it according to the datasheet. // Unlock the command register. - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); // Select PG0 - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); // Turn off all LEDs. for (int i = 0x00; i <= 0x17; i++) { - IS31FL3733_write_register(addr, i, 0x00); + is31fl3733_write_register(addr, i, 0x00); } // Unlock the command register. - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); // Select PG1 - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); // Set PWM on all LEDs to 0 // No need to setup Breath registers to PWM as that is the default. for (int i = 0x00; i <= 0xBF; i++) { - IS31FL3733_write_register(addr, i, 0x00); + is31fl3733_write_register(addr, i, 0x00); } // Unlock the command register. - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); // Select PG3 - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); // Set de-ghost pull-up resistors (SWx) - IS31FL3733_write_register(addr, ISSI_REG_SWPULLUP, ISSI_SWPULLUP); + is31fl3733_write_register(addr, ISSI_REG_SWPULLUP, ISSI_SWPULLUP); // Set de-ghost pull-down resistors (CSx) - IS31FL3733_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP); + is31fl3733_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP); // Set global current to maximum. - IS31FL3733_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT); + is31fl3733_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT); // Disable software shutdown. - IS31FL3733_write_register(addr, ISSI_REG_CONFIGURATION, ((sync & 0b11) << 6) | ((ISSI_PWM_FREQUENCY & 0b111) << 3) | 0x01); + is31fl3733_write_register(addr, ISSI_REG_CONFIGURATION, ((sync & 0b11) << 6) | ((ISSI_PWM_FREQUENCY & 0b111) << 3) | 0x01); // Wait 10ms to ensure the device has woken up. wait_ms(10); } -void IS31FL3733_set_value(int index, uint8_t value) { +void is31fl3733_set_value(int index, uint8_t value) { + is31_led led; if (index >= 0 && index < LED_MATRIX_LED_COUNT) { - is31_led led = g_is31_leds[index]; + memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); + if (g_pwm_buffer[led.driver][led.v] == value) { + return; + } g_pwm_buffer[led.driver][led.v] = value; g_pwm_buffer_update_required[led.driver] = true; } } -void IS31FL3733_set_value_all(uint8_t value) { +void is31fl3733_set_value_all(uint8_t value) { for (int i = 0; i < LED_MATRIX_LED_COUNT; i++) { - IS31FL3733_set_value(i, value); + is31fl3733_set_value(i, value); } } -void IS31FL3733_set_led_control_register(uint8_t index, bool value) { - is31_led led = g_is31_leds[index]; +void is31fl3733_set_led_control_register(uint8_t index, bool value) { + is31_led led; + memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); uint8_t control_register = led.v / 8; uint8_t bit_value = led.v % 8; @@ -222,28 +227,28 @@ void IS31FL3733_set_led_control_register(uint8_t index, bool value) { g_led_control_registers_update_required[led.driver] = true; } -void IS31FL3733_update_pwm_buffers(uint8_t addr, uint8_t index) { +void is31fl3733_update_pwm_buffers(uint8_t addr, uint8_t index) { if (g_pwm_buffer_update_required[index]) { // Firstly we need to unlock the command register and select PG1. - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); // If any of the transactions fail we risk writing dirty PG0, // refresh page 0 just in case. - if (!IS31FL3733_write_pwm_buffer(addr, g_pwm_buffer[index])) { + if (!is31fl3733_write_pwm_buffer(addr, g_pwm_buffer[index])) { g_led_control_registers_update_required[index] = true; } g_pwm_buffer_update_required[index] = false; } } -void IS31FL3733_update_led_control_registers(uint8_t addr, uint8_t index) { +void is31fl3733_update_led_control_registers(uint8_t addr, uint8_t index) { if (g_led_control_registers_update_required[index]) { // Firstly we need to unlock the command register and select PG0 - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); for (int i = 0; i < 24; i++) { - IS31FL3733_write_register(addr, i, g_led_control_registers[index][i]); + is31fl3733_write_register(addr, i, g_led_control_registers[index][i]); } g_led_control_registers_update_required[index] = false; } diff --git a/drivers/led/issi/is31fl3733-simple.h b/drivers/led/issi/is31fl3733-simple.h index 1571fdd3d5..1458f7ac8d 100644 --- a/drivers/led/issi/is31fl3733-simple.h +++ b/drivers/led/issi/is31fl3733-simple.h @@ -30,23 +30,23 @@ typedef struct is31_led { uint8_t v; } __attribute__((packed)) is31_led; -extern const is31_led __flash g_is31_leds[LED_MATRIX_LED_COUNT]; +extern const is31_led PROGMEM g_is31_leds[LED_MATRIX_LED_COUNT]; -void IS31FL3733_init(uint8_t addr, uint8_t sync); -bool IS31FL3733_write_register(uint8_t addr, uint8_t reg, uint8_t data); -bool IS31FL3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); +void is31fl3733_init(uint8_t addr, uint8_t sync); +bool is31fl3733_write_register(uint8_t addr, uint8_t reg, uint8_t data); +bool is31fl3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); -void IS31FL3733_set_value(int index, uint8_t value); -void IS31FL3733_set_value_all(uint8_t value); +void is31fl3733_set_value(int index, uint8_t value); +void is31fl3733_set_value_all(uint8_t value); -void IS31FL3733_set_led_control_register(uint8_t index, bool value); +void is31fl3733_set_led_control_register(uint8_t index, bool value); // This should not be called from an interrupt // (eg. from a timer interrupt). // Call this while idle (in between matrix scans). // If the buffer is dirty, it will update the driver with the buffer. -void IS31FL3733_update_pwm_buffers(uint8_t addr, uint8_t index); -void IS31FL3733_update_led_control_registers(uint8_t addr, uint8_t index); +void is31fl3733_update_pwm_buffers(uint8_t addr, uint8_t index); +void is31fl3733_update_led_control_registers(uint8_t addr, uint8_t index); #define PUR_0R 0x00 // No PUR resistor #define PUR_05KR 0x02 // 0.5k Ohm resistor in t_NOL diff --git a/drivers/led/issi/is31fl3733.c b/drivers/led/issi/is31fl3733.c index 379eaa0ae3..ca431838ef 100644 --- a/drivers/led/issi/is31fl3733.c +++ b/drivers/led/issi/is31fl3733.c @@ -80,7 +80,7 @@ uint8_t g_twi_transfer_buffer[20]; // The control buffers match the PG0 LED On/Off registers. // Storing them like this is optimal for I2C transfers to the registers. // We could optimize this and take out the unused registers from these -// buffers and the transfers in IS31FL3733_write_pwm_buffer() but it's +// buffers and the transfers in is31fl3733_write_pwm_buffer() but it's // probably not worth the extra complexity. uint8_t g_pwm_buffer[DRIVER_COUNT][192]; bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; @@ -88,7 +88,7 @@ bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; uint8_t g_led_control_registers[DRIVER_COUNT][24] = {0}; bool g_led_control_registers_update_required[DRIVER_COUNT] = {false}; -bool IS31FL3733_write_register(uint8_t addr, uint8_t reg, uint8_t data) { +bool is31fl3733_write_register(uint8_t addr, uint8_t reg, uint8_t data) { // If the transaction fails function returns false. g_twi_transfer_buffer[0] = reg; g_twi_transfer_buffer[1] = data; @@ -107,7 +107,7 @@ bool IS31FL3733_write_register(uint8_t addr, uint8_t reg, uint8_t data) { return true; } -bool IS31FL3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { +bool is31fl3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { // Assumes PG1 is already selected. // If any of the transactions fails function returns false. // Transmit PWM registers in 12 transfers of 16 bytes. @@ -138,7 +138,7 @@ bool IS31FL3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { return true; } -void IS31FL3733_init(uint8_t addr, uint8_t sync) { +void is31fl3733_init(uint8_t addr, uint8_t sync) { // In order to avoid the LEDs being driven with garbage data // in the LED driver's PWM registers, shutdown is enabled last. // Set up the mode and other settings, clear the PWM registers, @@ -146,49 +146,52 @@ void IS31FL3733_init(uint8_t addr, uint8_t sync) { // Sync is passed so set it according to the datasheet. // Unlock the command register. - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); // Select PG0 - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); // Turn off all LEDs. for (int i = 0x00; i <= 0x17; i++) { - IS31FL3733_write_register(addr, i, 0x00); + is31fl3733_write_register(addr, i, 0x00); } // Unlock the command register. - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); // Select PG1 - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); // Set PWM on all LEDs to 0 // No need to setup Breath registers to PWM as that is the default. for (int i = 0x00; i <= 0xBF; i++) { - IS31FL3733_write_register(addr, i, 0x00); + is31fl3733_write_register(addr, i, 0x00); } // Unlock the command register. - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); // Select PG3 - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); // Set de-ghost pull-up resistors (SWx) - IS31FL3733_write_register(addr, ISSI_REG_SWPULLUP, ISSI_SWPULLUP); + is31fl3733_write_register(addr, ISSI_REG_SWPULLUP, ISSI_SWPULLUP); // Set de-ghost pull-down resistors (CSx) - IS31FL3733_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP); + is31fl3733_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP); // Set global current to maximum. - IS31FL3733_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT); + is31fl3733_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT); // Disable software shutdown. - IS31FL3733_write_register(addr, ISSI_REG_CONFIGURATION, ((sync & 0b11) << 6) | ((ISSI_PWM_FREQUENCY & 0b111) << 3) | 0x01); + is31fl3733_write_register(addr, ISSI_REG_CONFIGURATION, ((sync & 0b11) << 6) | ((ISSI_PWM_FREQUENCY & 0b111) << 3) | 0x01); // Wait 10ms to ensure the device has woken up. wait_ms(10); } -void IS31FL3733_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { +void is31fl3733_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { is31_led led; if (index >= 0 && index < RGB_MATRIX_LED_COUNT) { memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); + if (g_pwm_buffer[led.driver][led.r] == red && g_pwm_buffer[led.driver][led.g] == green && g_pwm_buffer[led.driver][led.b] == blue) { + return; + } g_pwm_buffer[led.driver][led.r] = red; g_pwm_buffer[led.driver][led.g] = green; g_pwm_buffer[led.driver][led.b] = blue; @@ -196,13 +199,13 @@ void IS31FL3733_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { } } -void IS31FL3733_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { +void is31fl3733_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { for (int i = 0; i < RGB_MATRIX_LED_COUNT; i++) { - IS31FL3733_set_color(i, red, green, blue); + is31fl3733_set_color(i, red, green, blue); } } -void IS31FL3733_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { +void is31fl3733_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { is31_led led; memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); @@ -232,28 +235,28 @@ void IS31FL3733_set_led_control_register(uint8_t index, bool red, bool green, bo g_led_control_registers_update_required[led.driver] = true; } -void IS31FL3733_update_pwm_buffers(uint8_t addr, uint8_t index) { +void is31fl3733_update_pwm_buffers(uint8_t addr, uint8_t index) { if (g_pwm_buffer_update_required[index]) { // Firstly we need to unlock the command register and select PG1. - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); // If any of the transactions fail we risk writing dirty PG0, // refresh page 0 just in case. - if (!IS31FL3733_write_pwm_buffer(addr, g_pwm_buffer[index])) { + if (!is31fl3733_write_pwm_buffer(addr, g_pwm_buffer[index])) { g_led_control_registers_update_required[index] = true; } } g_pwm_buffer_update_required[index] = false; } -void IS31FL3733_update_led_control_registers(uint8_t addr, uint8_t index) { +void is31fl3733_update_led_control_registers(uint8_t addr, uint8_t index) { if (g_led_control_registers_update_required[index]) { // Firstly we need to unlock the command register and select PG0 - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); - IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); for (int i = 0; i < 24; i++) { - IS31FL3733_write_register(addr, i, g_led_control_registers[index][i]); + is31fl3733_write_register(addr, i, g_led_control_registers[index][i]); } } g_led_control_registers_update_required[index] = false; diff --git a/drivers/led/issi/is31fl3733.h b/drivers/led/issi/is31fl3733.h index 29441846ac..f37a58de0f 100644 --- a/drivers/led/issi/is31fl3733.h +++ b/drivers/led/issi/is31fl3733.h @@ -32,21 +32,21 @@ typedef struct is31_led { extern const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT]; -void IS31FL3733_init(uint8_t addr, uint8_t sync); -bool IS31FL3733_write_register(uint8_t addr, uint8_t reg, uint8_t data); -bool IS31FL3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); +void is31fl3733_init(uint8_t addr, uint8_t sync); +bool is31fl3733_write_register(uint8_t addr, uint8_t reg, uint8_t data); +bool is31fl3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); -void IS31FL3733_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); -void IS31FL3733_set_color_all(uint8_t red, uint8_t green, uint8_t blue); +void is31fl3733_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); +void is31fl3733_set_color_all(uint8_t red, uint8_t green, uint8_t blue); -void IS31FL3733_set_led_control_register(uint8_t index, bool red, bool green, bool blue); +void is31fl3733_set_led_control_register(uint8_t index, bool red, bool green, bool blue); // This should not be called from an interrupt // (eg. from a timer interrupt). // Call this while idle (in between matrix scans). // If the buffer is dirty, it will update the driver with the buffer. -void IS31FL3733_update_pwm_buffers(uint8_t addr, uint8_t index); -void IS31FL3733_update_led_control_registers(uint8_t addr, uint8_t index); +void is31fl3733_update_pwm_buffers(uint8_t addr, uint8_t index); +void is31fl3733_update_led_control_registers(uint8_t addr, uint8_t index); #define PUR_0R 0x00 // No PUR resistor #define PUR_05KR 0x02 // 0.5k Ohm resistor in t_NOL diff --git a/drivers/led/issi/is31fl3736.c b/drivers/led/issi/is31fl3736.c index d6b0881139..0de8b3bbae 100644 --- a/drivers/led/issi/is31fl3736.c +++ b/drivers/led/issi/is31fl3736.c @@ -74,7 +74,7 @@ uint8_t g_twi_transfer_buffer[20]; // The control buffers match the PG0 LED On/Off registers. // Storing them like this is optimal for I2C transfers to the registers. // We could optimize this and take out the unused registers from these -// buffers and the transfers in IS31FL3736_write_pwm_buffer() but it's +// buffers and the transfers in is31fl3736_write_pwm_buffer() but it's // probably not worth the extra complexity. uint8_t g_pwm_buffer[DRIVER_COUNT][192]; bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; @@ -82,7 +82,7 @@ bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; uint8_t g_led_control_registers[DRIVER_COUNT][24] = {{0}, {0}}; bool g_led_control_registers_update_required = false; -void IS31FL3736_write_register(uint8_t addr, uint8_t reg, uint8_t data) { +void is31fl3736_write_register(uint8_t addr, uint8_t reg, uint8_t data) { g_twi_transfer_buffer[0] = reg; g_twi_transfer_buffer[1] = data; @@ -95,7 +95,7 @@ void IS31FL3736_write_register(uint8_t addr, uint8_t reg, uint8_t data) { #endif } -void IS31FL3736_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { +void is31fl3736_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { // assumes PG1 is already selected // transmit PWM registers in 12 transfers of 16 bytes @@ -119,56 +119,59 @@ void IS31FL3736_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { } } -void IS31FL3736_init(uint8_t addr) { +void is31fl3736_init(uint8_t addr) { // In order to avoid the LEDs being driven with garbage data // in the LED driver's PWM registers, shutdown is enabled last. // Set up the mode and other settings, clear the PWM registers, // then disable software shutdown. // Unlock the command register. - IS31FL3736_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3736_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); // Select PG0 - IS31FL3736_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); + is31fl3736_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); // Turn off all LEDs. for (int i = 0x00; i <= 0x17; i++) { - IS31FL3736_write_register(addr, i, 0x00); + is31fl3736_write_register(addr, i, 0x00); } // Unlock the command register. - IS31FL3736_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3736_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); // Select PG1 - IS31FL3736_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); + is31fl3736_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); // Set PWM on all LEDs to 0 // No need to setup Breath registers to PWM as that is the default. for (int i = 0x00; i <= 0xBF; i++) { - IS31FL3736_write_register(addr, i, 0x00); + is31fl3736_write_register(addr, i, 0x00); } // Unlock the command register. - IS31FL3736_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3736_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); // Select PG3 - IS31FL3736_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); + is31fl3736_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); // Set de-ghost pull-up resistors (SWx) - IS31FL3736_write_register(addr, ISSI_REG_SWPULLUP, ISSI_SWPULLUP); + is31fl3736_write_register(addr, ISSI_REG_SWPULLUP, ISSI_SWPULLUP); // Set de-ghost pull-down resistors (CSx) - IS31FL3736_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP); + is31fl3736_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP); // Set global current to maximum. - IS31FL3736_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT); + is31fl3736_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT); // Disable software shutdown. - IS31FL3736_write_register(addr, ISSI_REG_CONFIGURATION, 0x01); + is31fl3736_write_register(addr, ISSI_REG_CONFIGURATION, 0x01); // Wait 10ms to ensure the device has woken up. wait_ms(10); } -void IS31FL3736_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { +void is31fl3736_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { is31_led led; if (index >= 0 && index < RGB_MATRIX_LED_COUNT) { memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); + if (g_pwm_buffer[led.driver][led.r] == red && g_pwm_buffer[led.driver][led.g] == green && g_pwm_buffer[led.driver][led.b] == blue) { + return; + } g_pwm_buffer[led.driver][led.r] = red; g_pwm_buffer[led.driver][led.g] = green; g_pwm_buffer[led.driver][led.b] = blue; @@ -176,13 +179,13 @@ void IS31FL3736_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { } } -void IS31FL3736_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { +void is31fl3736_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { for (int i = 0; i < RGB_MATRIX_LED_COUNT; i++) { - IS31FL3736_set_color(i, red, green, blue); + is31fl3736_set_color(i, red, green, blue); } } -void IS31FL3736_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { +void is31fl3736_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { is31_led led; memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); @@ -226,7 +229,7 @@ void IS31FL3736_set_led_control_register(uint8_t index, bool red, bool green, bo g_led_control_registers_update_required = true; } -void IS31FL3736_mono_set_brightness(int index, uint8_t value) { +void is31fl3736_mono_set_brightness(int index, uint8_t value) { if (index >= 0 && index < 96) { // Index in range 0..95 -> A1..A8, B1..B8, etc. // Map index 0..95 to registers 0x00..0xBE (interleaved) @@ -236,13 +239,13 @@ void IS31FL3736_mono_set_brightness(int index, uint8_t value) { } } -void IS31FL3736_mono_set_brightness_all(uint8_t value) { +void is31fl3736_mono_set_brightness_all(uint8_t value) { for (int i = 0; i < 96; i++) { - IS31FL3736_mono_set_brightness(i, value); + is31fl3736_mono_set_brightness(i, value); } } -void IS31FL3736_mono_set_led_control_register(uint8_t index, bool enabled) { +void is31fl3736_mono_set_led_control_register(uint8_t index, bool enabled) { // Index in range 0..95 -> A1..A8, B1..B8, etc. // Map index 0..95 to registers 0x00..0xBE (interleaved) @@ -260,25 +263,25 @@ void IS31FL3736_mono_set_led_control_register(uint8_t index, bool enabled) { g_led_control_registers_update_required = true; } -void IS31FL3736_update_pwm_buffers(uint8_t addr, uint8_t index) { +void is31fl3736_update_pwm_buffers(uint8_t addr, uint8_t index) { if (g_pwm_buffer_update_required[index]) { // Firstly we need to unlock the command register and select PG1 - IS31FL3736_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); - IS31FL3736_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); + is31fl3736_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3736_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); - IS31FL3736_write_pwm_buffer(addr, g_pwm_buffer[index]); + is31fl3736_write_pwm_buffer(addr, g_pwm_buffer[index]); } g_pwm_buffer_update_required[index] = false; } -void IS31FL3736_update_led_control_registers(uint8_t addr1, uint8_t addr2) { +void is31fl3736_update_led_control_registers(uint8_t addr1, uint8_t addr2) { if (g_led_control_registers_update_required) { // Firstly we need to unlock the command register and select PG0 - IS31FL3736_write_register(addr1, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); - IS31FL3736_write_register(addr1, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); + is31fl3736_write_register(addr1, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3736_write_register(addr1, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); for (int i = 0; i < 24; i++) { - IS31FL3736_write_register(addr1, i, g_led_control_registers[0][i]); - // IS31FL3736_write_register(addr2, i, g_led_control_registers[1][i]); + is31fl3736_write_register(addr1, i, g_led_control_registers[0][i]); + // is31fl3736_write_register(addr2, i, g_led_control_registers[1][i]); } g_led_control_registers_update_required = false; } diff --git a/drivers/led/issi/is31fl3736.h b/drivers/led/issi/is31fl3736.h index 332b2035f3..32bdef4a80 100644 --- a/drivers/led/issi/is31fl3736.h +++ b/drivers/led/issi/is31fl3736.h @@ -42,25 +42,25 @@ typedef struct is31_led { extern const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT]; -void IS31FL3736_init(uint8_t addr); -void IS31FL3736_write_register(uint8_t addr, uint8_t reg, uint8_t data); -void IS31FL3736_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); +void is31fl3736_init(uint8_t addr); +void is31fl3736_write_register(uint8_t addr, uint8_t reg, uint8_t data); +void is31fl3736_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); -void IS31FL3736_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); -void IS31FL3736_set_color_all(uint8_t red, uint8_t green, uint8_t blue); +void is31fl3736_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); +void is31fl3736_set_color_all(uint8_t red, uint8_t green, uint8_t blue); -void IS31FL3736_set_led_control_register(uint8_t index, bool red, bool green, bool blue); +void is31fl3736_set_led_control_register(uint8_t index, bool red, bool green, bool blue); -void IS31FL3736_mono_set_brightness(int index, uint8_t value); -void IS31FL3736_mono_set_brightness_all(uint8_t value); -void IS31FL3736_mono_set_led_control_register(uint8_t index, bool enabled); +void is31fl3736_mono_set_brightness(int index, uint8_t value); +void is31fl3736_mono_set_brightness_all(uint8_t value); +void is31fl3736_mono_set_led_control_register(uint8_t index, bool enabled); // This should not be called from an interrupt // (eg. from a timer interrupt). // Call this while idle (in between matrix scans). // If the buffer is dirty, it will update the driver with the buffer. -void IS31FL3736_update_pwm_buffers(uint8_t addr, uint8_t index); -void IS31FL3736_update_led_control_registers(uint8_t addr, uint8_t index); +void is31fl3736_update_pwm_buffers(uint8_t addr, uint8_t index); +void is31fl3736_update_led_control_registers(uint8_t addr, uint8_t index); #define PUR_0R 0x00 // No PUR resistor #define PUR_05KR 0x01 // 0.5k Ohm resistor diff --git a/drivers/led/issi/is31fl3737.c b/drivers/led/issi/is31fl3737.c index b6ed6b2629..947c0a1d1a 100644 --- a/drivers/led/issi/is31fl3737.c +++ b/drivers/led/issi/is31fl3737.c @@ -80,7 +80,7 @@ uint8_t g_twi_transfer_buffer[20]; // The control buffers match the PG0 LED On/Off registers. // Storing them like this is optimal for I2C transfers to the registers. // We could optimize this and take out the unused registers from these -// buffers and the transfers in IS31FL3737_write_pwm_buffer() but it's +// buffers and the transfers in is31fl3737_write_pwm_buffer() but it's // probably not worth the extra complexity. uint8_t g_pwm_buffer[DRIVER_COUNT][192]; @@ -89,7 +89,7 @@ bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; uint8_t g_led_control_registers[DRIVER_COUNT][24] = {0}; bool g_led_control_registers_update_required[DRIVER_COUNT] = {false}; -void IS31FL3737_write_register(uint8_t addr, uint8_t reg, uint8_t data) { +void is31fl3737_write_register(uint8_t addr, uint8_t reg, uint8_t data) { g_twi_transfer_buffer[0] = reg; g_twi_transfer_buffer[1] = data; @@ -102,7 +102,7 @@ void IS31FL3737_write_register(uint8_t addr, uint8_t reg, uint8_t data) { #endif } -void IS31FL3737_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { +void is31fl3737_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { // assumes PG1 is already selected // transmit PWM registers in 12 transfers of 16 bytes @@ -126,56 +126,59 @@ void IS31FL3737_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { } } -void IS31FL3737_init(uint8_t addr) { +void is31fl3737_init(uint8_t addr) { // In order to avoid the LEDs being driven with garbage data // in the LED driver's PWM registers, shutdown is enabled last. // Set up the mode and other settings, clear the PWM registers, // then disable software shutdown. // Unlock the command register. - IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3737_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); // Select PG0 - IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); + is31fl3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); // Turn off all LEDs. for (int i = 0x00; i <= 0x17; i++) { - IS31FL3737_write_register(addr, i, 0x00); + is31fl3737_write_register(addr, i, 0x00); } // Unlock the command register. - IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3737_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); // Select PG1 - IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); + is31fl3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); // Set PWM on all LEDs to 0 // No need to setup Breath registers to PWM as that is the default. for (int i = 0x00; i <= 0xBF; i++) { - IS31FL3737_write_register(addr, i, 0x00); + is31fl3737_write_register(addr, i, 0x00); } // Unlock the command register. - IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3737_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); // Select PG3 - IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); + is31fl3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); // Set de-ghost pull-up resistors (SWx) - IS31FL3737_write_register(addr, ISSI_REG_SWPULLUP, ISSI_SWPULLUP); + is31fl3737_write_register(addr, ISSI_REG_SWPULLUP, ISSI_SWPULLUP); // Set de-ghost pull-down resistors (CSx) - IS31FL3737_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP); + is31fl3737_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP); // Set global current to maximum. - IS31FL3737_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT); + is31fl3737_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT); // Disable software shutdown. - IS31FL3737_write_register(addr, ISSI_REG_CONFIGURATION, ((ISSI_PWM_FREQUENCY & 0b111) << 3) | 0x01); + is31fl3737_write_register(addr, ISSI_REG_CONFIGURATION, ((ISSI_PWM_FREQUENCY & 0b111) << 3) | 0x01); // Wait 10ms to ensure the device has woken up. wait_ms(10); } -void IS31FL3737_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { +void is31fl3737_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { is31_led led; if (index >= 0 && index < RGB_MATRIX_LED_COUNT) { memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); + if (g_pwm_buffer[led.driver][led.r] == red && g_pwm_buffer[led.driver][led.g] == green && g_pwm_buffer[led.driver][led.b] == blue) { + return; + } g_pwm_buffer[led.driver][led.r] = red; g_pwm_buffer[led.driver][led.g] = green; g_pwm_buffer[led.driver][led.b] = blue; @@ -183,13 +186,13 @@ void IS31FL3737_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { } } -void IS31FL3737_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { +void is31fl3737_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { for (int i = 0; i < RGB_MATRIX_LED_COUNT; i++) { - IS31FL3737_set_color(i, red, green, blue); + is31fl3737_set_color(i, red, green, blue); } } -void IS31FL3737_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { +void is31fl3737_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { is31_led led; memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); @@ -219,24 +222,24 @@ void IS31FL3737_set_led_control_register(uint8_t index, bool red, bool green, bo g_led_control_registers_update_required[led.driver] = true; } -void IS31FL3737_update_pwm_buffers(uint8_t addr, uint8_t index) { +void is31fl3737_update_pwm_buffers(uint8_t addr, uint8_t index) { if (g_pwm_buffer_update_required[index]) { // Firstly we need to unlock the command register and select PG1 - IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); - IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); + is31fl3737_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM); - IS31FL3737_write_pwm_buffer(addr, g_pwm_buffer[index]); + is31fl3737_write_pwm_buffer(addr, g_pwm_buffer[index]); } g_pwm_buffer_update_required[index] = false; } -void IS31FL3737_update_led_control_registers(uint8_t addr, uint8_t index) { +void is31fl3737_update_led_control_registers(uint8_t addr, uint8_t index) { if (g_led_control_registers_update_required[index]) { // Firstly we need to unlock the command register and select PG0 - IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); - IS31FL3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); + is31fl3737_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3737_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL); for (int i = 0; i < 24; i++) { - IS31FL3737_write_register(addr, i, g_led_control_registers[index][i]); + is31fl3737_write_register(addr, i, g_led_control_registers[index][i]); } } g_led_control_registers_update_required[index] = false; diff --git a/drivers/led/issi/is31fl3737.h b/drivers/led/issi/is31fl3737.h index ca9a917ee2..e7fc97872c 100644 --- a/drivers/led/issi/is31fl3737.h +++ b/drivers/led/issi/is31fl3737.h @@ -33,21 +33,21 @@ typedef struct is31_led { extern const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT]; -void IS31FL3737_init(uint8_t addr); -void IS31FL3737_write_register(uint8_t addr, uint8_t reg, uint8_t data); -void IS31FL3737_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); +void is31fl3737_init(uint8_t addr); +void is31fl3737_write_register(uint8_t addr, uint8_t reg, uint8_t data); +void is31fl3737_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); -void IS31FL3737_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); -void IS31FL3737_set_color_all(uint8_t red, uint8_t green, uint8_t blue); +void is31fl3737_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); +void is31fl3737_set_color_all(uint8_t red, uint8_t green, uint8_t blue); -void IS31FL3737_set_led_control_register(uint8_t index, bool red, bool green, bool blue); +void is31fl3737_set_led_control_register(uint8_t index, bool red, bool green, bool blue); // This should not be called from an interrupt // (eg. from a timer interrupt). // Call this while idle (in between matrix scans). // If the buffer is dirty, it will update the driver with the buffer. -void IS31FL3737_update_pwm_buffers(uint8_t addr, uint8_t index); -void IS31FL3737_update_led_control_registers(uint8_t addr, uint8_t index); +void is31fl3737_update_pwm_buffers(uint8_t addr, uint8_t index); +void is31fl3737_update_led_control_registers(uint8_t addr, uint8_t index); #define PUR_0R 0x00 // No PUR resistor #define PUR_05KR 0x01 // 0.5k Ohm resistor in t_NOL diff --git a/drivers/led/issi/is31fl3741.c b/drivers/led/issi/is31fl3741.c index 2f43473fc1..70671c2a40 100644 --- a/drivers/led/issi/is31fl3741.c +++ b/drivers/led/issi/is31fl3741.c @@ -82,7 +82,7 @@ uint8_t g_twi_transfer_buffer[20] = {0xFF}; // The scaling buffers match the PG2 and PG3 LED On/Off registers. // Storing them like this is optimal for I2C transfers to the registers. // We could optimize this and take out the unused registers from these -// buffers and the transfers in IS31FL3741_write_pwm_buffer() but it's +// buffers and the transfers in is31fl3741_write_pwm_buffer() but it's // probably not worth the extra complexity. uint8_t g_pwm_buffer[DRIVER_COUNT][ISSI_MAX_LEDS]; bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false}; @@ -90,7 +90,7 @@ bool g_scaling_registers_update_required[DRIVER_COUNT] = {false}; uint8_t g_scaling_registers[DRIVER_COUNT][ISSI_MAX_LEDS]; -void IS31FL3741_write_register(uint8_t addr, uint8_t reg, uint8_t data) { +void is31fl3741_write_register(uint8_t addr, uint8_t reg, uint8_t data) { g_twi_transfer_buffer[0] = reg; g_twi_transfer_buffer[1] = data; @@ -103,14 +103,14 @@ void IS31FL3741_write_register(uint8_t addr, uint8_t reg, uint8_t data) { #endif } -bool IS31FL3741_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { +bool is31fl3741_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { // Assume PG0 is already selected for (int i = 0; i < 342; i += 18) { if (i == 180) { // unlock the command register and select PG1 - IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); - IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM1); + is31fl3741_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3741_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM1); } g_twi_transfer_buffer[0] = i % 180; @@ -148,7 +148,7 @@ bool IS31FL3741_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) { return true; } -void IS31FL3741_init(uint8_t addr) { +void is31fl3741_init(uint8_t addr) { // In order to avoid the LEDs being driven with garbage data // in the LED driver's PWM registers, shutdown is enabled last. // Set up the mode and other settings, clear the PWM registers, @@ -156,44 +156,47 @@ void IS31FL3741_init(uint8_t addr) { // Unlock the command register. // Unlock the command register. - IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3741_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); // Select PG4 - IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); + is31fl3741_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION); // Set to Normal operation - IS31FL3741_write_register(addr, ISSI_REG_CONFIGURATION, 0x01); + is31fl3741_write_register(addr, ISSI_REG_CONFIGURATION, 0x01); // Set Golbal Current Control Register - IS31FL3741_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT); + is31fl3741_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT); // Set Pull up & Down for SWx CSy - IS31FL3741_write_register(addr, ISSI_REG_PULLDOWNUP, ((ISSI_CSPULLUP << 4) | ISSI_SWPULLUP)); + is31fl3741_write_register(addr, ISSI_REG_PULLDOWNUP, ((ISSI_CSPULLUP << 4) | ISSI_SWPULLUP)); - // IS31FL3741_update_led_scaling_registers(addr, 0xFF, 0xFF, 0xFF); + // is31fl3741_update_led_scaling_registers(addr, 0xFF, 0xFF, 0xFF); // Wait 10ms to ensure the device has woken up. wait_ms(10); } -void IS31FL3741_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { +void is31fl3741_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { is31_led led; if (index >= 0 && index < RGB_MATRIX_LED_COUNT) { memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); + if (g_pwm_buffer[led.driver][led.r] == red && g_pwm_buffer[led.driver][led.g] == green && g_pwm_buffer[led.driver][led.b] == blue) { + return; + } + g_pwm_buffer_update_required[led.driver] = true; g_pwm_buffer[led.driver][led.r] = red; g_pwm_buffer[led.driver][led.g] = green; g_pwm_buffer[led.driver][led.b] = blue; - g_pwm_buffer_update_required[led.driver] = true; } } -void IS31FL3741_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { +void is31fl3741_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { for (int i = 0; i < RGB_MATRIX_LED_COUNT; i++) { - IS31FL3741_set_color(i, red, green, blue); + is31fl3741_set_color(i, red, green, blue); } } -void IS31FL3741_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { +void is31fl3741_set_led_control_register(uint8_t index, bool red, bool green, bool blue) { is31_led led; memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); @@ -218,19 +221,19 @@ void IS31FL3741_set_led_control_register(uint8_t index, bool red, bool green, bo g_scaling_registers_update_required[led.driver] = true; } -void IS31FL3741_update_pwm_buffers(uint8_t addr, uint8_t index) { +void is31fl3741_update_pwm_buffers(uint8_t addr, uint8_t index) { if (g_pwm_buffer_update_required[index]) { // unlock the command register and select PG2 - IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); - IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM0); + is31fl3741_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3741_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM0); - IS31FL3741_write_pwm_buffer(addr, g_pwm_buffer[index]); + is31fl3741_write_pwm_buffer(addr, g_pwm_buffer[index]); } g_pwm_buffer_update_required[index] = false; } -void IS31FL3741_set_pwm_buffer(const is31_led *pled, uint8_t red, uint8_t green, uint8_t blue) { +void is31fl3741_set_pwm_buffer(const is31_led *pled, uint8_t red, uint8_t green, uint8_t blue) { g_pwm_buffer[pled->driver][pled->r] = red; g_pwm_buffer[pled->driver][pled->g] = green; g_pwm_buffer[pled->driver][pled->b] = blue; @@ -238,31 +241,31 @@ void IS31FL3741_set_pwm_buffer(const is31_led *pled, uint8_t red, uint8_t green, g_pwm_buffer_update_required[pled->driver] = true; } -void IS31FL3741_update_led_control_registers(uint8_t addr, uint8_t index) { +void is31fl3741_update_led_control_registers(uint8_t addr, uint8_t index) { if (g_scaling_registers_update_required[index]) { // unlock the command register and select PG2 - IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); - IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_SCALING_0); + is31fl3741_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3741_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_SCALING_0); // CS1_SW1 to CS30_SW6 are on PG2 for (int i = CS1_SW1; i <= CS30_SW6; ++i) { - IS31FL3741_write_register(addr, i, g_scaling_registers[index][i]); + is31fl3741_write_register(addr, i, g_scaling_registers[index][i]); } // unlock the command register and select PG3 - IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); - IS31FL3741_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_SCALING_1); + is31fl3741_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5); + is31fl3741_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_SCALING_1); // CS1_SW7 to CS39_SW9 are on PG3 for (int i = CS1_SW7; i <= CS39_SW9; ++i) { - IS31FL3741_write_register(addr, i - CS1_SW7, g_scaling_registers[index][i]); + is31fl3741_write_register(addr, i - CS1_SW7, g_scaling_registers[index][i]); } g_scaling_registers_update_required[index] = false; } } -void IS31FL3741_set_scaling_registers(const is31_led *pled, uint8_t red, uint8_t green, uint8_t blue) { +void is31fl3741_set_scaling_registers(const is31_led *pled, uint8_t red, uint8_t green, uint8_t blue) { g_scaling_registers[pled->driver][pled->r] = red; g_scaling_registers[pled->driver][pled->g] = green; g_scaling_registers[pled->driver][pled->b] = blue; diff --git a/drivers/led/issi/is31fl3741.h b/drivers/led/issi/is31fl3741.h index b0089ea5ba..4ae84dc3c6 100644 --- a/drivers/led/issi/is31fl3741.h +++ b/drivers/led/issi/is31fl3741.h @@ -32,24 +32,24 @@ typedef struct is31_led { extern const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT]; -void IS31FL3741_init(uint8_t addr); -void IS31FL3741_write_register(uint8_t addr, uint8_t reg, uint8_t data); -bool IS31FL3741_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); +void is31fl3741_init(uint8_t addr); +void is31fl3741_write_register(uint8_t addr, uint8_t reg, uint8_t data); +bool is31fl3741_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer); -void IS31FL3741_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); -void IS31FL3741_set_color_all(uint8_t red, uint8_t green, uint8_t blue); +void is31fl3741_set_color(int index, uint8_t red, uint8_t green, uint8_t blue); +void is31fl3741_set_color_all(uint8_t red, uint8_t green, uint8_t blue); -void IS31FL3741_set_led_control_register(uint8_t index, bool red, bool green, bool blue); +void is31fl3741_set_led_control_register(uint8_t index, bool red, bool green, bool blue); // This should not be called from an interrupt // (eg. from a timer interrupt). // Call this while idle (in between matrix scans). // If the buffer is dirty, it will update the driver with the buffer. -void IS31FL3741_update_pwm_buffers(uint8_t addr, uint8_t index); -void IS31FL3741_update_led_control_registers(uint8_t addr, uint8_t index); -void IS31FL3741_set_scaling_registers(const is31_led *pled, uint8_t red, uint8_t green, uint8_t blue); +void is31fl3741_update_pwm_buffers(uint8_t addr, uint8_t index); +void is31fl3741_update_led_control_registers(uint8_t addr, uint8_t index); +void is31fl3741_set_scaling_registers(const is31_led *pled, uint8_t red, uint8_t green, uint8_t blue); -void IS31FL3741_set_pwm_buffer(const is31_led *pled, uint8_t red, uint8_t green, uint8_t blue); +void is31fl3741_set_pwm_buffer(const is31_led *pled, uint8_t red, uint8_t green, uint8_t blue); #define PUR_0R 0x00 // No PUR resistor #define PUR_05KR 0x01 // 0.5k Ohm resistor diff --git a/drivers/led/issi/is31flcommon.c b/drivers/led/issi/is31flcommon.c index 106890a8bf..4b78947ada 100644 --- a/drivers/led/issi/is31flcommon.c +++ b/drivers/led/issi/is31flcommon.c @@ -133,19 +133,28 @@ void IS31FL_common_update_pwm_register(uint8_t addr, uint8_t index) { #ifdef ISSI_MANUAL_SCALING void IS31FL_set_manual_scaling_buffer(void) { + is31_led led; + is31_led scale; for (int i = 0; i < ISSI_MANUAL_SCALING; i++) { - is31_led scale = g_is31_scaling[i]; + memcpy_P(&scale, (&g_is31_scaling[i]), sizeof(scale)); + # ifdef RGB_MATRIX_ENABLE if (scale.driver >= 0 && scale.driver < RGB_MATRIX_LED_COUNT) { - is31_led led = g_is31_leds[scale.driver]; + memcpy_P(&led, (&g_is31_leds[scale.driver]), sizeof(led)); + if (g_scaling_buffer[led.driver][led.r] = scale.r && g_scaling_buffer[led.driver][led.g] = scale.g && g_scaling_buffer[led.driver][led.b] = scale.b) { + return; + } g_scaling_buffer[led.driver][led.r] = scale.r; g_scaling_buffer[led.driver][led.g] = scale.g; g_scaling_buffer[led.driver][led.b] = scale.b; # elif defined(LED_MATRIX_ENABLE) if (scale.driver >= 0 && scale.driver < LED_MATRIX_LED_COUNT) { - is31_led led = g_is31_leds[scale.driver]; + memcpy_P(&led, (&g_is31_leds[scale.driver]), sizeof(led)); + if (g_scaling_buffer[led.driver][led.v] == scale.v) { + return; + } g_scaling_buffer[led.driver][led.v] = scale.v; # endif g_scaling_buffer_update_required[led.driver] = true; @@ -169,7 +178,8 @@ void IS31FL_common_update_scaling_register(uint8_t addr, uint8_t index) { // Colour is set by adjusting PWM register void IS31FL_RGB_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { if (index >= 0 && index < RGB_MATRIX_LED_COUNT) { - is31_led led = g_is31_leds[index]; + is31_led led; + memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); g_pwm_buffer[led.driver][led.r] = red; g_pwm_buffer[led.driver][led.g] = green; @@ -186,7 +196,8 @@ void IS31FL_RGB_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { // Setup Scaling register that decides the peak current of each LED void IS31FL_RGB_set_scaling_buffer(uint8_t index, bool red, bool green, bool blue) { - is31_led led = g_is31_leds[index]; + is31_led led; + memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); if (red) { g_scaling_buffer[led.driver][led.r] = ISSI_SCAL_RED; } else { @@ -208,7 +219,8 @@ void IS31FL_RGB_set_scaling_buffer(uint8_t index, bool red, bool green, bool blu #elif defined(LED_MATRIX_ENABLE) // LED Matrix Specific scripts void IS31FL_simple_set_scaling_buffer(uint8_t index, bool value) { - is31_led led = g_is31_leds[index]; + is31_led led; + memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); if (value) { g_scaling_buffer[led.driver][led.v] = ISSI_SCAL_LED; } else { @@ -219,7 +231,9 @@ void IS31FL_simple_set_scaling_buffer(uint8_t index, bool value) { void IS31FL_simple_set_brightness(int index, uint8_t value) { if (index >= 0 && index < LED_MATRIX_LED_COUNT) { - is31_led led = g_is31_leds[index]; + is31_led led; + memcpy_P(&led, (&g_is31_leds[index]), sizeof(led)); + g_pwm_buffer[led.driver][led.v] = value; g_pwm_buffer_update_required[led.driver] = true; } diff --git a/drivers/led/issi/is31flcommon.h b/drivers/led/issi/is31flcommon.h index 18432ffc31..4b3add558b 100644 --- a/drivers/led/issi/is31flcommon.h +++ b/drivers/led/issi/is31flcommon.h @@ -43,7 +43,7 @@ typedef struct is31_led { uint8_t b; } __attribute__((packed)) is31_led; -extern const is31_led __flash g_is31_leds[RGB_MATRIX_LED_COUNT]; +extern const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT]; #elif defined(LED_MATRIX_ENABLE) typedef struct is31_led { @@ -51,11 +51,11 @@ typedef struct is31_led { uint8_t v; } __attribute__((packed)) is31_led; -extern const is31_led __flash g_is31_leds[LED_MATRIX_LED_COUNT]; +extern const is31_led PROGMEM g_is31_leds[LED_MATRIX_LED_COUNT]; #endif #ifdef ISSI_MANUAL_SCALING -extern const is31_led __flash g_is31_scaling[]; +extern const is31_led PROGMEM g_is31_scaling[]; void IS31FL_set_manual_scaling_buffer(void); #endif diff --git a/drivers/painter/ili9xxx/qp_ili9xxx_opcodes.h b/drivers/painter/ili9xxx/qp_ili9xxx_opcodes.h index 47bb703648..f57e638e03 100644 --- a/drivers/painter/ili9xxx/qp_ili9xxx_opcodes.h +++ b/drivers/painter/ili9xxx/qp_ili9xxx_opcodes.h @@ -19,8 +19,8 @@ #define ILI9XXX_CMD_SLEEP_OFF 0x11 // Exist sleep mode #define ILI9XXX_CMD_PARTIAL_ON 0x12 // Enter partial mode #define ILI9XXX_CMD_PARTIAL_OFF 0x13 // Exit partial mode -#define ILI9XXX_CMD_INVERT_ON 0x20 // Enter inverted mode -#define ILI9XXX_CMD_INVERT_OFF 0x21 // Exit inverted mode +#define ILI9XXX_CMD_INVERT_OFF 0x20 // Exit inverted mode +#define ILI9XXX_CMD_INVERT_ON 0x21 // Enter inverted mode #define ILI9XXX_SET_GAMMA 0x26 // Set gamma params #define ILI9XXX_CMD_DISPLAY_OFF 0x28 // Disable display #define ILI9XXX_CMD_DISPLAY_ON 0x29 // Enable display diff --git a/drivers/ps2/ps2_mouse.c b/drivers/ps2/ps2_mouse.c index d6911d66f2..ae594c94bc 100644 --- a/drivers/ps2/ps2_mouse.c +++ b/drivers/ps2/ps2_mouse.c @@ -191,13 +191,12 @@ static inline void ps2_mouse_convert_report_to_hid(report_mouse_t *mouse_report) #ifdef PS2_MOUSE_INVERT_BUTTONS // swap left & right buttons - uint8_t needs_left = mouse_report->buttons & PS2_MOUSE_BTN_RIGHT; - uint8_t needs_right = mouse_report->buttons & PS2_MOUSE_BTN_LEFT; - mouse_report->buttons = (mouse_report->buttons & ~(PS2_MOUSE_BTN_MASK)) | (needs_left ? PS2_MOUSE_BTN_LEFT : 0) | (needs_right ? PS2_MOUSE_BTN_RIGHT : 0); -#else + bool needs_left = mouse_report->buttons & (1 << PS2_MOUSE_BTN_RIGHT); + bool needs_right = mouse_report->buttons & (1 << PS2_MOUSE_BTN_LEFT); + mouse_report->buttons = (mouse_report->buttons & ~((1 << PS2_MOUSE_BTN_LEFT) | (1 << PS2_MOUSE_BTN_RIGHT))) | (needs_left << PS2_MOUSE_BTN_LEFT) | (needs_right << PS2_MOUSE_BTN_RIGHT); +#endif // remove sign and overflow flags mouse_report->buttons &= PS2_MOUSE_BTN_MASK; -#endif #ifdef PS2_MOUSE_INVERT_X mouse_report->x = -mouse_report->x; diff --git a/drivers/sensors/pmw33xx_common.h b/drivers/sensors/pmw33xx_common.h index 88523b8420..b30ee3d596 100644 --- a/drivers/sensors/pmw33xx_common.h +++ b/drivers/sensors/pmw33xx_common.h @@ -10,7 +10,7 @@ #pragma once -#include "quantum.h" //to get is_keyboard_left +#include "keyboard.h" #include <stdint.h> #include "spi_master.h" #include "util.h" |