Merge branch 'develop' into bluefruit_le_uart

This commit is contained in:
KANATSU Minoru 2024-02-14 11:52:00 +09:00 committed by GitHub
commit adfc7cf2ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2677 changed files with 52556 additions and 38736 deletions

View File

@ -35,7 +35,7 @@ jobs:
- name: Get changed files
id: file_changes
uses: tj-actions/changed-files@v40
uses: tj-actions/changed-files@v42
- name: Run qmk formatters
shell: 'bash {0}'

View File

@ -27,7 +27,7 @@ jobs:
- name: Get changed files
id: file_changes
uses: tj-actions/changed-files@v40
uses: tj-actions/changed-files@v42
- name: Print info
run: |

5
.gitignore vendored
View File

@ -18,6 +18,11 @@
*.lst
*.map
*.o
*.a
*.so
*.dylib
*.dll
*.la
*.stackdump
*.sym

View File

@ -337,24 +337,23 @@ define BUILD_TEST
endif
endef
define LIST_TEST
include $(BUILDDEFS_PATH)/testlist.mk
FOUND_TESTS := $$(patsubst ./tests/%,%,$$(TEST_LIST))
$$(info $$(FOUND_TESTS))
endef
define PARSE_TEST
TESTS :=
# list of possible targets, colon-delimited, to reassign to MAKE_TARGET and remove
TARGETS := :clean:
ifneq (,$$(findstring :$$(lastword $$(subst :, ,$$(RULE))):, $$(TARGETS)))
MAKE_TARGET := $$(lastword $$(subst :, ,$$(RULE)))
TEST_SUBPATH := $$(subst $$(eval) ,/,$$(wordlist 2, $$(words $$(subst :, ,$$(RULE))), _ $$(subst :, ,$$(RULE))))
else
MAKE_TARGET :=
TEST_SUBPATH := $$(subst :,/,$$(RULE))
endif
TEST_NAME := $$(firstword $$(subst :, ,$$(RULE)))
TEST_TARGET := $$(subst $$(TEST_NAME),,$$(subst $$(TEST_NAME):,,$$(RULE)))
include $(BUILDDEFS_PATH)/testlist.mk
ifeq ($$(RULE),all)
ifeq ($$(TEST_NAME),all)
MATCHED_TESTS := $$(TEST_LIST)
else
MATCHED_TESTS := $$(foreach TEST, $$(TEST_LIST),$$(if $$(findstring /$$(TEST_SUBPATH)/, $$(patsubst %,%/,$$(TEST))), $$(TEST),))
MATCHED_TESTS := $$(foreach TEST, $$(TEST_LIST),$$(if $$(findstring x$$(TEST_NAME)x, x$$(patsubst ./tests/%,%,$$(TEST)x)), $$(TEST),))
endif
$$(foreach TEST,$$(MATCHED_TESTS),$$(eval $$(call BUILD_TEST,$$(TEST),$$(MAKE_TARGET))))
$$(foreach TEST,$$(MATCHED_TESTS),$$(eval $$(call BUILD_TEST,$$(TEST),$$(TEST_TARGET))))
endef
@ -437,6 +436,10 @@ git-submodules: git-submodule
list-keyboards:
$(QMK_BIN) list-keyboards --no-resolve-defaults | tr '\n' ' '
.PHONY: list-tests
list-tests:
$(eval $(call LIST_TEST))
.PHONY: generate-keyboards-file
generate-keyboards-file:
$(QMK_BIN) list-keyboards --no-resolve-defaults

View File

@ -362,71 +362,67 @@ ifeq ($(strip $(LED_MATRIX_ENABLE)), yes)
ifeq ($(strip $(LED_MATRIX_DRIVER)), is31fl3218)
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31fl3218-simple.c
SRC += is31fl3218-mono.c
endif
ifeq ($(strip $(LED_MATRIX_DRIVER)), is31fl3731)
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31fl3731-simple.c
SRC += is31fl3731-mono.c
endif
ifeq ($(strip $(LED_MATRIX_DRIVER)), is31fl3733)
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31fl3733-simple.c
SRC += is31fl3733-mono.c
endif
ifeq ($(strip $(LED_MATRIX_DRIVER)), is31fl3736)
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31fl3736-simple.c
SRC += is31fl3736-mono.c
endif
ifeq ($(strip $(LED_MATRIX_DRIVER)), is31fl3737)
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31fl3737-simple.c
SRC += is31fl3737-mono.c
endif
ifeq ($(strip $(LED_MATRIX_DRIVER)), is31fl3741)
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31fl3741-simple.c
SRC += is31fl3741-mono.c
endif
ifeq ($(strip $(LED_MATRIX_DRIVER)), is31fl3742a)
OPT_DEFS += -DIS31FLCOMMON
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31flcommon.c
SRC += is31fl3742a-mono.c
endif
ifeq ($(strip $(LED_MATRIX_DRIVER)), is31fl3743a)
OPT_DEFS += -DIS31FLCOMMON
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31flcommon.c
SRC += is31fl3743a-mono.c
endif
ifeq ($(strip $(LED_MATRIX_DRIVER)), is31fl3745)
OPT_DEFS += -DIS31FLCOMMON
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31flcommon.c
SRC += is31fl3745-mono.c
endif
ifeq ($(strip $(LED_MATRIX_DRIVER)), is31fl3746a)
OPT_DEFS += -DIS31FLCOMMON
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31flcommon.c
SRC += is31fl3746a-mono.c
endif
ifeq ($(strip $(LED_MATRIX_DRIVER)), snled27351)
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led
SRC += snled27351-simple.c
SRC += snled27351-mono.c
endif
endif
@ -503,31 +499,27 @@ ifeq ($(strip $(RGB_MATRIX_ENABLE)), yes)
endif
ifeq ($(strip $(RGB_MATRIX_DRIVER)), is31fl3742a)
OPT_DEFS += -DIS31FLCOMMON
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31flcommon.c
SRC += is31fl3742a.c
endif
ifeq ($(strip $(RGB_MATRIX_DRIVER)), is31fl3743a)
OPT_DEFS += -DIS31FLCOMMON
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31flcommon.c
SRC += is31fl3743a.c
endif
ifeq ($(strip $(RGB_MATRIX_DRIVER)), is31fl3745)
OPT_DEFS += -DIS31FLCOMMON
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31flcommon.c
SRC += is31fl3745.c
endif
ifeq ($(strip $(RGB_MATRIX_DRIVER)), is31fl3746a)
OPT_DEFS += -DIS31FLCOMMON
I2C_DRIVER_REQUIRED = yes
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31flcommon.c
SRC += is31fl3746a.c
endif
ifeq ($(strip $(RGB_MATRIX_DRIVER)), snled27351)
@ -616,24 +608,9 @@ ifeq ($(strip $(VIA_ENABLE)), yes)
TRI_LAYER_ENABLE := yes
endif
VALID_MAGIC_TYPES := yes
BOOTMAGIC_ENABLE ?= no
ifneq ($(strip $(BOOTMAGIC_ENABLE)), no)
ifeq ($(filter $(BOOTMAGIC_ENABLE),$(VALID_MAGIC_TYPES)),)
$(call CATASTROPHIC_ERROR,Invalid BOOTMAGIC_ENABLE,BOOTMAGIC_ENABLE="$(BOOTMAGIC_ENABLE)" is not a valid type of magic)
endif
ifneq ($(strip $(BOOTMAGIC_ENABLE)), no)
OPT_DEFS += -DBOOTMAGIC_LITE
QUANTUM_SRC += $(QUANTUM_DIR)/bootmagic/bootmagic_lite.c
endif
endif
COMMON_VPATH += $(QUANTUM_DIR)/bootmagic
QUANTUM_SRC += $(QUANTUM_DIR)/bootmagic/magic.c
VALID_CUSTOM_MATRIX_TYPES:= yes lite no
CUSTOM_MATRIX ?= no
ifneq ($(strip $(CUSTOM_MATRIX)), yes)
ifeq ($(filter $(CUSTOM_MATRIX),$(VALID_CUSTOM_MATRIX_TYPES)),)
$(call CATASTROPHIC_ERROR,Invalid CUSTOM_MATRIX,CUSTOM_MATRIX="$(CUSTOM_MATRIX)" is not a valid custom matrix type)

View File

@ -21,6 +21,7 @@ SPACE_CADET_ENABLE ?= yes
GENERIC_FEATURES = \
AUTO_SHIFT \
AUTOCORRECT \
BOOTMAGIC \
CAPS_WORD \
COMBO \
COMMAND \

View File

@ -0,0 +1,407 @@
{
"aliases": {
/*
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
* │ # │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ = │ │
* ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
* │ │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ ^ │ ¸ │ │
* ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐ │
* │ │ A │ S │ D │ F │ G │ H │ J │ K │ L │ ; │ ` │ < │ │
* ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
* │ │ « │ Z │ X │ C │ V │ B │ N │ M │ , │ . │ É │ │
* ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
* │ │ │ │ │ │ │ │ │
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
*/
"KC_GRV": {
"key": "FR_HASH",
"label": "#",
}
"KC_1": {
"key": "FR_1",
"label": "1",
}
"KC_2": {
"key": "FR_2",
"label": "2",
}
"KC_3": {
"key": "FR_3",
"label": "3",
}
"KC_4": {
"key": "FR_4",
"label": "4",
}
"KC_5": {
"key": "FR_5",
"label": "5",
}
"KC_6": {
"key": "FR_6",
"label": "6",
}
"KC_7": {
"key": "FR_7",
"label": "7",
}
"KC_8": {
"key": "FR_8",
"label": "8",
}
"KC_9": {
"key": "FR_9",
"label": "9",
}
"KC_0": {
"key": "FR_0",
"label": "0",
}
"KC_MINS": {
"key": "FR_MINS",
"label": "-",
}
"KC_EQL": {
"key": "FR_EQL",
"label": "=",
}
"KC_Q": {
"key": "FR_Q",
"label": "Q",
}
"KC_W": {
"key": "FR_W",
"label": "W",
}
"KC_E": {
"key": "FR_E",
"label": "E",
}
"KC_R": {
"key": "FR_R",
"label": "R",
}
"KC_T": {
"key": "FR_T",
"label": "T",
}
"KC_Y": {
"key": "FR_Y",
"label": "Y",
}
"KC_U": {
"key": "FR_U",
"label": "U",
}
"KC_I": {
"key": "FR_I",
"label": "I",
}
"KC_O": {
"key": "FR_O",
"label": "O",
}
"KC_P": {
"key": "FR_P",
"label": "P",
}
"KC_LBRC": {
"key": "FR_DCIR",
"label": "^ (dead)",
}
"KC_RBRC": {
"key": "FR_CEDL",
"label": "¸ (dead)",
}
"KC_A": {
"key": "FR_A",
"label": "A",
}
"KC_S": {
"key": "FR_S",
"label": "S",
}
"KC_D": {
"key": "FR_D",
"label": "D",
}
"KC_F": {
"key": "FR_F",
"label": "F",
}
"KC_G": {
"key": "FR_G",
"label": "G",
}
"KC_H": {
"key": "FR_H",
"label": "H",
}
"KC_J": {
"key": "FR_J",
"label": "J",
}
"KC_K": {
"key": "FR_K",
"label": "K",
}
"KC_L": {
"key": "FR_L",
"label": "L",
}
"KC_SCLN": {
"key": "FR_SCLN",
"label": ";",
}
"KC_QUOT": {
"key": "FR_DGRV",
"label": "` (dead)",
}
"KC_NUHS": {
"key": "FR_LABK",
"label": "<",
}
"KC_NUBS": {
"key": "FR_LDAQ",
"label": "«",
}
"KC_Z": {
"key": "FR_Z",
"label": "Z",
}
"KC_X": {
"key": "FR_X",
"label": "X",
}
"KC_C": {
"key": "FR_C",
"label": "C",
}
"KC_V": {
"key": "FR_V",
"label": "V",
}
"KC_B": {
"key": "FR_B",
"label": "B",
}
"KC_N": {
"key": "FR_N",
"label": "N",
}
"KC_M": {
"key": "FR_M",
"label": "M",
}
"KC_COMM": {
"key": "FR_COMM",
"label": ",",
}
"KC_DOT": {
"key": "FR_DOT",
"label": ".",
}
"KC_SLSH": {
"key": "FR_EACU",
"label": "É",
}
/* Shifted symbols
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
* │ | │ ! │ " │ / │ $ │ % │ ? │ & │ * │ ( │ ) │ _ │ + │ │
* ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
* │ │ │ │ │ │ │ │ │ │ │ │ │ ¨ │ │
* ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐ │
* │ │ │ │ │ │ │ │ │ │ │ : │ │ > │ │
* ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
* │ │ » │ │ │ │ │ │ │ │ ' │ │ │ │
* ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
* │ │ │ │ │ │ │ │ │
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
*/
"S(FR_HASH)": {
"key": "FR_PIPE",
"label": "|",
}
"S(FR_1)": {
"key": "FR_EXLM",
"label": "!",
}
"S(FR_2)": {
"key": "FR_DQUO",
"label": "\"",
}
"S(FR_3)": {
"key": "FR_SLSH",
"label": "/",
}
"S(FR_4)": {
"key": "FR_DLR",
"label": "$",
}
"S(FR_5)": {
"key": "FR_PERC",
"label": "%",
}
"S(FR_6)": {
"key": "FR_QUES",
"label": "?",
}
"S(FR_7)": {
"key": "FR_AMPR",
"label": "&",
}
"S(FR_8)": {
"key": "FR_ASTR",
"label": "*",
}
"S(FR_9)": {
"key": "FR_LPRN",
"label": "(",
}
"S(FR_0)": {
"key": "FR_RPRN",
"label": ")",
}
"S(FR_MINS)": {
"key": "FR_UNDS",
"label": "_",
}
"S(FR_EQL)": {
"key": "FR_PLUS",
"label": "+",
}
"S(FR_CEDL)": {
"key": "FR_DIAE",
"label": "¨ (dead)",
}
"S(FR_SCLN)": {
"key": "FR_COLN",
"label": ":",
}
"S(FR_LABK)": {
"key": "FR_RABK",
"label": ">",
}
"S(FR_LDAQ)": {
"key": "FR_RDAQ",
"label": "»",
}
"S(FR_COMM)": {
"key": "FR_QUOT",
"label": "'",
}
/* AltGr symbols
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
* │ \ │ ± │ @ │ £ │ ¢ │ ¤ │ ¬ │ ¦ │ ² │ ³ │ ¼ │ ½ │ ¾ │ │
* ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
* │ │ │ │ │ │ │ │ │ │ § │ ¶ │ [ │ ] │ │
* ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐ │
* │ │ │ │ │ │ │ │ │ │ │ ~ │ { │ } │ │
* ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
* │ │ ° │ │ │ │ │ │ │ µ │ ¯ │ - │ ´ │ │
* ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
* │ │ │ │ │ │ │ │ │
* └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
*/
"ALGR(FR_HASH)": {
"key": "FR_BSLS",
"label": "\\",
}
"ALGR(FR_1)": {
"key": "FR_PLMN",
"label": "±",
}
"ALGR(FR_2)": {
"key": "FR_AT",
"label": "@",
}
"ALGR(FR_3)": {
"key": "FR_PND",
"label": "£",
}
"ALGR(FR_4)": {
"key": "FR_CENT",
"label": "¢",
}
"ALGR(FR_5)": {
"key": "FR_CURR",
"label": "¤",
}
"ALGR(FR_6)": {
"key": "FR_NOT",
"label": "¬",
}
"ALGR(FR_7)": {
"key": "FR_BRKP",
"label": "¦",
}
"ALGR(FR_8)": {
"key": "FR_SUP2",
"label": "²",
}
"ALGR(FR_9)": {
"key": "FR_SUP3",
"label": "³",
}
"ALGR(FR_0)": {
"key": "FR_QRTR",
"label": "¼",
}
"ALGR(FR_MINS)": {
"key": "FR_HALF",
"label": "½",
}
"ALGR(FR_EQL)": {
"key": "FR_TQTR",
"label": "¾",
}
"ALGR(FR_O)": {
"key": "FR_SECT",
"label": "§",
}
"ALGR(FR_P)": {
"key": "FR_PARA",
"label": "¶",
}
"ALGR(FR_DCIR)": {
"key": "FR_LBRC",
"label": "[",
}
"ALGR(FR_CEDL)": {
"key": "FR_RBRC",
"label": "]",
}
"ALGR(FR_SCLN)": {
"key": "FR_TILD",
"label": "~",
}
"ALGR(FR_DGRV)": {
"key": "FR_LCBR",
"label": "{",
}
"ALGR(FR_LABK)": {
"key": "FR_RCBR",
"label": "}",
}
"ALGR(FR_LDAQ)": {
"key": "FR_DEG",
"label": "°",
}
"ALGR(FR_M)": {
"key": "FR_MICR",
"label": "µ",
}
"ALGR(FR_COMM)": {
"key": "FR_MACR",
"label": "¯",
}
"ALGR(FR_DOT)": {
"key": "FR_SHYP",
"label": "­ (soft hyphen)",
}
"ALGR(FR_EACU)": {
"key": "FR_ACUT",
"label": "´ (dead)",
}
}
}

View File

@ -3,7 +3,7 @@
{
// Format:
// <config.h key>: {"info_key": <info.json key>, ["value_type": <value_type>], ["to_json": <true/false>], ["to_c": <true/false>]}
// value_type: one of "array", "array.int", "bool", "int", "hex", "list", "mapping", "str", "raw"
// value_type: one of "array", "array.int", "bool, "flag", "int", "hex", "list", "mapping", "str", "raw"
// to_json: Default `true`. Set to `false` to exclude this mapping from info.json
// to_c: Default `true`. Set to `false` to exclude this mapping from config.h
// warn_duplicate: Default `true`. Set to `false` to turn off warning when a value exists in both places
@ -17,12 +17,14 @@
"APA102_DI_PIN": {"info_key": "apa102.data_pin"},
// Audio
"AUDIO_VOICES": {"info_key": "audio.voices", "value_type": "bool"},
"SENDSTRING_BELL": {"info_key": "audio.macro_beep", "value_type": "bool"},
"AUDIO_DEFAULT_ON": {"info_key": "audio.default.on", "value_type": "bool"},
"AUDIO_DEFAULT_CLICKY_ON": {"info_key": "audio.default.clicky", "value_type": "bool"},
"AUDIO_VOICES": {"info_key": "audio.voices", "value_type": "flag"},
"SENDSTRING_BELL": {"info_key": "audio.macro_beep", "value_type": "flag"},
// Backlight
"BACKLIGHT_BREATHING": {"info_key": "backlight.breathing", "value_type": "bool"},
"BACKLIGHT_CAPS_LOCK": {"info_key": "backlight.as_caps_lock", "value_type": "bool"},
"BACKLIGHT_BREATHING": {"info_key": "backlight.breathing", "value_type": "flag"},
"BACKLIGHT_CAPS_LOCK": {"info_key": "backlight.as_caps_lock", "value_type": "flag"},
"BACKLIGHT_LEVELS": {"info_key": "backlight.levels", "value_type": "int"},
"BACKLIGHT_LIMIT_VAL": {"info_key": "backlight.max_brightness", "value_type": "int"},
"BACKLIGHT_ON_STATE": {"info_key": "backlight.on_state", "value_type": "int"},
@ -40,10 +42,10 @@
"BOOTMAGIC_LITE_ROW_RIGHT": {"info_key": "split.bootmagic.matrix.0", "value_type": "int"},
// Caps Word
"BOTH_SHIFTS_TURNS_ON_CAPS_WORD": {"info_key": "caps_word.both_shifts_turns_on", "value_type": "bool"},
"BOTH_SHIFTS_TURNS_ON_CAPS_WORD": {"info_key": "caps_word.both_shifts_turns_on", "value_type": "flag"},
"CAPS_WORD_IDLE_TIMEOUT": {"info_key": "caps_word.idle_timeout", "value_type": "int"},
"CAPS_WORD_INVERT_ON_SHIFT": {"info_key": "caps_word.invert_on_shift", "value_type": "bool"},
"DOUBLE_TAP_SHIFT_TURNS_ON_CAPS_WORD": {"info_key": "caps_word.double_tap_shift_turns_on", "value_type": "bool"},
"CAPS_WORD_INVERT_ON_SHIFT": {"info_key": "caps_word.invert_on_shift", "value_type": "flag"},
"DOUBLE_TAP_SHIFT_TURNS_ON_CAPS_WORD": {"info_key": "caps_word.double_tap_shift_turns_on", "value_type": "flag"},
// Combos
"COMBO_TERM": {"info_key": "combo.term", "value_type": "int"},
@ -69,17 +71,17 @@
"LED_PIN_ON_STATE": {"info_key": "indicators.on_state", "value_type": "int"},
// Leader Key
"LEADER_PER_KEY_TIMING": {"info_key": "leader_key.timing", "value_type": "bool"},
"LEADER_KEY_STRICT_KEY_PROCESSING": {"info_key": "leader_key.strict_processing", "value_type": "bool"},
"LEADER_PER_KEY_TIMING": {"info_key": "leader_key.timing", "value_type": "flag"},
"LEADER_KEY_STRICT_KEY_PROCESSING": {"info_key": "leader_key.strict_processing", "value_type": "flag"},
"LEADER_TIMEOUT": {"info_key": "leader_key.timeout", "value_type": "int"},
// LED Matrix
"LED_MATRIX_CENTER": {"info_key": "led_matrix.center_point", "value_type": "array.int"},
"LED_MATRIX_KEYRELEASES": {"info_key": "led_matrix.react_on_keyup", "value_type": "bool"},
"LED_MATRIX_KEYRELEASES": {"info_key": "led_matrix.react_on_keyup", "value_type": "flag"},
"LED_MATRIX_LED_FLUSH_LIMIT": {"info_key": "led_matrix.led_flush_limit", "value_type": "int"},
"LED_MATRIX_LED_PROCESS_LIMIT": {"info_key": "led_matrix.led_process_limit", "value_type": "int", "to_json": false},
"LED_MATRIX_MAXIMUM_BRIGHTNESS": {"info_key": "led_matrix.max_brightness", "value_type": "int"},
"LED_MATRIX_SLEEP": {"info_key": "led_matrix.sleep", "value_type": "bool"},
"LED_MATRIX_SLEEP": {"info_key": "led_matrix.sleep", "value_type": "flag"},
"LED_MATRIX_SPD_STEP": {"info_key": "led_matrix.speed_steps", "value_type": "int"},
"LED_MATRIX_SPLIT": {"info_key": "led_matrix.split_count", "value_type": "array.int"},
"LED_MATRIX_TIMEOUT": {"info_key": "led_matrix.timeout", "value_type": "int"},
@ -90,8 +92,8 @@
"LED_MATRIX_DEFAULT_SPD": {"info_key": "led_matrix.default.speed", "value_type": "int"},
// Locking Switch
"LOCKING_SUPPORT_ENABLE": {"info_key": "qmk.locking.enabled", "value_type": "bool"},
"LOCKING_RESYNC_ENABLE": {"info_key": "qmk.locking.resync", "value_type": "bool"},
"LOCKING_SUPPORT_ENABLE": {"info_key": "qmk.locking.enabled", "value_type": "flag"},
"LOCKING_RESYNC_ENABLE": {"info_key": "qmk.locking.resync", "value_type": "flag"},
// LUFA Bootloader
"QMK_ESC_INPUT": {"info_key": "qmk_lufa_bootloader.esc_input"},
@ -102,7 +104,7 @@
// Matrix
"DEBOUNCE": {"info_key": "debounce", "value_type": "int"},
"DIODE_DIRECTION": {"info_key": "diode_direction"},
"MATRIX_HAS_GHOST": {"info_key": "matrix_pins.ghost", "value_type": "bool"},
"MATRIX_HAS_GHOST": {"info_key": "matrix_pins.ghost", "value_type": "flag"},
"MATRIX_INPUT_PRESSED_STATE": {"info_key": "matrix_pins.input_pressed_state", "value_type": "int"},
"MATRIX_IO_DELAY": {"info_key": "matrix_pins.io_delay", "value_type": "int"},
@ -124,12 +126,12 @@
// RGB Matrix
"RGB_MATRIX_CENTER": {"info_key": "rgb_matrix.center_point", "value_type": "array.int"},
"RGB_MATRIX_HUE_STEP": {"info_key": "rgb_matrix.hue_steps", "value_type": "int"},
"RGB_MATRIX_KEYRELEASES": {"info_key": "rgb_matrix.react_on_keyup", "value_type": "bool"},
"RGB_MATRIX_KEYRELEASES": {"info_key": "rgb_matrix.react_on_keyup", "value_type": "flag"},
"RGB_MATRIX_LED_FLUSH_LIMIT": {"info_key": "rgb_matrix.led_flush_limit", "value_type": "int"},
"RGB_MATRIX_LED_PROCESS_LIMIT": {"info_key": "rgb_matrix.led_process_limit", "value_type": "int", "to_json": false},
"RGB_MATRIX_MAXIMUM_BRIGHTNESS": {"info_key": "rgb_matrix.max_brightness", "value_type": "int"},
"RGB_MATRIX_SAT_STEP": {"info_key": "rgb_matrix.sat_steps", "value_type": "int"},
"RGB_MATRIX_SLEEP": {"info_key": "rgb_matrix.sleep", "value_type": "bool"},
"RGB_MATRIX_SLEEP": {"info_key": "rgb_matrix.sleep", "value_type": "flag"},
"RGB_MATRIX_SPD_STEP": {"info_key": "rgb_matrix.speed_steps", "value_type": "int"},
"RGB_MATRIX_SPLIT": {"info_key": "rgb_matrix.split_count", "value_type": "array.int"},
"RGB_MATRIX_TIMEOUT": {"info_key": "rgb_matrix.timeout", "value_type": "int"},
@ -144,23 +146,23 @@
// RGBLight
"RGBLED_SPLIT": {"info_key": "rgblight.split_count", "value_type": "array.int"},
"RGBLIGHT_HUE_STEP": {"info_key": "rgblight.hue_steps", "value_type": "int"},
"RGBLIGHT_LAYER_BLINK": {"info_key": "rgblight.layers.blink", "value_type": "bool"},
"RGBLIGHT_LAYERS": {"info_key": "rgblight.layers.enabled", "value_type": "bool"},
"RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF": {"info_key": "rgblight.layers.override_rgb", "value_type": "bool"},
"RGBLIGHT_LAYER_BLINK": {"info_key": "rgblight.layers.blink", "value_type": "flag"},
"RGBLIGHT_LAYERS": {"info_key": "rgblight.layers.enabled", "value_type": "flag"},
"RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF": {"info_key": "rgblight.layers.override_rgb", "value_type": "flag"},
"RGBLIGHT_LED_COUNT": {"info_key": "rgblight.led_count", "value_type": "int"},
"RGBLIGHT_LED_MAP": {"info_key": "rgblight.led_map", "value_type": "array.int"},
"RGBLIGHT_LIMIT_VAL": {"info_key": "rgblight.max_brightness", "value_type": "int"},
"RGBLIGHT_MAX_LAYERS": {"info_key": "rgblight.layers.max", "value_type": "int"},
"RGBLIGHT_SAT_STEP": {"info_key": "rgblight.saturation_steps", "value_type": "int"},
"RGBLIGHT_SLEEP": {"info_key": "rgblight.sleep", "value_type": "bool"},
"RGBLIGHT_SPLIT": {"info_key": "rgblight.split", "value_type": "bool"},
"RGBLIGHT_SLEEP": {"info_key": "rgblight.sleep", "value_type": "flag"},
"RGBLIGHT_SPLIT": {"info_key": "rgblight.split", "value_type": "flag"},
"RGBLIGHT_VAL_STEP": {"info_key": "rgblight.brightness_steps", "value_type": "int"},
"RGBLIGHT_DEFAULT_ON": {"info_key": "rgblight.default.on", "value_type": "bool"},
"RGBLIGHT_DEFAULT_HUE": {"info_key": "rgblight.default.hue", "value_type": "int"},
"RGBLIGHT_DEFAULT_SAT": {"info_key": "rgblight.default.sat", "value_type": "int"},
"RGBLIGHT_DEFAULT_VAL": {"info_key": "rgblight.default.val", "value_type": "int"},
"RGBLIGHT_DEFAULT_SPD": {"info_key": "rgblight.default.speed", "value_type": "int"},
"RGBW": {"info_key": "rgblight.rgbw", "value_type": "bool"},
"RGBW": {"info_key": "rgblight.rgbw", "value_type": "flag"},
// Secure
"SECURE_IDLE_TIMEOUT": {"info_key": "secure.idle_timeout", "value_type": "int"},
@ -172,37 +174,37 @@
"SOFT_SERIAL_SPEED": {"info_key": "split.soft_serial_speed"},
"SPLIT_HAND_MATRIX_GRID": {"info_key": "split.handedness.matrix_grid", "value_type": "array", "to_c": false},
"SPLIT_HAND_PIN": {"info_key": "split.handedness.pin"},
"SPLIT_USB_DETECT": {"info_key": "split.usb_detect.enabled", "value_type": "bool"},
"SPLIT_USB_DETECT": {"info_key": "split.usb_detect.enabled", "value_type": "flag"},
"SPLIT_USB_TIMEOUT": {"info_key": "split.usb_detect.timeout", "value_type": "int"},
"SPLIT_USB_TIMEOUT_POLL": {"info_key": "split.usb_detect.polling_interval", "value_type": "int"},
"SPLIT_WATCHDOG_ENABLE": {"info_key": "split.transport.watchdog", "value_type": "bool"},
"SPLIT_WATCHDOG_ENABLE": {"info_key": "split.transport.watchdog", "value_type": "flag"},
"SPLIT_WATCHDOG_TIMEOUT": {"info_key": "split.transport.watchdog_timeout", "value_type": "int"},
"SPLIT_ACTIVITY_ENABLE": {"info_key": "split.transport.sync.activity", "value_type": "bool"},
"SPLIT_DETECTED_OS_ENABLE": {"info_key": "split.transport.sync.detected_os", "value_type": "bool"},
"SPLIT_HAPTIC_ENABLE": {"info_key": "split.transport.sync.haptic", "value_type": "bool"},
"SPLIT_LAYER_STATE_ENABLE": {"info_key": "split.transport.sync.layer_state", "value_type": "bool"},
"SPLIT_LED_STATE_ENABLE": {"info_key": "split.transport.sync.indicators", "value_type": "bool"},
"SPLIT_TRANSPORT_MIRROR": {"info_key": "split.transport.sync.matrix_state", "value_type": "bool"},
"SPLIT_MODS_ENABLE": {"info_key": "split.transport.sync.modifiers", "value_type": "bool"},
"SPLIT_OLED_ENABLE": {"info_key": "split.transport.sync.oled", "value_type": "bool"},
"SPLIT_ST7565_ENABLE": {"info_key": "split.transport.sync.st7565", "value_type": "bool"},
"SPLIT_WPM_ENABLE": {"info_key": "split.transport.sync.wpm", "value_type": "bool"},
"SPLIT_ACTIVITY_ENABLE": {"info_key": "split.transport.sync.activity", "value_type": "flag"},
"SPLIT_DETECTED_OS_ENABLE": {"info_key": "split.transport.sync.detected_os", "value_type": "flag"},
"SPLIT_HAPTIC_ENABLE": {"info_key": "split.transport.sync.haptic", "value_type": "flag"},
"SPLIT_LAYER_STATE_ENABLE": {"info_key": "split.transport.sync.layer_state", "value_type": "flag"},
"SPLIT_LED_STATE_ENABLE": {"info_key": "split.transport.sync.indicators", "value_type": "flag"},
"SPLIT_TRANSPORT_MIRROR": {"info_key": "split.transport.sync.matrix_state", "value_type": "flag"},
"SPLIT_MODS_ENABLE": {"info_key": "split.transport.sync.modifiers", "value_type": "flag"},
"SPLIT_OLED_ENABLE": {"info_key": "split.transport.sync.oled", "value_type": "flag"},
"SPLIT_ST7565_ENABLE": {"info_key": "split.transport.sync.st7565", "value_type": "flag"},
"SPLIT_WPM_ENABLE": {"info_key": "split.transport.sync.wpm", "value_type": "flag"},
// Tapping
"HOLD_ON_OTHER_KEY_PRESS": {"info_key": "tapping.hold_on_other_key_press", "value_type": "bool"},
"HOLD_ON_OTHER_KEY_PRESS_PER_KEY": {"info_key": "tapping.hold_on_other_key_press_per_key", "value_type": "bool"},
"PERMISSIVE_HOLD": {"info_key": "tapping.permissive_hold", "value_type": "bool"},
"PERMISSIVE_HOLD_PER_KEY": {"info_key": "tapping.permissive_hold_per_key", "value_type": "bool"},
"RETRO_TAPPING": {"info_key": "tapping.retro", "value_type": "bool"},
"RETRO_TAPPING_PER_KEY": {"info_key": "tapping.retro_per_key", "value_type": "bool"},
"HOLD_ON_OTHER_KEY_PRESS": {"info_key": "tapping.hold_on_other_key_press", "value_type": "flag"},
"HOLD_ON_OTHER_KEY_PRESS_PER_KEY": {"info_key": "tapping.hold_on_other_key_press_per_key", "value_type": "flag"},
"PERMISSIVE_HOLD": {"info_key": "tapping.permissive_hold", "value_type": "flag"},
"PERMISSIVE_HOLD_PER_KEY": {"info_key": "tapping.permissive_hold_per_key", "value_type": "flag"},
"RETRO_TAPPING": {"info_key": "tapping.retro", "value_type": "flag"},
"RETRO_TAPPING_PER_KEY": {"info_key": "tapping.retro_per_key", "value_type": "flag"},
"TAP_CODE_DELAY": {"info_key": "qmk.tap_keycode_delay", "value_type": "int"},
"TAP_HOLD_CAPS_DELAY": {"info_key": "qmk.tap_capslock_delay", "value_type": "int"},
"TAPPING_TERM": {"info_key": "tapping.term", "value_type": "int"},
"TAPPING_TERM_PER_KEY": {"info_key": "tapping.term_per_key", "value_type": "bool"},
"TAPPING_TERM_PER_KEY": {"info_key": "tapping.term_per_key", "value_type": "flag"},
"TAPPING_TOGGLE": {"info_key": "tapping.toggle", "value_type": "int"},
// USB
"FORCE_NKRO": {"info_key": "usb.force_nkro", "value_type": "bool"},
"FORCE_NKRO": {"info_key": "usb.force_nkro", "value_type": "flag"},
"USB_MAX_POWER_CONSUMPTION": {"info_key": "usb.max_power", "value_type": "int"},
"USB_POLLING_INTERVAL_MS": {"info_key": "usb.polling_interval", "value_type": "int"},
"USB_SUSPEND_WAKEUP_DELAY": {"info_key": "usb.suspend_wakeup_delay", "value_type": "int"},
@ -217,7 +219,7 @@
// Items we want flagged in lint
"DEBOUNCING_DELAY": {"info_key": "_invalid.debouncing_delay", "invalid": true, "replace_with": "DEBOUNCE"},
"DESCRIPTION": {"info_key": "_invalid.usb_description", "invalid": true},
"IGNORE_MOD_TAP_INTERRUPT": {"info_key": "_invalid.ignore_mod_tap_interrupt", "value_type": "bool", "invalid": true},
"IGNORE_MOD_TAP_INTERRUPT": {"info_key": "_invalid.ignore_mod_tap_interrupt", "value_type": "flag", "invalid": true},
"IGNORE_MOD_TAP_INTERRUPT_PER_KEY": {"info_key": "_invalid.ignore_mod_tap_interrupt_per_key", "invalid": true},
"LED_DISABLE_WHEN_USB_SUSPENDED": {"info_key": "_invalid.led_matrix_sleep", "invalid": true, "replace_with": "LED_MATRIX_SLEEP"},
"NO_ACTION_FUNCTION": {"info_key": "_invalid.no_action_function", "invalid": true},
@ -226,9 +228,9 @@
"QMK_KEYS_PER_SCAN": {"info_key": "qmk.keys_per_scan", "value_type": "int", "deprecated": true},
"RGB_DI_PIN": {"info_key": "rgblight.pin", "invalid": true, "replace_with": "WS2812_DI_PIN or APA102_DI_PIN"},
"RGB_DISABLE_WHEN_USB_SUSPENDED": {"info_key": "_invalid.rgb_matrix_sleep", "invalid": true, "replace_with": "RGB_MATRIX_SLEEP"},
"RGBLIGHT_ANIMATIONS": {"info_key": "_invalid.rgblight.animations.all", "value_type": "bool", "invalid": true},
"TAPPING_FORCE_HOLD": {"info_key": "tapping.force_hold", "value_type": "bool", "deprecated": true},
"TAPPING_FORCE_HOLD_PER_KEY": {"info_key": "tapping.force_hold_per_key", "value_type": "bool", "deprecated": true},
"RGBLIGHT_ANIMATIONS": {"info_key": "_invalid.rgblight.animations.all", "value_type": "flag", "invalid": true},
"TAPPING_FORCE_HOLD": {"info_key": "tapping.force_hold", "value_type": "flag", "deprecated": true},
"TAPPING_FORCE_HOLD_PER_KEY": {"info_key": "tapping.force_hold_per_key", "value_type": "flag", "deprecated": true},
"UNUSED_PINS": {"info_key": "_invalid.unused_pins", "deprecated": true},
"COMBO_COUNT": {"info_key": "_invalid.combo.count", "invalid": true},

View File

@ -287,6 +287,12 @@
"honeycomb": {
"target": "keyhive/honeycomb"
},
"hub16": {
"target": "joshajohnson/hub16"
},
"hub20": {
"target": "joshajohnson/hub20"
},
"idb_60": {
"target": "idb/idb_60"
},
@ -329,8 +335,41 @@
"keycapsss/plaid_pad": {
"target": "keycapsss/plaid_pad/rev1"
},
"kira75": {
"target": "kira/kira75"
},
"kira80": {
"target": "kira/kira80"
},
"kudox": {
"target": "kudox/rev1"
"target": "kumaokobo/kudox/rev1"
},
"kudox/columner": {
"target": "kumaokobo/kudox/columner"
},
"kudox/rev1": {
"target": "kumaokobo/kudox/rev1"
},
"kudox/rev2": {
"target": "kumaokobo/kudox/rev2"
},
"kudox/rev3": {
"target": "kumaokobo/kudox/rev3"
},
"kudox_full": {
"target": "kumaokobo/kudox_full/rev1"
},
"kudox_full/rev1": {
"target": "kumaokobo/kudox_full/rev1"
},
"kudox_game": {
"target": "kumaokobo/kudox_game/rev1"
},
"kudox_game/rev1": {
"target": "kumaokobo/kudox_game/rev1"
},
"kudox_game/rev2": {
"target": "kumaokobo/kudox_game/rev2"
},
"kyria": {
"target": "splitkb/kyria"
@ -452,6 +491,15 @@
"minim": {
"target": "matthewdias/minim"
},
"mnk1800s": {
"target": "monokei/mnk1800s"
},
"mnk50": {
"target": "monokei/mnk50"
},
"mnk75": {
"target": "monokei/mnk75"
},
"model01": {
"target": "keyboardio/model01"
},
@ -464,6 +512,9 @@
"montsinger/rebound": {
"target": "montsinger/rebound/rev1"
},
"moonlander": {
"target": "zsa/moonlander"
},
"mschwingen/modelm": {
"target": "ibm/model_m/mschwingen"
},
@ -491,6 +542,15 @@
"peiorisboards/ixora": {
"target": "coarse/ixora"
},
"pico": {
"target": "kumaokobo/pico/65keys"
},
"pico/65keys": {
"target": "kumaokobo/pico/65keys"
},
"pico/70keys": {
"target": "kumaokobo/pico/70keys"
},
"plaid": {
"target": "dm9records/plaid"
},
@ -536,6 +596,9 @@
"ramonimbao/mona": {
"target": "rmi_kb/mona/v1"
},
"redox_w": {
"target": "redox/wireless"
},
"rgbkb/pan": {
"target": "rgbkb/pan/rev1/32a"
},
@ -804,6 +867,12 @@
"eggman": {
"target": "qpockets/eggman"
},
"enter67": {
"target": "kezewa/enter67"
},
"enter80": {
"target": "kezewa/enter80"
},
"ergo42": {
"target": "biacco42/ergo42"
},
@ -825,9 +894,15 @@
"espectro": {
"target": "mechkeys/espectro"
},
"eu_isolation": {
"target": "p3d/eu_isolation"
},
"felix": {
"target": "unikeyboard/felix"
},
"flygone60/rev3": {
"target": "shandoncodes/flygone60/rev3"
},
"four_banger": {
"target": "bpiphany/four_banger"
},
@ -921,6 +996,12 @@
"keychron/q4": {
"target": "keychron/q4/ansi/v1"
}
"kmac": {
"target": "kbdmania/kmac"
}
"kmac_pad": {
"target": "kbdmania/kmac_pad"
}
"kprepublic/bm40hsrgb": {
"target": "kprepublic/bm40hsrgb/rev1"
},
@ -930,6 +1011,9 @@
"kprepublic/bm68hsrgb": {
"target": "kprepublic/bm68hsrgb/rev1"
},
"late9/rev1": {
"target": "rookiebwoy/late9/rev1"
},
"latin17rgb": {
"target": "latincompass/latin17rgb"
},
@ -975,9 +1059,21 @@
"ls_60": {
"target": "weirdo/ls_60"
},
"lpad": {
"target": "laneware/lpad"
},
"lw67": {
"target": "laneware/lw67"
},
"lw75": {
"target": "laneware/lw75"
},
"m3n3van": {
"target": "matthewdias/m3n3van"
},
"macro1": {
"target": "laneware/macro1"
},
"massdrop/thekey": {
"target": "drop/thekey/v1"
},
@ -1002,9 +1098,21 @@
"melody96": {
"target": "ymdk/melody96"
},
"miniaxe": {
"target": "kagizaraya/miniaxe"
},
"minidox/rev1": {
"target": "maple_computing/minidox/rev1"
},
"mino/hotswap": {
"target": "shandoncodes/mino/hotswap"
},
"mino_plus/hotswap": {
"target": "shandoncodes/mino_plus/hotswap"
},
"mino_plus/soldered": {
"target": "shandoncodes/mino_plus/soldered"
},
"mio": {
"target": "recompile_keys/mio"
},
@ -1059,6 +1167,9 @@
"nebula68b": {
"target": "spaceholdings/nebula68b"
},
"neopad/rev1": {
"target": "rookiebwoy/neopad/rev1"
},
"niu_mini": {
"target": "kbdfans/niu_mini"
},
@ -1116,6 +1227,9 @@
"pw88": {
"target": "smoll/pw88"
},
"q4z": {
"target": "p3d/q4z"
},
"qaz": {
"target": "tominabox1/qaz"
},
@ -1125,6 +1239,9 @@
"rabbit_capture_plan": {
"target": "kakunpc/rabbit_capture_plan"
},
"raindrop": {
"target": "laneware/raindrop"
},
"ramonimbao/aelith": {
"target": "rmi_kb/aelith"
},
@ -1191,6 +1308,9 @@
"reviung61": {
"target": "reviung/reviung61"
},
"riot_pad": {
"target": "shandoncodes/riot_pad"
},
"runner3680/3x6": {
"target": "omkbd/runner3680/3x6"
},
@ -1245,6 +1365,9 @@
"space_space/rev2": {
"target": "qpockets/space_space/rev2"
},
"spacey": {
"target": "p3d/spacey"
},
"spiderisland/winry25tc": {
"target": "winry/winry25tc"
},
@ -1275,6 +1398,9 @@
"suihankey/split": {
"target": "kakunpc/suihankey/split"
},
"synapse": {
"target": "p3d/synapse"
},
"the_ruler": {
"target": "maple_computing/the_ruler"
},
@ -1296,6 +1422,9 @@
"tronguylabs/m122_3270": {
"target": "ibm/model_m_122/m122_3270/teensy"
},
"tw40": {
"target": "p3d/tw40"
},
"ua62": {
"target": "nacly/ua62"
},
@ -1365,6 +1494,12 @@
"yurei": {
"target": "kkatano/yurei"
},
"z12": {
"target": "zigotica/z12"
},
"z34": {
"target": "zigotica/z34"
},
"zinc": {
"target": "25keys/zinc"
},

View File

@ -123,6 +123,14 @@
"type": "object",
"additionalProperties": false,
"properties": {
"default": {
"type": "object",
"additionalProperties": false,
"properties": {
"on": {"type": "boolean"},
"clicky": {"type": "boolean"}
}
},
"macro_beep": {"type": "boolean"},
"pins": {"$ref": "qmk.definitions.v1#/mcu_pin_array"},
"voices": {"type": "boolean"}
@ -306,8 +314,8 @@
},
"features": {
"$ref": "qmk.definitions.v1#/boolean_array",
"propertyNames": { "$ref": "qmk.definitions.v1#/snake_case" }
"propertyNames": { "$ref": "qmk.definitions.v1#/snake_case" },
"not": { "required": [ "lto" ] }
},
"indicators": {
"type": "object",

View File

@ -275,7 +275,7 @@ There are a few different ways to set handedness for split keyboards (listed in
* For using high/low pin to determine handedness, low = right hand, high = left hand. Replace `B7` with the pin you are using. This is optional, and if you leave `SPLIT_HAND_PIN` undefined, then you can still use the EE_HANDS method or MASTER_LEFT / MASTER_RIGHT defines like the stock Let's Split uses.
* `#define SPLIT_HAND_MATRIX_GRID <out_pin>,<in_pin>`
* The handedness is determined by using the intersection of the keyswitches in the key matrix, which does not exist. Normally, when this intersection is shorted (level low), it is considered left. If you define `#define SPLIT_HAND_MATRIX_GRID_LOW_IS_RIGHT`, it is determined to be right when the level is low.
* The handedness is determined by using the intersection of the keyswitches in the key matrix, which does not exist. Normally, when this intersection is shorted (level low), it is considered right. If you define `#define SPLIT_HAND_MATRIX_GRID_LOW_IS_LEFT`, it is determined to be left when the level is low.
* `#define EE_HANDS` (only works if `SPLIT_HAND_PIN` and `SPLIT_HAND_MATRIX_GRID` are not defined)
* Reads the handedness value stored in the EEPROM after `eeprom-lefthand.eep`/`eeprom-righthand.eep` has been flashed to their respective halves.

View File

@ -82,10 +82,10 @@ Your `keymap.c` will then need an encoder mapping defined (for four layers and t
```c
#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
[_BASE] = { ENCODER_CCW_CW(KC_MS_WH_UP, KC_MS_WH_DOWN), ENCODER_CCW_CW(KC_VOLD, KC_VOLU) },
[_LOWER] = { ENCODER_CCW_CW(RGB_HUD, RGB_HUI), ENCODER_CCW_CW(RGB_SAD, RGB_SAI) },
[_RAISE] = { ENCODER_CCW_CW(RGB_VAD, RGB_VAI), ENCODER_CCW_CW(RGB_SPD, RGB_SPI) },
[_ADJUST] = { ENCODER_CCW_CW(RGB_RMOD, RGB_MOD), ENCODER_CCW_CW(KC_RIGHT, KC_LEFT) },
[0] = { ENCODER_CCW_CW(KC_MS_WH_UP, KC_MS_WH_DOWN), ENCODER_CCW_CW(KC_VOLD, KC_VOLU) },
[1] = { ENCODER_CCW_CW(RGB_HUD, RGB_HUI), ENCODER_CCW_CW(RGB_SAD, RGB_SAI) },
[2] = { ENCODER_CCW_CW(RGB_VAD, RGB_VAI), ENCODER_CCW_CW(RGB_SPD, RGB_SPI) },
[3] = { ENCODER_CCW_CW(RGB_RMOD, RGB_MOD), ENCODER_CCW_CW(KC_RIGHT, KC_LEFT) },
};
#endif
```

View File

@ -65,7 +65,7 @@ const is31fl3731_led_t PROGMEM g_is31fl3731_leds[IS31FL3731_LED_COUNT] = {
}
```
Where `Cx_y` is the location of the LED in the matrix defined by [the datasheet](https://www.issi.com/WW/pdf/31FL3731.pdf) and the header file `drivers/led/issi/is31fl3731-simple.h`. The `driver` is the index of the driver you defined in your `config.h` (`0`, `1`, `2`, or `3` ).
Where `Cx_y` is the location of the LED in the matrix defined by [the datasheet](https://www.issi.com/WW/pdf/31FL3731.pdf) and the header file `drivers/led/issi/is31fl3731-mono.h`. The `driver` is the index of the driver you defined in your `config.h` (`0`, `1`, `2`, or `3` ).
---
### IS31FLCOMMON :id=is31flcommon
@ -142,8 +142,8 @@ const is31_led PROGMEM g_is31_leds[LED_MATRIX_LED_COUNT] = {
* driver
* | LED address
* | | */
{ 0, CS1_SW1 },
{ 0, CS2_SW1 },
{ 0, SW1_CS1 },
{ 0, SW1_CS2 },
// ...
}
```
@ -365,6 +365,7 @@ For inspiration and examples, check out the built-in effects under `quantum/led_
#define LED_MATRIX_DEFAULT_MODE LED_MATRIX_SOLID // Sets the default mode, if none has been set
#define LED_MATRIX_DEFAULT_VAL LED_MATRIX_MAXIMUM_BRIGHTNESS // Sets the default brightness value, if none has been set
#define LED_MATRIX_DEFAULT_SPD 127 // Sets the default animation speed, if none has been set
#define LED_MATRIX_DEFAULT_FLAGS LED_FLAG_ALL // Sets the default LED flags, if none has been set
#define LED_MATRIX_SPLIT { X, Y } // (Optional) For split keyboards, the number of LEDs connected on each half. X = left, Y = Right.
// If reactive effects are enabled, you also will want to enable SPLIT_TRANSPORT_MIRROR
```

View File

@ -217,12 +217,13 @@ Also see the `POINTING_DEVICE_TASK_THROTTLE_MS`, which defaults to 10ms when usi
#### Absolute mode settings
| Setting | Description | Default |
| -------------------------------- | ---------------------------------------------------------- | ------------------ |
| `CIRQUE_PINNACLE_X_LOWER` | (Optional) The minimum reachable X value on the sensor. | `127` |
| `CIRQUE_PINNACLE_X_UPPER` | (Optional) The maximum reachable X value on the sensor. | `1919` |
| `CIRQUE_PINNACLE_Y_LOWER` | (Optional) The minimum reachable Y value on the sensor. | `63` |
| `CIRQUE_PINNACLE_Y_UPPER` | (Optional) The maximum reachable Y value on the sensor. | `1471` |
| Setting | Description | Default |
|-----------------------------------------|-------------------------------------------------------------------------|-------------|
| `CIRQUE_PINNACLE_X_LOWER` | (Optional) The minimum reachable X value on the sensor. | `127` |
| `CIRQUE_PINNACLE_X_UPPER` | (Optional) The maximum reachable X value on the sensor. | `1919` |
| `CIRQUE_PINNACLE_Y_LOWER` | (Optional) The minimum reachable Y value on the sensor. | `63` |
| `CIRQUE_PINNACLE_Y_UPPER` | (Optional) The maximum reachable Y value on the sensor. | `1471` |
| `CIRQUE_PINNACLE_REACHABLE_CALIBRATION` | (Optional) Enable console messages to aide in calibrating above values. | not defined |
#### Absolute mode gestures
@ -728,6 +729,7 @@ There are a few ways to control the auto mouse feature with both `config.h` opti
| `AUTO_MOUSE_TIME` | (Optional) Time layer remains active after activation | _ideally_ (250-1000) | _ms_ | `650 ms` |
| `AUTO_MOUSE_DELAY` | (Optional) Lockout time after non-mouse key is pressed | _ideally_ (100-1000) | _ms_ | `TAPPING_TERM` or `200 ms` |
| `AUTO_MOUSE_DEBOUNCE` | (Optional) Time delay from last activation to next update | _ideally_ (10 - 100) | _ms_ | `25 ms` |
| `AUTO_MOUSE_THRESHOLD` | (Optional) Amount of mouse movement required to switch layers | 0 - | _units_ | `10 units` |
### Adding mouse keys

View File

@ -28,7 +28,7 @@ To send data to the keyboard, you must first find a library for communicating wi
* **Node.js:** [node-hid](https://github.com/node-hid/node-hid)
* **C/C++:** [hidapi](https://github.com/libusb/hidapi)
* **Java:** [purejavahidapi](https://github.com/nyholku/purejavahidapi) and [hid4java](https://github.com/gary-rowe/hid4java)
* **Python:** [pyhidapi](https://pypi.org/project/hid/)
* **Python:** [pyhidapi](https://pypi.org/project/hid/) and [pywinusb](https://pypi.org/project/pywinusb)
Please refer to these libraries' own documentation for instructions on usage. Remember to close the device once you are finished with it!

View File

@ -143,15 +143,15 @@ const is31fl3733_led_t PROGMEM g_is31fl3733_leds[IS31FL3733_LED_COUNT] = {
/* Refer to IS31 manual for these locations
* driver
* | R location
* | | G location
* | | | B location
* | | | | */
{0, B_1, A_1, C_1},
* | | G location
* | | | B location
* | | | | */
{0, SW1_CS1, SW1_CS2, SW1_CS3},
....
}
```
Where `X_Y` is the location of the LED in the matrix defined by [the datasheet](https://www.issi.com/WW/pdf/31FL3733.pdf) and the header file `drivers/led/issi/is31fl3733.h`. The `driver` is the index of the driver you defined in your `config.h` (`0`, `1`, `2`, or `3` for now).
Where `SWx_CSy` is the location of the LED in the matrix defined by [the datasheet](https://www.issi.com/WW/pdf/31FL3733.pdf) and the header file `drivers/led/issi/is31fl3733.h`. The `driver` is the index of the driver you defined in your `config.h` (`0`, `1`, `2`, or `3` for now).
---
### IS31FL3736 :id=is31fl3736
@ -222,10 +222,10 @@ const is31fl3736_led_t PROGMEM g_is31fl3736_leds[IS31FL3736_LED_COUNT] = {
/* Refer to IS31 manual for these locations
* driver
* | R location
* | | G location
* | | | B location
* | | | | */
{0, B_1, A_1, C_1},
* | | G location
* | | | B location
* | | | | */
{0, SW1_CS1, SW1_CS2, SW1_CS3},
....
}
```
@ -296,15 +296,15 @@ const is31fl3737_led_t PROGMEM g_is31fl3737_leds[IS31FL3737_LED_COUNT] = {
/* Refer to IS31 manual for these locations
* driver
* | R location
* | | G location
* | | | B location
* | | | | */
{0, B_1, A_1, C_1},
* | | G location
* | | | B location
* | | | | */
{0, SW1_CS1, SW1_CS2, SW1_CS3},
....
}
```
Where `X_Y` is the location of the LED in the matrix defined by [the datasheet](https://www.issi.com/WW/pdf/31FL3737.pdf) and the header file `drivers/led/issi/is31fl3737.h`. The `driver` is the index of the driver you defined in your `config.h` (Only `0`, `1`, `2`, or `3` for now).
Where `SWx_CSy` is the location of the LED in the matrix defined by [the datasheet](https://www.issi.com/WW/pdf/31FL3737.pdf) and the header file `drivers/led/issi/is31fl3737.h`. The `driver` is the index of the driver you defined in your `config.h` (Only `0`, `1`, `2`, or `3` for now).
---
### IS31FLCOMMON :id=is31flcommon
@ -386,7 +386,7 @@ const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT] = {
* | | G location
* | | | B location
* | | | | */
{0, CS1_SW1, CS2_SW1, CS3_SW1},
{0, SW1_CS1, SW1_CS2, SW1_CS3},
....
}
```
@ -511,16 +511,16 @@ const aw20216s_led_t PROGMEM g_aw20216s_leds[AW20216S_LED_COUNT] = {
* | | G location
* | | | B location
* | | | | */
{ 0, CS1_SW1, CS2_SW1, CS3_SW1 },
{ 0, CS4_SW1, CS5_SW1, CS6_SW1 },
{ 0, CS7_SW1, CS8_SW1, CS9_SW1 },
{ 0, CS10_SW1, CS11_SW1, CS12_SW1 },
{ 0, CS13_SW1, CS14_SW1, CS15_SW1 },
{ 0, SW1_CS1, SW1_CS2, SW1_CS3 },
{ 0, SW1_CS4, SW1_CS5, SW1_CS6 },
{ 0, SW1_CS7, SW1_CS8, SW1_CS9 },
{ 0, SW1_CS10, SW1_CS11, SW1_CS12 },
{ 0, SW1_CS13, SW1_CS14, SW1_CS15 },
...
{ 1, CS1_SW1, CS2_SW1, CS3_SW1 },
{ 1, CS13_SW1, CS14_SW1, CS15_SW1 },
{ 1, CS16_SW1, CS17_SW1, CS18_SW1 },
{ 1, CS4_SW2, CS5_SW2, CS6_SW2 },
{ 1, SW1_CS1, SW1_CS2, SW1_CS3 },
{ 1, SW1_CS13, SW1_CS14, SW1_CS15 },
{ 1, SW1_CS16, SW1_CS17, SW1_CS18 },
{ 1, SW2_CS4, SW2_CS5, SW2_CS6 },
...
};
```
@ -873,12 +873,13 @@ These are defined in [`color.h`](https://github.com/qmk/qmk_firmware/blob/master
#define RGB_MATRIX_LED_PROCESS_LIMIT (RGB_MATRIX_LED_COUNT + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
#define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
#define RGB_MATRIX_DEFAULT_ON true // Sets the default enabled state, if none has been set
#define RGB_MATRIX_DEFAULT_MODE RGB_MATRIX_CYCLE_LEFT_RIGHT // Sets the default mode, if none has been set
#define RGB_MATRIX_DEFAULT_HUE 0 // Sets the default hue value, if none has been set
#define RGB_MATRIX_DEFAULT_SAT 255 // Sets the default saturation value, if none has been set
#define RGB_MATRIX_DEFAULT_ON true // Sets the default enabled state, if none has been set
#define RGB_MATRIX_DEFAULT_VAL RGB_MATRIX_MAXIMUM_BRIGHTNESS // Sets the default brightness value, if none has been set
#define RGB_MATRIX_DEFAULT_SPD 127 // Sets the default animation speed, if none has been set
#define RGB_MATRIX_DEFAULT_FLAGS LED_FLAG_ALL // Sets the default LED flags, if none has been set
#define RGB_MATRIX_DISABLE_KEYCODES // disables control of rgb matrix by keycodes (must use code functions to control the feature)
#define RGB_MATRIX_SPLIT { X, Y } // (Optional) For split keyboards, the number of LEDs connected on each half. X = left, Y = Right.
// If reactive effects are enabled, you also will want to enable SPLIT_TRANSPORT_MIRROR

View File

@ -119,12 +119,12 @@ You can configure the firmware to read key matrix pins on the controller to dete
The first pin is the output pin and the second is the input pin.
Some keyboards have unused intersections in the key matrix. This setting uses one of these unused intersections to determine the handness.
Some keyboards have unused intersections in the key matrix. This setting uses one of these unused intersections to determine the handedness.
Normally, when a diode is connected to an intersection, it is judged to be left. If you add the following definition, it will be judged to be right.
Normally, when a diode is connected to an intersection, it is judged to be right. If you add the following definition, it will be judged to be left.
```c
#define SPLIT_HAND_MATRIX_GRID_LOW_IS_RIGHT
#define SPLIT_HAND_MATRIX_GRID_LOW_IS_LEFT
```
Note that adding a diode at a previously unused intersection will effectively tell the firmware that there is a key held down at that point. You can instruct qmk to ignore that intersection by defining `MATRIX_MASKED` and then defining a `matrix_row_t matrix_mask[MATRIX_ROWS]` array in your keyboard config. Each bit of a single value (starting form the least-significant bit) is used to tell qmk whether or not to pay attention to key presses at that intersection.

View File

@ -173,7 +173,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case TD(CT_CLN): // list all tap dance keycodes with tap-hold configurations
action = &tap_dance_actions[TD_INDEX(keycode)];
action = &tap_dance_actions[QK_TAP_DANCE_GET_INDEX(keycode)];
if (!record->event.pressed && action->state.count && !action->state.finished) {
tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)action->user_data;
tap_code16(tap_hold->tap);

View File

@ -138,23 +138,6 @@ void i2c_init(void) {
---
### `i2c_status_t i2c_start(uint8_t address, uint16_t timeout)` :id=api-i2c-start
Start an I2C transaction.
#### Arguments :id=api-i2c-start-arguments
- `uint8_t address`
The 7-bit I2C address of the device (ie. without the read/write bit - this will be set automatically).
- `uint16_t timeout`
The time in milliseconds to wait for a response from the target device.
#### Return Value :id=api-i2c-start-return
`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
---
### `i2c_status_t i2c_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout)` :id=api-i2c-transmit
Send multiple bytes to the selected I2C device.
@ -197,11 +180,11 @@ Receive multiple bytes from the selected I2C device.
---
### `i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)` :id=api-i2c-writereg
### `i2c_status_t i2c_write_register(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)` :id=api-i2c-write-register
Writes to a register with an 8-bit address on the I2C device.
#### Arguments :id=api-i2c-writereg-arguments
#### Arguments :id=api-i2c-write-register-arguments
- `uint8_t devaddr`
The 7-bit I2C address of the device.
@ -214,17 +197,17 @@ Writes to a register with an 8-bit address on the I2C device.
- `uint16_t timeout`
The time in milliseconds to wait for a response from the target device.
#### Return Value :id=api-i2c-writereg-return
#### Return Value :id=api-i2c-write-register-return
`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
---
### `i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)` :id=api-i2c-writereg16
### `i2c_status_t i2c_write_register16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)` :id=api-i2c-write-register16
Writes to a register with a 16-bit address (big endian) on the I2C device.
#### Arguments :id=api-i2c-writereg16-arguments
#### Arguments :id=api-i2c-write-register16-arguments
- `uint8_t devaddr`
The 7-bit I2C address of the device.
@ -237,17 +220,17 @@ Writes to a register with a 16-bit address (big endian) on the I2C device.
- `uint16_t timeout`
The time in milliseconds to wait for a response from the target device.
#### Return Value :id=api-i2c-writereg16-return
#### Return Value :id=api-i2c-write-register16-return
`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
---
### `i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)` :id=api-i2c-readreg
### `i2c_status_t i2c_read_register(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)` :id=api-i2c-read-register
Reads from a register with an 8-bit address on the I2C device.
#### Arguments :id=api-i2c-readreg-arguments
#### Arguments :id=api-i2c-read-register-arguments
- `uint8_t devaddr`
The 7-bit I2C address of the device.
@ -258,17 +241,17 @@ Reads from a register with an 8-bit address on the I2C device.
- `uint16_t timeout`
The time in milliseconds to wait for a response from the target device.
#### Return Value :id=api-i2c-readreg-return
#### Return Value :id=api-i2c-read-register-return
`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
---
### `i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)`
### `i2c_status_t i2c_read_register16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)` :id=api-i2c-read-register16
Reads from a register with a 16-bit address (big endian) on the I2C device.
#### Arguments :id=api-i2c-readreg16-arguments
#### Arguments :id=api-i2c-read-register16-arguments
- `uint8_t devaddr`
The 7-bit I2C address of the device.
@ -279,12 +262,27 @@ Reads from a register with a 16-bit address (big endian) on the I2C device.
- `uint16_t timeout`
The time in milliseconds to wait for a response from the target device.
#### Return Value :id=api-i2c-readreg16-return
#### Return Value :id=api-i2c-read-register16-return
`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
---
### `i2c_status_t i2c_stop(void)` :id=api-i2c-stop
### `i2c_status_t i2c_ping_address(uint8_t address, uint16_t timeout)` :id=api-i2c-ping-address
Stop the current I2C transaction.
Pings the I2C bus for a specific address.
On ChibiOS a "best effort" attempt is made by reading a single byte from register 0 at the requested address. This should generally work except for I2C devices that do not not respond to a register 0 read request, which will result in a false negative result (unsucessful response to ping attempt).
This function is weakly defined, meaning it can be overridden if necessary for your particular use case:
#### Arguments
- `uint8_t address`
The 7-bit I2C address of the device (ie. without the read/write bit - this will be set automatically).
- `uint16_t timeout`
The time in milliseconds to wait for a response from the target device.
#### Return Value
`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.

View File

@ -248,7 +248,7 @@ QMK での全ての利用可能な設定にはデフォルトがあります。
* high/low ピンを使って左右を決定します。low = 右手、high = 左手。`B7` を使っているピンに置き換えます。これはオプションで、`SPLIT_HAND_PIN` が未定義のままである場合、EE_HANDS メソッドまたは標準の Let's Splitが使っている MASTER_LEFT / MASTER_RIGHT 定義をまだ使うことができます。
* `#define SPLIT_HAND_MATRIX_GRID <out_pin>,<in_pin>`
* 左右はキーマトリックスのキースイッチが存在しない交点を使って決定されます。通常、この交点が短絡している(ローレベル)のときに左側と見なされます。もし `#define SPLIT_HAND_MATRIX_GRID_LOW_IS_RIGHT` が定義されている場合は、ローレベルの時に右側と決定されます。
* 左右はキーマトリックスのキースイッチが存在しない交点を使って決定されます。通常、この交点が短絡している(ローレベル)のときに右側と見なされます。もし `#define SPLIT_HAND_MATRIX_GRID_LOW_IS_LEFT` が定義されている場合は、ローレベルの時に左側と決定されます。
* `#define EE_HANDS` (`SPLIT_HAND_PIN` と `SPLIT_HAND_MATRIX_GRID` が定義されていない場合のみ動作します)
* `eeprom-lefthand.eep`/`eeprom-righthand.eep` がそれぞれの半分に書き込まれた後で、EEPROM 内に格納されている左右の設定の値を読み込みます。

View File

@ -108,10 +108,10 @@ SPLIT_TRANSPORT = custom
キーマトリックスに未使用の交点があるキーボードがあります。この設定は、左右の決定にこれらの未使用の交点の1つを使用します。
通常、ダイオードが交点に接続されている場合、左側と判断されます。次の定義を追加すると、右側と判断されます。
通常、ダイオードが交点に接続されている場合、右側と判断されます。次の定義を追加すると、左側と判断されます。
```c
#define SPLIT_HAND_MATRIX_GRID_LOW_IS_RIGHT
#define SPLIT_HAND_MATRIX_GRID_LOW_IS_LEFT
```
#### EEPROM による左右の設定

View File

@ -23,12 +23,11 @@ I2C アドレスと他の技術詳細について、さらなる情報を得る
| 関数 | 説明 |
|-------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `void i2c_init(void);` | I2C ドライバを初期化します。他のあらゆるトランザクションを開始する前に、この関数を一度だけ呼ぶ必要があります。 |
| `i2c_status_t i2c_start(uint8_t address, uint16_t timeout);` | I2C トランザクションを開始します。アドレスは方向ビットのない7ビットスレーブアドレスです。 |
| `i2c_status_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);` | I2C 経由でデータを送信します。アドレスは方向ビットのない7ビットスレーブアドレスです。トランザクションのステータスを返します。 |
| `i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);` | I2C 経由でデータを受信します。アドレスは方向ビットのない7ビットスレーブアドレスです。 `length` で指定した長さのバイト列を `data` に保存し、トランザクションのステータスを返します。 |
| `i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);` | `i2c_transmit` と同様ですが、 `regaddr` でスレーブのデータ書き込み先のレジスタを指定します。 |
| `i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);` | `i2c_receive` と同様ですが、 `regaddr` でスレーブのデータ読み込み先のレジスタを指定します。 |
| `i2c_status_t i2c_stop(void);` | I2C トランザクションを終了します。 |
| `i2c_status_t i2c_ping_address(uint8_t address, uint16_t timeout);` | I2C アドレスをテストします。アドレスは方向ビットのない7ビットスレーブアドレスです。 |
### 関数の戻り値 :id=function-return

View File

@ -125,7 +125,7 @@ At the top of the file you'll find this:
These are some handy definitions we can use when building our keymap and our custom function. The `GRAVE_MODS` definition will be used later in our custom function, and the following `_BL`, `_FL`, and `_CL` defines make it easier to refer to each of our layers.
Note: You may also find some older keymap files may also have a define(s) for `_______` and/or `XXXXXXX`. These can be used in place for `KC_TRNS` and `KC_NO` respectively, making it easier to see what keys a layer is overriding. These definitions are now unecessary, as they are included by default.
Note: You may also find some older keymap files may also have a define(s) for `_______` and/or `XXXXXXX`. These can be used in place for `KC_TRNS` and `KC_NO` respectively, making it easier to see what keys a layer is overriding. These definitions are now unnecessary, as they are included by default.
### Layers and Keymaps

View File

@ -111,6 +111,13 @@ Configures the [APA102](apa102_driver.md) driver.
Configures the [Audio](feature_audio.md) feature.
* `audio`
* `default`
* `on`
* The default audio enabled state.
* Default: `true`
* `clicky`
* The default audio clicky enabled state.
* Default: `true`
* `macro_beep`
* Play a short beep for `\a` (ASCII `BEL`) characters in Send String macros.
* Default: `false`

View File

@ -36,6 +36,7 @@ These headers are located in [`quantum/keymap_extras/`](https://github.com/qmk/q
|French (AFNOR) |`keymap_french_afnor.h` |`sendstring_french_afnor.h` |
|French (BÉPO) |`keymap_bepo.h` |`sendstring_bepo.h` |
|French (Belgium) |`keymap_belgian.h` |`sendstring_belgian.h` |
|French (Canada) |`keymap_canadian_french.h` |`sendstring_canadian_french.h` |
|French (Switzerland) |`keymap_swiss_fr.h` |`sendstring_swiss_fr.h` |
|French (macOS, ISO) |`keymap_french_mac_iso.h` |`sendstring_french_mac_iso.h` |
|German |`keymap_german.h` |`sendstring_german.h` |

View File

@ -33,13 +33,13 @@ bool mcp23018_set_config(uint8_t slave_addr, mcp23018_port_t port, uint8_t conf)
uint8_t cmdDirection = port ? CMD_IODIRB : CMD_IODIRA;
uint8_t cmdPullup = port ? CMD_GPPUB : CMD_GPPUA;
i2c_status_t ret = i2c_writeReg(addr, cmdDirection, &conf, sizeof(conf), TIMEOUT);
i2c_status_t ret = i2c_write_register(addr, cmdDirection, &conf, sizeof(conf), TIMEOUT);
if (ret != I2C_STATUS_SUCCESS) {
dprintf("mcp23018_set_config::directionFAILED::%u\n", ret);
return false;
}
ret = i2c_writeReg(addr, cmdPullup, &conf, sizeof(conf), TIMEOUT);
ret = i2c_write_register(addr, cmdPullup, &conf, sizeof(conf), TIMEOUT);
if (ret != I2C_STATUS_SUCCESS) {
dprintf("mcp23018_set_config::pullupFAILED::%u\n", ret);
return false;
@ -52,7 +52,7 @@ bool mcp23018_set_output(uint8_t slave_addr, mcp23018_port_t port, uint8_t conf)
uint8_t addr = SLAVE_TO_ADDR(slave_addr);
uint8_t cmd = port ? CMD_GPIOB : CMD_GPIOA;
i2c_status_t ret = i2c_writeReg(addr, cmd, &conf, sizeof(conf), TIMEOUT);
i2c_status_t ret = i2c_write_register(addr, cmd, &conf, sizeof(conf), TIMEOUT);
if (ret != I2C_STATUS_SUCCESS) {
dprintf("mcp23018_set_output::FAILED::%u\n", ret);
return false;
@ -65,7 +65,7 @@ bool mcp23018_set_output_all(uint8_t slave_addr, uint8_t confA, uint8_t confB) {
uint8_t addr = SLAVE_TO_ADDR(slave_addr);
uint8_t conf[2] = {confA, confB};
i2c_status_t ret = i2c_writeReg(addr, CMD_GPIOA, &conf[0], sizeof(conf), TIMEOUT);
i2c_status_t ret = i2c_write_register(addr, CMD_GPIOA, &conf[0], sizeof(conf), TIMEOUT);
if (ret != I2C_STATUS_SUCCESS) {
dprintf("mcp23018_set_output::FAILED::%u\n", ret);
return false;
@ -78,7 +78,7 @@ bool mcp23018_readPins(uint8_t slave_addr, mcp23018_port_t port, uint8_t* out) {
uint8_t addr = SLAVE_TO_ADDR(slave_addr);
uint8_t cmd = port ? CMD_GPIOB : CMD_GPIOA;
i2c_status_t ret = i2c_readReg(addr, cmd, out, sizeof(uint8_t), TIMEOUT);
i2c_status_t ret = i2c_read_register(addr, cmd, out, sizeof(uint8_t), TIMEOUT);
if (ret != I2C_STATUS_SUCCESS) {
dprintf("mcp23018_readPins::FAILED::%u\n", ret);
return false;
@ -97,7 +97,7 @@ bool mcp23018_readPins_all(uint8_t slave_addr, uint16_t* out) {
data16 data = {.u16 = 0};
i2c_status_t ret = i2c_readReg(addr, CMD_GPIOA, &data.u8[0], sizeof(data), TIMEOUT);
i2c_status_t ret = i2c_read_register(addr, CMD_GPIOA, &data.u8[0], sizeof(data), TIMEOUT);
if (ret != I2C_STATUS_SUCCESS) {
dprintf("mcp23018_readPins::FAILED::%u\n", ret);
return false;

View File

@ -41,8 +41,6 @@ void pca9505_init(uint8_t slave_addr) {
}
// TODO: could check device connected
// i2c_start(SLAVE_TO_ADDR(slave) | I2C_WRITE);
// i2c_stop();
}
bool pca9505_set_config(uint8_t slave_addr, pca9505_port_t port, uint8_t conf) {
@ -66,7 +64,7 @@ bool pca9505_set_config(uint8_t slave_addr, pca9505_port_t port, uint8_t conf) {
break;
}
i2c_status_t ret = i2c_writeReg(addr, cmd, &conf, sizeof(conf), TIMEOUT);
i2c_status_t ret = i2c_write_register(addr, cmd, &conf, sizeof(conf), TIMEOUT);
if (ret != I2C_STATUS_SUCCESS) {
print("pca9505_set_config::FAILED\n");
return false;
@ -96,7 +94,7 @@ bool pca9505_set_polarity(uint8_t slave_addr, pca9505_port_t port, uint8_t conf)
break;
}
i2c_status_t ret = i2c_writeReg(addr, cmd, &conf, sizeof(conf), TIMEOUT);
i2c_status_t ret = i2c_write_register(addr, cmd, &conf, sizeof(conf), TIMEOUT);
if (ret != I2C_STATUS_SUCCESS) {
print("pca9505_set_polarity::FAILED\n");
return false;
@ -126,7 +124,7 @@ bool pca9505_set_output(uint8_t slave_addr, pca9505_port_t port, uint8_t conf) {
break;
}
i2c_status_t ret = i2c_writeReg(addr, cmd, &conf, sizeof(conf), TIMEOUT);
i2c_status_t ret = i2c_write_register(addr, cmd, &conf, sizeof(conf), TIMEOUT);
if (ret != I2C_STATUS_SUCCESS) {
print("pca9505_set_output::FAILED\n");
return false;
@ -156,7 +154,7 @@ bool pca9505_readPins(uint8_t slave_addr, pca9505_port_t port, uint8_t* out) {
break;
}
i2c_status_t ret = i2c_readReg(addr, cmd, out, sizeof(uint8_t), TIMEOUT);
i2c_status_t ret = i2c_read_register(addr, cmd, out, sizeof(uint8_t), TIMEOUT);
if (ret != I2C_STATUS_SUCCESS) {
print("pca9505_readPins::FAILED\n");
return false;

View File

@ -29,15 +29,13 @@ void pca9555_init(uint8_t slave_addr) {
}
// TODO: could check device connected
// i2c_start(SLAVE_TO_ADDR(slave) | I2C_WRITE);
// i2c_stop();
}
bool pca9555_set_config(uint8_t slave_addr, pca9555_port_t port, uint8_t conf) {
uint8_t addr = SLAVE_TO_ADDR(slave_addr);
uint8_t cmd = port ? CMD_CONFIG_1 : CMD_CONFIG_0;
i2c_status_t ret = i2c_writeReg(addr, cmd, &conf, sizeof(conf), TIMEOUT);
i2c_status_t ret = i2c_write_register(addr, cmd, &conf, sizeof(conf), TIMEOUT);
if (ret != I2C_STATUS_SUCCESS) {
print("pca9555_set_config::FAILED\n");
return false;
@ -50,7 +48,7 @@ bool pca9555_set_output(uint8_t slave_addr, pca9555_port_t port, uint8_t conf) {
uint8_t addr = SLAVE_TO_ADDR(slave_addr);
uint8_t cmd = port ? CMD_OUTPUT_1 : CMD_OUTPUT_0;
i2c_status_t ret = i2c_writeReg(addr, cmd, &conf, sizeof(conf), TIMEOUT);
i2c_status_t ret = i2c_write_register(addr, cmd, &conf, sizeof(conf), TIMEOUT);
if (ret != I2C_STATUS_SUCCESS) {
print("pca9555_set_output::FAILED\n");
return false;
@ -63,7 +61,7 @@ bool pca9555_set_output_all(uint8_t slave_addr, uint8_t confA, uint8_t confB) {
uint8_t addr = SLAVE_TO_ADDR(slave_addr);
uint8_t conf[2] = {confA, confB};
i2c_status_t ret = i2c_writeReg(addr, CMD_OUTPUT_0, &conf[0], sizeof(conf), TIMEOUT);
i2c_status_t ret = i2c_write_register(addr, CMD_OUTPUT_0, &conf[0], sizeof(conf), TIMEOUT);
if (ret != I2C_STATUS_SUCCESS) {
dprintf("pca9555_set_output::FAILED::%u\n", ret);
return false;
@ -76,7 +74,7 @@ bool pca9555_readPins(uint8_t slave_addr, pca9555_port_t port, uint8_t* out) {
uint8_t addr = SLAVE_TO_ADDR(slave_addr);
uint8_t cmd = port ? CMD_INPUT_1 : CMD_INPUT_0;
i2c_status_t ret = i2c_readReg(addr, cmd, out, sizeof(uint8_t), TIMEOUT);
i2c_status_t ret = i2c_read_register(addr, cmd, out, sizeof(uint8_t), TIMEOUT);
if (ret != I2C_STATUS_SUCCESS) {
print("pca9555_readPins::FAILED\n");
return false;
@ -95,7 +93,7 @@ bool pca9555_readPins_all(uint8_t slave_addr, uint16_t* out) {
data16 data = {.u16 = 0};
i2c_status_t ret = i2c_readReg(addr, CMD_INPUT_0, &data.u8[0], sizeof(data), TIMEOUT);
i2c_status_t ret = i2c_read_register(addr, CMD_INPUT_0, &data.u8[0], sizeof(data), TIMEOUT);
if (ret != I2C_STATUS_SUCCESS) {
print("pca9555_readPins_all::FAILED\n");
return false;

View File

@ -29,7 +29,7 @@ void drv2605l_write(uint8_t reg_addr, uint8_t data) {
}
uint8_t drv2605l_read(uint8_t reg_addr) {
i2c_readReg(DRV2605L_I2C_ADDRESS << 1, reg_addr, &drv2605l_read_buffer, 1, 100);
i2c_read_register(DRV2605L_I2C_ADDRESS << 1, reg_addr, &drv2605l_read_buffer, 1, 100);
return drv2605l_read_buffer;
}

View File

@ -55,55 +55,25 @@
uint8_t apa102_led_brightness = APA102_DEFAULT_BRIGHTNESS;
void static apa102_start_frame(void);
void static apa102_end_frame(uint16_t num_leds);
void static apa102_send_frame(uint8_t red, uint8_t green, uint8_t blue, uint8_t brightness);
void static apa102_send_byte(uint8_t byte);
void apa102_setleds(rgb_led_t *start_led, uint16_t num_leds) {
rgb_led_t *end = start_led + num_leds;
apa102_start_frame();
for (rgb_led_t *led = start_led; led < end; led++) {
apa102_send_frame(led->r, led->g, led->b, apa102_led_brightness);
}
apa102_end_frame(num_leds);
static void apa102_send_byte(uint8_t byte) {
APA102_SEND_BIT(byte, 7);
APA102_SEND_BIT(byte, 6);
APA102_SEND_BIT(byte, 5);
APA102_SEND_BIT(byte, 4);
APA102_SEND_BIT(byte, 3);
APA102_SEND_BIT(byte, 2);
APA102_SEND_BIT(byte, 1);
APA102_SEND_BIT(byte, 0);
}
void static apa102_init(void) {
setPinOutput(APA102_DI_PIN);
setPinOutput(APA102_CI_PIN);
writePinLow(APA102_DI_PIN);
writePinLow(APA102_CI_PIN);
}
void apa102_set_brightness(uint8_t brightness) {
if (brightness > APA102_MAX_BRIGHTNESS) {
apa102_led_brightness = APA102_MAX_BRIGHTNESS;
} else if (brightness < 0) {
apa102_led_brightness = 0;
} else {
apa102_led_brightness = brightness;
}
}
void static apa102_send_frame(uint8_t red, uint8_t green, uint8_t blue, uint8_t brightness) {
apa102_send_byte(0b11100000 | brightness);
apa102_send_byte(blue);
apa102_send_byte(green);
apa102_send_byte(red);
}
void static apa102_start_frame(void) {
static void apa102_start_frame(void) {
apa102_init();
for (uint16_t i = 0; i < 4; i++) {
apa102_send_byte(0);
}
}
void static apa102_end_frame(uint16_t num_leds) {
static void apa102_end_frame(uint16_t num_leds) {
// This function has been taken from: https://github.com/pololu/apa102-arduino/blob/master/APA102.h
// and adapted. The code is MIT licensed. I think thats compatible?
//
@ -136,13 +106,37 @@ void static apa102_end_frame(uint16_t num_leds) {
apa102_init();
}
void static apa102_send_byte(uint8_t byte) {
APA102_SEND_BIT(byte, 7);
APA102_SEND_BIT(byte, 6);
APA102_SEND_BIT(byte, 5);
APA102_SEND_BIT(byte, 4);
APA102_SEND_BIT(byte, 3);
APA102_SEND_BIT(byte, 2);
APA102_SEND_BIT(byte, 1);
APA102_SEND_BIT(byte, 0);
static void apa102_send_frame(uint8_t red, uint8_t green, uint8_t blue, uint8_t brightness) {
apa102_send_byte(0b11100000 | brightness);
apa102_send_byte(blue);
apa102_send_byte(green);
apa102_send_byte(red);
}
void apa102_init(void) {
setPinOutput(APA102_DI_PIN);
setPinOutput(APA102_CI_PIN);
writePinLow(APA102_DI_PIN);
writePinLow(APA102_CI_PIN);
}
void apa102_setleds(rgb_led_t *start_led, uint16_t num_leds) {
rgb_led_t *end = start_led + num_leds;
apa102_start_frame();
for (rgb_led_t *led = start_led; led < end; led++) {
apa102_send_frame(led->r, led->g, led->b, apa102_led_brightness);
}
apa102_end_frame(num_leds);
}
void apa102_set_brightness(uint8_t brightness) {
if (brightness > APA102_MAX_BRIGHTNESS) {
apa102_led_brightness = APA102_MAX_BRIGHTNESS;
} else if (brightness < 0) {
apa102_led_brightness = 0;
} else {
apa102_led_brightness = brightness;
}
}

View File

@ -31,7 +31,7 @@
#define APA102_MAX_BRIGHTNESS 31
extern uint8_t apa102_led_brightness;
void apa102_init(void);
/* User Interface
*
@ -44,4 +44,5 @@ extern uint8_t apa102_led_brightness;
* - Send out the LED data
*/
void apa102_setleds(rgb_led_t *start_led, uint16_t num_leds);
void apa102_set_brightness(uint8_t brightness);

View File

@ -45,8 +45,15 @@
# define AW20216S_SPI_DIVISOR 4
#endif
uint8_t g_pwm_buffer[AW20216S_DRIVER_COUNT][AW20216S_PWM_REGISTER_COUNT];
bool g_pwm_buffer_update_required[AW20216S_DRIVER_COUNT] = {false};
typedef struct aw20216s_driver_t {
uint8_t pwm_buffer[AW20216S_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
} PACKED aw20216s_driver_t;
aw20216s_driver_t driver_buffers[AW20216S_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
}};
bool aw20216s_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};
@ -131,13 +138,14 @@ void aw20216s_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
aw20216s_led_t led;
memcpy_P(&led, (&g_aw20216s_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) {
if (driver_buffers[led.driver].pwm_buffer[led.r] == red && driver_buffers[led.driver].pwm_buffer[led.g] == green && driver_buffers[led.driver].pwm_buffer[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;
driver_buffers[led.driver].pwm_buffer[led.r] = red;
driver_buffers[led.driver].pwm_buffer[led.g] = green;
driver_buffers[led.driver].pwm_buffer[led.b] = blue;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
void aw20216s_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
@ -147,10 +155,10 @@ void aw20216s_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
}
void aw20216s_update_pwm_buffers(pin_t cs_pin, uint8_t index) {
if (g_pwm_buffer_update_required[index]) {
aw20216s_write(cs_pin, AW20216S_PAGE_PWM, 0, g_pwm_buffer[index], AW20216S_PWM_REGISTER_COUNT);
if (driver_buffers[index].pwm_buffer_dirty) {
aw20216s_write(cs_pin, AW20216S_PAGE_PWM, 0, driver_buffers[index].pwm_buffer, AW20216S_PWM_REGISTER_COUNT);
driver_buffers[index].pwm_buffer_dirty = false;
}
g_pwm_buffer_update_required[index] = false;
}
void aw20216s_flush(void) {

View File

@ -101,219 +101,460 @@ void aw20216s_update_pwm_buffers(pin_t cs_pin, uint8_t index);
void aw20216s_flush(void);
#define CS1_SW1 0x00
#define CS2_SW1 0x01
#define CS3_SW1 0x02
#define CS4_SW1 0x03
#define CS5_SW1 0x04
#define CS6_SW1 0x05
#define CS7_SW1 0x06
#define CS8_SW1 0x07
#define CS9_SW1 0x08
#define CS10_SW1 0x09
#define CS11_SW1 0x0A
#define CS12_SW1 0x0B
#define CS13_SW1 0x0C
#define CS14_SW1 0x0D
#define CS15_SW1 0x0E
#define CS16_SW1 0x0F
#define CS17_SW1 0x10
#define CS18_SW1 0x11
#define CS1_SW2 0x12
#define CS2_SW2 0x13
#define CS3_SW2 0x14
#define CS4_SW2 0x15
#define CS5_SW2 0x16
#define CS6_SW2 0x17
#define CS7_SW2 0x18
#define CS8_SW2 0x19
#define CS9_SW2 0x1A
#define CS10_SW2 0x1B
#define CS11_SW2 0x1C
#define CS12_SW2 0x1D
#define CS13_SW2 0x1E
#define CS14_SW2 0x1F
#define CS15_SW2 0x20
#define CS16_SW2 0x21
#define CS17_SW2 0x22
#define CS18_SW2 0x23
#define CS1_SW3 0x24
#define CS2_SW3 0x25
#define CS3_SW3 0x26
#define CS4_SW3 0x27
#define CS5_SW3 0x28
#define CS6_SW3 0x29
#define CS7_SW3 0x2A
#define CS8_SW3 0x2B
#define CS9_SW3 0x2C
#define CS10_SW3 0x2D
#define CS11_SW3 0x2E
#define CS12_SW3 0x2F
#define CS13_SW3 0x30
#define CS14_SW3 0x31
#define CS15_SW3 0x32
#define CS16_SW3 0x33
#define CS17_SW3 0x34
#define CS18_SW3 0x35
#define CS1_SW4 0x36
#define CS2_SW4 0x37
#define CS3_SW4 0x38
#define CS4_SW4 0x39
#define CS5_SW4 0x3A
#define CS6_SW4 0x3B
#define CS7_SW4 0x3C
#define CS8_SW4 0x3D
#define CS9_SW4 0x3E
#define CS10_SW4 0x3F
#define CS11_SW4 0x40
#define CS12_SW4 0x41
#define CS13_SW4 0x42
#define CS14_SW4 0x43
#define CS15_SW4 0x44
#define CS16_SW4 0x45
#define CS17_SW4 0x46
#define CS18_SW4 0x47
#define CS1_SW5 0x48
#define CS2_SW5 0x49
#define CS3_SW5 0x4A
#define CS4_SW5 0x4B
#define CS5_SW5 0x4C
#define CS6_SW5 0x4D
#define CS7_SW5 0x4E
#define CS8_SW5 0x4F
#define CS9_SW5 0x50
#define CS10_SW5 0x51
#define CS11_SW5 0x52
#define CS12_SW5 0x53
#define CS13_SW5 0x54
#define CS14_SW5 0x55
#define CS15_SW5 0x56
#define CS16_SW5 0x57
#define CS17_SW5 0x58
#define CS18_SW5 0x59
#define CS1_SW6 0x5A
#define CS2_SW6 0x5B
#define CS3_SW6 0x5C
#define CS4_SW6 0x5D
#define CS5_SW6 0x5E
#define CS6_SW6 0x5F
#define CS7_SW6 0x60
#define CS8_SW6 0x61
#define CS9_SW6 0x62
#define CS10_SW6 0x63
#define CS11_SW6 0x64
#define CS12_SW6 0x65
#define CS13_SW6 0x66
#define CS14_SW6 0x67
#define CS15_SW6 0x68
#define CS16_SW6 0x69
#define CS17_SW6 0x6A
#define CS18_SW6 0x6B
#define CS1_SW7 0x6C
#define CS2_SW7 0x6D
#define CS3_SW7 0x6E
#define CS4_SW7 0x6F
#define CS5_SW7 0x70
#define CS6_SW7 0x71
#define CS7_SW7 0x72
#define CS8_SW7 0x73
#define CS9_SW7 0x74
#define CS10_SW7 0x75
#define CS11_SW7 0x76
#define CS12_SW7 0x77
#define CS13_SW7 0x78
#define CS14_SW7 0x79
#define CS15_SW7 0x7A
#define CS16_SW7 0x7B
#define CS17_SW7 0x7C
#define CS18_SW7 0x7D
#define CS1_SW8 0x7E
#define CS2_SW8 0x7F
#define CS3_SW8 0x80
#define CS4_SW8 0x81
#define CS5_SW8 0x82
#define CS6_SW8 0x83
#define CS7_SW8 0x84
#define CS8_SW8 0x85
#define CS9_SW8 0x86
#define CS10_SW8 0x87
#define CS11_SW8 0x88
#define CS12_SW8 0x89
#define CS13_SW8 0x8A
#define CS14_SW8 0x8B
#define CS15_SW8 0x8C
#define CS16_SW8 0x8D
#define CS17_SW8 0x8E
#define CS18_SW8 0x8F
#define CS1_SW9 0x90
#define CS2_SW9 0x91
#define CS3_SW9 0x92
#define CS4_SW9 0x93
#define CS5_SW9 0x94
#define CS6_SW9 0x95
#define CS7_SW9 0x96
#define CS8_SW9 0x97
#define CS9_SW9 0x98
#define CS10_SW9 0x99
#define CS11_SW9 0x9A
#define CS12_SW9 0x9B
#define CS13_SW9 0x9C
#define CS14_SW9 0x9D
#define CS15_SW9 0x9E
#define CS16_SW9 0x9F
#define CS17_SW9 0xA0
#define CS18_SW9 0xA1
#define CS1_SW10 0xA2
#define CS2_SW10 0xA3
#define CS3_SW10 0xA4
#define CS4_SW10 0xA5
#define CS5_SW10 0xA6
#define CS6_SW10 0xA7
#define CS7_SW10 0xA8
#define CS8_SW10 0xA9
#define CS9_SW10 0xAA
#define CS10_SW10 0xAB
#define CS11_SW10 0xAC
#define CS12_SW10 0xAD
#define CS13_SW10 0xAE
#define CS14_SW10 0xAF
#define CS15_SW10 0xB0
#define CS16_SW10 0xB1
#define CS17_SW10 0xB2
#define CS18_SW10 0xB3
#define CS1_SW11 0xB4
#define CS2_SW11 0xB5
#define CS3_SW11 0xB6
#define CS4_SW11 0xB7
#define CS5_SW11 0xB8
#define CS6_SW11 0xB9
#define CS7_SW11 0xBA
#define CS8_SW11 0xBB
#define CS9_SW11 0xBC
#define CS10_SW11 0xBD
#define CS11_SW11 0xBE
#define CS12_SW11 0xBF
#define CS13_SW11 0xC0
#define CS14_SW11 0xC1
#define CS15_SW11 0xC2
#define CS16_SW11 0xC3
#define CS17_SW11 0xC4
#define CS18_SW11 0xC5
#define CS1_SW12 0xC6
#define CS2_SW12 0xC7
#define CS3_SW12 0xC8
#define CS4_SW12 0xC9
#define CS5_SW12 0xCA
#define CS6_SW12 0xCB
#define CS7_SW12 0xCC
#define CS8_SW12 0xCD
#define CS9_SW12 0xCE
#define CS10_SW12 0xCF
#define CS11_SW12 0xD0
#define CS12_SW12 0xD1
#define CS13_SW12 0xD2
#define CS14_SW12 0xD3
#define CS15_SW12 0xD4
#define CS16_SW12 0xD5
#define CS17_SW12 0xD6
#define CS18_SW12 0xD7
#define SW1_CS1 0x00
#define SW1_CS2 0x01
#define SW1_CS3 0x02
#define SW1_CS4 0x03
#define SW1_CS5 0x04
#define SW1_CS6 0x05
#define SW1_CS7 0x06
#define SW1_CS8 0x07
#define SW1_CS9 0x08
#define SW1_CS10 0x09
#define SW1_CS11 0x0A
#define SW1_CS12 0x0B
#define SW1_CS13 0x0C
#define SW1_CS14 0x0D
#define SW1_CS15 0x0E
#define SW1_CS16 0x0F
#define SW1_CS17 0x10
#define SW1_CS18 0x11
#define SW2_CS1 0x12
#define SW2_CS2 0x13
#define SW2_CS3 0x14
#define SW2_CS4 0x15
#define SW2_CS5 0x16
#define SW2_CS6 0x17
#define SW2_CS7 0x18
#define SW2_CS8 0x19
#define SW2_CS9 0x1A
#define SW2_CS10 0x1B
#define SW2_CS11 0x1C
#define SW2_CS12 0x1D
#define SW2_CS13 0x1E
#define SW2_CS14 0x1F
#define SW2_CS15 0x20
#define SW2_CS16 0x21
#define SW2_CS17 0x22
#define SW2_CS18 0x23
#define SW3_CS1 0x24
#define SW3_CS2 0x25
#define SW3_CS3 0x26
#define SW3_CS4 0x27
#define SW3_CS5 0x28
#define SW3_CS6 0x29
#define SW3_CS7 0x2A
#define SW3_CS8 0x2B
#define SW3_CS9 0x2C
#define SW3_CS10 0x2D
#define SW3_CS11 0x2E
#define SW3_CS12 0x2F
#define SW3_CS13 0x30
#define SW3_CS14 0x31
#define SW3_CS15 0x32
#define SW3_CS16 0x33
#define SW3_CS17 0x34
#define SW3_CS18 0x35
#define SW4_CS1 0x36
#define SW4_CS2 0x37
#define SW4_CS3 0x38
#define SW4_CS4 0x39
#define SW4_CS5 0x3A
#define SW4_CS6 0x3B
#define SW4_CS7 0x3C
#define SW4_CS8 0x3D
#define SW4_CS9 0x3E
#define SW4_CS10 0x3F
#define SW4_CS11 0x40
#define SW4_CS12 0x41
#define SW4_CS13 0x42
#define SW4_CS14 0x43
#define SW4_CS15 0x44
#define SW4_CS16 0x45
#define SW4_CS17 0x46
#define SW4_CS18 0x47
#define SW5_CS1 0x48
#define SW5_CS2 0x49
#define SW5_CS3 0x4A
#define SW5_CS4 0x4B
#define SW5_CS5 0x4C
#define SW5_CS6 0x4D
#define SW5_CS7 0x4E
#define SW5_CS8 0x4F
#define SW5_CS9 0x50
#define SW5_CS10 0x51
#define SW5_CS11 0x52
#define SW5_CS12 0x53
#define SW5_CS13 0x54
#define SW5_CS14 0x55
#define SW5_CS15 0x56
#define SW5_CS16 0x57
#define SW5_CS17 0x58
#define SW5_CS18 0x59
#define SW6_CS1 0x5A
#define SW6_CS2 0x5B
#define SW6_CS3 0x5C
#define SW6_CS4 0x5D
#define SW6_CS5 0x5E
#define SW6_CS6 0x5F
#define SW6_CS7 0x60
#define SW6_CS8 0x61
#define SW6_CS9 0x62
#define SW6_CS10 0x63
#define SW6_CS11 0x64
#define SW6_CS12 0x65
#define SW6_CS13 0x66
#define SW6_CS14 0x67
#define SW6_CS15 0x68
#define SW6_CS16 0x69
#define SW6_CS17 0x6A
#define SW6_CS18 0x6B
#define SW7_CS1 0x6C
#define SW7_CS2 0x6D
#define SW7_CS3 0x6E
#define SW7_CS4 0x6F
#define SW7_CS5 0x70
#define SW7_CS6 0x71
#define SW7_CS7 0x72
#define SW7_CS8 0x73
#define SW7_CS9 0x74
#define SW7_CS10 0x75
#define SW7_CS11 0x76
#define SW7_CS12 0x77
#define SW7_CS13 0x78
#define SW7_CS14 0x79
#define SW7_CS15 0x7A
#define SW7_CS16 0x7B
#define SW7_CS17 0x7C
#define SW7_CS18 0x7D
#define SW8_CS1 0x7E
#define SW8_CS2 0x7F
#define SW8_CS3 0x80
#define SW8_CS4 0x81
#define SW8_CS5 0x82
#define SW8_CS6 0x83
#define SW8_CS7 0x84
#define SW8_CS8 0x85
#define SW8_CS9 0x86
#define SW8_CS10 0x87
#define SW8_CS11 0x88
#define SW8_CS12 0x89
#define SW8_CS13 0x8A
#define SW8_CS14 0x8B
#define SW8_CS15 0x8C
#define SW8_CS16 0x8D
#define SW8_CS17 0x8E
#define SW8_CS18 0x8F
#define SW9_CS1 0x90
#define SW9_CS2 0x91
#define SW9_CS3 0x92
#define SW9_CS4 0x93
#define SW9_CS5 0x94
#define SW9_CS6 0x95
#define SW9_CS7 0x96
#define SW9_CS8 0x97
#define SW9_CS9 0x98
#define SW9_CS10 0x99
#define SW9_CS11 0x9A
#define SW9_CS12 0x9B
#define SW9_CS13 0x9C
#define SW9_CS14 0x9D
#define SW9_CS15 0x9E
#define SW9_CS16 0x9F
#define SW9_CS17 0xA0
#define SW9_CS18 0xA1
#define SW10_CS1 0xA2
#define SW10_CS2 0xA3
#define SW10_CS3 0xA4
#define SW10_CS4 0xA5
#define SW10_CS5 0xA6
#define SW10_CS6 0xA7
#define SW10_CS7 0xA8
#define SW10_CS8 0xA9
#define SW10_CS9 0xAA
#define SW10_CS10 0xAB
#define SW10_CS11 0xAC
#define SW10_CS12 0xAD
#define SW10_CS13 0xAE
#define SW10_CS14 0xAF
#define SW10_CS15 0xB0
#define SW10_CS16 0xB1
#define SW10_CS17 0xB2
#define SW10_CS18 0xB3
#define SW11_CS1 0xB4
#define SW11_CS2 0xB5
#define SW11_CS3 0xB6
#define SW11_CS4 0xB7
#define SW11_CS5 0xB8
#define SW11_CS6 0xB9
#define SW11_CS7 0xBA
#define SW11_CS8 0xBB
#define SW11_CS9 0xBC
#define SW11_CS10 0xBD
#define SW11_CS11 0xBE
#define SW11_CS12 0xBF
#define SW11_CS13 0xC0
#define SW11_CS14 0xC1
#define SW11_CS15 0xC2
#define SW11_CS16 0xC3
#define SW11_CS17 0xC4
#define SW11_CS18 0xC5
#define SW12_CS1 0xC6
#define SW12_CS2 0xC7
#define SW12_CS3 0xC8
#define SW12_CS4 0xC9
#define SW12_CS5 0xCA
#define SW12_CS6 0xCB
#define SW12_CS7 0xCC
#define SW12_CS8 0xCD
#define SW12_CS9 0xCE
#define SW12_CS10 0xCF
#define SW12_CS11 0xD0
#define SW12_CS12 0xD1
#define SW12_CS13 0xD2
#define SW12_CS14 0xD3
#define SW12_CS15 0xD4
#define SW12_CS16 0xD5
#define SW12_CS17 0xD6
#define SW12_CS18 0xD7
// DEPRECATED - DO NOT USE
#define CS1_SW1 SW1_CS1
#define CS2_SW1 SW1_CS2
#define CS3_SW1 SW1_CS3
#define CS4_SW1 SW1_CS4
#define CS5_SW1 SW1_CS5
#define CS6_SW1 SW1_CS6
#define CS7_SW1 SW1_CS7
#define CS8_SW1 SW1_CS8
#define CS9_SW1 SW1_CS9
#define CS10_SW1 SW1_CS10
#define CS11_SW1 SW1_CS11
#define CS12_SW1 SW1_CS12
#define CS13_SW1 SW1_CS13
#define CS14_SW1 SW1_CS14
#define CS15_SW1 SW1_CS15
#define CS16_SW1 SW1_CS16
#define CS17_SW1 SW1_CS17
#define CS18_SW1 SW1_CS18
#define CS1_SW2 SW2_CS1
#define CS2_SW2 SW2_CS2
#define CS3_SW2 SW2_CS3
#define CS4_SW2 SW2_CS4
#define CS5_SW2 SW2_CS5
#define CS6_SW2 SW2_CS6
#define CS7_SW2 SW2_CS7
#define CS8_SW2 SW2_CS8
#define CS9_SW2 SW2_CS9
#define CS10_SW2 SW2_CS10
#define CS11_SW2 SW2_CS11
#define CS12_SW2 SW2_CS12
#define CS13_SW2 SW2_CS13
#define CS14_SW2 SW2_CS14
#define CS15_SW2 SW2_CS15
#define CS16_SW2 SW2_CS16
#define CS17_SW2 SW2_CS17
#define CS18_SW2 SW2_CS18
#define CS1_SW3 SW3_CS1
#define CS2_SW3 SW3_CS2
#define CS3_SW3 SW3_CS3
#define CS4_SW3 SW3_CS4
#define CS5_SW3 SW3_CS5
#define CS6_SW3 SW3_CS6
#define CS7_SW3 SW3_CS7
#define CS8_SW3 SW3_CS8
#define CS9_SW3 SW3_CS9
#define CS10_SW3 SW3_CS10
#define CS11_SW3 SW3_CS11
#define CS12_SW3 SW3_CS12
#define CS13_SW3 SW3_CS13
#define CS14_SW3 SW3_CS14
#define CS15_SW3 SW3_CS15
#define CS16_SW3 SW3_CS16
#define CS17_SW3 SW3_CS17
#define CS18_SW3 SW3_CS18
#define CS1_SW4 SW4_CS1
#define CS2_SW4 SW4_CS2
#define CS3_SW4 SW4_CS3
#define CS4_SW4 SW4_CS4
#define CS5_SW4 SW4_CS5
#define CS6_SW4 SW4_CS6
#define CS7_SW4 SW4_CS7
#define CS8_SW4 SW4_CS8
#define CS9_SW4 SW4_CS9
#define CS10_SW4 SW4_CS10
#define CS11_SW4 SW4_CS11
#define CS12_SW4 SW4_CS12
#define CS13_SW4 SW4_CS13
#define CS14_SW4 SW4_CS14
#define CS15_SW4 SW4_CS15
#define CS16_SW4 SW4_CS16
#define CS17_SW4 SW4_CS17
#define CS18_SW4 SW4_CS18
#define CS1_SW5 SW5_CS1
#define CS2_SW5 SW5_CS2
#define CS3_SW5 SW5_CS3
#define CS4_SW5 SW5_CS4
#define CS5_SW5 SW5_CS5
#define CS6_SW5 SW5_CS6
#define CS7_SW5 SW5_CS7
#define CS8_SW5 SW5_CS8
#define CS9_SW5 SW5_CS9
#define CS10_SW5 SW5_CS10
#define CS11_SW5 SW5_CS11
#define CS12_SW5 SW5_CS12
#define CS13_SW5 SW5_CS13
#define CS14_SW5 SW5_CS14
#define CS15_SW5 SW5_CS15
#define CS16_SW5 SW5_CS16
#define CS17_SW5 SW5_CS17
#define CS18_SW5 SW5_CS18
#define CS1_SW6 SW6_CS1
#define CS2_SW6 SW6_CS2
#define CS3_SW6 SW6_CS3
#define CS4_SW6 SW6_CS4
#define CS5_SW6 SW6_CS5
#define CS6_SW6 SW6_CS6
#define CS7_SW6 SW6_CS7
#define CS8_SW6 SW6_CS8
#define CS9_SW6 SW6_CS9
#define CS10_SW6 SW6_CS10
#define CS11_SW6 SW6_CS11
#define CS12_SW6 SW6_CS12
#define CS13_SW6 SW6_CS13
#define CS14_SW6 SW6_CS14
#define CS15_SW6 SW6_CS15
#define CS16_SW6 SW6_CS16
#define CS17_SW6 SW6_CS17
#define CS18_SW6 SW6_CS18
#define CS1_SW7 SW7_CS1
#define CS2_SW7 SW7_CS2
#define CS3_SW7 SW7_CS3
#define CS4_SW7 SW7_CS4
#define CS5_SW7 SW7_CS5
#define CS6_SW7 SW7_CS6
#define CS7_SW7 SW7_CS7
#define CS8_SW7 SW7_CS8
#define CS9_SW7 SW7_CS9
#define CS10_SW7 SW7_CS10
#define CS11_SW7 SW7_CS11
#define CS12_SW7 SW7_CS12
#define CS13_SW7 SW7_CS13
#define CS14_SW7 SW7_CS14
#define CS15_SW7 SW7_CS15
#define CS16_SW7 SW7_CS16
#define CS17_SW7 SW7_CS17
#define CS18_SW7 SW7_CS18
#define CS1_SW8 SW8_CS1
#define CS2_SW8 SW8_CS2
#define CS3_SW8 SW8_CS3
#define CS4_SW8 SW8_CS4
#define CS5_SW8 SW8_CS5
#define CS6_SW8 SW8_CS6
#define CS7_SW8 SW8_CS7
#define CS8_SW8 SW8_CS8
#define CS9_SW8 SW8_CS9
#define CS10_SW8 SW8_CS10
#define CS11_SW8 SW8_CS11
#define CS12_SW8 SW8_CS12
#define CS13_SW8 SW8_CS13
#define CS14_SW8 SW8_CS14
#define CS15_SW8 SW8_CS15
#define CS16_SW8 SW8_CS16
#define CS17_SW8 SW8_CS17
#define CS18_SW8 SW8_CS18
#define CS1_SW9 SW9_CS1
#define CS2_SW9 SW9_CS2
#define CS3_SW9 SW9_CS3
#define CS4_SW9 SW9_CS4
#define CS5_SW9 SW9_CS5
#define CS6_SW9 SW9_CS6
#define CS7_SW9 SW9_CS7
#define CS8_SW9 SW9_CS8
#define CS9_SW9 SW9_CS9
#define CS10_SW9 SW9_CS10
#define CS11_SW9 SW9_CS11
#define CS12_SW9 SW9_CS12
#define CS13_SW9 SW9_CS13
#define CS14_SW9 SW9_CS14
#define CS15_SW9 SW9_CS15
#define CS16_SW9 SW9_CS16
#define CS17_SW9 SW9_CS17
#define CS18_SW9 SW9_CS18
#define CS1_SW10 SW10_CS1
#define CS2_SW10 SW10_CS2
#define CS3_SW10 SW10_CS3
#define CS4_SW10 SW10_CS4
#define CS5_SW10 SW10_CS5
#define CS6_SW10 SW10_CS6
#define CS7_SW10 SW10_CS7
#define CS8_SW10 SW10_CS8
#define CS9_SW10 SW10_CS9
#define CS10_SW10 SW10_CS10
#define CS11_SW10 SW10_CS11
#define CS12_SW10 SW10_CS12
#define CS13_SW10 SW10_CS13
#define CS14_SW10 SW10_CS14
#define CS15_SW10 SW10_CS15
#define CS16_SW10 SW10_CS16
#define CS17_SW10 SW10_CS17
#define CS18_SW10 SW10_CS18
#define CS1_SW11 SW11_CS1
#define CS2_SW11 SW11_CS2
#define CS3_SW11 SW11_CS3
#define CS4_SW11 SW11_CS4
#define CS5_SW11 SW11_CS5
#define CS6_SW11 SW11_CS6
#define CS7_SW11 SW11_CS7
#define CS8_SW11 SW11_CS8
#define CS9_SW11 SW11_CS9
#define CS10_SW11 SW11_CS10
#define CS11_SW11 SW11_CS11
#define CS12_SW11 SW11_CS12
#define CS13_SW11 SW11_CS13
#define CS14_SW11 SW11_CS14
#define CS15_SW11 SW11_CS15
#define CS16_SW11 SW11_CS16
#define CS17_SW11 SW11_CS17
#define CS18_SW11 SW11_CS18
#define CS1_SW12 SW12_CS1
#define CS2_SW12 SW12_CS2
#define CS3_SW12 SW12_CS3
#define CS4_SW12 SW12_CS4
#define CS5_SW12 SW12_CS5
#define CS6_SW12 SW12_CS6
#define CS7_SW12 SW12_CS7
#define CS8_SW12 SW12_CS8
#define CS9_SW12 SW12_CS9
#define CS10_SW12 SW12_CS10
#define CS11_SW12 SW12_CS11
#define CS12_SW12 SW12_CS12
#define CS13_SW12 SW12_CS13
#define CS14_SW12 SW12_CS14
#define CS15_SW12 SW12_CS15
#define CS16_SW12 SW12_CS16
#define CS17_SW12 SW12_CS17
#define CS18_SW12 SW12_CS18

View File

@ -0,0 +1,150 @@
/* Copyright 2018 Jason Williams (Wilba)
*
* 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 "is31fl3218-mono.h"
#include "i2c_master.h"
#define IS31FL3218_PWM_REGISTER_COUNT 18
#define IS31FL3218_LED_CONTROL_REGISTER_COUNT 3
#ifndef IS31FL3218_I2C_TIMEOUT
# define IS31FL3218_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3218_I2C_PERSISTENCE
# define IS31FL3218_I2C_PERSISTENCE 0
#endif
typedef struct is31fl3218_driver_t {
uint8_t pwm_buffer[IS31FL3218_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t led_control_buffer[IS31FL3218_LED_CONTROL_REGISTER_COUNT];
bool led_control_buffer_dirty;
} PACKED is31fl3218_driver_t;
// IS31FL3218 has 18 PWM outputs and a fixed I2C address, so no chaining.
is31fl3218_driver_t driver_buffers = {
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.led_control_buffer = {0},
.led_control_buffer_dirty = false,
};
void is31fl3218_write_register(uint8_t reg, uint8_t data) {
#if IS31FL3218_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3218_I2C_PERSISTENCE; i++) {
if (i2c_write_register(IS31FL3218_I2C_ADDRESS << 1, reg, &data, 1, IS31FL3218_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(IS31FL3218_I2C_ADDRESS << 1, reg, &data, 1, IS31FL3218_I2C_TIMEOUT);
#endif
}
void is31fl3218_write_pwm_buffer(void) {
#if IS31FL3218_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3218_I2C_PERSISTENCE; i++) {
if (i2c_write_register(IS31FL3218_I2C_ADDRESS << 1, IS31FL3218_REG_PWM, driver_buffers.pwm_buffer, 18, IS31FL3218_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(IS31FL3218_I2C_ADDRESS << 1, IS31FL3218_REG_PWM, driver_buffers.pwm_buffer, 18, IS31FL3218_I2C_TIMEOUT);
#endif
}
void is31fl3218_init(void) {
i2c_init();
// In case we ever want to reinitialize (?)
is31fl3218_write_register(IS31FL3218_REG_RESET, 0x00);
// Turn off software shutdown
is31fl3218_write_register(IS31FL3218_REG_SHUTDOWN, 0x01);
// Set all PWM values to zero
for (uint8_t i = 0; i < IS31FL3218_PWM_REGISTER_COUNT; i++) {
is31fl3218_write_register(IS31FL3218_REG_PWM + i, 0x00);
}
// turn off all LEDs in the LED control register
for (uint8_t i = 0; i < IS31FL3218_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3218_write_register(IS31FL3218_REG_LED_CONTROL_1 + i, 0x00);
}
// Load PWM registers and LED Control register data
is31fl3218_write_register(IS31FL3218_REG_UPDATE, 0x01);
for (int i = 0; i < IS31FL3218_LED_COUNT; i++) {
is31fl3218_set_led_control_register(i, true);
}
is31fl3218_update_led_control_registers();
}
void is31fl3218_set_value(int index, uint8_t value) {
is31fl3218_led_t led;
if (index >= 0 && index < IS31FL3218_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3218_leds[index]), sizeof(led));
if (driver_buffers.pwm_buffer[led.v] == value) {
return;
}
driver_buffers.pwm_buffer[led.v] = value;
driver_buffers.pwm_buffer_dirty = true;
}
}
void is31fl3218_set_value_all(uint8_t value) {
for (int i = 0; i < IS31FL3218_LED_COUNT; i++) {
is31fl3218_set_value(i, value);
}
}
void is31fl3218_set_led_control_register(uint8_t index, bool value) {
is31fl3218_led_t led;
memcpy_P(&led, (&g_is31fl3218_leds[index]), sizeof(led));
uint8_t control_register = led.v / 6;
uint8_t bit_value = led.v % 6;
if (value) {
driver_buffers.led_control_buffer[control_register] |= (1 << bit_value);
} else {
driver_buffers.led_control_buffer[control_register] &= ~(1 << bit_value);
}
driver_buffers.led_control_buffer_dirty = true;
}
void is31fl3218_update_pwm_buffers(void) {
if (driver_buffers.pwm_buffer_dirty) {
is31fl3218_write_pwm_buffer();
// Load PWM registers and LED Control register data
is31fl3218_write_register(IS31FL3218_REG_UPDATE, 0x01);
driver_buffers.pwm_buffer_dirty = false;
}
}
void is31fl3218_update_led_control_registers(void) {
if (driver_buffers.led_control_buffer_dirty) {
for (uint8_t i = 0; i < IS31FL3218_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3218_write_register(IS31FL3218_REG_LED_CONTROL_1 + i, driver_buffers.led_control_buffer[i]);
}
driver_buffers.led_control_buffer_dirty = false;
}
}

View File

@ -0,0 +1,75 @@
/* Copyright 2018 Jason Williams (Wilba)
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
#define IS31FL3218_REG_SHUTDOWN 0x00
#define IS31FL3218_REG_PWM 0x01
#define IS31FL3218_REG_LED_CONTROL_1 0x13
#define IS31FL3218_REG_LED_CONTROL_2 0x14
#define IS31FL3218_REG_LED_CONTROL_3 0x15
#define IS31FL3218_REG_UPDATE 0x16
#define IS31FL3218_REG_RESET 0x17
#define IS31FL3218_I2C_ADDRESS 0x54
#if defined(LED_MATRIX_IS31FL3218)
# define IS31FL3218_LED_COUNT LED_MATRIX_LED_COUNT
#endif
typedef struct is31fl3218_led_t {
uint8_t v;
} PACKED is31fl3218_led_t;
extern const is31fl3218_led_t PROGMEM g_is31fl3218_leds[IS31FL3218_LED_COUNT];
void is31fl3218_init(void);
void is31fl3218_write_register(uint8_t reg, uint8_t data);
void is31fl3218_set_value(int index, uint8_t value);
void is31fl3218_set_value_all(uint8_t value);
void is31fl3218_set_led_control_register(uint8_t index, bool value);
void is31fl3218_update_pwm_buffers(void);
void is31fl3218_update_led_control_registers(void);
#define OUT1 0x00
#define OUT2 0x01
#define OUT3 0x02
#define OUT4 0x03
#define OUT5 0x04
#define OUT6 0x05
#define OUT7 0x06
#define OUT8 0x07
#define OUT9 0x08
#define OUT10 0x09
#define OUT11 0x0A
#define OUT12 0x0B
#define OUT13 0x0C
#define OUT14 0x0D
#define OUT15 0x0E
#define OUT16 0x0F
#define OUT17 0x10
#define OUT18 0x11

View File

@ -1,146 +0,0 @@
/* Copyright 2018 Jason Williams (Wilba)
*
* 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 "is31fl3218-simple.h"
#include <string.h>
#include "i2c_master.h"
#define IS31FL3218_PWM_REGISTER_COUNT 18
#define IS31FL3218_LED_CONTROL_REGISTER_COUNT 3
#ifndef IS31FL3218_I2C_TIMEOUT
# define IS31FL3218_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3218_I2C_PERSISTENCE
# define IS31FL3218_I2C_PERSISTENCE 0
#endif
uint8_t i2c_transfer_buffer[20];
// IS31FL3218 has 18 PWM outputs and a fixed I2C address, so no chaining.
uint8_t g_pwm_buffer[IS31FL3218_PWM_REGISTER_COUNT];
bool g_pwm_buffer_update_required = false;
uint8_t g_led_control_registers[IS31FL3218_LED_CONTROL_REGISTER_COUNT] = {0};
bool g_led_control_registers_update_required = false;
void is31fl3218_write_register(uint8_t reg, uint8_t data) {
i2c_transfer_buffer[0] = reg;
i2c_transfer_buffer[1] = data;
#if IS31FL3218_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3218_I2C_PERSISTENCE; i++) {
if (i2c_transmit(IS31FL3218_I2C_ADDRESS << 1, i2c_transfer_buffer, 2, IS31FL3218_I2C_TIMEOUT) == 0) break;
}
#else
i2c_transmit(IS31FL3218_I2C_ADDRESS << 1, i2c_transfer_buffer, 2, IS31FL3218_I2C_TIMEOUT);
#endif
}
void is31fl3218_write_pwm_buffer(uint8_t *pwm_buffer) {
i2c_transfer_buffer[0] = IS31FL3218_REG_PWM;
memcpy(i2c_transfer_buffer + 1, pwm_buffer, 18);
#if IS31FL3218_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3218_I2C_PERSISTENCE; i++) {
i2c_transmit(IS31FL3218_I2C_ADDRESS << 1, i2c_transfer_buffer, 19, IS31FL3218_I2C_TIMEOUT);
}
#else
i2c_transmit(IS31FL3218_I2C_ADDRESS << 1, i2c_transfer_buffer, 19, IS31FL3218_I2C_TIMEOUT);
#endif
}
void is31fl3218_init(void) {
i2c_init();
// In case we ever want to reinitialize (?)
is31fl3218_write_register(IS31FL3218_REG_RESET, 0x00);
// Turn off software shutdown
is31fl3218_write_register(IS31FL3218_REG_SHUTDOWN, 0x01);
// Set all PWM values to zero
for (uint8_t i = 0; i < IS31FL3218_PWM_REGISTER_COUNT; i++) {
is31fl3218_write_register(IS31FL3218_REG_PWM + i, 0x00);
}
// turn off all LEDs in the LED control register
for (uint8_t i = 0; i < IS31FL3218_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3218_write_register(IS31FL3218_REG_LED_CONTROL_1 + i, 0x00);
}
// Load PWM registers and LED Control register data
is31fl3218_write_register(IS31FL3218_REG_UPDATE, 0x01);
for (int i = 0; i < IS31FL3218_LED_COUNT; i++) {
is31fl3218_set_led_control_register(i, true);
}
is31fl3218_update_led_control_registers();
}
void is31fl3218_set_value(int index, uint8_t value) {
is31fl3218_led_t led;
if (index >= 0 && index < IS31FL3218_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3218_leds[index]), sizeof(led));
}
if (g_pwm_buffer[led.v - IS31FL3218_REG_PWM] == value) {
return;
}
g_pwm_buffer[led.v - IS31FL3218_REG_PWM] = value;
g_pwm_buffer_update_required = true;
}
void is31fl3218_set_value_all(uint8_t value) {
for (int i = 0; i < IS31FL3218_LED_COUNT; i++) {
is31fl3218_set_value(i, value);
}
}
void is31fl3218_set_led_control_register(uint8_t index, bool value) {
is31fl3218_led_t led;
memcpy_P(&led, (&g_is31fl3218_leds[index]), sizeof(led));
uint8_t control_register = (led.v - IS31FL3218_REG_PWM) / 6;
uint8_t bit_value = (led.v - IS31FL3218_REG_PWM) % 6;
if (value) {
g_led_control_registers[control_register] |= (1 << bit_value);
} else {
g_led_control_registers[control_register] &= ~(1 << bit_value);
}
g_led_control_registers_update_required = true;
}
void is31fl3218_update_pwm_buffers(void) {
if (g_pwm_buffer_update_required) {
is31fl3218_write_pwm_buffer(g_pwm_buffer);
// Load PWM registers and LED Control register data
is31fl3218_write_register(IS31FL3218_REG_UPDATE, 0x01);
g_pwm_buffer_update_required = false;
}
}
void is31fl3218_update_led_control_registers(void) {
if (g_led_control_registers_update_required) {
for (int i = 0; i < IS31FL3218_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3218_write_register(IS31FL3218_REG_LED_CONTROL_1 + i, g_led_control_registers[i]);
}
g_led_control_registers_update_required = false;
}
}

View File

@ -1,75 +0,0 @@
/* Copyright 2018 Jason Williams (Wilba)
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
#define IS31FL3218_REG_SHUTDOWN 0x00
#define IS31FL3218_REG_PWM 0x01
#define IS31FL3218_REG_LED_CONTROL_1 0x13
#define IS31FL3218_REG_LED_CONTROL_2 0x14
#define IS31FL3218_REG_LED_CONTROL_3 0x15
#define IS31FL3218_REG_UPDATE 0x16
#define IS31FL3218_REG_RESET 0x17
#define IS31FL3218_I2C_ADDRESS 0x54
#if defined(LED_MATRIX_IS31FL3218)
# define IS31FL3218_LED_COUNT LED_MATRIX_LED_COUNT
#endif
typedef struct is31fl3218_led_t {
uint8_t v;
} PACKED is31fl3218_led_t;
extern const is31fl3218_led_t PROGMEM g_is31fl3218_leds[IS31FL3218_LED_COUNT];
void is31fl3218_init(void);
void is31fl3218_write_register(uint8_t reg, uint8_t data);
void is31fl3218_set_value(int index, uint8_t value);
void is31fl3218_set_value_all(uint8_t value);
void is31fl3218_set_led_control_register(uint8_t index, bool value);
void is31fl3218_update_pwm_buffers(void);
void is31fl3218_update_led_control_registers(void);
#define OUT1 0x01
#define OUT2 0x02
#define OUT3 0x03
#define OUT4 0x04
#define OUT5 0x05
#define OUT6 0x06
#define OUT7 0x07
#define OUT8 0x08
#define OUT9 0x09
#define OUT10 0x0A
#define OUT11 0x0B
#define OUT12 0x0C
#define OUT13 0x0D
#define OUT14 0x0E
#define OUT15 0x0F
#define OUT16 0x10
#define OUT17 0x11
#define OUT18 0x12

View File

@ -13,8 +13,8 @@
* 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 "is31fl3218.h"
#include <string.h>
#include "i2c_master.h"
#define IS31FL3218_PWM_REGISTER_COUNT 18
@ -28,37 +28,38 @@
# define IS31FL3218_I2C_PERSISTENCE 0
#endif
uint8_t i2c_transfer_buffer[20];
typedef struct is31fl3218_driver_t {
uint8_t pwm_buffer[IS31FL3218_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t led_control_buffer[IS31FL3218_LED_CONTROL_REGISTER_COUNT];
bool led_control_buffer_dirty;
} PACKED is31fl3218_driver_t;
// IS31FL3218 has 18 PWM outputs and a fixed I2C address, so no chaining.
uint8_t g_pwm_buffer[IS31FL3218_PWM_REGISTER_COUNT];
bool g_pwm_buffer_update_required = false;
uint8_t g_led_control_registers[IS31FL3218_LED_CONTROL_REGISTER_COUNT] = {0};
bool g_led_control_registers_update_required = false;
is31fl3218_driver_t driver_buffers = {
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.led_control_buffer = {0},
.led_control_buffer_dirty = false,
};
void is31fl3218_write_register(uint8_t reg, uint8_t data) {
i2c_transfer_buffer[0] = reg;
i2c_transfer_buffer[1] = data;
#if IS31FL3218_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3218_I2C_PERSISTENCE; i++) {
if (i2c_transmit(IS31FL3218_I2C_ADDRESS << 1, i2c_transfer_buffer, 2, IS31FL3218_I2C_TIMEOUT) == 0) break;
if (i2c_write_register(IS31FL3218_I2C_ADDRESS << 1, reg, &data, 1, IS31FL3218_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_transmit(IS31FL3218_I2C_ADDRESS << 1, i2c_transfer_buffer, 2, IS31FL3218_I2C_TIMEOUT);
i2c_write_register(IS31FL3218_I2C_ADDRESS << 1, reg, &data, 1, IS31FL3218_I2C_TIMEOUT);
#endif
}
void is31fl3218_write_pwm_buffer(uint8_t *pwm_buffer) {
i2c_transfer_buffer[0] = IS31FL3218_REG_PWM;
memcpy(i2c_transfer_buffer + 1, pwm_buffer, 18);
void is31fl3218_write_pwm_buffer(void) {
#if IS31FL3218_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3218_I2C_PERSISTENCE; i++) {
i2c_transmit(IS31FL3218_I2C_ADDRESS << 1, i2c_transfer_buffer, 19, IS31FL3218_I2C_TIMEOUT);
if (i2c_write_register(IS31FL3218_I2C_ADDRESS << 1, IS31FL3218_REG_PWM, driver_buffers.pwm_buffer, 18, IS31FL3218_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_transmit(IS31FL3218_I2C_ADDRESS << 1, i2c_transfer_buffer, 19, IS31FL3218_I2C_TIMEOUT);
i2c_write_register(IS31FL3218_I2C_ADDRESS << 1, IS31FL3218_REG_PWM, driver_buffers.pwm_buffer, 18, IS31FL3218_I2C_TIMEOUT);
#endif
}
@ -93,16 +94,19 @@ void is31fl3218_init(void) {
void is31fl3218_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
is31fl3218_led_t led;
if (index >= 0 && index < IS31FL3218_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3218_leds[index]), sizeof(led));
if (driver_buffers.pwm_buffer[led.r] == red && driver_buffers.pwm_buffer[led.g] == green && driver_buffers.pwm_buffer[led.b] == blue) {
return;
}
driver_buffers.pwm_buffer[led.r] = red;
driver_buffers.pwm_buffer[led.g] = green;
driver_buffers.pwm_buffer[led.b] = blue;
driver_buffers.pwm_buffer_dirty = true;
}
if (g_pwm_buffer[led.r - IS31FL3218_REG_PWM] == red && g_pwm_buffer[led.g - IS31FL3218_REG_PWM] == green && g_pwm_buffer[led.b - IS31FL3218_REG_PWM] == blue) {
return;
}
g_pwm_buffer[led.r - IS31FL3218_REG_PWM] = red;
g_pwm_buffer[led.g - IS31FL3218_REG_PWM] = green;
g_pwm_buffer[led.b - IS31FL3218_REG_PWM] = blue;
g_pwm_buffer_update_required = true;
}
void is31fl3218_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
@ -115,48 +119,48 @@ void is31fl3218_set_led_control_register(uint8_t index, bool red, bool green, bo
is31fl3218_led_t led;
memcpy_P(&led, (&g_is31fl3218_leds[index]), sizeof(led));
uint8_t control_register_r = (led.r - IS31FL3218_REG_PWM) / 6;
uint8_t control_register_g = (led.g - IS31FL3218_REG_PWM) / 6;
uint8_t control_register_b = (led.b - IS31FL3218_REG_PWM) / 6;
uint8_t bit_r = (led.r - IS31FL3218_REG_PWM) % 6;
uint8_t bit_g = (led.g - IS31FL3218_REG_PWM) % 6;
uint8_t bit_b = (led.b - IS31FL3218_REG_PWM) % 6;
uint8_t control_register_r = led.r / 6;
uint8_t control_register_g = led.g / 6;
uint8_t control_register_b = led.b / 6;
uint8_t bit_r = led.r % 6;
uint8_t bit_g = led.g % 6;
uint8_t bit_b = led.b % 6;
if (red) {
g_led_control_registers[control_register_r] |= (1 << bit_r);
driver_buffers.led_control_buffer[control_register_r] |= (1 << bit_r);
} else {
g_led_control_registers[control_register_r] &= ~(1 << bit_r);
driver_buffers.led_control_buffer[control_register_r] &= ~(1 << bit_r);
}
if (green) {
g_led_control_registers[control_register_g] |= (1 << bit_g);
driver_buffers.led_control_buffer[control_register_g] |= (1 << bit_g);
} else {
g_led_control_registers[control_register_g] &= ~(1 << bit_g);
driver_buffers.led_control_buffer[control_register_g] &= ~(1 << bit_g);
}
if (blue) {
g_led_control_registers[control_register_b] |= (1 << bit_b);
driver_buffers.led_control_buffer[control_register_b] |= (1 << bit_b);
} else {
g_led_control_registers[control_register_b] &= ~(1 << bit_b);
driver_buffers.led_control_buffer[control_register_b] &= ~(1 << bit_b);
}
g_led_control_registers_update_required = true;
driver_buffers.led_control_buffer_dirty = true;
}
void is31fl3218_update_pwm_buffers(void) {
if (g_pwm_buffer_update_required) {
is31fl3218_write_pwm_buffer(g_pwm_buffer);
if (driver_buffers.pwm_buffer_dirty) {
is31fl3218_write_pwm_buffer();
// Load PWM registers and LED Control register data
is31fl3218_write_register(IS31FL3218_REG_UPDATE, 0x01);
g_pwm_buffer_update_required = false;
driver_buffers.pwm_buffer_dirty = false;
}
}
void is31fl3218_update_led_control_registers(void) {
if (g_led_control_registers_update_required) {
for (int i = 0; i < IS31FL3218_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3218_write_register(IS31FL3218_REG_LED_CONTROL_1 + i, g_led_control_registers[i]);
if (driver_buffers.led_control_buffer_dirty) {
for (uint8_t i = 0; i < IS31FL3218_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3218_write_register(IS31FL3218_REG_LED_CONTROL_1 + i, driver_buffers.led_control_buffer[i]);
}
g_led_control_registers_update_required = false;
driver_buffers.led_control_buffer_dirty = false;
}
}

View File

@ -57,21 +57,21 @@ void is31fl3218_update_pwm_buffers(void);
void is31fl3218_update_led_control_registers(void);
#define OUT1 0x01
#define OUT2 0x02
#define OUT3 0x03
#define OUT4 0x04
#define OUT5 0x05
#define OUT6 0x06
#define OUT7 0x07
#define OUT8 0x08
#define OUT9 0x09
#define OUT10 0x0A
#define OUT11 0x0B
#define OUT12 0x0C
#define OUT13 0x0D
#define OUT14 0x0E
#define OUT15 0x0F
#define OUT16 0x10
#define OUT17 0x11
#define OUT18 0x12
#define OUT1 0x00
#define OUT2 0x01
#define OUT3 0x02
#define OUT4 0x03
#define OUT5 0x04
#define OUT6 0x05
#define OUT7 0x06
#define OUT8 0x07
#define OUT9 0x08
#define OUT10 0x09
#define OUT11 0x0A
#define OUT12 0x0B
#define OUT13 0x0C
#define OUT14 0x0D
#define OUT15 0x0E
#define OUT16 0x0F
#define OUT17 0x10
#define OUT18 0x11

View File

@ -0,0 +1,224 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2019 Clueboard
* Copyright 2021 Doni Crosby
*
* 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 "is31fl3731-mono.h"
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3731_PWM_REGISTER_COUNT 144
#define IS31FL3731_LED_CONTROL_REGISTER_COUNT 18
#ifndef IS31FL3731_I2C_TIMEOUT
# define IS31FL3731_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3731_I2C_PERSISTENCE
# define IS31FL3731_I2C_PERSISTENCE 0
#endif
const uint8_t i2c_addresses[IS31FL3731_DRIVER_COUNT] = {
IS31FL3731_I2C_ADDRESS_1,
#ifdef IS31FL3731_I2C_ADDRESS_2
IS31FL3731_I2C_ADDRESS_2,
# ifdef IS31FL3731_I2C_ADDRESS_3
IS31FL3731_I2C_ADDRESS_3,
# ifdef IS31FL3731_I2C_ADDRESS_4
IS31FL3731_I2C_ADDRESS_4,
# endif
# endif
#endif
};
// 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
// probably not worth the extra complexity.
typedef struct is31fl3731_driver_t {
uint8_t pwm_buffer[IS31FL3731_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t led_control_buffer[IS31FL3731_LED_CONTROL_REGISTER_COUNT];
bool led_control_buffer_dirty;
} PACKED is31fl3731_driver_t;
is31fl3731_driver_t driver_buffers[IS31FL3731_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.led_control_buffer = {0},
.led_control_buffer_dirty = false,
}};
void is31fl3731_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3731_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3731_I2C_PERSISTENCE; i++) {
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3731_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3731_I2C_TIMEOUT);
#endif
}
void is31fl3731_select_page(uint8_t index, uint8_t page) {
is31fl3731_write_register(index, IS31FL3731_REG_COMMAND, page);
}
void is31fl3731_write_pwm_buffer(uint8_t index) {
// Assumes page 0 is already selected.
// Transmit PWM registers in 9 transfers of 16 bytes.
// Iterate over the pwm_buffer contents at 16 byte intervals.
for (uint8_t i = 0; i < IS31FL3731_PWM_REGISTER_COUNT; i += 16) {
#if IS31FL3731_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < IS31FL3731_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, IS31FL3731_FRAME_REG_PWM + i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3731_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, IS31FL3731_FRAME_REG_PWM + i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3731_I2C_TIMEOUT);
#endif
}
}
void is31fl3731_init_drivers(void) {
i2c_init();
for (uint8_t i = 0; i < IS31FL3731_DRIVER_COUNT; i++) {
is31fl3731_init(i);
}
for (int i = 0; i < IS31FL3731_LED_COUNT; i++) {
is31fl3731_set_led_control_register(i, true);
}
for (uint8_t i = 0; i < IS31FL3731_DRIVER_COUNT; i++) {
is31fl3731_update_led_control_registers(i);
}
}
void is31fl3731_init(uint8_t index) {
// 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.
is31fl3731_select_page(index, IS31FL3731_COMMAND_FUNCTION);
// enable software shutdown
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_SHUTDOWN, 0x00);
#ifdef IS31FL3731_DEGHOST // set to enable de-ghosting of the array
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_GHOST_IMAGE_PREVENTION, IS31FL3731_GHOST_IMAGE_PREVENTION_GEN);
#endif
// this delay was copied from other drivers, might not be needed
wait_ms(10);
// picture mode
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_CONFIG, IS31FL3731_CONFIG_MODE_PICTURE);
// display frame 0
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_PICTURE_DISPLAY, 0x00);
// audio sync off
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_AUDIO_SYNC, 0x00);
is31fl3731_select_page(index, IS31FL3731_COMMAND_FRAME_1);
// turn off all LEDs in the LED control register
for (uint8_t i = 0; i < IS31FL3731_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3731_write_register(index, IS31FL3731_FRAME_REG_LED_CONTROL + i, 0x00);
}
// turn off all LEDs in the blink control register (not really needed)
for (uint8_t i = 0; i < IS31FL3731_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3731_write_register(index, IS31FL3731_FRAME_REG_BLINK_CONTROL + i, 0x00);
}
// set PWM on all LEDs to 0
for (uint8_t i = 0; i < IS31FL3731_PWM_REGISTER_COUNT; i++) {
is31fl3731_write_register(index, IS31FL3731_FRAME_REG_PWM + i, 0x00);
}
is31fl3731_select_page(index, IS31FL3731_COMMAND_FUNCTION);
// disable software shutdown
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_SHUTDOWN, 0x01);
// select page 0 and leave it selected.
// most usage after initialization is just writing PWM buffers in page 0
// as there's not much point in double-buffering
is31fl3731_select_page(index, IS31FL3731_COMMAND_FRAME_1);
}
void is31fl3731_set_value(int index, uint8_t value) {
is31fl3731_led_t led;
if (index >= 0 && index < IS31FL3731_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3731_leds[index]), sizeof(led));
if (driver_buffers[led.driver].pwm_buffer[led.v] == value) {
return;
}
driver_buffers[led.driver].pwm_buffer[led.v] = value;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
void is31fl3731_set_value_all(uint8_t value) {
for (int i = 0; i < IS31FL3731_LED_COUNT; i++) {
is31fl3731_set_value(i, value);
}
}
void is31fl3731_set_led_control_register(uint8_t index, bool value) {
is31fl3731_led_t led;
memcpy_P(&led, (&g_is31fl3731_leds[index]), sizeof(led));
uint8_t control_register = led.v / 8;
uint8_t bit_value = led.v % 8;
if (value) {
driver_buffers[led.driver].led_control_buffer[control_register] |= (1 << bit_value);
} else {
driver_buffers[led.driver].led_control_buffer[control_register] &= ~(1 << bit_value);
}
driver_buffers[led.driver].led_control_buffer_dirty = true;
}
void is31fl3731_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3731_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void is31fl3731_update_led_control_registers(uint8_t index) {
if (driver_buffers[index].led_control_buffer_dirty) {
for (uint8_t i = 0; i < IS31FL3731_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3731_write_register(index, i, driver_buffers[index].led_control_buffer[i]);
}
driver_buffers[index].led_control_buffer_dirty = false;
}
}
void is31fl3731_flush(void) {
for (uint8_t i = 0; i < IS31FL3731_DRIVER_COUNT; i++) {
is31fl3731_update_pwm_buffers(i);
}
}

View File

@ -0,0 +1,286 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2019 Clueboard
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
// ======== DEPRECATED DEFINES - DO NOT USE ========
#ifdef LED_DRIVER_ADDR_1
# define IS31FL3731_I2C_ADDRESS_1 LED_DRIVER_ADDR_1
#endif
#ifdef LED_DRIVER_ADDR_2
# define IS31FL3731_I2C_ADDRESS_2 LED_DRIVER_ADDR_2
#endif
#ifdef LED_DRIVER_ADDR_3
# define IS31FL3731_I2C_ADDRESS_3 LED_DRIVER_ADDR_3
#endif
#ifdef LED_DRIVER_ADDR_4
# define IS31FL3731_I2C_ADDRESS_4 LED_DRIVER_ADDR_4
#endif
#ifdef ISSI_TIMEOUT
# define IS31FL3731_I2C_TIMEOUT ISSI_TIMEOUT
#endif
#ifdef ISSI_PERSISTENCE
# define IS31FL3731_I2C_PERSISTENCE ISSI_PERSISTENCE
#endif
#ifdef ISSI_3731_DEGHOST
# define IS31FL3731_DEGHOST ISSI_3731_DEGHOST
#endif
#define is31_led is31fl3731_led_t
#define g_is31_leds g_is31fl3731_leds
// ========
#define IS31FL3731_REG_COMMAND 0xFD
#define IS31FL3731_COMMAND_FRAME_1 0x00
#define IS31FL3731_COMMAND_FRAME_2 0x01
#define IS31FL3731_COMMAND_FRAME_3 0x02
#define IS31FL3731_COMMAND_FRAME_4 0x03
#define IS31FL3731_COMMAND_FRAME_5 0x04
#define IS31FL3731_COMMAND_FRAME_6 0x05
#define IS31FL3731_COMMAND_FRAME_7 0x06
#define IS31FL3731_COMMAND_FRAME_8 0x07
#define IS31FL3731_COMMAND_FUNCTION 0x0B
#define IS31FL3731_FRAME_REG_LED_CONTROL 0x00
#define IS31FL3731_FRAME_REG_BLINK_CONTROL 0x12
#define IS31FL3731_FRAME_REG_PWM 0x24
#define IS31FL3731_FUNCTION_REG_CONFIG 0x00
#define IS31FL3731_CONFIG_MODE_PICTURE 0x00
#define IS31FL3731_CONFIG_MODE_AUTO_PLAY 0x08
#define IS31FL3731_CONFIG_MODE_AUDIO_PLAY 0x18
#define IS31FL3731_FUNCTION_REG_PICTURE_DISPLAY 0x01
#define IS31FL3731_FUNCTION_REG_AUDIO_SYNC 0x06
#define IS31FL3731_FUNCTION_REG_SHUTDOWN 0x0A
// Not defined in the datasheet -- See AN for IC
#define IS31FL3731_FUNCTION_REG_GHOST_IMAGE_PREVENTION 0xC2
#define IS31FL3731_GHOST_IMAGE_PREVENTION_GEN 0x10
#define IS31FL3731_I2C_ADDRESS_GND 0x74
#define IS31FL3731_I2C_ADDRESS_SCL 0x75
#define IS31FL3731_I2C_ADDRESS_SDA 0x76
#define IS31FL3731_I2C_ADDRESS_VCC 0x77
#if defined(LED_MATRIX_IS31FL3731)
# define IS31FL3731_LED_COUNT LED_MATRIX_LED_COUNT
#endif
#if defined IS31FL3731_I2C_ADDRESS_4
# define IS31FL3731_DRIVER_COUNT 4
#elif defined IS31FL3731_I2C_ADDRESS_3
# define IS31FL3731_DRIVER_COUNT 3
#elif defined IS31FL3731_I2C_ADDRESS_2
# define IS31FL3731_DRIVER_COUNT 2
#elif defined IS31FL3731_I2C_ADDRESS_1
# define IS31FL3731_DRIVER_COUNT 1
#endif
typedef struct is31fl3731_led_t {
uint8_t driver : 2;
uint8_t v;
} PACKED is31fl3731_led_t;
extern const is31fl3731_led_t PROGMEM g_is31fl3731_leds[IS31FL3731_LED_COUNT];
void is31fl3731_init_drivers(void);
void is31fl3731_init(uint8_t index);
void is31fl3731_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3731_select_page(uint8_t index, uint8_t page);
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);
// 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 index);
void is31fl3731_update_led_control_registers(uint8_t index);
void is31fl3731_flush(void);
#define C1_1 0x00
#define C1_2 0x01
#define C1_3 0x02
#define C1_4 0x03
#define C1_5 0x04
#define C1_6 0x05
#define C1_7 0x06
#define C1_8 0x07
#define C1_9 0x08
#define C1_10 0x09
#define C1_11 0x0A
#define C1_12 0x0B
#define C1_13 0x0C
#define C1_14 0x0D
#define C1_15 0x0E
#define C1_16 0x0F
#define C2_1 0x10
#define C2_2 0x11
#define C2_3 0x12
#define C2_4 0x13
#define C2_5 0x14
#define C2_6 0x15
#define C2_7 0x16
#define C2_8 0x17
#define C2_9 0x18
#define C2_10 0x19
#define C2_11 0x1A
#define C2_12 0x1B
#define C2_13 0x1C
#define C2_14 0x1D
#define C2_15 0x1E
#define C2_16 0x1F
#define C3_1 0x20
#define C3_2 0x21
#define C3_3 0x22
#define C3_4 0x23
#define C3_5 0x24
#define C3_6 0x25
#define C3_7 0x26
#define C3_8 0x27
#define C3_9 0x28
#define C3_10 0x29
#define C3_11 0x2A
#define C3_12 0x2B
#define C3_13 0x2C
#define C3_14 0x2D
#define C3_15 0x2E
#define C3_16 0x2F
#define C4_1 0x30
#define C4_2 0x31
#define C4_3 0x32
#define C4_4 0x33
#define C4_5 0x34
#define C4_6 0x35
#define C4_7 0x36
#define C4_8 0x37
#define C4_9 0x38
#define C4_10 0x39
#define C4_11 0x3A
#define C4_12 0x3B
#define C4_13 0x3C
#define C4_14 0x3D
#define C4_15 0x3E
#define C4_16 0x3F
#define C5_1 0x40
#define C5_2 0x41
#define C5_3 0x42
#define C5_4 0x43
#define C5_5 0x44
#define C5_6 0x45
#define C5_7 0x46
#define C5_8 0x47
#define C5_9 0x48
#define C5_10 0x49
#define C5_11 0x4A
#define C5_12 0x4B
#define C5_13 0x4C
#define C5_14 0x4D
#define C5_15 0x4E
#define C5_16 0x4F
#define C6_1 0x50
#define C6_2 0x51
#define C6_3 0x52
#define C6_4 0x53
#define C6_5 0x54
#define C6_6 0x55
#define C6_7 0x56
#define C6_8 0x57
#define C6_9 0x58
#define C6_10 0x59
#define C6_11 0x5A
#define C6_12 0x5B
#define C6_13 0x5C
#define C6_14 0x5D
#define C6_15 0x5E
#define C6_16 0x5F
#define C7_1 0x60
#define C7_2 0x61
#define C7_3 0x62
#define C7_4 0x63
#define C7_5 0x64
#define C7_6 0x65
#define C7_7 0x66
#define C7_8 0x67
#define C7_9 0x68
#define C7_10 0x69
#define C7_11 0x6A
#define C7_12 0x6B
#define C7_13 0x6C
#define C7_14 0x6D
#define C7_15 0x6E
#define C7_16 0x6F
#define C8_1 0x70
#define C8_2 0x71
#define C8_3 0x72
#define C8_4 0x73
#define C8_5 0x74
#define C8_6 0x75
#define C8_7 0x76
#define C8_8 0x77
#define C8_9 0x78
#define C8_10 0x79
#define C8_11 0x7A
#define C8_12 0x7B
#define C8_13 0x7C
#define C8_14 0x7D
#define C8_15 0x7E
#define C8_16 0x7F
#define C9_1 0x80
#define C9_2 0x81
#define C9_3 0x82
#define C9_4 0x83
#define C9_5 0x84
#define C9_6 0x85
#define C9_7 0x86
#define C9_8 0x87
#define C9_9 0x88
#define C9_10 0x89
#define C9_11 0x8A
#define C9_12 0x8B
#define C9_13 0x8C
#define C9_14 0x8D
#define C9_15 0x8E
#define C9_16 0x8F

View File

@ -1,239 +0,0 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2019 Clueboard
* Copyright 2021 Doni Crosby
*
* 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 "is31fl3731-simple.h"
#include <string.h>
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3731_PWM_REGISTER_COUNT 144
#define IS31FL3731_LED_CONTROL_REGISTER_COUNT 18
#ifndef IS31FL3731_I2C_TIMEOUT
# define IS31FL3731_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3731_I2C_PERSISTENCE
# define IS31FL3731_I2C_PERSISTENCE 0
#endif
uint8_t i2c_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
// probably not worth the extra complexity.
uint8_t g_pwm_buffer[IS31FL3731_DRIVER_COUNT][IS31FL3731_PWM_REGISTER_COUNT];
bool g_pwm_buffer_update_required[IS31FL3731_DRIVER_COUNT] = {false};
uint8_t g_led_control_registers[IS31FL3731_DRIVER_COUNT][IS31FL3731_LED_CONTROL_REGISTER_COUNT] = {0};
bool g_led_control_registers_update_required[IS31FL3731_DRIVER_COUNT] = {false};
void is31fl3731_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
i2c_transfer_buffer[0] = reg;
i2c_transfer_buffer[1] = data;
#if IS31FL3731_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3731_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3731_I2C_TIMEOUT) == 0) {
break;
}
}
#else
i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3731_I2C_TIMEOUT);
#endif
}
void is31fl3731_select_page(uint8_t addr, uint8_t page) {
is31fl3731_write_register(addr, IS31FL3731_REG_COMMAND, page);
}
void is31fl3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
// assumes page 0 is already selected
// transmit PWM registers in 9 transfers of 16 bytes
// i2c_transfer_buffer[] is 20 bytes
// iterate over the pwm_buffer contents at 16 byte intervals
for (int i = 0; i < IS31FL3731_PWM_REGISTER_COUNT; i += 16) {
// set the first register, e.g. 0x24, 0x34, 0x44, etc.
i2c_transfer_buffer[0] = 0x24 + i;
// copy the data from i to i+15
// device will auto-increment register for data after the first byte
// thus this sets registers 0x24-0x33, 0x34-0x43, etc. in one transfer
memcpy(i2c_transfer_buffer + 1, pwm_buffer + i, 16);
#if IS31FL3731_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3731_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3731_I2C_TIMEOUT) == 0) break;
}
#else
i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3731_I2C_TIMEOUT);
#endif
}
}
void is31fl3731_init_drivers(void) {
i2c_init();
is31fl3731_init(IS31FL3731_I2C_ADDRESS_1);
#if defined(IS31FL3731_I2C_ADDRESS_2)
is31fl3731_init(IS31FL3731_I2C_ADDRESS_2);
# if defined(IS31FL3731_I2C_ADDRESS_3)
is31fl3731_init(IS31FL3731_I2C_ADDRESS_3);
# if defined(IS31FL3731_I2C_ADDRESS_4)
is31fl3731_init(IS31FL3731_I2C_ADDRESS_4);
# endif
# endif
#endif
for (int i = 0; i < IS31FL3731_LED_COUNT; i++) {
is31fl3731_set_led_control_register(i, true);
}
is31fl3731_update_led_control_registers(IS31FL3731_I2C_ADDRESS_1, 0);
#if defined(IS31FL3731_I2C_ADDRESS_2)
is31fl3731_update_led_control_registers(IS31FL3731_I2C_ADDRESS_2, 1);
# if defined(IS31FL3731_I2C_ADDRESS_3)
is31fl3731_update_led_control_registers(IS31FL3731_I2C_ADDRESS_3, 2);
# if defined(IS31FL3731_I2C_ADDRESS_4)
is31fl3731_update_led_control_registers(IS31FL3731_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
}
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.
is31fl3731_select_page(addr, IS31FL3731_COMMAND_FUNCTION);
// enable software shutdown
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_SHUTDOWN, 0x00);
#ifdef IS31FL3731_DEGHOST // set to enable de-ghosting of the array
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_GHOST_IMAGE_PREVENTION, IS31FL3731_GHOST_IMAGE_PREVENTION_GEN);
#endif
// this delay was copied from other drivers, might not be needed
wait_ms(10);
// picture mode
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_CONFIG, IS31FL3731_CONFIG_MODE_PICTURE);
// display frame 0
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_PICTURE_DISPLAY, 0x00);
// audio sync off
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_AUDIO_SYNC, 0x00);
is31fl3731_select_page(addr, IS31FL3731_COMMAND_FRAME_1);
// turn off all LEDs in the LED control register
for (int i = 0; i < IS31FL3731_LED_CONTROL_REGISTER_COUNT; i++) {
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);
}
// set PWM on all LEDs to 0
for (int i = 0x24; i <= 0xB3; i++) {
is31fl3731_write_register(addr, i, 0x00);
}
is31fl3731_select_page(addr, IS31FL3731_COMMAND_FUNCTION);
// disable software shutdown
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_SHUTDOWN, 0x01);
// select page 0 and leave it selected.
// most usage after initialization is just writing PWM buffers in page 0
// as there's not much point in double-buffering
is31fl3731_select_page(addr, IS31FL3731_COMMAND_FRAME_1);
}
void is31fl3731_set_value(int index, uint8_t value) {
is31fl3731_led_t led;
if (index >= 0 && index < IS31FL3731_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3731_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) {
for (int i = 0; i < IS31FL3731_LED_COUNT; i++) {
is31fl3731_set_value(i, value);
}
}
void is31fl3731_set_led_control_register(uint8_t index, bool value) {
is31fl3731_led_t led;
memcpy_P(&led, (&g_is31fl3731_leds[index]), sizeof(led));
uint8_t control_register = (led.v - 0x24) / 8;
uint8_t bit_value = (led.v - 0x24) % 8;
if (value) {
g_led_control_registers[led.driver][control_register] |= (1 << bit_value);
} else {
g_led_control_registers[led.driver][control_register] &= ~(1 << bit_value);
}
g_led_control_registers_update_required[led.driver] = true;
}
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]);
g_pwm_buffer_update_required[index] = false;
}
}
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 < IS31FL3731_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3731_write_register(addr, i, g_led_control_registers[index][i]);
}
g_led_control_registers_update_required[index] = false;
}
}
void is31fl3731_flush(void) {
is31fl3731_update_pwm_buffers(IS31FL3731_I2C_ADDRESS_1, 0);
#if defined(IS31FL3731_I2C_ADDRESS_2)
is31fl3731_update_pwm_buffers(IS31FL3731_I2C_ADDRESS_2, 1);
# if defined(IS31FL3731_I2C_ADDRESS_3)
is31fl3731_update_pwm_buffers(IS31FL3731_I2C_ADDRESS_3, 2);
# if defined(IS31FL3731_I2C_ADDRESS_4)
is31fl3731_update_pwm_buffers(IS31FL3731_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
}

View File

@ -1,283 +0,0 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2019 Clueboard
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
// ======== DEPRECATED DEFINES - DO NOT USE ========
#ifdef LED_DRIVER_ADDR_1
# define IS31FL3731_I2C_ADDRESS_1 LED_DRIVER_ADDR_1
#endif
#ifdef LED_DRIVER_ADDR_2
# define IS31FL3731_I2C_ADDRESS_2 LED_DRIVER_ADDR_2
#endif
#ifdef LED_DRIVER_ADDR_3
# define IS31FL3731_I2C_ADDRESS_3 LED_DRIVER_ADDR_3
#endif
#ifdef LED_DRIVER_ADDR_4
# define IS31FL3731_I2C_ADDRESS_4 LED_DRIVER_ADDR_4
#endif
#ifdef ISSI_TIMEOUT
# define IS31FL3731_I2C_TIMEOUT ISSI_TIMEOUT
#endif
#ifdef ISSI_PERSISTENCE
# define IS31FL3731_I2C_PERSISTENCE ISSI_PERSISTENCE
#endif
#ifdef ISSI_3731_DEGHOST
# define IS31FL3731_DEGHOST ISSI_3731_DEGHOST
#endif
#define is31_led is31fl3731_led_t
#define g_is31_leds g_is31fl3731_leds
// ========
#define IS31FL3731_REG_COMMAND 0xFD
#define IS31FL3731_COMMAND_FRAME_1 0x00
#define IS31FL3731_COMMAND_FRAME_2 0x01
#define IS31FL3731_COMMAND_FRAME_3 0x02
#define IS31FL3731_COMMAND_FRAME_4 0x03
#define IS31FL3731_COMMAND_FRAME_5 0x04
#define IS31FL3731_COMMAND_FRAME_6 0x05
#define IS31FL3731_COMMAND_FRAME_7 0x06
#define IS31FL3731_COMMAND_FRAME_8 0x07
#define IS31FL3731_COMMAND_FUNCTION 0x0B
#define IS31FL3731_FUNCTION_REG_CONFIG 0x00
#define IS31FL3731_CONFIG_MODE_PICTURE 0x00
#define IS31FL3731_CONFIG_MODE_AUTO_PLAY 0x08
#define IS31FL3731_CONFIG_MODE_AUDIO_PLAY 0x18
#define IS31FL3731_FUNCTION_REG_PICTURE_DISPLAY 0x01
#define IS31FL3731_FUNCTION_REG_AUDIO_SYNC 0x06
#define IS31FL3731_FUNCTION_REG_SHUTDOWN 0x0A
// Not defined in the datasheet -- See AN for IC
#define IS31FL3731_FUNCTION_REG_GHOST_IMAGE_PREVENTION 0xC2
#define IS31FL3731_GHOST_IMAGE_PREVENTION_GEN 0x10
#define IS31FL3731_I2C_ADDRESS_GND 0x74
#define IS31FL3731_I2C_ADDRESS_SCL 0x75
#define IS31FL3731_I2C_ADDRESS_SDA 0x76
#define IS31FL3731_I2C_ADDRESS_VCC 0x77
#if defined(LED_MATRIX_IS31FL3731)
# define IS31FL3731_LED_COUNT LED_MATRIX_LED_COUNT
#endif
#if defined IS31FL3731_I2C_ADDRESS_4
# define IS31FL3731_DRIVER_COUNT 4
#elif defined IS31FL3731_I2C_ADDRESS_3
# define IS31FL3731_DRIVER_COUNT 3
#elif defined IS31FL3731_I2C_ADDRESS_2
# define IS31FL3731_DRIVER_COUNT 2
#elif defined IS31FL3731_I2C_ADDRESS_1
# define IS31FL3731_DRIVER_COUNT 1
#endif
typedef struct is31fl3731_led_t {
uint8_t driver : 2;
uint8_t v;
} PACKED is31fl3731_led_t;
extern const is31fl3731_led_t PROGMEM g_is31fl3731_leds[IS31FL3731_LED_COUNT];
void is31fl3731_init_drivers(void);
void is31fl3731_init(uint8_t addr);
void is31fl3731_write_register(uint8_t addr, uint8_t reg, uint8_t data);
void is31fl3731_select_page(uint8_t addr, uint8_t page);
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_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_flush(void);
#define C1_1 0x24
#define C1_2 0x25
#define C1_3 0x26
#define C1_4 0x27
#define C1_5 0x28
#define C1_6 0x29
#define C1_7 0x2A
#define C1_8 0x2B
#define C1_9 0x2C
#define C1_10 0x2D
#define C1_11 0x2E
#define C1_12 0x2F
#define C1_13 0x30
#define C1_14 0x31
#define C1_15 0x32
#define C1_16 0x33
#define C2_1 0x34
#define C2_2 0x35
#define C2_3 0x36
#define C2_4 0x37
#define C2_5 0x38
#define C2_6 0x39
#define C2_7 0x3A
#define C2_8 0x3B
#define C2_9 0x3C
#define C2_10 0x3D
#define C2_11 0x3E
#define C2_12 0x3F
#define C2_13 0x40
#define C2_14 0x41
#define C2_15 0x42
#define C2_16 0x43
#define C3_1 0x44
#define C3_2 0x45
#define C3_3 0x46
#define C3_4 0x47
#define C3_5 0x48
#define C3_6 0x49
#define C3_7 0x4A
#define C3_8 0x4B
#define C3_9 0x4C
#define C3_10 0x4D
#define C3_11 0x4E
#define C3_12 0x4F
#define C3_13 0x50
#define C3_14 0x51
#define C3_15 0x52
#define C3_16 0x53
#define C4_1 0x54
#define C4_2 0x55
#define C4_3 0x56
#define C4_4 0x57
#define C4_5 0x58
#define C4_6 0x59
#define C4_7 0x5A
#define C4_8 0x5B
#define C4_9 0x5C
#define C4_10 0x5D
#define C4_11 0x5E
#define C4_12 0x5F
#define C4_13 0x60
#define C4_14 0x61
#define C4_15 0x62
#define C4_16 0x63
#define C5_1 0x64
#define C5_2 0x65
#define C5_3 0x66
#define C5_4 0x67
#define C5_5 0x68
#define C5_6 0x69
#define C5_7 0x6A
#define C5_8 0x6B
#define C5_9 0x6C
#define C5_10 0x6D
#define C5_11 0x6E
#define C5_12 0x6F
#define C5_13 0x70
#define C5_14 0x71
#define C5_15 0x72
#define C5_16 0x73
#define C6_1 0x74
#define C6_2 0x75
#define C6_3 0x76
#define C6_4 0x77
#define C6_5 0x78
#define C6_6 0x79
#define C6_7 0x7A
#define C6_8 0x7B
#define C6_9 0x7C
#define C6_10 0x7D
#define C6_11 0x7E
#define C6_12 0x7F
#define C6_13 0x80
#define C6_14 0x81
#define C6_15 0x82
#define C6_16 0x83
#define C7_1 0x84
#define C7_2 0x85
#define C7_3 0x86
#define C7_4 0x87
#define C7_5 0x88
#define C7_6 0x89
#define C7_7 0x8A
#define C7_8 0x8B
#define C7_9 0x8C
#define C7_10 0x8D
#define C7_11 0x8E
#define C7_12 0x8F
#define C7_13 0x90
#define C7_14 0x91
#define C7_15 0x92
#define C7_16 0x93
#define C8_1 0x94
#define C8_2 0x95
#define C8_3 0x96
#define C8_4 0x97
#define C8_5 0x98
#define C8_6 0x99
#define C8_7 0x9A
#define C8_8 0x9B
#define C8_9 0x9C
#define C8_10 0x9D
#define C8_11 0x9E
#define C8_12 0x9F
#define C8_13 0xA0
#define C8_14 0xA1
#define C8_15 0xA2
#define C8_16 0xA3
#define C9_1 0xA4
#define C9_2 0xA5
#define C9_3 0xA6
#define C9_4 0xA7
#define C9_5 0xA8
#define C9_6 0xA9
#define C9_7 0xAA
#define C9_8 0xAB
#define C9_9 0xAC
#define C9_10 0xAD
#define C9_11 0xAE
#define C9_12 0xAF
#define C9_13 0xB0
#define C9_14 0xB1
#define C9_15 0xB2
#define C9_16 0xB3

View File

@ -17,7 +17,6 @@
*/
#include "is31fl3731.h"
#include <string.h>
#include "i2c_master.h"
#include "wait.h"
@ -32,57 +31,64 @@
# define IS31FL3731_I2C_PERSISTENCE 0
#endif
uint8_t i2c_transfer_buffer[20];
const uint8_t i2c_addresses[IS31FL3731_DRIVER_COUNT] = {
IS31FL3731_I2C_ADDRESS_1,
#ifdef IS31FL3731_I2C_ADDRESS_2
IS31FL3731_I2C_ADDRESS_2,
# ifdef IS31FL3731_I2C_ADDRESS_3
IS31FL3731_I2C_ADDRESS_3,
# ifdef IS31FL3731_I2C_ADDRESS_4
IS31FL3731_I2C_ADDRESS_4,
# endif
# endif
#endif
};
// 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
// probably not worth the extra complexity.
uint8_t g_pwm_buffer[IS31FL3731_DRIVER_COUNT][IS31FL3731_PWM_REGISTER_COUNT];
bool g_pwm_buffer_update_required[IS31FL3731_DRIVER_COUNT] = {false};
typedef struct is31fl3731_driver_t {
uint8_t pwm_buffer[IS31FL3731_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t led_control_buffer[IS31FL3731_LED_CONTROL_REGISTER_COUNT];
bool led_control_buffer_dirty;
} PACKED is31fl3731_driver_t;
uint8_t g_led_control_registers[IS31FL3731_DRIVER_COUNT][IS31FL3731_LED_CONTROL_REGISTER_COUNT] = {0};
bool g_led_control_registers_update_required[IS31FL3731_DRIVER_COUNT] = {false};
void is31fl3731_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
i2c_transfer_buffer[0] = reg;
i2c_transfer_buffer[1] = data;
is31fl3731_driver_t driver_buffers[IS31FL3731_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.led_control_buffer = {0},
.led_control_buffer_dirty = false,
}};
void is31fl3731_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3731_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3731_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3731_I2C_TIMEOUT) == 0) break;
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3731_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3731_I2C_TIMEOUT);
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3731_I2C_TIMEOUT);
#endif
}
void is31fl3731_select_page(uint8_t addr, uint8_t page) {
is31fl3731_write_register(addr, IS31FL3731_REG_COMMAND, page);
void is31fl3731_select_page(uint8_t index, uint8_t page) {
is31fl3731_write_register(index, IS31FL3731_REG_COMMAND, page);
}
void is31fl3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
// assumes page 0 is already selected
// transmit PWM registers in 9 transfers of 16 bytes
// i2c_transfer_buffer[] is 20 bytes
// iterate over the pwm_buffer contents at 16 byte intervals
for (int i = 0; i < IS31FL3731_PWM_REGISTER_COUNT; i += 16) {
// set the first register, e.g. 0x24, 0x34, 0x44, etc.
i2c_transfer_buffer[0] = 0x24 + i;
// copy the data from i to i+15
// device will auto-increment register for data after the first byte
// thus this sets registers 0x24-0x33, 0x34-0x43, etc. in one transfer
memcpy(i2c_transfer_buffer + 1, pwm_buffer + i, 16);
void is31fl3731_write_pwm_buffer(uint8_t index) {
// Assumes page 0 is already selected.
// Transmit PWM registers in 9 transfers of 16 bytes.
// Iterate over the pwm_buffer contents at 16 byte intervals.
for (uint8_t i = 0; i < IS31FL3731_PWM_REGISTER_COUNT; i += 16) {
#if IS31FL3731_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3731_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3731_I2C_TIMEOUT) == 0) break;
for (uint8_t j = 0; j < IS31FL3731_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, IS31FL3731_FRAME_REG_PWM + i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3731_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3731_I2C_TIMEOUT);
i2c_write_register(i2c_addresses[index] << 1, IS31FL3731_FRAME_REG_PWM + i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3731_I2C_TIMEOUT);
#endif
}
}
@ -90,98 +96,85 @@ void is31fl3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
void is31fl3731_init_drivers(void) {
i2c_init();
is31fl3731_init(IS31FL3731_I2C_ADDRESS_1);
#if defined(IS31FL3731_I2C_ADDRESS_2)
is31fl3731_init(IS31FL3731_I2C_ADDRESS_2);
# if defined(IS31FL3731_I2C_ADDRESS_3)
is31fl3731_init(IS31FL3731_I2C_ADDRESS_3);
# if defined(IS31FL3731_I2C_ADDRESS_4)
is31fl3731_init(IS31FL3731_I2C_ADDRESS_4);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3731_DRIVER_COUNT; i++) {
is31fl3731_init(i);
}
for (int i = 0; i < IS31FL3731_LED_COUNT; i++) {
is31fl3731_set_led_control_register(i, true, true, true);
}
is31fl3731_update_led_control_registers(IS31FL3731_I2C_ADDRESS_1, 0);
#if defined(IS31FL3731_I2C_ADDRESS_2)
is31fl3731_update_led_control_registers(IS31FL3731_I2C_ADDRESS_2, 1);
# if defined(IS31FL3731_I2C_ADDRESS_3)
is31fl3731_update_led_control_registers(IS31FL3731_I2C_ADDRESS_3, 2);
# if defined(IS31FL3731_I2C_ADDRESS_4)
is31fl3731_update_led_control_registers(IS31FL3731_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3731_DRIVER_COUNT; i++) {
is31fl3731_update_led_control_registers(i);
}
}
void is31fl3731_init(uint8_t addr) {
void is31fl3731_init(uint8_t index) {
// 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.
is31fl3731_select_page(addr, IS31FL3731_COMMAND_FUNCTION);
is31fl3731_select_page(index, IS31FL3731_COMMAND_FUNCTION);
// enable software shutdown
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_SHUTDOWN, 0x00);
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_SHUTDOWN, 0x00);
#ifdef IS31FL3731_DEGHOST // set to enable de-ghosting of the array
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_GHOST_IMAGE_PREVENTION, IS31FL3731_GHOST_IMAGE_PREVENTION_GEN);
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_GHOST_IMAGE_PREVENTION, IS31FL3731_GHOST_IMAGE_PREVENTION_GEN);
#endif
// this delay was copied from other drivers, might not be needed
wait_ms(10);
// picture mode
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_CONFIG, IS31FL3731_CONFIG_MODE_PICTURE);
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_CONFIG, IS31FL3731_CONFIG_MODE_PICTURE);
// display frame 0
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_PICTURE_DISPLAY, 0x00);
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_PICTURE_DISPLAY, 0x00);
// audio sync off
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_AUDIO_SYNC, 0x00);
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_AUDIO_SYNC, 0x00);
is31fl3731_select_page(addr, IS31FL3731_COMMAND_FRAME_1);
is31fl3731_select_page(index, IS31FL3731_COMMAND_FRAME_1);
// turn off all LEDs in the LED control register
for (int i = 0; i < IS31FL3731_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3731_write_register(addr, i, 0x00);
for (uint8_t i = 0; i < IS31FL3731_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3731_write_register(index, IS31FL3731_FRAME_REG_LED_CONTROL + 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);
for (uint8_t i = 0; i < IS31FL3731_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3731_write_register(index, IS31FL3731_FRAME_REG_BLINK_CONTROL + i, 0x00);
}
// set PWM on all LEDs to 0
for (int i = 0x24; i <= 0xB3; i++) {
is31fl3731_write_register(addr, i, 0x00);
for (uint8_t i = 0; i < IS31FL3731_PWM_REGISTER_COUNT; i++) {
is31fl3731_write_register(index, IS31FL3731_FRAME_REG_PWM + i, 0x00);
}
is31fl3731_select_page(addr, IS31FL3731_COMMAND_FUNCTION);
is31fl3731_select_page(index, IS31FL3731_COMMAND_FUNCTION);
// disable software shutdown
is31fl3731_write_register(addr, IS31FL3731_FUNCTION_REG_SHUTDOWN, 0x01);
is31fl3731_write_register(index, IS31FL3731_FUNCTION_REG_SHUTDOWN, 0x01);
// select page 0 and leave it selected.
// most usage after initialization is just writing PWM buffers in page 0
// as there's not much point in double-buffering
is31fl3731_select_page(addr, IS31FL3731_COMMAND_FRAME_1);
is31fl3731_select_page(index, IS31FL3731_COMMAND_FRAME_1);
}
void is31fl3731_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
is31fl3731_led_t led;
if (index >= 0 && index < IS31FL3731_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3731_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) {
if (driver_buffers[led.driver].pwm_buffer[led.r] == red && driver_buffers[led.driver].pwm_buffer[led.g] == green && driver_buffers[led.driver].pwm_buffer[led.b] == 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;
g_pwm_buffer_update_required[led.driver] = true;
driver_buffers[led.driver].pwm_buffer[led.r] = red;
driver_buffers[led.driver].pwm_buffer[led.g] = green;
driver_buffers[led.driver].pwm_buffer[led.b] = blue;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
@ -195,57 +188,52 @@ void is31fl3731_set_led_control_register(uint8_t index, bool red, bool green, bo
is31fl3731_led_t led;
memcpy_P(&led, (&g_is31fl3731_leds[index]), sizeof(led));
uint8_t control_register_r = (led.r - 0x24) / 8;
uint8_t control_register_g = (led.g - 0x24) / 8;
uint8_t control_register_b = (led.b - 0x24) / 8;
uint8_t bit_r = (led.r - 0x24) % 8;
uint8_t bit_g = (led.g - 0x24) % 8;
uint8_t bit_b = (led.b - 0x24) % 8;
uint8_t control_register_r = led.r / 8;
uint8_t control_register_g = led.g / 8;
uint8_t control_register_b = led.b / 8;
uint8_t bit_r = led.r % 8;
uint8_t bit_g = led.g % 8;
uint8_t bit_b = led.b % 8;
if (red) {
g_led_control_registers[led.driver][control_register_r] |= (1 << bit_r);
driver_buffers[led.driver].led_control_buffer[control_register_r] |= (1 << bit_r);
} else {
g_led_control_registers[led.driver][control_register_r] &= ~(1 << bit_r);
driver_buffers[led.driver].led_control_buffer[control_register_r] &= ~(1 << bit_r);
}
if (green) {
g_led_control_registers[led.driver][control_register_g] |= (1 << bit_g);
driver_buffers[led.driver].led_control_buffer[control_register_g] |= (1 << bit_g);
} else {
g_led_control_registers[led.driver][control_register_g] &= ~(1 << bit_g);
driver_buffers[led.driver].led_control_buffer[control_register_g] &= ~(1 << bit_g);
}
if (blue) {
g_led_control_registers[led.driver][control_register_b] |= (1 << bit_b);
driver_buffers[led.driver].led_control_buffer[control_register_b] |= (1 << bit_b);
} else {
g_led_control_registers[led.driver][control_register_b] &= ~(1 << bit_b);
driver_buffers[led.driver].led_control_buffer[control_register_b] &= ~(1 << bit_b);
}
g_led_control_registers_update_required[led.driver] = true;
driver_buffers[led.driver].led_control_buffer_dirty = true;
}
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]);
void is31fl3731_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3731_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
g_pwm_buffer_update_required[index] = false;
}
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 < IS31FL3731_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3731_write_register(addr, i, g_led_control_registers[index][i]);
void is31fl3731_update_led_control_registers(uint8_t index) {
if (driver_buffers[index].led_control_buffer_dirty) {
for (uint8_t i = 0; i < IS31FL3731_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3731_write_register(index, i, driver_buffers[index].led_control_buffer[i]);
}
driver_buffers[index].led_control_buffer_dirty = false;
}
g_led_control_registers_update_required[index] = false;
}
void is31fl3731_flush(void) {
is31fl3731_update_pwm_buffers(IS31FL3731_I2C_ADDRESS_1, 0);
#if defined(IS31FL3731_I2C_ADDRESS_2)
is31fl3731_update_pwm_buffers(IS31FL3731_I2C_ADDRESS_2, 1);
# if defined(IS31FL3731_I2C_ADDRESS_3)
is31fl3731_update_pwm_buffers(IS31FL3731_I2C_ADDRESS_3, 2);
# if defined(IS31FL3731_I2C_ADDRESS_4)
is31fl3731_update_pwm_buffers(IS31FL3731_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3731_DRIVER_COUNT; i++) {
is31fl3731_update_pwm_buffers(i);
}
}

View File

@ -60,6 +60,10 @@
#define IS31FL3731_COMMAND_FRAME_8 0x07
#define IS31FL3731_COMMAND_FUNCTION 0x0B
#define IS31FL3731_FRAME_REG_LED_CONTROL 0x00
#define IS31FL3731_FRAME_REG_BLINK_CONTROL 0x12
#define IS31FL3731_FRAME_REG_PWM 0x24
#define IS31FL3731_FUNCTION_REG_CONFIG 0x00
#define IS31FL3731_CONFIG_MODE_PICTURE 0x00
#define IS31FL3731_CONFIG_MODE_AUTO_PLAY 0x08
@ -102,10 +106,9 @@ typedef struct is31fl3731_led_t {
extern const is31fl3731_led_t PROGMEM g_is31fl3731_leds[IS31FL3731_LED_COUNT];
void is31fl3731_init_drivers(void);
void is31fl3731_init(uint8_t addr);
void is31fl3731_write_register(uint8_t addr, uint8_t reg, uint8_t data);
void is31fl3731_select_page(uint8_t addr, uint8_t page);
void is31fl3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
void is31fl3731_init(uint8_t index);
void is31fl3731_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3731_select_page(uint8_t index, uint8_t page);
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);
@ -116,169 +119,169 @@ void is31fl3731_set_led_control_register(uint8_t index, bool red, bool green, bo
// (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 index);
void is31fl3731_update_led_control_registers(uint8_t index);
void is31fl3731_flush(void);
#define C1_1 0x24
#define C1_2 0x25
#define C1_3 0x26
#define C1_4 0x27
#define C1_5 0x28
#define C1_6 0x29
#define C1_7 0x2A
#define C1_8 0x2B
#define C1_1 0x00
#define C1_2 0x01
#define C1_3 0x02
#define C1_4 0x03
#define C1_5 0x04
#define C1_6 0x05
#define C1_7 0x06
#define C1_8 0x07
#define C1_9 0x2C
#define C1_10 0x2D
#define C1_11 0x2E
#define C1_12 0x2F
#define C1_13 0x30
#define C1_14 0x31
#define C1_15 0x32
#define C1_16 0x33
#define C1_9 0x08
#define C1_10 0x09
#define C1_11 0x0A
#define C1_12 0x0B
#define C1_13 0x0C
#define C1_14 0x0D
#define C1_15 0x0E
#define C1_16 0x0F
#define C2_1 0x34
#define C2_2 0x35
#define C2_3 0x36
#define C2_4 0x37
#define C2_5 0x38
#define C2_6 0x39
#define C2_7 0x3A
#define C2_8 0x3B
#define C2_1 0x10
#define C2_2 0x11
#define C2_3 0x12
#define C2_4 0x13
#define C2_5 0x14
#define C2_6 0x15
#define C2_7 0x16
#define C2_8 0x17
#define C2_9 0x3C
#define C2_10 0x3D
#define C2_11 0x3E
#define C2_12 0x3F
#define C2_13 0x40
#define C2_14 0x41
#define C2_15 0x42
#define C2_16 0x43
#define C2_9 0x18
#define C2_10 0x19
#define C2_11 0x1A
#define C2_12 0x1B
#define C2_13 0x1C
#define C2_14 0x1D
#define C2_15 0x1E
#define C2_16 0x1F
#define C3_1 0x44
#define C3_2 0x45
#define C3_3 0x46
#define C3_4 0x47
#define C3_5 0x48
#define C3_6 0x49
#define C3_7 0x4A
#define C3_8 0x4B
#define C3_1 0x20
#define C3_2 0x21
#define C3_3 0x22
#define C3_4 0x23
#define C3_5 0x24
#define C3_6 0x25
#define C3_7 0x26
#define C3_8 0x27
#define C3_9 0x4C
#define C3_10 0x4D
#define C3_11 0x4E
#define C3_12 0x4F
#define C3_13 0x50
#define C3_14 0x51
#define C3_15 0x52
#define C3_16 0x53
#define C3_9 0x28
#define C3_10 0x29
#define C3_11 0x2A
#define C3_12 0x2B
#define C3_13 0x2C
#define C3_14 0x2D
#define C3_15 0x2E
#define C3_16 0x2F
#define C4_1 0x54
#define C4_2 0x55
#define C4_3 0x56
#define C4_4 0x57
#define C4_5 0x58
#define C4_6 0x59
#define C4_7 0x5A
#define C4_8 0x5B
#define C4_1 0x30
#define C4_2 0x31
#define C4_3 0x32
#define C4_4 0x33
#define C4_5 0x34
#define C4_6 0x35
#define C4_7 0x36
#define C4_8 0x37
#define C4_9 0x5C
#define C4_10 0x5D
#define C4_11 0x5E
#define C4_12 0x5F
#define C4_13 0x60
#define C4_14 0x61
#define C4_15 0x62
#define C4_16 0x63
#define C4_9 0x38
#define C4_10 0x39
#define C4_11 0x3A
#define C4_12 0x3B
#define C4_13 0x3C
#define C4_14 0x3D
#define C4_15 0x3E
#define C4_16 0x3F
#define C5_1 0x64
#define C5_2 0x65
#define C5_3 0x66
#define C5_4 0x67
#define C5_5 0x68
#define C5_6 0x69
#define C5_7 0x6A
#define C5_8 0x6B
#define C5_1 0x40
#define C5_2 0x41
#define C5_3 0x42
#define C5_4 0x43
#define C5_5 0x44
#define C5_6 0x45
#define C5_7 0x46
#define C5_8 0x47
#define C5_9 0x6C
#define C5_10 0x6D
#define C5_11 0x6E
#define C5_12 0x6F
#define C5_13 0x70
#define C5_14 0x71
#define C5_15 0x72
#define C5_16 0x73
#define C5_9 0x48
#define C5_10 0x49
#define C5_11 0x4A
#define C5_12 0x4B
#define C5_13 0x4C
#define C5_14 0x4D
#define C5_15 0x4E
#define C5_16 0x4F
#define C6_1 0x74
#define C6_2 0x75
#define C6_3 0x76
#define C6_4 0x77
#define C6_5 0x78
#define C6_6 0x79
#define C6_7 0x7A
#define C6_8 0x7B
#define C6_1 0x50
#define C6_2 0x51
#define C6_3 0x52
#define C6_4 0x53
#define C6_5 0x54
#define C6_6 0x55
#define C6_7 0x56
#define C6_8 0x57
#define C6_9 0x7C
#define C6_10 0x7D
#define C6_11 0x7E
#define C6_12 0x7F
#define C6_13 0x80
#define C6_14 0x81
#define C6_15 0x82
#define C6_16 0x83
#define C6_9 0x58
#define C6_10 0x59
#define C6_11 0x5A
#define C6_12 0x5B
#define C6_13 0x5C
#define C6_14 0x5D
#define C6_15 0x5E
#define C6_16 0x5F
#define C7_1 0x84
#define C7_2 0x85
#define C7_3 0x86
#define C7_4 0x87
#define C7_5 0x88
#define C7_6 0x89
#define C7_7 0x8A
#define C7_8 0x8B
#define C7_1 0x60
#define C7_2 0x61
#define C7_3 0x62
#define C7_4 0x63
#define C7_5 0x64
#define C7_6 0x65
#define C7_7 0x66
#define C7_8 0x67
#define C7_9 0x8C
#define C7_10 0x8D
#define C7_11 0x8E
#define C7_12 0x8F
#define C7_13 0x90
#define C7_14 0x91
#define C7_15 0x92
#define C7_16 0x93
#define C7_9 0x68
#define C7_10 0x69
#define C7_11 0x6A
#define C7_12 0x6B
#define C7_13 0x6C
#define C7_14 0x6D
#define C7_15 0x6E
#define C7_16 0x6F
#define C8_1 0x94
#define C8_2 0x95
#define C8_3 0x96
#define C8_4 0x97
#define C8_5 0x98
#define C8_6 0x99
#define C8_7 0x9A
#define C8_8 0x9B
#define C8_1 0x70
#define C8_2 0x71
#define C8_3 0x72
#define C8_4 0x73
#define C8_5 0x74
#define C8_6 0x75
#define C8_7 0x76
#define C8_8 0x77
#define C8_9 0x9C
#define C8_10 0x9D
#define C8_11 0x9E
#define C8_12 0x9F
#define C8_13 0xA0
#define C8_14 0xA1
#define C8_15 0xA2
#define C8_16 0xA3
#define C8_9 0x78
#define C8_10 0x79
#define C8_11 0x7A
#define C8_12 0x7B
#define C8_13 0x7C
#define C8_14 0x7D
#define C8_15 0x7E
#define C8_16 0x7F
#define C9_1 0xA4
#define C9_2 0xA5
#define C9_3 0xA6
#define C9_4 0xA7
#define C9_5 0xA8
#define C9_6 0xA9
#define C9_7 0xAA
#define C9_8 0xAB
#define C9_1 0x80
#define C9_2 0x81
#define C9_3 0x82
#define C9_4 0x83
#define C9_5 0x84
#define C9_6 0x85
#define C9_7 0x86
#define C9_8 0x87
#define C9_9 0xAC
#define C9_10 0xAD
#define C9_11 0xAE
#define C9_12 0xAF
#define C9_13 0xB0
#define C9_14 0xB1
#define C9_15 0xB2
#define C9_16 0xB3
#define C9_9 0x88
#define C9_10 0x89
#define C9_11 0x8A
#define C9_12 0x8B
#define C9_13 0x8C
#define C9_14 0x8D
#define C9_15 0x8E
#define C9_16 0x8F

View File

@ -0,0 +1,259 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2021 Doni Crosby
* Copyright 2021 Leo Deng
*
* 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 "is31fl3733-mono.h"
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3733_PWM_REGISTER_COUNT 192
#define IS31FL3733_LED_CONTROL_REGISTER_COUNT 24
#ifndef IS31FL3733_I2C_TIMEOUT
# define IS31FL3733_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3733_I2C_PERSISTENCE
# define IS31FL3733_I2C_PERSISTENCE 0
#endif
#ifndef IS31FL3733_PWM_FREQUENCY
# define IS31FL3733_PWM_FREQUENCY IS31FL3733_PWM_FREQUENCY_8K4_HZ // PFS - IS31FL3733B only
#endif
#ifndef IS31FL3733_SW_PULLUP
# define IS31FL3733_SW_PULLUP IS31FL3733_PUR_0_OHM
#endif
#ifndef IS31FL3733_CS_PULLDOWN
# define IS31FL3733_CS_PULLDOWN IS31FL3733_PDR_0_OHM
#endif
#ifndef IS31FL3733_GLOBAL_CURRENT
# define IS31FL3733_GLOBAL_CURRENT 0xFF
#endif
#ifndef IS31FL3733_SYNC_1
# define IS31FL3733_SYNC_1 IS31FL3733_SYNC_NONE
#endif
#ifndef IS31FL3733_SYNC_2
# define IS31FL3733_SYNC_2 IS31FL3733_SYNC_NONE
#endif
#ifndef IS31FL3733_SYNC_3
# define IS31FL3733_SYNC_3 IS31FL3733_SYNC_NONE
#endif
#ifndef IS31FL3733_SYNC_4
# define IS31FL3733_SYNC_4 IS31FL3733_SYNC_NONE
#endif
const uint8_t i2c_addresses[IS31FL3733_DRIVER_COUNT] = {
IS31FL3733_I2C_ADDRESS_1,
#ifdef IS31FL3733_I2C_ADDRESS_2
IS31FL3733_I2C_ADDRESS_2,
# ifdef IS31FL3733_I2C_ADDRESS_3
IS31FL3733_I2C_ADDRESS_3,
# ifdef IS31FL3733_I2C_ADDRESS_4
IS31FL3733_I2C_ADDRESS_4,
# endif
# endif
#endif
};
const uint8_t driver_sync[IS31FL3733_DRIVER_COUNT] = {
IS31FL3733_SYNC_1,
#ifdef IS31FL3733_I2C_ADDRESS_2
IS31FL3733_SYNC_2,
# ifdef IS31FL3733_I2C_ADDRESS_3
IS31FL3733_SYNC_3,
# ifdef IS31FL3733_I2C_ADDRESS_4
IS31FL3733_SYNC_4,
# endif
# endif
#endif
};
// These buffers match the IS31FL3733 PWM registers.
// The control buffers match the page 0 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
// probably not worth the extra complexity.
typedef struct is31fl3733_driver_t {
uint8_t pwm_buffer[IS31FL3733_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t led_control_buffer[IS31FL3733_LED_CONTROL_REGISTER_COUNT];
bool led_control_buffer_dirty;
} PACKED is31fl3733_driver_t;
is31fl3733_driver_t driver_buffers[IS31FL3733_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.led_control_buffer = {0},
.led_control_buffer_dirty = false,
}};
void is31fl3733_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3733_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3733_I2C_PERSISTENCE; i++) {
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3733_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3733_I2C_TIMEOUT);
#endif
}
void is31fl3733_select_page(uint8_t index, uint8_t page) {
is31fl3733_write_register(index, IS31FL3733_REG_COMMAND_WRITE_LOCK, IS31FL3733_COMMAND_WRITE_LOCK_MAGIC);
is31fl3733_write_register(index, IS31FL3733_REG_COMMAND, page);
}
void is31fl3733_write_pwm_buffer(uint8_t index) {
// Assumes page 1 is already selected.
// Transmit PWM registers in 12 transfers of 16 bytes.
// Iterate over the pwm_buffer contents at 16 byte intervals.
for (uint8_t i = 0; i < IS31FL3733_PWM_REGISTER_COUNT; i += 16) {
#if IS31FL3733_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < IS31FL3733_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3733_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3733_I2C_TIMEOUT);
#endif
}
}
void is31fl3733_init_drivers(void) {
i2c_init();
for (uint8_t i = 0; i < IS31FL3733_DRIVER_COUNT; i++) {
is31fl3733_init(i);
}
for (int i = 0; i < IS31FL3733_LED_COUNT; i++) {
is31fl3733_set_led_control_register(i, true);
}
for (uint8_t i = 0; i < IS31FL3733_DRIVER_COUNT; i++) {
is31fl3733_update_led_control_registers(i);
}
}
void is31fl3733_init(uint8_t index) {
// 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.
is31fl3733_select_page(index, IS31FL3733_COMMAND_LED_CONTROL);
// Turn off all LEDs.
for (uint8_t i = 0; i < IS31FL3733_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3733_write_register(index, i, 0x00);
}
is31fl3733_select_page(index, IS31FL3733_COMMAND_PWM);
// Set PWM on all LEDs to 0
// No need to setup Breath registers to PWM as that is the default.
for (uint8_t i = 0; i < IS31FL3733_PWM_REGISTER_COUNT; i++) {
is31fl3733_write_register(index, i, 0x00);
}
is31fl3733_select_page(index, IS31FL3733_COMMAND_FUNCTION);
uint8_t sync = driver_sync[index];
// Set de-ghost pull-up resistors (SWx)
is31fl3733_write_register(index, IS31FL3733_FUNCTION_REG_SW_PULLUP, IS31FL3733_SW_PULLUP);
// Set de-ghost pull-down resistors (CSx)
is31fl3733_write_register(index, IS31FL3733_FUNCTION_REG_CS_PULLDOWN, IS31FL3733_CS_PULLDOWN);
// Set global current to maximum.
is31fl3733_write_register(index, IS31FL3733_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3733_GLOBAL_CURRENT);
// Disable software shutdown.
is31fl3733_write_register(index, IS31FL3733_FUNCTION_REG_CONFIGURATION, ((sync & 0b11) << 6) | ((IS31FL3733_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) {
is31fl3733_led_t led;
if (index >= 0 && index < IS31FL3733_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3733_leds[index]), sizeof(led));
if (driver_buffers[led.driver].pwm_buffer[led.v] == value) {
return;
}
driver_buffers[led.driver].pwm_buffer[led.v] = value;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
void is31fl3733_set_value_all(uint8_t value) {
for (int i = 0; i < IS31FL3733_LED_COUNT; i++) {
is31fl3733_set_value(i, value);
}
}
void is31fl3733_set_led_control_register(uint8_t index, bool value) {
is31fl3733_led_t led;
memcpy_P(&led, (&g_is31fl3733_leds[index]), sizeof(led));
uint8_t control_register = led.v / 8;
uint8_t bit_value = led.v % 8;
if (value) {
driver_buffers[led.driver].led_control_buffer[control_register] |= (1 << bit_value);
} else {
driver_buffers[led.driver].led_control_buffer[control_register] &= ~(1 << bit_value);
}
driver_buffers[led.driver].led_control_buffer_dirty = true;
}
void is31fl3733_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3733_select_page(index, IS31FL3733_COMMAND_PWM);
is31fl3733_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void is31fl3733_update_led_control_registers(uint8_t index) {
if (driver_buffers[index].led_control_buffer_dirty) {
is31fl3733_select_page(index, IS31FL3733_COMMAND_LED_CONTROL);
for (uint8_t i = 0; i < IS31FL3733_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3733_write_register(index, i, driver_buffers[index].led_control_buffer[i]);
}
driver_buffers[index].led_control_buffer_dirty = false;
}
}
void is31fl3733_flush(void) {
for (uint8_t i = 0; i < IS31FL3733_DRIVER_COUNT; i++) {
is31fl3733_update_pwm_buffers(i);
}
}

View File

@ -0,0 +1,366 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2021 Doni Crosby
* Copyright 2021 Leo Deng
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
// ======== DEPRECATED DEFINES - DO NOT USE ========
#ifdef ISSI_TIMEOUT
# define IS31FL3733_I2C_TIMEOUT ISSI_TIMEOUT
#endif
#ifdef ISSI_PERSISTENCE
# define IS31FL3733_I2C_PERSISTENCE ISSI_PERSISTENCE
#endif
#ifdef ISSI_PWM_FREQUENCY
# define IS31FL3733_PWM_FREQUENCY ISSI_PWM_FREQUENCY
#endif
#ifdef ISSI_SWPULLUP
# define IS31FL3733_SW_PULLUP ISSI_SWPULLUP
#endif
#ifdef ISSI_CSPULLUP
# define IS31FL3733_CS_PULLDOWN ISSI_CSPULLUP
#endif
#ifdef ISSI_GLOBALCURRENT
# define IS31FL3733_GLOBAL_CURRENT ISSI_GLOBALCURRENT
#endif
#define is31_led is31fl3733_led_t
#define g_is31_leds g_is31fl3733_leds
#define PUR_0R IS31FL3733_PUR_0_OHM
#define PUR_05KR IS31FL3733_PUR_1K_OHM
#define PUR_3KR IS31FL3733_PUR_2K_OHM
#define PUR_4KR IS31FL3733_PUR_4K_OHM
#define PUR_8KR IS31FL3733_PUR_8K_OHM
#define PUR_16KR IS31FL3733_PUR_16K_OHM
#define PUR_32KR IS31FL3733_PUR_32K_OHM
// ========
#define IS31FL3733_REG_INTERRUPT_MASK 0xF0
#define IS31FL3733_REG_INTERRUPT_STATUS 0xF1
#define IS31FL3733_REG_COMMAND 0xFD
#define IS31FL3733_COMMAND_LED_CONTROL 0x00
#define IS31FL3733_COMMAND_PWM 0x01
#define IS31FL3733_COMMAND_AUTO_BREATH 0x02
#define IS31FL3733_COMMAND_FUNCTION 0x03
#define IS31FL3733_FUNCTION_REG_CONFIGURATION 0x00
#define IS31FL3733_FUNCTION_REG_GLOBAL_CURRENT 0x01
#define IS31FL3733_FUNCTION_REG_SW_PULLUP 0x0F
#define IS31FL3733_FUNCTION_REG_CS_PULLDOWN 0x10
#define IS31FL3733_FUNCTION_REG_RESET 0x11
#define IS31FL3733_REG_COMMAND_WRITE_LOCK 0xFE
#define IS31FL3733_COMMAND_WRITE_LOCK_MAGIC 0xC5
#define IS31FL3733_I2C_ADDRESS_GND_GND 0x50
#define IS31FL3733_I2C_ADDRESS_GND_SCL 0x51
#define IS31FL3733_I2C_ADDRESS_GND_SDA 0x52
#define IS31FL3733_I2C_ADDRESS_GND_VCC 0x53
#define IS31FL3733_I2C_ADDRESS_SCL_GND 0x54
#define IS31FL3733_I2C_ADDRESS_SCL_SCL 0x55
#define IS31FL3733_I2C_ADDRESS_SCL_SDA 0x56
#define IS31FL3733_I2C_ADDRESS_SCL_VCC 0x57
#define IS31FL3733_I2C_ADDRESS_SDA_GND 0x58
#define IS31FL3733_I2C_ADDRESS_SDA_SCL 0x59
#define IS31FL3733_I2C_ADDRESS_SDA_SDA 0x5A
#define IS31FL3733_I2C_ADDRESS_SDA_VCC 0x5B
#define IS31FL3733_I2C_ADDRESS_VCC_GND 0x5C
#define IS31FL3733_I2C_ADDRESS_VCC_SCL 0x5D
#define IS31FL3733_I2C_ADDRESS_VCC_SDA 0x5E
#define IS31FL3733_I2C_ADDRESS_VCC_VCC 0x5F
#if defined(LED_MATRIX_IS31FL3733)
# define IS31FL3733_LED_COUNT LED_MATRIX_LED_COUNT
#endif
#if defined(IS31FL3733_I2C_ADDRESS_4)
# define IS31FL3733_DRIVER_COUNT 4
#elif defined(IS31FL3733_I2C_ADDRESS_3)
# define IS31FL3733_DRIVER_COUNT 3
#elif defined(IS31FL3733_I2C_ADDRESS_2)
# define IS31FL3733_DRIVER_COUNT 2
#elif defined(IS31FL3733_I2C_ADDRESS_1)
# define IS31FL3733_DRIVER_COUNT 1
#endif
typedef struct is31fl3733_led_t {
uint8_t driver : 2;
uint8_t v;
} PACKED is31fl3733_led_t;
extern const is31fl3733_led_t PROGMEM g_is31fl3733_leds[IS31FL3733_LED_COUNT];
void is31fl3733_init_drivers(void);
void is31fl3733_init(uint8_t index);
void is31fl3733_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3733_select_page(uint8_t index, uint8_t page);
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);
// 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 index);
void is31fl3733_update_led_control_registers(uint8_t index);
void is31fl3733_flush(void);
#define IS31FL3733_PDR_0_OHM 0b000 // No pull-down resistor
#define IS31FL3733_PDR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3733_PDR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3733_PDR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3733_PDR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3733_PDR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3733_PDR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3733_PDR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3733_PUR_0_OHM 0b000 // No pull-up resistor
#define IS31FL3733_PUR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3733_PUR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3733_PUR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3733_PUR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3733_PUR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3733_PUR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3733_PUR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3733_PWM_FREQUENCY_8K4_HZ 0b000
#define IS31FL3733_PWM_FREQUENCY_4K2_HZ 0b001
#define IS31FL3733_PWM_FREQUENCY_26K7_HZ 0b010
#define IS31FL3733_PWM_FREQUENCY_2K1_HZ 0b011
#define IS31FL3733_PWM_FREQUENCY_1K05_HZ 0b100
#define IS31FL3733_SYNC_NONE 0b00
#define IS31FL3733_SYNC_MASTER 0b01
#define IS31FL3733_SYNC_SLAVE 0b10
#define SW1_CS1 0x00
#define SW1_CS2 0x01
#define SW1_CS3 0x02
#define SW1_CS4 0x03
#define SW1_CS5 0x04
#define SW1_CS6 0x05
#define SW1_CS7 0x06
#define SW1_CS8 0x07
#define SW1_CS9 0x08
#define SW1_CS10 0x09
#define SW1_CS11 0x0A
#define SW1_CS12 0x0B
#define SW1_CS13 0x0C
#define SW1_CS14 0x0D
#define SW1_CS15 0x0E
#define SW1_CS16 0x0F
#define SW2_CS1 0x10
#define SW2_CS2 0x11
#define SW2_CS3 0x12
#define SW2_CS4 0x13
#define SW2_CS5 0x14
#define SW2_CS6 0x15
#define SW2_CS7 0x16
#define SW2_CS8 0x17
#define SW2_CS9 0x18
#define SW2_CS10 0x19
#define SW2_CS11 0x1A
#define SW2_CS12 0x1B
#define SW2_CS13 0x1C
#define SW2_CS14 0x1D
#define SW2_CS15 0x1E
#define SW2_CS16 0x1F
#define SW3_CS1 0x20
#define SW3_CS2 0x21
#define SW3_CS3 0x22
#define SW3_CS4 0x23
#define SW3_CS5 0x24
#define SW3_CS6 0x25
#define SW3_CS7 0x26
#define SW3_CS8 0x27
#define SW3_CS9 0x28
#define SW3_CS10 0x29
#define SW3_CS11 0x2A
#define SW3_CS12 0x2B
#define SW3_CS13 0x2C
#define SW3_CS14 0x2D
#define SW3_CS15 0x2E
#define SW3_CS16 0x2F
#define SW4_CS1 0x30
#define SW4_CS2 0x31
#define SW4_CS3 0x32
#define SW4_CS4 0x33
#define SW4_CS5 0x34
#define SW4_CS6 0x35
#define SW4_CS7 0x36
#define SW4_CS8 0x37
#define SW4_CS9 0x38
#define SW4_CS10 0x39
#define SW4_CS11 0x3A
#define SW4_CS12 0x3B
#define SW4_CS13 0x3C
#define SW4_CS14 0x3D
#define SW4_CS15 0x3E
#define SW4_CS16 0x3F
#define SW5_CS1 0x40
#define SW5_CS2 0x41
#define SW5_CS3 0x42
#define SW5_CS4 0x43
#define SW5_CS5 0x44
#define SW5_CS6 0x45
#define SW5_CS7 0x46
#define SW5_CS8 0x47
#define SW5_CS9 0x48
#define SW5_CS10 0x49
#define SW5_CS11 0x4A
#define SW5_CS12 0x4B
#define SW5_CS13 0x4C
#define SW5_CS14 0x4D
#define SW5_CS15 0x4E
#define SW5_CS16 0x4F
#define SW6_CS1 0x50
#define SW6_CS2 0x51
#define SW6_CS3 0x52
#define SW6_CS4 0x53
#define SW6_CS5 0x54
#define SW6_CS6 0x55
#define SW6_CS7 0x56
#define SW6_CS8 0x57
#define SW6_CS9 0x58
#define SW6_CS10 0x59
#define SW6_CS11 0x5A
#define SW6_CS12 0x5B
#define SW6_CS13 0x5C
#define SW6_CS14 0x5D
#define SW6_CS15 0x5E
#define SW6_CS16 0x5F
#define SW7_CS1 0x60
#define SW7_CS2 0x61
#define SW7_CS3 0x62
#define SW7_CS4 0x63
#define SW7_CS5 0x64
#define SW7_CS6 0x65
#define SW7_CS7 0x66
#define SW7_CS8 0x67
#define SW7_CS9 0x68
#define SW7_CS10 0x69
#define SW7_CS11 0x6A
#define SW7_CS12 0x6B
#define SW7_CS13 0x6C
#define SW7_CS14 0x6D
#define SW7_CS15 0x6E
#define SW7_CS16 0x6F
#define SW8_CS1 0x70
#define SW8_CS2 0x71
#define SW8_CS3 0x72
#define SW8_CS4 0x73
#define SW8_CS5 0x74
#define SW8_CS6 0x75
#define SW8_CS7 0x76
#define SW8_CS8 0x77
#define SW8_CS9 0x78
#define SW8_CS10 0x79
#define SW8_CS11 0x7A
#define SW8_CS12 0x7B
#define SW8_CS13 0x7C
#define SW8_CS14 0x7D
#define SW8_CS15 0x7E
#define SW8_CS16 0x7F
#define SW9_CS1 0x80
#define SW9_CS2 0x81
#define SW9_CS3 0x82
#define SW9_CS4 0x83
#define SW9_CS5 0x84
#define SW9_CS6 0x85
#define SW9_CS7 0x86
#define SW9_CS8 0x87
#define SW9_CS9 0x88
#define SW9_CS10 0x89
#define SW9_CS11 0x8A
#define SW9_CS12 0x8B
#define SW9_CS13 0x8C
#define SW9_CS14 0x8D
#define SW9_CS15 0x8E
#define SW9_CS16 0x8F
#define SW10_CS1 0x90
#define SW10_CS2 0x91
#define SW10_CS3 0x92
#define SW10_CS4 0x93
#define SW10_CS5 0x94
#define SW10_CS6 0x95
#define SW10_CS7 0x96
#define SW10_CS8 0x97
#define SW10_CS9 0x98
#define SW10_CS10 0x99
#define SW10_CS11 0x9A
#define SW10_CS12 0x9B
#define SW10_CS13 0x9C
#define SW10_CS14 0x9D
#define SW10_CS15 0x9E
#define SW10_CS16 0x9F
#define SW11_CS1 0xA0
#define SW11_CS2 0xA1
#define SW11_CS3 0xA2
#define SW11_CS4 0xA3
#define SW11_CS5 0xA4
#define SW11_CS6 0xA5
#define SW11_CS7 0xA6
#define SW11_CS8 0xA7
#define SW11_CS9 0xA8
#define SW11_CS10 0xA9
#define SW11_CS11 0xAA
#define SW11_CS12 0xAB
#define SW11_CS13 0xAC
#define SW11_CS14 0xAD
#define SW11_CS15 0xAE
#define SW11_CS16 0xAF
#define SW12_CS1 0xB0
#define SW12_CS2 0xB1
#define SW12_CS3 0xB2
#define SW12_CS4 0xB3
#define SW12_CS5 0xB4
#define SW12_CS6 0xB5
#define SW12_CS7 0xB6
#define SW12_CS8 0xB7
#define SW12_CS9 0xB8
#define SW12_CS10 0xB9
#define SW12_CS11 0xBA
#define SW12_CS12 0xBB
#define SW12_CS13 0xBC
#define SW12_CS14 0xBD
#define SW12_CS15 0xBE
#define SW12_CS16 0xBF

View File

@ -1,270 +0,0 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2021 Doni Crosby
* Copyright 2021 Leo Deng
*
* 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 "is31fl3733-simple.h"
#include <string.h>
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3733_PWM_REGISTER_COUNT 192
#define IS31FL3733_LED_CONTROL_REGISTER_COUNT 24
#ifndef IS31FL3733_I2C_TIMEOUT
# define IS31FL3733_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3733_I2C_PERSISTENCE
# define IS31FL3733_I2C_PERSISTENCE 0
#endif
#ifndef IS31FL3733_PWM_FREQUENCY
# define IS31FL3733_PWM_FREQUENCY IS31FL3733_PWM_FREQUENCY_8K4_HZ // PFS - IS31FL3733B only
#endif
#ifndef IS31FL3733_SW_PULLUP
# define IS31FL3733_SW_PULLUP IS31FL3733_PUR_0_OHM
#endif
#ifndef IS31FL3733_CS_PULLDOWN
# define IS31FL3733_CS_PULLDOWN IS31FL3733_PDR_0_OHM
#endif
#ifndef IS31FL3733_GLOBAL_CURRENT
# define IS31FL3733_GLOBAL_CURRENT 0xFF
#endif
#ifndef IS31FL3733_SYNC_1
# define IS31FL3733_SYNC_1 IS31FL3733_SYNC_NONE
#endif
#ifndef IS31FL3733_SYNC_2
# define IS31FL3733_SYNC_2 IS31FL3733_SYNC_NONE
#endif
#ifndef IS31FL3733_SYNC_3
# define IS31FL3733_SYNC_3 IS31FL3733_SYNC_NONE
#endif
#ifndef IS31FL3733_SYNC_4
# define IS31FL3733_SYNC_4 IS31FL3733_SYNC_NONE
#endif
uint8_t i2c_transfer_buffer[20];
// These buffers match the IS31FL3733 PWM registers.
// The control buffers match the page 0 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
// probably not worth the extra complexity.
uint8_t g_pwm_buffer[IS31FL3733_DRIVER_COUNT][IS31FL3733_PWM_REGISTER_COUNT];
bool g_pwm_buffer_update_required[IS31FL3733_DRIVER_COUNT] = {false};
uint8_t g_led_control_registers[IS31FL3733_DRIVER_COUNT][IS31FL3733_LED_CONTROL_REGISTER_COUNT] = {0};
bool g_led_control_registers_update_required[IS31FL3733_DRIVER_COUNT] = {false};
bool is31fl3733_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
// If the transaction fails function returns false.
i2c_transfer_buffer[0] = reg;
i2c_transfer_buffer[1] = data;
#if IS31FL3733_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3733_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3733_I2C_TIMEOUT) != 0) {
return false;
}
}
#else
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3733_I2C_TIMEOUT) != 0) {
return false;
}
#endif
return true;
}
void is31fl3733_select_page(uint8_t addr, uint8_t page) {
is31fl3733_write_register(addr, IS31FL3733_REG_COMMAND_WRITE_LOCK, IS31FL3733_COMMAND_WRITE_LOCK_MAGIC);
is31fl3733_write_register(addr, IS31FL3733_REG_COMMAND, page);
}
bool is31fl3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
// Assumes page 1 is already selected.
// If any of the transactions fails function returns false.
// Transmit PWM registers in 12 transfers of 16 bytes.
// i2c_transfer_buffer[] is 20 bytes
// Iterate over the pwm_buffer contents at 16 byte intervals.
for (int i = 0; i < IS31FL3733_PWM_REGISTER_COUNT; i += 16) {
i2c_transfer_buffer[0] = i;
// Copy the data from i to i+15.
// Device will auto-increment register for data after the first byte
// Thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer.
memcpy(i2c_transfer_buffer + 1, pwm_buffer + i, 16);
#if IS31FL3733_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3733_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3733_I2C_TIMEOUT) != 0) {
return false;
}
}
#else
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3733_I2C_TIMEOUT) != 0) {
return false;
}
#endif
}
return true;
}
void is31fl3733_init_drivers(void) {
i2c_init();
is31fl3733_init(IS31FL3733_I2C_ADDRESS_1, IS31FL3733_SYNC_1);
#if defined(IS31FL3733_I2C_ADDRESS_2)
is31fl3733_init(IS31FL3733_I2C_ADDRESS_2, IS31FL3733_SYNC_2);
# if defined(IS31FL3733_I2C_ADDRESS_3)
is31fl3733_init(IS31FL3733_I2C_ADDRESS_3, IS31FL3733_SYNC_3);
# if defined(IS31FL3733_I2C_ADDRESS_4)
is31fl3733_init(IS31FL3733_I2C_ADDRESS_4, IS31FL3733_SYNC_4);
# endif
# endif
#endif
for (int i = 0; i < IS31FL3733_LED_COUNT; i++) {
is31fl3733_set_led_control_register(i, true);
}
is31fl3733_update_led_control_registers(IS31FL3733_I2C_ADDRESS_1, 0);
#if defined(IS31FL3733_I2C_ADDRESS_2)
is31fl3733_update_led_control_registers(IS31FL3733_I2C_ADDRESS_2, 1);
# if defined(IS31FL3733_I2C_ADDRESS_3)
is31fl3733_update_led_control_registers(IS31FL3733_I2C_ADDRESS_3, 2);
# if defined(IS31FL3733_I2C_ADDRESS_4)
is31fl3733_update_led_control_registers(IS31FL3733_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
}
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,
// then disable software shutdown.
// Sync is passed so set it according to the datasheet.
is31fl3733_select_page(addr, IS31FL3733_COMMAND_LED_CONTROL);
// Turn off all LEDs.
for (int i = 0; i < IS31FL3733_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3733_write_register(addr, i, 0x00);
}
is31fl3733_select_page(addr, IS31FL3733_COMMAND_PWM);
// Set PWM on all LEDs to 0
// No need to setup Breath registers to PWM as that is the default.
for (int i = 0; i < IS31FL3733_PWM_REGISTER_COUNT; i++) {
is31fl3733_write_register(addr, i, 0x00);
}
is31fl3733_select_page(addr, IS31FL3733_COMMAND_FUNCTION);
// Set de-ghost pull-up resistors (SWx)
is31fl3733_write_register(addr, IS31FL3733_FUNCTION_REG_SW_PULLUP, IS31FL3733_SW_PULLUP);
// Set de-ghost pull-down resistors (CSx)
is31fl3733_write_register(addr, IS31FL3733_FUNCTION_REG_CS_PULLDOWN, IS31FL3733_CS_PULLDOWN);
// Set global current to maximum.
is31fl3733_write_register(addr, IS31FL3733_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3733_GLOBAL_CURRENT);
// Disable software shutdown.
is31fl3733_write_register(addr, IS31FL3733_FUNCTION_REG_CONFIGURATION, ((sync & 0b11) << 6) | ((IS31FL3733_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) {
is31fl3733_led_t led;
if (index >= 0 && index < IS31FL3733_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3733_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) {
for (int i = 0; i < IS31FL3733_LED_COUNT; i++) {
is31fl3733_set_value(i, value);
}
}
void is31fl3733_set_led_control_register(uint8_t index, bool value) {
is31fl3733_led_t led;
memcpy_P(&led, (&g_is31fl3733_leds[index]), sizeof(led));
uint8_t control_register = led.v / 8;
uint8_t bit_value = led.v % 8;
if (value) {
g_led_control_registers[led.driver][control_register] |= (1 << bit_value);
} else {
g_led_control_registers[led.driver][control_register] &= ~(1 << bit_value);
}
g_led_control_registers_update_required[led.driver] = true;
}
void is31fl3733_update_pwm_buffers(uint8_t addr, uint8_t index) {
if (g_pwm_buffer_update_required[index]) {
is31fl3733_select_page(addr, IS31FL3733_COMMAND_PWM);
// If any of the transactions fail we risk writing dirty page 0,
// refresh page 0 just in case.
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) {
if (g_led_control_registers_update_required[index]) {
is31fl3733_select_page(addr, IS31FL3733_COMMAND_LED_CONTROL);
for (int i = 0; i < IS31FL3733_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3733_write_register(addr, i, g_led_control_registers[index][i]);
}
g_led_control_registers_update_required[index] = false;
}
}
void is31fl3733_flush(void) {
is31fl3733_update_pwm_buffers(IS31FL3733_I2C_ADDRESS_1, 0);
#if defined(IS31FL3733_I2C_ADDRESS_2)
is31fl3733_update_pwm_buffers(IS31FL3733_I2C_ADDRESS_2, 1);
# if defined(IS31FL3733_I2C_ADDRESS_3)
is31fl3733_update_pwm_buffers(IS31FL3733_I2C_ADDRESS_3, 2);
# if defined(IS31FL3733_I2C_ADDRESS_4)
is31fl3733_update_pwm_buffers(IS31FL3733_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
}

View File

@ -1,367 +0,0 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2021 Doni Crosby
* Copyright 2021 Leo Deng
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
// ======== DEPRECATED DEFINES - DO NOT USE ========
#ifdef ISSI_TIMEOUT
# define IS31FL3733_I2C_TIMEOUT ISSI_TIMEOUT
#endif
#ifdef ISSI_PERSISTENCE
# define IS31FL3733_I2C_PERSISTENCE ISSI_PERSISTENCE
#endif
#ifdef ISSI_PWM_FREQUENCY
# define IS31FL3733_PWM_FREQUENCY ISSI_PWM_FREQUENCY
#endif
#ifdef ISSI_SWPULLUP
# define IS31FL3733_SW_PULLUP ISSI_SWPULLUP
#endif
#ifdef ISSI_CSPULLUP
# define IS31FL3733_CS_PULLDOWN ISSI_CSPULLUP
#endif
#ifdef ISSI_GLOBALCURRENT
# define IS31FL3733_GLOBAL_CURRENT ISSI_GLOBALCURRENT
#endif
#define is31_led is31fl3733_led_t
#define g_is31_leds g_is31fl3733_leds
#define PUR_0R IS31FL3733_PUR_0_OHM
#define PUR_05KR IS31FL3733_PUR_1K_OHM
#define PUR_3KR IS31FL3733_PUR_2K_OHM
#define PUR_4KR IS31FL3733_PUR_4K_OHM
#define PUR_8KR IS31FL3733_PUR_8K_OHM
#define PUR_16KR IS31FL3733_PUR_16K_OHM
#define PUR_32KR IS31FL3733_PUR_32K_OHM
// ========
#define IS31FL3733_REG_INTERRUPT_MASK 0xF0
#define IS31FL3733_REG_INTERRUPT_STATUS 0xF1
#define IS31FL3733_REG_COMMAND 0xFD
#define IS31FL3733_COMMAND_LED_CONTROL 0x00
#define IS31FL3733_COMMAND_PWM 0x01
#define IS31FL3733_COMMAND_AUTO_BREATH 0x02
#define IS31FL3733_COMMAND_FUNCTION 0x03
#define IS31FL3733_FUNCTION_REG_CONFIGURATION 0x00
#define IS31FL3733_FUNCTION_REG_GLOBAL_CURRENT 0x01
#define IS31FL3733_FUNCTION_REG_SW_PULLUP 0x0F
#define IS31FL3733_FUNCTION_REG_CS_PULLDOWN 0x10
#define IS31FL3733_FUNCTION_REG_RESET 0x11
#define IS31FL3733_REG_COMMAND_WRITE_LOCK 0xFE
#define IS31FL3733_COMMAND_WRITE_LOCK_MAGIC 0xC5
#define IS31FL3733_I2C_ADDRESS_GND_GND 0x50
#define IS31FL3733_I2C_ADDRESS_GND_SCL 0x51
#define IS31FL3733_I2C_ADDRESS_GND_SDA 0x52
#define IS31FL3733_I2C_ADDRESS_GND_VCC 0x53
#define IS31FL3733_I2C_ADDRESS_SCL_GND 0x54
#define IS31FL3733_I2C_ADDRESS_SCL_SCL 0x55
#define IS31FL3733_I2C_ADDRESS_SCL_SDA 0x56
#define IS31FL3733_I2C_ADDRESS_SCL_VCC 0x57
#define IS31FL3733_I2C_ADDRESS_SDA_GND 0x58
#define IS31FL3733_I2C_ADDRESS_SDA_SCL 0x59
#define IS31FL3733_I2C_ADDRESS_SDA_SDA 0x5A
#define IS31FL3733_I2C_ADDRESS_SDA_VCC 0x5B
#define IS31FL3733_I2C_ADDRESS_VCC_GND 0x5C
#define IS31FL3733_I2C_ADDRESS_VCC_SCL 0x5D
#define IS31FL3733_I2C_ADDRESS_VCC_SDA 0x5E
#define IS31FL3733_I2C_ADDRESS_VCC_VCC 0x5F
#if defined(LED_MATRIX_IS31FL3733)
# define IS31FL3733_LED_COUNT LED_MATRIX_LED_COUNT
#endif
#if defined(IS31FL3733_I2C_ADDRESS_4)
# define IS31FL3733_DRIVER_COUNT 4
#elif defined(IS31FL3733_I2C_ADDRESS_3)
# define IS31FL3733_DRIVER_COUNT 3
#elif defined(IS31FL3733_I2C_ADDRESS_2)
# define IS31FL3733_DRIVER_COUNT 2
#elif defined(IS31FL3733_I2C_ADDRESS_1)
# define IS31FL3733_DRIVER_COUNT 1
#endif
typedef struct is31fl3733_led_t {
uint8_t driver : 2;
uint8_t v;
} PACKED is31fl3733_led_t;
extern const is31fl3733_led_t PROGMEM g_is31fl3733_leds[IS31FL3733_LED_COUNT];
void is31fl3733_init_drivers(void);
void is31fl3733_init(uint8_t addr, uint8_t sync);
bool is31fl3733_write_register(uint8_t addr, uint8_t reg, uint8_t data);
void is31fl3733_select_page(uint8_t addr, uint8_t page);
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_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_flush(void);
#define IS31FL3733_PDR_0_OHM 0b000 // No pull-down resistor
#define IS31FL3733_PDR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3733_PDR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3733_PDR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3733_PDR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3733_PDR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3733_PDR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3733_PDR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3733_PUR_0_OHM 0b000 // No pull-up resistor
#define IS31FL3733_PUR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3733_PUR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3733_PUR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3733_PUR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3733_PUR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3733_PUR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3733_PUR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3733_PWM_FREQUENCY_8K4_HZ 0b000
#define IS31FL3733_PWM_FREQUENCY_4K2_HZ 0b001
#define IS31FL3733_PWM_FREQUENCY_26K7_HZ 0b010
#define IS31FL3733_PWM_FREQUENCY_2K1_HZ 0b011
#define IS31FL3733_PWM_FREQUENCY_1K05_HZ 0b100
#define IS31FL3733_SYNC_NONE 0b00
#define IS31FL3733_SYNC_MASTER 0b01
#define IS31FL3733_SYNC_SLAVE 0b10
#define A_1 0x00
#define A_2 0x01
#define A_3 0x02
#define A_4 0x03
#define A_5 0x04
#define A_6 0x05
#define A_7 0x06
#define A_8 0x07
#define A_9 0x08
#define A_10 0x09
#define A_11 0x0A
#define A_12 0x0B
#define A_13 0x0C
#define A_14 0x0D
#define A_15 0x0E
#define A_16 0x0F
#define B_1 0x10
#define B_2 0x11
#define B_3 0x12
#define B_4 0x13
#define B_5 0x14
#define B_6 0x15
#define B_7 0x16
#define B_8 0x17
#define B_9 0x18
#define B_10 0x19
#define B_11 0x1A
#define B_12 0x1B
#define B_13 0x1C
#define B_14 0x1D
#define B_15 0x1E
#define B_16 0x1F
#define C_1 0x20
#define C_2 0x21
#define C_3 0x22
#define C_4 0x23
#define C_5 0x24
#define C_6 0x25
#define C_7 0x26
#define C_8 0x27
#define C_9 0x28
#define C_10 0x29
#define C_11 0x2A
#define C_12 0x2B
#define C_13 0x2C
#define C_14 0x2D
#define C_15 0x2E
#define C_16 0x2F
#define D_1 0x30
#define D_2 0x31
#define D_3 0x32
#define D_4 0x33
#define D_5 0x34
#define D_6 0x35
#define D_7 0x36
#define D_8 0x37
#define D_9 0x38
#define D_10 0x39
#define D_11 0x3A
#define D_12 0x3B
#define D_13 0x3C
#define D_14 0x3D
#define D_15 0x3E
#define D_16 0x3F
#define E_1 0x40
#define E_2 0x41
#define E_3 0x42
#define E_4 0x43
#define E_5 0x44
#define E_6 0x45
#define E_7 0x46
#define E_8 0x47
#define E_9 0x48
#define E_10 0x49
#define E_11 0x4A
#define E_12 0x4B
#define E_13 0x4C
#define E_14 0x4D
#define E_15 0x4E
#define E_16 0x4F
#define F_1 0x50
#define F_2 0x51
#define F_3 0x52
#define F_4 0x53
#define F_5 0x54
#define F_6 0x55
#define F_7 0x56
#define F_8 0x57
#define F_9 0x58
#define F_10 0x59
#define F_11 0x5A
#define F_12 0x5B
#define F_13 0x5C
#define F_14 0x5D
#define F_15 0x5E
#define F_16 0x5F
#define G_1 0x60
#define G_2 0x61
#define G_3 0x62
#define G_4 0x63
#define G_5 0x64
#define G_6 0x65
#define G_7 0x66
#define G_8 0x67
#define G_9 0x68
#define G_10 0x69
#define G_11 0x6A
#define G_12 0x6B
#define G_13 0x6C
#define G_14 0x6D
#define G_15 0x6E
#define G_16 0x6F
#define H_1 0x70
#define H_2 0x71
#define H_3 0x72
#define H_4 0x73
#define H_5 0x74
#define H_6 0x75
#define H_7 0x76
#define H_8 0x77
#define H_9 0x78
#define H_10 0x79
#define H_11 0x7A
#define H_12 0x7B
#define H_13 0x7C
#define H_14 0x7D
#define H_15 0x7E
#define H_16 0x7F
#define I_1 0x80
#define I_2 0x81
#define I_3 0x82
#define I_4 0x83
#define I_5 0x84
#define I_6 0x85
#define I_7 0x86
#define I_8 0x87
#define I_9 0x88
#define I_10 0x89
#define I_11 0x8A
#define I_12 0x8B
#define I_13 0x8C
#define I_14 0x8D
#define I_15 0x8E
#define I_16 0x8F
#define J_1 0x90
#define J_2 0x91
#define J_3 0x92
#define J_4 0x93
#define J_5 0x94
#define J_6 0x95
#define J_7 0x96
#define J_8 0x97
#define J_9 0x98
#define J_10 0x99
#define J_11 0x9A
#define J_12 0x9B
#define J_13 0x9C
#define J_14 0x9D
#define J_15 0x9E
#define J_16 0x9F
#define K_1 0xA0
#define K_2 0xA1
#define K_3 0xA2
#define K_4 0xA3
#define K_5 0xA4
#define K_6 0xA5
#define K_7 0xA6
#define K_8 0xA7
#define K_9 0xA8
#define K_10 0xA9
#define K_11 0xAA
#define K_12 0xAB
#define K_13 0xAC
#define K_14 0xAD
#define K_15 0xAE
#define K_16 0xAF
#define L_1 0xB0
#define L_2 0xB1
#define L_3 0xB2
#define L_4 0xB3
#define L_5 0xB4
#define L_6 0xB5
#define L_7 0xB6
#define L_8 0xB7
#define L_9 0xB8
#define L_10 0xB9
#define L_11 0xBA
#define L_12 0xBB
#define L_13 0xBC
#define L_14 0xBD
#define L_15 0xBE
#define L_16 0xBF

View File

@ -18,7 +18,6 @@
*/
#include "is31fl3733.h"
#include <string.h>
#include "i2c_master.h"
#include "wait.h"
@ -62,7 +61,31 @@
# define IS31FL3733_SYNC_4 IS31FL3733_SYNC_NONE
#endif
uint8_t i2c_transfer_buffer[20];
const uint8_t i2c_addresses[IS31FL3733_DRIVER_COUNT] = {
IS31FL3733_I2C_ADDRESS_1,
#ifdef IS31FL3733_I2C_ADDRESS_2
IS31FL3733_I2C_ADDRESS_2,
# ifdef IS31FL3733_I2C_ADDRESS_3
IS31FL3733_I2C_ADDRESS_3,
# ifdef IS31FL3733_I2C_ADDRESS_4
IS31FL3733_I2C_ADDRESS_4,
# endif
# endif
#endif
};
const uint8_t driver_sync[IS31FL3733_DRIVER_COUNT] = {
IS31FL3733_SYNC_1,
#ifdef IS31FL3733_I2C_ADDRESS_2
IS31FL3733_SYNC_2,
# ifdef IS31FL3733_I2C_ADDRESS_3
IS31FL3733_SYNC_3,
# ifdef IS31FL3733_I2C_ADDRESS_4
IS31FL3733_SYNC_4,
# endif
# endif
#endif
};
// These buffers match the IS31FL3733 PWM registers.
// The control buffers match the page 0 LED On/Off registers.
@ -70,127 +93,100 @@ uint8_t i2c_transfer_buffer[20];
// We could optimize this and take out the unused registers from these
// buffers and the transfers in is31fl3733_write_pwm_buffer() but it's
// probably not worth the extra complexity.
uint8_t g_pwm_buffer[IS31FL3733_DRIVER_COUNT][IS31FL3733_PWM_REGISTER_COUNT];
bool g_pwm_buffer_update_required[IS31FL3733_DRIVER_COUNT] = {false};
typedef struct is31fl3733_driver_t {
uint8_t pwm_buffer[IS31FL3733_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t led_control_buffer[IS31FL3733_LED_CONTROL_REGISTER_COUNT];
bool led_control_buffer_dirty;
} PACKED is31fl3733_driver_t;
uint8_t g_led_control_registers[IS31FL3733_DRIVER_COUNT][IS31FL3733_LED_CONTROL_REGISTER_COUNT] = {0};
bool g_led_control_registers_update_required[IS31FL3733_DRIVER_COUNT] = {false};
bool is31fl3733_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
// If the transaction fails function returns false.
i2c_transfer_buffer[0] = reg;
i2c_transfer_buffer[1] = data;
is31fl3733_driver_t driver_buffers[IS31FL3733_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.led_control_buffer = {0},
.led_control_buffer_dirty = false,
}};
void is31fl3733_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3733_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3733_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3733_I2C_TIMEOUT) != 0) {
return false;
}
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3733_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3733_I2C_TIMEOUT) != 0) {
return false;
}
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3733_I2C_TIMEOUT);
#endif
return true;
}
void is31fl3733_select_page(uint8_t addr, uint8_t page) {
is31fl3733_write_register(addr, IS31FL3733_REG_COMMAND_WRITE_LOCK, IS31FL3733_COMMAND_WRITE_LOCK_MAGIC);
is31fl3733_write_register(addr, IS31FL3733_REG_COMMAND, page);
void is31fl3733_select_page(uint8_t index, uint8_t page) {
is31fl3733_write_register(index, IS31FL3733_REG_COMMAND_WRITE_LOCK, IS31FL3733_COMMAND_WRITE_LOCK_MAGIC);
is31fl3733_write_register(index, IS31FL3733_REG_COMMAND, page);
}
bool is31fl3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
void is31fl3733_write_pwm_buffer(uint8_t index) {
// Assumes page 1 is already selected.
// If any of the transactions fails function returns false.
// Transmit PWM registers in 12 transfers of 16 bytes.
// i2c_transfer_buffer[] is 20 bytes
// Iterate over the pwm_buffer contents at 16 byte intervals.
for (int i = 0; i < IS31FL3733_PWM_REGISTER_COUNT; i += 16) {
i2c_transfer_buffer[0] = i;
// Copy the data from i to i+15.
// Device will auto-increment register for data after the first byte
// Thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer.
memcpy(i2c_transfer_buffer + 1, pwm_buffer + i, 16);
for (uint8_t i = 0; i < IS31FL3733_PWM_REGISTER_COUNT; i += 16) {
#if IS31FL3733_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3733_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3733_I2C_TIMEOUT) != 0) {
return false;
}
for (uint8_t j = 0; j < IS31FL3733_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3733_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3733_I2C_TIMEOUT) != 0) {
return false;
}
i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3733_I2C_TIMEOUT);
#endif
}
return true;
}
void is31fl3733_init_drivers(void) {
i2c_init();
is31fl3733_init(IS31FL3733_I2C_ADDRESS_1, IS31FL3733_SYNC_1);
#if defined(IS31FL3733_I2C_ADDRESS_2)
is31fl3733_init(IS31FL3733_I2C_ADDRESS_2, IS31FL3733_SYNC_2);
# if defined(IS31FL3733_I2C_ADDRESS_3)
is31fl3733_init(IS31FL3733_I2C_ADDRESS_3, IS31FL3733_SYNC_3);
# if defined(IS31FL3733_I2C_ADDRESS_4)
is31fl3733_init(IS31FL3733_I2C_ADDRESS_4, IS31FL3733_SYNC_4);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3733_DRIVER_COUNT; i++) {
is31fl3733_init(i);
}
for (int i = 0; i < IS31FL3733_LED_COUNT; i++) {
is31fl3733_set_led_control_register(i, true, true, true);
}
is31fl3733_update_led_control_registers(IS31FL3733_I2C_ADDRESS_1, 0);
#if defined(IS31FL3733_I2C_ADDRESS_2)
is31fl3733_update_led_control_registers(IS31FL3733_I2C_ADDRESS_2, 1);
# if defined(IS31FL3733_I2C_ADDRESS_3)
is31fl3733_update_led_control_registers(IS31FL3733_I2C_ADDRESS_3, 2);
# if defined(IS31FL3733_I2C_ADDRESS_4)
is31fl3733_update_led_control_registers(IS31FL3733_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3733_DRIVER_COUNT; i++) {
is31fl3733_update_led_control_registers(i);
}
}
void is31fl3733_init(uint8_t addr, uint8_t sync) {
void is31fl3733_init(uint8_t index) {
// 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.
// Sync is passed so set it according to the datasheet.
is31fl3733_select_page(addr, IS31FL3733_COMMAND_LED_CONTROL);
is31fl3733_select_page(index, IS31FL3733_COMMAND_LED_CONTROL);
// Turn off all LEDs.
for (int i = 0; i < IS31FL3733_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3733_write_register(addr, i, 0x00);
for (uint8_t i = 0; i < IS31FL3733_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3733_write_register(index, i, 0x00);
}
is31fl3733_select_page(addr, IS31FL3733_COMMAND_PWM);
is31fl3733_select_page(index, IS31FL3733_COMMAND_PWM);
// Set PWM on all LEDs to 0
// No need to setup Breath registers to PWM as that is the default.
for (int i = 0; i < IS31FL3733_PWM_REGISTER_COUNT; i++) {
is31fl3733_write_register(addr, i, 0x00);
for (uint8_t i = 0; i < IS31FL3733_PWM_REGISTER_COUNT; i++) {
is31fl3733_write_register(index, i, 0x00);
}
is31fl3733_select_page(addr, IS31FL3733_COMMAND_FUNCTION);
is31fl3733_select_page(index, IS31FL3733_COMMAND_FUNCTION);
uint8_t sync = driver_sync[index];
// Set de-ghost pull-up resistors (SWx)
is31fl3733_write_register(addr, IS31FL3733_FUNCTION_REG_SW_PULLUP, IS31FL3733_SW_PULLUP);
is31fl3733_write_register(index, IS31FL3733_FUNCTION_REG_SW_PULLUP, IS31FL3733_SW_PULLUP);
// Set de-ghost pull-down resistors (CSx)
is31fl3733_write_register(addr, IS31FL3733_FUNCTION_REG_CS_PULLDOWN, IS31FL3733_CS_PULLDOWN);
is31fl3733_write_register(index, IS31FL3733_FUNCTION_REG_CS_PULLDOWN, IS31FL3733_CS_PULLDOWN);
// Set global current to maximum.
is31fl3733_write_register(addr, IS31FL3733_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3733_GLOBAL_CURRENT);
is31fl3733_write_register(index, IS31FL3733_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3733_GLOBAL_CURRENT);
// Disable software shutdown.
is31fl3733_write_register(addr, IS31FL3733_FUNCTION_REG_CONFIGURATION, ((sync & 0b11) << 6) | ((IS31FL3733_PWM_FREQUENCY & 0b111) << 3) | 0x01);
is31fl3733_write_register(index, IS31FL3733_FUNCTION_REG_CONFIGURATION, ((sync & 0b11) << 6) | ((IS31FL3733_PWM_FREQUENCY & 0b111) << 3) | 0x01);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
@ -198,16 +194,18 @@ void is31fl3733_init(uint8_t addr, uint8_t sync) {
void is31fl3733_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
is31fl3733_led_t led;
if (index >= 0 && index < IS31FL3733_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3733_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) {
if (driver_buffers[led.driver].pwm_buffer[led.r] == red && driver_buffers[led.driver].pwm_buffer[led.g] == green && driver_buffers[led.driver].pwm_buffer[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;
driver_buffers[led.driver].pwm_buffer[led.r] = red;
driver_buffers[led.driver].pwm_buffer[led.g] = green;
driver_buffers[led.driver].pwm_buffer[led.b] = blue;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
@ -229,57 +227,48 @@ void is31fl3733_set_led_control_register(uint8_t index, bool red, bool green, bo
uint8_t bit_b = led.b % 8;
if (red) {
g_led_control_registers[led.driver][control_register_r] |= (1 << bit_r);
driver_buffers[led.driver].led_control_buffer[control_register_r] |= (1 << bit_r);
} else {
g_led_control_registers[led.driver][control_register_r] &= ~(1 << bit_r);
driver_buffers[led.driver].led_control_buffer[control_register_r] &= ~(1 << bit_r);
}
if (green) {
g_led_control_registers[led.driver][control_register_g] |= (1 << bit_g);
driver_buffers[led.driver].led_control_buffer[control_register_g] |= (1 << bit_g);
} else {
g_led_control_registers[led.driver][control_register_g] &= ~(1 << bit_g);
driver_buffers[led.driver].led_control_buffer[control_register_g] &= ~(1 << bit_g);
}
if (blue) {
g_led_control_registers[led.driver][control_register_b] |= (1 << bit_b);
driver_buffers[led.driver].led_control_buffer[control_register_b] |= (1 << bit_b);
} else {
g_led_control_registers[led.driver][control_register_b] &= ~(1 << bit_b);
driver_buffers[led.driver].led_control_buffer[control_register_b] &= ~(1 << bit_b);
}
g_led_control_registers_update_required[led.driver] = true;
driver_buffers[led.driver].led_control_buffer_dirty = true;
}
void is31fl3733_update_pwm_buffers(uint8_t addr, uint8_t index) {
if (g_pwm_buffer_update_required[index]) {
is31fl3733_select_page(addr, IS31FL3733_COMMAND_PWM);
void is31fl3733_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3733_select_page(index, IS31FL3733_COMMAND_PWM);
// If any of the transactions fail we risk writing dirty page 0,
// refresh page 0 just in case.
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;
is31fl3733_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void is31fl3733_update_led_control_registers(uint8_t addr, uint8_t index) {
if (g_led_control_registers_update_required[index]) {
is31fl3733_select_page(addr, IS31FL3733_COMMAND_LED_CONTROL);
void is31fl3733_update_led_control_registers(uint8_t index) {
if (driver_buffers[index].led_control_buffer_dirty) {
is31fl3733_select_page(index, IS31FL3733_COMMAND_LED_CONTROL);
for (int i = 0; i < IS31FL3733_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3733_write_register(addr, i, g_led_control_registers[index][i]);
for (uint8_t i = 0; i < IS31FL3733_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3733_write_register(index, i, driver_buffers[index].led_control_buffer[i]);
}
g_led_control_registers_update_required[index] = false;
driver_buffers[index].led_control_buffer_dirty = false;
}
}
void is31fl3733_flush(void) {
is31fl3733_update_pwm_buffers(IS31FL3733_I2C_ADDRESS_1, 0);
#if defined(IS31FL3733_I2C_ADDRESS_2)
is31fl3733_update_pwm_buffers(IS31FL3733_I2C_ADDRESS_2, 1);
# if defined(IS31FL3733_I2C_ADDRESS_3)
is31fl3733_update_pwm_buffers(IS31FL3733_I2C_ADDRESS_3, 2);
# if defined(IS31FL3733_I2C_ADDRESS_4)
is31fl3733_update_pwm_buffers(IS31FL3733_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3733_DRIVER_COUNT; i++) {
is31fl3733_update_pwm_buffers(i);
}
}

View File

@ -40,13 +40,13 @@
#ifdef DRIVER_SYNC_1
# define IS31FL3733_SYNC_1 DRIVER_SYNC_1
#endif
#ifdef DRIVER_ADDR_2
#ifdef DRIVER_SYNC_2
# define IS31FL3733_SYNC_2 DRIVER_SYNC_2
#endif
#ifdef DRIVER_ADDR_3
#ifdef DRIVER_SYNC_3
# define IS31FL3733_SYNC_3 DRIVER_SYNC_3
#endif
#ifdef DRIVER_ADDR_4
#ifdef DRIVER_SYNC_4
# define IS31FL3733_SYNC_4 DRIVER_SYNC_4
#endif
#ifdef ISSI_TIMEOUT
@ -140,10 +140,9 @@ typedef struct is31fl3733_led_t {
extern const is31fl3733_led_t PROGMEM g_is31fl3733_leds[IS31FL3733_LED_COUNT];
void is31fl3733_init_drivers(void);
void is31fl3733_init(uint8_t addr, uint8_t sync);
bool is31fl3733_write_register(uint8_t addr, uint8_t reg, uint8_t data);
void is31fl3733_select_page(uint8_t addr, uint8_t page);
bool is31fl3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
void is31fl3733_init(uint8_t index);
void is31fl3733_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3733_select_page(uint8_t index, uint8_t page);
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);
@ -154,8 +153,8 @@ void is31fl3733_set_led_control_register(uint8_t index, bool red, bool green, bo
// (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 index);
void is31fl3733_update_led_control_registers(uint8_t index);
void is31fl3733_flush(void);
@ -187,206 +186,412 @@ void is31fl3733_flush(void);
#define IS31FL3733_SYNC_MASTER 0b01
#define IS31FL3733_SYNC_SLAVE 0b10
#define A_1 0x00
#define A_2 0x01
#define A_3 0x02
#define A_4 0x03
#define A_5 0x04
#define A_6 0x05
#define A_7 0x06
#define A_8 0x07
#define A_9 0x08
#define A_10 0x09
#define A_11 0x0A
#define A_12 0x0B
#define A_13 0x0C
#define A_14 0x0D
#define A_15 0x0E
#define A_16 0x0F
#define SW1_CS1 0x00
#define SW1_CS2 0x01
#define SW1_CS3 0x02
#define SW1_CS4 0x03
#define SW1_CS5 0x04
#define SW1_CS6 0x05
#define SW1_CS7 0x06
#define SW1_CS8 0x07
#define SW1_CS9 0x08
#define SW1_CS10 0x09
#define SW1_CS11 0x0A
#define SW1_CS12 0x0B
#define SW1_CS13 0x0C
#define SW1_CS14 0x0D
#define SW1_CS15 0x0E
#define SW1_CS16 0x0F
#define B_1 0x10
#define B_2 0x11
#define B_3 0x12
#define B_4 0x13
#define B_5 0x14
#define B_6 0x15
#define B_7 0x16
#define B_8 0x17
#define B_9 0x18
#define B_10 0x19
#define B_11 0x1A
#define B_12 0x1B
#define B_13 0x1C
#define B_14 0x1D
#define B_15 0x1E
#define B_16 0x1F
#define SW2_CS1 0x10
#define SW2_CS2 0x11
#define SW2_CS3 0x12
#define SW2_CS4 0x13
#define SW2_CS5 0x14
#define SW2_CS6 0x15
#define SW2_CS7 0x16
#define SW2_CS8 0x17
#define SW2_CS9 0x18
#define SW2_CS10 0x19
#define SW2_CS11 0x1A
#define SW2_CS12 0x1B
#define SW2_CS13 0x1C
#define SW2_CS14 0x1D
#define SW2_CS15 0x1E
#define SW2_CS16 0x1F
#define C_1 0x20
#define C_2 0x21
#define C_3 0x22
#define C_4 0x23
#define C_5 0x24
#define C_6 0x25
#define C_7 0x26
#define C_8 0x27
#define C_9 0x28
#define C_10 0x29
#define C_11 0x2A
#define C_12 0x2B
#define C_13 0x2C
#define C_14 0x2D
#define C_15 0x2E
#define C_16 0x2F
#define SW3_CS1 0x20
#define SW3_CS2 0x21
#define SW3_CS3 0x22
#define SW3_CS4 0x23
#define SW3_CS5 0x24
#define SW3_CS6 0x25
#define SW3_CS7 0x26
#define SW3_CS8 0x27
#define SW3_CS9 0x28
#define SW3_CS10 0x29
#define SW3_CS11 0x2A
#define SW3_CS12 0x2B
#define SW3_CS13 0x2C
#define SW3_CS14 0x2D
#define SW3_CS15 0x2E
#define SW3_CS16 0x2F
#define D_1 0x30
#define D_2 0x31
#define D_3 0x32
#define D_4 0x33
#define D_5 0x34
#define D_6 0x35
#define D_7 0x36
#define D_8 0x37
#define D_9 0x38
#define D_10 0x39
#define D_11 0x3A
#define D_12 0x3B
#define D_13 0x3C
#define D_14 0x3D
#define D_15 0x3E
#define D_16 0x3F
#define SW4_CS1 0x30
#define SW4_CS2 0x31
#define SW4_CS3 0x32
#define SW4_CS4 0x33
#define SW4_CS5 0x34
#define SW4_CS6 0x35
#define SW4_CS7 0x36
#define SW4_CS8 0x37
#define SW4_CS9 0x38
#define SW4_CS10 0x39
#define SW4_CS11 0x3A
#define SW4_CS12 0x3B
#define SW4_CS13 0x3C
#define SW4_CS14 0x3D
#define SW4_CS15 0x3E
#define SW4_CS16 0x3F
#define E_1 0x40
#define E_2 0x41
#define E_3 0x42
#define E_4 0x43
#define E_5 0x44
#define E_6 0x45
#define E_7 0x46
#define E_8 0x47
#define E_9 0x48
#define E_10 0x49
#define E_11 0x4A
#define E_12 0x4B
#define E_13 0x4C
#define E_14 0x4D
#define E_15 0x4E
#define E_16 0x4F
#define SW5_CS1 0x40
#define SW5_CS2 0x41
#define SW5_CS3 0x42
#define SW5_CS4 0x43
#define SW5_CS5 0x44
#define SW5_CS6 0x45
#define SW5_CS7 0x46
#define SW5_CS8 0x47
#define SW5_CS9 0x48
#define SW5_CS10 0x49
#define SW5_CS11 0x4A
#define SW5_CS12 0x4B
#define SW5_CS13 0x4C
#define SW5_CS14 0x4D
#define SW5_CS15 0x4E
#define SW5_CS16 0x4F
#define F_1 0x50
#define F_2 0x51
#define F_3 0x52
#define F_4 0x53
#define F_5 0x54
#define F_6 0x55
#define F_7 0x56
#define F_8 0x57
#define F_9 0x58
#define F_10 0x59
#define F_11 0x5A
#define F_12 0x5B
#define F_13 0x5C
#define F_14 0x5D
#define F_15 0x5E
#define F_16 0x5F
#define SW6_CS1 0x50
#define SW6_CS2 0x51
#define SW6_CS3 0x52
#define SW6_CS4 0x53
#define SW6_CS5 0x54
#define SW6_CS6 0x55
#define SW6_CS7 0x56
#define SW6_CS8 0x57
#define SW6_CS9 0x58
#define SW6_CS10 0x59
#define SW6_CS11 0x5A
#define SW6_CS12 0x5B
#define SW6_CS13 0x5C
#define SW6_CS14 0x5D
#define SW6_CS15 0x5E
#define SW6_CS16 0x5F
#define G_1 0x60
#define G_2 0x61
#define G_3 0x62
#define G_4 0x63
#define G_5 0x64
#define G_6 0x65
#define G_7 0x66
#define G_8 0x67
#define G_9 0x68
#define G_10 0x69
#define G_11 0x6A
#define G_12 0x6B
#define G_13 0x6C
#define G_14 0x6D
#define G_15 0x6E
#define G_16 0x6F
#define SW7_CS1 0x60
#define SW7_CS2 0x61
#define SW7_CS3 0x62
#define SW7_CS4 0x63
#define SW7_CS5 0x64
#define SW7_CS6 0x65
#define SW7_CS7 0x66
#define SW7_CS8 0x67
#define SW7_CS9 0x68
#define SW7_CS10 0x69
#define SW7_CS11 0x6A
#define SW7_CS12 0x6B
#define SW7_CS13 0x6C
#define SW7_CS14 0x6D
#define SW7_CS15 0x6E
#define SW7_CS16 0x6F
#define H_1 0x70
#define H_2 0x71
#define H_3 0x72
#define H_4 0x73
#define H_5 0x74
#define H_6 0x75
#define H_7 0x76
#define H_8 0x77
#define H_9 0x78
#define H_10 0x79
#define H_11 0x7A
#define H_12 0x7B
#define H_13 0x7C
#define H_14 0x7D
#define H_15 0x7E
#define H_16 0x7F
#define SW8_CS1 0x70
#define SW8_CS2 0x71
#define SW8_CS3 0x72
#define SW8_CS4 0x73
#define SW8_CS5 0x74
#define SW8_CS6 0x75
#define SW8_CS7 0x76
#define SW8_CS8 0x77
#define SW8_CS9 0x78
#define SW8_CS10 0x79
#define SW8_CS11 0x7A
#define SW8_CS12 0x7B
#define SW8_CS13 0x7C
#define SW8_CS14 0x7D
#define SW8_CS15 0x7E
#define SW8_CS16 0x7F
#define I_1 0x80
#define I_2 0x81
#define I_3 0x82
#define I_4 0x83
#define I_5 0x84
#define I_6 0x85
#define I_7 0x86
#define I_8 0x87
#define I_9 0x88
#define I_10 0x89
#define I_11 0x8A
#define I_12 0x8B
#define I_13 0x8C
#define I_14 0x8D
#define I_15 0x8E
#define I_16 0x8F
#define SW9_CS1 0x80
#define SW9_CS2 0x81
#define SW9_CS3 0x82
#define SW9_CS4 0x83
#define SW9_CS5 0x84
#define SW9_CS6 0x85
#define SW9_CS7 0x86
#define SW9_CS8 0x87
#define SW9_CS9 0x88
#define SW9_CS10 0x89
#define SW9_CS11 0x8A
#define SW9_CS12 0x8B
#define SW9_CS13 0x8C
#define SW9_CS14 0x8D
#define SW9_CS15 0x8E
#define SW9_CS16 0x8F
#define J_1 0x90
#define J_2 0x91
#define J_3 0x92
#define J_4 0x93
#define J_5 0x94
#define J_6 0x95
#define J_7 0x96
#define J_8 0x97
#define J_9 0x98
#define J_10 0x99
#define J_11 0x9A
#define J_12 0x9B
#define J_13 0x9C
#define J_14 0x9D
#define J_15 0x9E
#define J_16 0x9F
#define SW10_CS1 0x90
#define SW10_CS2 0x91
#define SW10_CS3 0x92
#define SW10_CS4 0x93
#define SW10_CS5 0x94
#define SW10_CS6 0x95
#define SW10_CS7 0x96
#define SW10_CS8 0x97
#define SW10_CS9 0x98
#define SW10_CS10 0x99
#define SW10_CS11 0x9A
#define SW10_CS12 0x9B
#define SW10_CS13 0x9C
#define SW10_CS14 0x9D
#define SW10_CS15 0x9E
#define SW10_CS16 0x9F
#define K_1 0xA0
#define K_2 0xA1
#define K_3 0xA2
#define K_4 0xA3
#define K_5 0xA4
#define K_6 0xA5
#define K_7 0xA6
#define K_8 0xA7
#define K_9 0xA8
#define K_10 0xA9
#define K_11 0xAA
#define K_12 0xAB
#define K_13 0xAC
#define K_14 0xAD
#define K_15 0xAE
#define K_16 0xAF
#define SW11_CS1 0xA0
#define SW11_CS2 0xA1
#define SW11_CS3 0xA2
#define SW11_CS4 0xA3
#define SW11_CS5 0xA4
#define SW11_CS6 0xA5
#define SW11_CS7 0xA6
#define SW11_CS8 0xA7
#define SW11_CS9 0xA8
#define SW11_CS10 0xA9
#define SW11_CS11 0xAA
#define SW11_CS12 0xAB
#define SW11_CS13 0xAC
#define SW11_CS14 0xAD
#define SW11_CS15 0xAE
#define SW11_CS16 0xAF
#define L_1 0xB0
#define L_2 0xB1
#define L_3 0xB2
#define L_4 0xB3
#define L_5 0xB4
#define L_6 0xB5
#define L_7 0xB6
#define L_8 0xB7
#define L_9 0xB8
#define L_10 0xB9
#define L_11 0xBA
#define L_12 0xBB
#define L_13 0xBC
#define L_14 0xBD
#define L_15 0xBE
#define L_16 0xBF
#define SW12_CS1 0xB0
#define SW12_CS2 0xB1
#define SW12_CS3 0xB2
#define SW12_CS4 0xB3
#define SW12_CS5 0xB4
#define SW12_CS6 0xB5
#define SW12_CS7 0xB6
#define SW12_CS8 0xB7
#define SW12_CS9 0xB8
#define SW12_CS10 0xB9
#define SW12_CS11 0xBA
#define SW12_CS12 0xBB
#define SW12_CS13 0xBC
#define SW12_CS14 0xBD
#define SW12_CS15 0xBE
#define SW12_CS16 0xBF
// DEPRECATED - DO NOT USE
#define A_1 SW1_CS1
#define A_2 SW1_CS2
#define A_3 SW1_CS3
#define A_4 SW1_CS4
#define A_5 SW1_CS5
#define A_6 SW1_CS6
#define A_7 SW1_CS7
#define A_8 SW1_CS8
#define A_9 SW1_CS9
#define A_10 SW1_CS10
#define A_11 SW1_CS11
#define A_12 SW1_CS12
#define A_13 SW1_CS13
#define A_14 SW1_CS14
#define A_15 SW1_CS15
#define A_16 SW1_CS16
#define B_1 SW2_CS1
#define B_2 SW2_CS2
#define B_3 SW2_CS3
#define B_4 SW2_CS4
#define B_5 SW2_CS5
#define B_6 SW2_CS6
#define B_7 SW2_CS7
#define B_8 SW2_CS8
#define B_9 SW2_CS9
#define B_10 SW2_CS10
#define B_11 SW2_CS11
#define B_12 SW2_CS12
#define B_13 SW2_CS13
#define B_14 SW2_CS14
#define B_15 SW2_CS15
#define B_16 SW2_CS16
#define C_1 SW3_CS1
#define C_2 SW3_CS2
#define C_3 SW3_CS3
#define C_4 SW3_CS4
#define C_5 SW3_CS5
#define C_6 SW3_CS6
#define C_7 SW3_CS7
#define C_8 SW3_CS8
#define C_9 SW3_CS9
#define C_10 SW3_CS10
#define C_11 SW3_CS11
#define C_12 SW3_CS12
#define C_13 SW3_CS13
#define C_14 SW3_CS14
#define C_15 SW3_CS15
#define C_16 SW3_CS16
#define D_1 SW4_CS1
#define D_2 SW4_CS2
#define D_3 SW4_CS3
#define D_4 SW4_CS4
#define D_5 SW4_CS5
#define D_6 SW4_CS6
#define D_7 SW4_CS7
#define D_8 SW4_CS8
#define D_9 SW4_CS9
#define D_10 SW4_CS10
#define D_11 SW4_CS11
#define D_12 SW4_CS12
#define D_13 SW4_CS13
#define D_14 SW4_CS14
#define D_15 SW4_CS15
#define D_16 SW4_CS16
#define E_1 SW5_CS1
#define E_2 SW5_CS2
#define E_3 SW5_CS3
#define E_4 SW5_CS4
#define E_5 SW5_CS5
#define E_6 SW5_CS6
#define E_7 SW5_CS7
#define E_8 SW5_CS8
#define E_9 SW5_CS9
#define E_10 SW5_CS10
#define E_11 SW5_CS11
#define E_12 SW5_CS12
#define E_13 SW5_CS13
#define E_14 SW5_CS14
#define E_15 SW5_CS15
#define E_16 SW5_CS16
#define F_1 SW6_CS1
#define F_2 SW6_CS2
#define F_3 SW6_CS3
#define F_4 SW6_CS4
#define F_5 SW6_CS5
#define F_6 SW6_CS6
#define F_7 SW6_CS7
#define F_8 SW6_CS8
#define F_9 SW6_CS9
#define F_10 SW6_CS10
#define F_11 SW6_CS11
#define F_12 SW6_CS12
#define F_13 SW6_CS13
#define F_14 SW6_CS14
#define F_15 SW6_CS15
#define F_16 SW6_CS16
#define G_1 SW7_CS1
#define G_2 SW7_CS2
#define G_3 SW7_CS3
#define G_4 SW7_CS4
#define G_5 SW7_CS5
#define G_6 SW7_CS6
#define G_7 SW7_CS7
#define G_8 SW7_CS8
#define G_9 SW7_CS9
#define G_10 SW7_CS10
#define G_11 SW7_CS11
#define G_12 SW7_CS12
#define G_13 SW7_CS13
#define G_14 SW7_CS14
#define G_15 SW7_CS15
#define G_16 SW7_CS16
#define H_1 SW8_CS1
#define H_2 SW8_CS2
#define H_3 SW8_CS3
#define H_4 SW8_CS4
#define H_5 SW8_CS5
#define H_6 SW8_CS6
#define H_7 SW8_CS7
#define H_8 SW8_CS8
#define H_9 SW8_CS9
#define H_10 SW8_CS10
#define H_11 SW8_CS11
#define H_12 SW8_CS12
#define H_13 SW8_CS13
#define H_14 SW8_CS14
#define H_15 SW8_CS15
#define H_16 SW8_CS16
#define I_1 SW9_CS1
#define I_2 SW9_CS2
#define I_3 SW9_CS3
#define I_4 SW9_CS4
#define I_5 SW9_CS5
#define I_6 SW9_CS6
#define I_7 SW9_CS7
#define I_8 SW9_CS8
#define I_9 SW9_CS9
#define I_10 SW9_CS10
#define I_11 SW9_CS11
#define I_12 SW9_CS12
#define I_13 SW9_CS13
#define I_14 SW9_CS14
#define I_15 SW9_CS15
#define I_16 SW9_CS16
#define J_1 SW10_CS1
#define J_2 SW10_CS2
#define J_3 SW10_CS3
#define J_4 SW10_CS4
#define J_5 SW10_CS5
#define J_6 SW10_CS6
#define J_7 SW10_CS7
#define J_8 SW10_CS8
#define J_9 SW10_CS9
#define J_10 SW10_CS10
#define J_11 SW10_CS11
#define J_12 SW10_CS12
#define J_13 SW10_CS13
#define J_14 SW10_CS14
#define J_15 SW10_CS15
#define J_16 SW10_CS16
#define K_1 SW11_CS1
#define K_2 SW11_CS2
#define K_3 SW11_CS3
#define K_4 SW11_CS4
#define K_5 SW11_CS5
#define K_6 SW11_CS6
#define K_7 SW11_CS7
#define K_8 SW11_CS8
#define K_9 SW11_CS9
#define K_10 SW11_CS10
#define K_11 SW11_CS11
#define K_12 SW11_CS12
#define K_13 SW11_CS13
#define K_14 SW11_CS14
#define K_15 SW11_CS15
#define K_16 SW11_CS16
#define L_1 SW12_CS1
#define L_2 SW12_CS2
#define L_3 SW12_CS3
#define L_4 SW12_CS4
#define L_5 SW12_CS5
#define L_6 SW12_CS6
#define L_7 SW12_CS7
#define L_8 SW12_CS8
#define L_9 SW12_CS9
#define L_10 SW12_CS10
#define L_11 SW12_CS11
#define L_12 SW12_CS12
#define L_13 SW12_CS13
#define L_14 SW12_CS14
#define L_15 SW12_CS15
#define L_16 SW12_CS16

View File

@ -0,0 +1,234 @@
/* Copyright 2018 Jason Williams (Wilba)
* Copyright 2021 Doni Crosby
*
* 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 "is31fl3736-mono.h"
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3736_PWM_REGISTER_COUNT 192 // actually 96
#define IS31FL3736_LED_CONTROL_REGISTER_COUNT 24
#ifndef IS31FL3736_I2C_TIMEOUT
# define IS31FL3736_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3736_I2C_PERSISTENCE
# define IS31FL3736_I2C_PERSISTENCE 0
#endif
#ifndef IS31FL3736_PWM_FREQUENCY
# define IS31FL3736_PWM_FREQUENCY IS31FL3736_PWM_FREQUENCY_8K4_HZ // PFS - IS31FL3736B only
#endif
#ifndef IS31FL3736_SW_PULLUP
# define IS31FL3736_SW_PULLUP IS31FL3736_PUR_0_OHM
#endif
#ifndef IS31FL3736_CS_PULLDOWN
# define IS31FL3736_CS_PULLDOWN IS31FL3736_PDR_0_OHM
#endif
#ifndef IS31FL3736_GLOBAL_CURRENT
# define IS31FL3736_GLOBAL_CURRENT 0xFF
#endif
const uint8_t i2c_addresses[IS31FL3736_DRIVER_COUNT] = {
IS31FL3736_I2C_ADDRESS_1,
#ifdef IS31FL3736_I2C_ADDRESS_2
IS31FL3736_I2C_ADDRESS_2,
# ifdef IS31FL3736_I2C_ADDRESS_3
IS31FL3736_I2C_ADDRESS_3,
# ifdef IS31FL3736_I2C_ADDRESS_4
IS31FL3736_I2C_ADDRESS_4,
# endif
# endif
#endif
};
// These buffers match the IS31FL3736 PWM registers.
// The control buffers match the page 0 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
// probably not worth the extra complexity.
typedef struct is31fl3736_driver_t {
uint8_t pwm_buffer[IS31FL3736_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t led_control_buffer[IS31FL3736_LED_CONTROL_REGISTER_COUNT];
bool led_control_buffer_dirty;
} PACKED is31fl3736_driver_t;
is31fl3736_driver_t driver_buffers[IS31FL3736_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.led_control_buffer = {0},
.led_control_buffer_dirty = false,
}};
void is31fl3736_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3736_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3736_I2C_PERSISTENCE; i++) {
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3736_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3736_I2C_TIMEOUT);
#endif
}
void is31fl3736_select_page(uint8_t index, uint8_t page) {
is31fl3736_write_register(index, IS31FL3736_REG_COMMAND_WRITE_LOCK, IS31FL3736_COMMAND_WRITE_LOCK_MAGIC);
is31fl3736_write_register(index, IS31FL3736_REG_COMMAND, page);
}
void is31fl3736_write_pwm_buffer(uint8_t index) {
// Assumes page 1 is already selected.
// Transmit PWM registers in 12 transfers of 16 bytes.
// Iterate over the pwm_buffer contents at 16 byte intervals.
for (uint8_t i = 0; i < IS31FL3736_PWM_REGISTER_COUNT; i += 16) {
#if IS31FL3736_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < IS31FL3736_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3736_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3736_I2C_TIMEOUT);
#endif
}
}
void is31fl3736_init_drivers(void) {
i2c_init();
for (uint8_t i = 0; i < IS31FL3736_DRIVER_COUNT; i++) {
is31fl3736_init(i);
}
for (int i = 0; i < IS31FL3736_LED_COUNT; i++) {
is31fl3736_set_led_control_register(i, true);
}
for (uint8_t i = 0; i < IS31FL3736_DRIVER_COUNT; i++) {
is31fl3736_update_led_control_registers(i);
}
}
void is31fl3736_init(uint8_t index) {
// 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.
is31fl3736_select_page(index, IS31FL3736_COMMAND_LED_CONTROL);
// Turn off all LEDs.
for (uint8_t i = 0; i < IS31FL3736_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3736_write_register(index, i, 0x00);
}
is31fl3736_select_page(index, IS31FL3736_COMMAND_PWM);
// Set PWM on all LEDs to 0
// No need to setup Breath registers to PWM as that is the default.
for (uint8_t i = 0; i < IS31FL3736_PWM_REGISTER_COUNT; i++) {
is31fl3736_write_register(index, i, 0x00);
}
is31fl3736_select_page(index, IS31FL3736_COMMAND_FUNCTION);
// Set de-ghost pull-up resistors (SWx)
is31fl3736_write_register(index, IS31FL3736_FUNCTION_REG_SW_PULLUP, IS31FL3736_SW_PULLUP);
// Set de-ghost pull-down resistors (CSx)
is31fl3736_write_register(index, IS31FL3736_FUNCTION_REG_CS_PULLDOWN, IS31FL3736_CS_PULLDOWN);
// Set global current to maximum.
is31fl3736_write_register(index, IS31FL3736_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3736_GLOBAL_CURRENT);
// Disable software shutdown.
is31fl3736_write_register(index, IS31FL3736_FUNCTION_REG_CONFIGURATION, ((IS31FL3736_PWM_FREQUENCY & 0b111) << 3) | 0x01);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}
void is31fl3736_set_value(int index, uint8_t value) {
is31fl3736_led_t led;
if (index >= 0 && index < IS31FL3736_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3736_leds[index]), sizeof(led));
if (driver_buffers[led.driver].pwm_buffer[led.v] == value) {
return;
}
driver_buffers[led.driver].pwm_buffer[led.v] = value;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
void is31fl3736_set_value_all(uint8_t value) {
for (int i = 0; i < IS31FL3736_LED_COUNT; i++) {
is31fl3736_set_value(i, value);
}
}
void is31fl3736_set_led_control_register(uint8_t index, bool value) {
is31fl3736_led_t led;
memcpy_P(&led, (&g_is31fl3736_leds[index]), sizeof(led));
// The PWM register for a matrix position (0x00 to 0xBF) is interleaved, so:
// A1=0x00 A2=0x02 A3=0x04 A4=0x06 A5=0x08 A6=0x0A A7=0x0C A8=0x0E
// B1=0x10 B2=0x12 B3=0x14
// But also, the LED control registers (0x00 to 0x17) are also interleaved, so:
// A1-A4=0x00 A5-A8=0x01
uint8_t control_register = led.v / 8;
uint8_t bit_value = led.v % 8;
if (value) {
driver_buffers[led.driver].led_control_buffer[control_register] |= (1 << bit_value);
} else {
driver_buffers[led.driver].led_control_buffer[control_register] &= ~(1 << bit_value);
}
driver_buffers[led.driver].led_control_buffer_dirty = true;
}
void is31fl3736_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3736_select_page(index, IS31FL3736_COMMAND_PWM);
is31fl3736_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void is31fl3736_update_led_control_registers(uint8_t index) {
if (driver_buffers[index].led_control_buffer_dirty) {
is31fl3736_select_page(index, IS31FL3736_COMMAND_LED_CONTROL);
for (uint8_t i = 0; i < IS31FL3736_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3736_write_register(index, i, driver_buffers[index].led_control_buffer[i]);
}
driver_buffers[index].led_control_buffer_dirty = false;
}
}
void is31fl3736_flush(void) {
for (uint8_t i = 0; i < IS31FL3736_DRIVER_COUNT; i++) {
is31fl3736_update_pwm_buffers(i);
}
}

View File

@ -0,0 +1,371 @@
/* Copyright 2018 Jason Williams (Wilba)
* Copyright 2021 Doni Crosby
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
// ======== DEPRECATED DEFINES - DO NOT USE ========
#ifdef ISSI_TIMEOUT
# define IS31FL3736_I2C_TIMEOUT ISSI_TIMEOUT
#endif
#ifdef ISSI_PERSISTENCE
# define IS31FL3736_I2C_PERSISTENCE ISSI_PERSISTENCE
#endif
#ifdef ISSI_SWPULLUP
# define IS31FL3736_SW_PULLUP ISSI_SWPULLUP
#endif
#ifdef ISSI_CSPULLUP
# define IS31FL3736_CS_PULLDOWN ISSI_CSPULLUP
#endif
#ifdef ISSI_GLOBALCURRENT
# define IS31FL3736_GLOBAL_CURRENT ISSI_GLOBALCURRENT
#endif
#define is31_led is31fl3736_led_t
#define g_is31_leds g_is31fl3736_leds
#define PUR_0R IS31FL3736_PUR_0_OHM
#define PUR_05KR IS31FL3736_PUR_05K_OHM
#define PUR_1KR IS31FL3736_PUR_1K_OHM
#define PUR_2KR IS31FL3736_PUR_2K_OHM
#define PUR_4KR IS31FL3736_PUR_4K_OHM
#define PUR_8KR IS31FL3736_PUR_8K_OHM
#define PUR_16KR IS31FL3736_PUR_16K_OHM
#define PUR_32KR IS31FL3736_PUR_32K_OHM
// ========
#define IS31FL3736_REG_INTERRUPT_MASK 0xF0
#define IS31FL3736_REG_INTERRUPT_STATUS 0xF1
#define IS31FL3736_REG_COMMAND 0xFD
#define IS31FL3736_COMMAND_LED_CONTROL 0x00
#define IS31FL3736_COMMAND_PWM 0x01
#define IS31FL3736_COMMAND_AUTO_BREATH 0x02
#define IS31FL3736_COMMAND_FUNCTION 0x03
#define IS31FL3736_FUNCTION_REG_CONFIGURATION 0x00
#define IS31FL3736_FUNCTION_REG_GLOBAL_CURRENT 0x01
#define IS31FL3736_FUNCTION_REG_SW_PULLUP 0x0F
#define IS31FL3736_FUNCTION_REG_CS_PULLDOWN 0x10
#define IS31FL3736_FUNCTION_REG_RESET 0x11
#define IS31FL3736_REG_COMMAND_WRITE_LOCK 0xFE
#define IS31FL3736_COMMAND_WRITE_LOCK_MAGIC 0xC5
#define IS31FL3736_I2C_ADDRESS_GND_GND 0x50
#define IS31FL3736_I2C_ADDRESS_GND_SCL 0x51
#define IS31FL3736_I2C_ADDRESS_GND_SDA 0x52
#define IS31FL3736_I2C_ADDRESS_GND_VCC 0x53
#define IS31FL3736_I2C_ADDRESS_SCL_GND 0x54
#define IS31FL3736_I2C_ADDRESS_SCL_SCL 0x55
#define IS31FL3736_I2C_ADDRESS_SCL_SDA 0x56
#define IS31FL3736_I2C_ADDRESS_SCL_VCC 0x57
#define IS31FL3736_I2C_ADDRESS_SDA_GND 0x58
#define IS31FL3736_I2C_ADDRESS_SDA_SCL 0x59
#define IS31FL3736_I2C_ADDRESS_SDA_SDA 0x5A
#define IS31FL3736_I2C_ADDRESS_SDA_VCC 0x5B
#define IS31FL3736_I2C_ADDRESS_VCC_GND 0x5C
#define IS31FL3736_I2C_ADDRESS_VCC_SCL 0x5D
#define IS31FL3736_I2C_ADDRESS_VCC_SDA 0x5E
#define IS31FL3736_I2C_ADDRESS_VCC_VCC 0x5F
#if defined(LED_MATRIX_IS31FL3736)
# define IS31FL3736_LED_COUNT LED_MATRIX_LED_COUNT
#endif
#if defined(IS31FL3736_I2C_ADDRESS_4)
# define IS31FL3736_DRIVER_COUNT 4
#elif defined(IS31FL3736_I2C_ADDRESS_3)
# define IS31FL3736_DRIVER_COUNT 3
#elif defined(IS31FL3736_I2C_ADDRESS_2)
# define IS31FL3736_DRIVER_COUNT 2
#elif defined(IS31FL3736_I2C_ADDRESS_1)
# define IS31FL3736_DRIVER_COUNT 1
#endif
typedef struct is31fl3736_led_t {
uint8_t driver : 2;
uint8_t v;
} PACKED is31fl3736_led_t;
extern const is31fl3736_led_t PROGMEM g_is31fl3736_leds[IS31FL3736_LED_COUNT];
void is31fl3736_init_drivers(void);
void is31fl3736_init(uint8_t index);
void is31fl3736_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3736_select_page(uint8_t index, uint8_t page);
void is31fl3736_set_value(int index, uint8_t value);
void is31fl3736_set_value_all(uint8_t value);
void is31fl3736_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 is31fl3736_update_pwm_buffers(uint8_t index);
void is31fl3736_update_led_control_registers(uint8_t index);
void is31fl3736_flush(void);
#define IS31FL3736_PDR_0_OHM 0b000 // No pull-down resistor
#define IS31FL3736_PDR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3736_PDR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3736_PDR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3736_PDR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3736_PDR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3736_PDR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3736_PDR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3736_PUR_0_OHM 0b000 // No pull-up resistor
#define IS31FL3736_PUR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3736_PUR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3736_PUR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3736_PUR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3736_PUR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3736_PUR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3736_PUR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3736_PWM_FREQUENCY_8K4_HZ 0b000
#define IS31FL3736_PWM_FREQUENCY_4K2_HZ 0b001
#define IS31FL3736_PWM_FREQUENCY_26K7_HZ 0b010
#define IS31FL3736_PWM_FREQUENCY_2K1_HZ 0b011
#define IS31FL3736_PWM_FREQUENCY_1K05_HZ 0b100
#define SW1_CS1 0x00
#define SW1_CS2 0x02
#define SW1_CS3 0x04
#define SW1_CS4 0x06
#define SW1_CS5 0x08
#define SW1_CS6 0x0A
#define SW1_CS7 0x0C
#define SW1_CS8 0x0E
#define SW2_CS1 0x10
#define SW2_CS2 0x12
#define SW2_CS3 0x14
#define SW2_CS4 0x16
#define SW2_CS5 0x18
#define SW2_CS6 0x1A
#define SW2_CS7 0x1C
#define SW2_CS8 0x1E
#define SW3_CS1 0x20
#define SW3_CS2 0x22
#define SW3_CS3 0x24
#define SW3_CS4 0x26
#define SW3_CS5 0x28
#define SW3_CS6 0x2A
#define SW3_CS7 0x2C
#define SW3_CS8 0x2E
#define SW4_CS1 0x30
#define SW4_CS2 0x32
#define SW4_CS3 0x34
#define SW4_CS4 0x36
#define SW4_CS5 0x38
#define SW4_CS6 0x3A
#define SW4_CS7 0x3C
#define SW4_CS8 0x3E
#define SW5_CS1 0x40
#define SW5_CS2 0x42
#define SW5_CS3 0x44
#define SW5_CS4 0x46
#define SW5_CS5 0x48
#define SW5_CS6 0x4A
#define SW5_CS7 0x4C
#define SW5_CS8 0x4E
#define SW6_CS1 0x50
#define SW6_CS2 0x52
#define SW6_CS3 0x54
#define SW6_CS4 0x56
#define SW6_CS5 0x58
#define SW6_CS6 0x5A
#define SW6_CS7 0x5C
#define SW6_CS8 0x5E
#define SW7_CS1 0x60
#define SW7_CS2 0x62
#define SW7_CS3 0x64
#define SW7_CS4 0x66
#define SW7_CS5 0x68
#define SW7_CS6 0x6A
#define SW7_CS7 0x6C
#define SW7_CS8 0x6E
#define SW8_CS1 0x70
#define SW8_CS2 0x72
#define SW8_CS3 0x74
#define SW8_CS4 0x76
#define SW8_CS5 0x78
#define SW8_CS6 0x7A
#define SW8_CS7 0x7C
#define SW8_CS8 0x7E
#define SW9_CS1 0x80
#define SW9_CS2 0x82
#define SW9_CS3 0x84
#define SW9_CS4 0x86
#define SW9_CS5 0x88
#define SW9_CS6 0x8A
#define SW9_CS7 0x8C
#define SW9_CS8 0x8E
#define SW10_CS1 0x90
#define SW10_CS2 0x92
#define SW10_CS3 0x94
#define SW10_CS4 0x96
#define SW10_CS5 0x98
#define SW10_CS6 0x9A
#define SW10_CS7 0x9C
#define SW10_CS8 0x9E
#define SW11_CS1 0xA0
#define SW11_CS2 0xA2
#define SW11_CS3 0xA4
#define SW11_CS4 0xA6
#define SW11_CS5 0xA8
#define SW11_CS6 0xAA
#define SW11_CS7 0xAC
#define SW11_CS8 0xAE
#define SW12_CS1 0xB0
#define SW12_CS2 0xB2
#define SW12_CS3 0xB4
#define SW12_CS4 0xB6
#define SW12_CS5 0xB8
#define SW12_CS6 0xBA
#define SW12_CS7 0xBC
#define SW12_CS8 0xBE
// DEPRECATED - DO NOT USE
#define A_1 SW1_CS1
#define A_2 SW1_CS2
#define A_3 SW1_CS3
#define A_4 SW1_CS4
#define A_5 SW1_CS5
#define A_6 SW1_CS6
#define A_7 SW1_CS7
#define A_8 SW1_CS8
#define B_1 SW2_CS1
#define B_2 SW2_CS2
#define B_3 SW2_CS3
#define B_4 SW2_CS4
#define B_5 SW2_CS5
#define B_6 SW2_CS6
#define B_7 SW2_CS7
#define B_8 SW2_CS8
#define C_1 SW3_CS1
#define C_2 SW3_CS2
#define C_3 SW3_CS3
#define C_4 SW3_CS4
#define C_5 SW3_CS5
#define C_6 SW3_CS6
#define C_7 SW3_CS7
#define C_8 SW3_CS8
#define D_1 SW4_CS1
#define D_2 SW4_CS2
#define D_3 SW4_CS3
#define D_4 SW4_CS4
#define D_5 SW4_CS5
#define D_6 SW4_CS6
#define D_7 SW4_CS7
#define D_8 SW4_CS8
#define E_1 SW5_CS1
#define E_2 SW5_CS2
#define E_3 SW5_CS3
#define E_4 SW5_CS4
#define E_5 SW5_CS5
#define E_6 SW5_CS6
#define E_7 SW5_CS7
#define E_8 SW5_CS8
#define F_1 SW6_CS1
#define F_2 SW6_CS2
#define F_3 SW6_CS3
#define F_4 SW6_CS4
#define F_5 SW6_CS5
#define F_6 SW6_CS6
#define F_7 SW6_CS7
#define F_8 SW6_CS8
#define G_1 SW7_CS1
#define G_2 SW7_CS2
#define G_3 SW7_CS3
#define G_4 SW7_CS4
#define G_5 SW7_CS5
#define G_6 SW7_CS6
#define G_7 SW7_CS7
#define G_8 SW7_CS8
#define H_1 SW8_CS1
#define H_2 SW8_CS2
#define H_3 SW8_CS3
#define H_4 SW8_CS4
#define H_5 SW8_CS5
#define H_6 SW8_CS6
#define H_7 SW8_CS7
#define H_8 SW8_CS8
#define I_1 SW9_CS1
#define I_2 SW9_CS2
#define I_3 SW9_CS3
#define I_4 SW9_CS4
#define I_5 SW9_CS5
#define I_6 SW9_CS6
#define I_7 SW9_CS7
#define I_8 SW9_CS8
#define J_1 SW10_CS1
#define J_2 SW10_CS2
#define J_3 SW10_CS3
#define J_4 SW10_CS4
#define J_5 SW10_CS5
#define J_6 SW10_CS6
#define J_7 SW10_CS7
#define J_8 SW10_CS8
#define K_1 SW11_CS1
#define K_2 SW11_CS2
#define K_3 SW11_CS3
#define K_4 SW11_CS4
#define K_5 SW11_CS5
#define K_6 SW11_CS6
#define K_7 SW11_CS7
#define K_8 SW11_CS8
#define L_1 SW12_CS1
#define L_2 SW12_CS2
#define L_3 SW12_CS3
#define L_4 SW12_CS4
#define L_5 SW12_CS5
#define L_6 SW12_CS6
#define L_7 SW12_CS7
#define L_8 SW12_CS8

View File

@ -1,244 +0,0 @@
/* Copyright 2018 Jason Williams (Wilba)
* Copyright 2021 Doni Crosby
*
* 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 "is31fl3736-simple.h"
#include <string.h>
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3736_PWM_REGISTER_COUNT 192 // actually 96
#define IS31FL3736_LED_CONTROL_REGISTER_COUNT 24
#ifndef IS31FL3736_I2C_TIMEOUT
# define IS31FL3736_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3736_I2C_PERSISTENCE
# define IS31FL3736_I2C_PERSISTENCE 0
#endif
#ifndef IS31FL3736_PWM_FREQUENCY
# define IS31FL3736_PWM_FREQUENCY IS31FL3736_PWM_FREQUENCY_8K4_HZ // PFS - IS31FL3736B only
#endif
#ifndef IS31FL3736_SW_PULLUP
# define IS31FL3736_SW_PULLUP IS31FL3736_PUR_0_OHM
#endif
#ifndef IS31FL3736_CS_PULLDOWN
# define IS31FL3736_CS_PULLDOWN IS31FL3736_PDR_0_OHM
#endif
#ifndef IS31FL3736_GLOBAL_CURRENT
# define IS31FL3736_GLOBAL_CURRENT 0xFF
#endif
uint8_t i2c_transfer_buffer[20];
// These buffers match the IS31FL3736 PWM registers.
// The control buffers match the page 0 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
// probably not worth the extra complexity.
uint8_t g_pwm_buffer[IS31FL3736_DRIVER_COUNT][IS31FL3736_PWM_REGISTER_COUNT];
bool g_pwm_buffer_update_required[IS31FL3736_DRIVER_COUNT] = {false};
uint8_t g_led_control_registers[IS31FL3736_DRIVER_COUNT][IS31FL3736_LED_CONTROL_REGISTER_COUNT] = {0};
bool g_led_control_registers_update_required[IS31FL3736_DRIVER_COUNT] = {false};
void is31fl3736_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
i2c_transfer_buffer[0] = reg;
i2c_transfer_buffer[1] = data;
#if IS31FL3736_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3736_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3736_I2C_TIMEOUT) == 0) break;
}
#else
i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3736_I2C_TIMEOUT);
#endif
}
void is31fl3736_select_page(uint8_t addr, uint8_t page) {
is31fl3736_write_register(addr, IS31FL3736_REG_COMMAND_WRITE_LOCK, IS31FL3736_COMMAND_WRITE_LOCK_MAGIC);
is31fl3736_write_register(addr, IS31FL3736_REG_COMMAND, page);
}
void is31fl3736_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
// assumes page 1 is already selected
// transmit PWM registers in 12 transfers of 16 bytes
// i2c_transfer_buffer[] is 20 bytes
// iterate over the pwm_buffer contents at 16 byte intervals
for (int i = 0; i < IS31FL3736_PWM_REGISTER_COUNT; i += 16) {
i2c_transfer_buffer[0] = i;
// copy the data from i to i+15
// device will auto-increment register for data after the first byte
// thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer
memcpy(i2c_transfer_buffer + 1, pwm_buffer + i, 16);
#if IS31FL3736_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3736_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3736_I2C_TIMEOUT) == 0) break;
}
#else
i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3736_I2C_TIMEOUT);
#endif
}
}
void is31fl3736_init_drivers(void) {
i2c_init();
is31fl3736_init(IS31FL3736_I2C_ADDRESS_1);
#if defined(IS31FL3736_I2C_ADDRESS_2)
is31fl3736_init(IS31FL3736_I2C_ADDRESS_2);
# if defined(IS31FL3736_I2C_ADDRESS_3)
is31fl3736_init(IS31FL3736_I2C_ADDRESS_3);
# if defined(IS31FL3736_I2C_ADDRESS_4)
is31fl3736_init(IS31FL3736_I2C_ADDRESS_4);
# endif
# endif
#endif
for (int i = 0; i < IS31FL3736_LED_COUNT; i++) {
is31fl3736_set_led_control_register(i, true);
}
is31fl3736_update_led_control_registers(IS31FL3736_I2C_ADDRESS_1, 0);
#if defined(IS31FL3736_I2C_ADDRESS_2)
is31fl3736_update_led_control_registers(IS31FL3736_I2C_ADDRESS_2, 1);
# if defined(IS31FL3736_I2C_ADDRESS_3)
is31fl3736_update_led_control_registers(IS31FL3736_I2C_ADDRESS_3, 2);
# if defined(IS31FL3736_I2C_ADDRESS_4)
is31fl3736_update_led_control_registers(IS31FL3736_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
}
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.
is31fl3736_select_page(addr, IS31FL3736_COMMAND_LED_CONTROL);
// Turn off all LEDs.
for (int i = 0; i < IS31FL3736_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3736_write_register(addr, i, 0x00);
}
is31fl3736_select_page(addr, IS31FL3736_COMMAND_PWM);
// Set PWM on all LEDs to 0
// No need to setup Breath registers to PWM as that is the default.
for (int i = 0; i < IS31FL3736_PWM_REGISTER_COUNT; i++) {
is31fl3736_write_register(addr, i, 0x00);
}
is31fl3736_select_page(addr, IS31FL3736_COMMAND_FUNCTION);
// Set de-ghost pull-up resistors (SWx)
is31fl3736_write_register(addr, IS31FL3736_FUNCTION_REG_SW_PULLUP, IS31FL3736_SW_PULLUP);
// Set de-ghost pull-down resistors (CSx)
is31fl3736_write_register(addr, IS31FL3736_FUNCTION_REG_CS_PULLDOWN, IS31FL3736_CS_PULLDOWN);
// Set global current to maximum.
is31fl3736_write_register(addr, IS31FL3736_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3736_GLOBAL_CURRENT);
// Disable software shutdown.
is31fl3736_write_register(addr, IS31FL3736_FUNCTION_REG_CONFIGURATION, ((IS31FL3736_PWM_FREQUENCY & 0b111) << 3) | 0x01);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}
void is31fl3736_set_value(int index, uint8_t value) {
is31fl3736_led_t led;
if (index >= 0 && index < IS31FL3736_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3736_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 is31fl3736_set_value_all(uint8_t value) {
for (int i = 0; i < IS31FL3736_LED_COUNT; i++) {
is31fl3736_set_value(i, value);
}
}
void is31fl3736_set_led_control_register(uint8_t index, bool value) {
is31fl3736_led_t led;
memcpy_P(&led, (&g_is31fl3736_leds[index]), sizeof(led));
// The PWM register for a matrix position (0x00 to 0xBF) is interleaved, so:
// A1=0x00 A2=0x02 A3=0x04 A4=0x06 A5=0x08 A6=0x0A A7=0x0C A8=0x0E
// B1=0x10 B2=0x12 B3=0x14
// But also, the LED control registers (0x00 to 0x17) are also interleaved, so:
// A1-A4=0x00 A5-A8=0x01
uint8_t control_register = led.v / 8;
uint8_t bit_value = led.v % 8;
if (value) {
g_led_control_registers[led.driver][control_register] |= (1 << bit_value);
} else {
g_led_control_registers[led.driver][control_register] &= ~(1 << bit_value);
}
g_led_control_registers_update_required[led.driver] = true;
}
void is31fl3736_update_pwm_buffers(uint8_t addr, uint8_t index) {
if (g_pwm_buffer_update_required[index]) {
is31fl3736_select_page(addr, IS31FL3736_COMMAND_PWM);
is31fl3736_write_pwm_buffer(addr, g_pwm_buffer[index]);
g_pwm_buffer_update_required[index] = false;
}
}
void is31fl3736_update_led_control_registers(uint8_t addr, uint8_t index) {
if (g_led_control_registers_update_required[index]) {
is31fl3736_select_page(addr, IS31FL3736_COMMAND_LED_CONTROL);
for (int i = 0; i < IS31FL3736_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3736_write_register(addr, i, g_led_control_registers[index][i]);
}
g_led_control_registers_update_required[index] = false;
}
}
void is31fl3736_flush(void) {
is31fl3736_update_pwm_buffers(IS31FL3736_I2C_ADDRESS_1, 0);
#if defined(IS31FL3736_I2C_ADDRESS_2)
is31fl3736_update_pwm_buffers(IS31FL3736_I2C_ADDRESS_2, 1);
# if defined(IS31FL3736_I2C_ADDRESS_3)
is31fl3736_update_pwm_buffers(IS31FL3736_I2C_ADDRESS_3, 2);
# if defined(IS31FL3736_I2C_ADDRESS_4)
is31fl3736_update_pwm_buffers(IS31FL3736_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
}

View File

@ -1,262 +0,0 @@
/* Copyright 2018 Jason Williams (Wilba)
* Copyright 2021 Doni Crosby
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
// ======== DEPRECATED DEFINES - DO NOT USE ========
#ifdef ISSI_TIMEOUT
# define IS31FL3736_I2C_TIMEOUT ISSI_TIMEOUT
#endif
#ifdef ISSI_PERSISTENCE
# define IS31FL3736_I2C_PERSISTENCE ISSI_PERSISTENCE
#endif
#ifdef ISSI_SWPULLUP
# define IS31FL3736_SW_PULLUP ISSI_SWPULLUP
#endif
#ifdef ISSI_CSPULLUP
# define IS31FL3736_CS_PULLDOWN ISSI_CSPULLUP
#endif
#ifdef ISSI_GLOBALCURRENT
# define IS31FL3736_GLOBAL_CURRENT ISSI_GLOBALCURRENT
#endif
#define is31_led is31fl3736_led_t
#define g_is31_leds g_is31fl3736_leds
#define PUR_0R IS31FL3736_PUR_0_OHM
#define PUR_05KR IS31FL3736_PUR_05K_OHM
#define PUR_1KR IS31FL3736_PUR_1K_OHM
#define PUR_2KR IS31FL3736_PUR_2K_OHM
#define PUR_4KR IS31FL3736_PUR_4K_OHM
#define PUR_8KR IS31FL3736_PUR_8K_OHM
#define PUR_16KR IS31FL3736_PUR_16K_OHM
#define PUR_32KR IS31FL3736_PUR_32K_OHM
// ========
#define IS31FL3736_REG_INTERRUPT_MASK 0xF0
#define IS31FL3736_REG_INTERRUPT_STATUS 0xF1
#define IS31FL3736_REG_COMMAND 0xFD
#define IS31FL3736_COMMAND_LED_CONTROL 0x00
#define IS31FL3736_COMMAND_PWM 0x01
#define IS31FL3736_COMMAND_AUTO_BREATH 0x02
#define IS31FL3736_COMMAND_FUNCTION 0x03
#define IS31FL3736_FUNCTION_REG_CONFIGURATION 0x00
#define IS31FL3736_FUNCTION_REG_GLOBAL_CURRENT 0x01
#define IS31FL3736_FUNCTION_REG_SW_PULLUP 0x0F
#define IS31FL3736_FUNCTION_REG_CS_PULLDOWN 0x10
#define IS31FL3736_FUNCTION_REG_RESET 0x11
#define IS31FL3736_REG_COMMAND_WRITE_LOCK 0xFE
#define IS31FL3736_COMMAND_WRITE_LOCK_MAGIC 0xC5
#define IS31FL3736_I2C_ADDRESS_GND_GND 0x50
#define IS31FL3736_I2C_ADDRESS_GND_SCL 0x51
#define IS31FL3736_I2C_ADDRESS_GND_SDA 0x52
#define IS31FL3736_I2C_ADDRESS_GND_VCC 0x53
#define IS31FL3736_I2C_ADDRESS_SCL_GND 0x54
#define IS31FL3736_I2C_ADDRESS_SCL_SCL 0x55
#define IS31FL3736_I2C_ADDRESS_SCL_SDA 0x56
#define IS31FL3736_I2C_ADDRESS_SCL_VCC 0x57
#define IS31FL3736_I2C_ADDRESS_SDA_GND 0x58
#define IS31FL3736_I2C_ADDRESS_SDA_SCL 0x59
#define IS31FL3736_I2C_ADDRESS_SDA_SDA 0x5A
#define IS31FL3736_I2C_ADDRESS_SDA_VCC 0x5B
#define IS31FL3736_I2C_ADDRESS_VCC_GND 0x5C
#define IS31FL3736_I2C_ADDRESS_VCC_SCL 0x5D
#define IS31FL3736_I2C_ADDRESS_VCC_SDA 0x5E
#define IS31FL3736_I2C_ADDRESS_VCC_VCC 0x5F
#if defined(LED_MATRIX_IS31FL3736)
# define IS31FL3736_LED_COUNT LED_MATRIX_LED_COUNT
#endif
#if defined(IS31FL3736_I2C_ADDRESS_4)
# define IS31FL3736_DRIVER_COUNT 4
#elif defined(IS31FL3736_I2C_ADDRESS_3)
# define IS31FL3736_DRIVER_COUNT 3
#elif defined(IS31FL3736_I2C_ADDRESS_2)
# define IS31FL3736_DRIVER_COUNT 2
#elif defined(IS31FL3736_I2C_ADDRESS_1)
# define IS31FL3736_DRIVER_COUNT 1
#endif
typedef struct is31fl3736_led_t {
uint8_t driver : 2;
uint8_t v;
} PACKED is31fl3736_led_t;
extern const is31fl3736_led_t PROGMEM g_is31fl3736_leds[IS31FL3736_LED_COUNT];
void is31fl3736_init_drivers(void);
void is31fl3736_init(uint8_t addr);
void is31fl3736_write_register(uint8_t addr, uint8_t reg, uint8_t data);
void is31fl3736_select_page(uint8_t addr, uint8_t page);
void is31fl3736_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
void is31fl3736_set_value(int index, uint8_t value);
void is31fl3736_set_value_all(uint8_t value);
void is31fl3736_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 is31fl3736_update_pwm_buffers(uint8_t addr, uint8_t index);
void is31fl3736_update_led_control_registers(uint8_t addr, uint8_t index);
void is31fl3736_flush(void);
#define IS31FL3736_PDR_0_OHM 0b000 // No pull-down resistor
#define IS31FL3736_PDR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3736_PDR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3736_PDR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3736_PDR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3736_PDR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3736_PDR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3736_PDR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3736_PUR_0_OHM 0b000 // No pull-up resistor
#define IS31FL3736_PUR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3736_PUR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3736_PUR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3736_PUR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3736_PUR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3736_PUR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3736_PUR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3736_PWM_FREQUENCY_8K4_HZ 0b000
#define IS31FL3736_PWM_FREQUENCY_4K2_HZ 0b001
#define IS31FL3736_PWM_FREQUENCY_26K7_HZ 0b010
#define IS31FL3736_PWM_FREQUENCY_2K1_HZ 0b011
#define IS31FL3736_PWM_FREQUENCY_1K05_HZ 0b100
#define A_1 0x00
#define A_2 0x02
#define A_3 0x04
#define A_4 0x06
#define A_5 0x08
#define A_6 0x0A
#define A_7 0x0C
#define A_8 0x0E
#define B_1 0x10
#define B_2 0x12
#define B_3 0x14
#define B_4 0x16
#define B_5 0x18
#define B_6 0x1A
#define B_7 0x1C
#define B_8 0x1E
#define C_1 0x20
#define C_2 0x22
#define C_3 0x24
#define C_4 0x26
#define C_5 0x28
#define C_6 0x2A
#define C_7 0x2C
#define C_8 0x2E
#define D_1 0x30
#define D_2 0x32
#define D_3 0x34
#define D_4 0x36
#define D_5 0x38
#define D_6 0x3A
#define D_7 0x3C
#define D_8 0x3E
#define E_1 0x40
#define E_2 0x42
#define E_3 0x44
#define E_4 0x46
#define E_5 0x48
#define E_6 0x4A
#define E_7 0x4C
#define E_8 0x4E
#define F_1 0x50
#define F_2 0x52
#define F_3 0x54
#define F_4 0x56
#define F_5 0x58
#define F_6 0x5A
#define F_7 0x5C
#define F_8 0x5E
#define G_1 0x60
#define G_2 0x62
#define G_3 0x64
#define G_4 0x66
#define G_5 0x68
#define G_6 0x6A
#define G_7 0x6C
#define G_8 0x6E
#define H_1 0x70
#define H_2 0x72
#define H_3 0x74
#define H_4 0x76
#define H_5 0x78
#define H_6 0x7A
#define H_7 0x7C
#define H_8 0x7E
#define I_1 0x80
#define I_2 0x82
#define I_3 0x84
#define I_4 0x86
#define I_5 0x88
#define I_6 0x8A
#define I_7 0x8C
#define I_8 0x8E
#define J_1 0x90
#define J_2 0x92
#define J_3 0x94
#define J_4 0x96
#define J_5 0x98
#define J_6 0x9A
#define J_7 0x9C
#define J_8 0x9E
#define K_1 0xA0
#define K_2 0xA2
#define K_3 0xA4
#define K_4 0xA6
#define K_5 0xA8
#define K_6 0xAA
#define K_7 0xAC
#define K_8 0xAE
#define L_1 0xB0
#define L_2 0xB2
#define L_3 0xB4
#define L_4 0xB6
#define L_5 0xB8
#define L_6 0xBA
#define L_7 0xBC
#define L_8 0xBE

View File

@ -16,7 +16,6 @@
*/
#include "is31fl3736.h"
#include <string.h>
#include "i2c_master.h"
#include "wait.h"
@ -47,7 +46,18 @@
# define IS31FL3736_GLOBAL_CURRENT 0xFF
#endif
uint8_t i2c_transfer_buffer[20];
const uint8_t i2c_addresses[IS31FL3736_DRIVER_COUNT] = {
IS31FL3736_I2C_ADDRESS_1,
#ifdef IS31FL3736_I2C_ADDRESS_2
IS31FL3736_I2C_ADDRESS_2,
# ifdef IS31FL3736_I2C_ADDRESS_3
IS31FL3736_I2C_ADDRESS_3,
# ifdef IS31FL3736_I2C_ADDRESS_4
IS31FL3736_I2C_ADDRESS_4,
# endif
# endif
#endif
};
// These buffers match the IS31FL3736 PWM registers.
// The control buffers match the page 0 LED On/Off registers.
@ -55,50 +65,47 @@ uint8_t i2c_transfer_buffer[20];
// We could optimize this and take out the unused registers from these
// buffers and the transfers in is31fl3736_write_pwm_buffer() but it's
// probably not worth the extra complexity.
uint8_t g_pwm_buffer[IS31FL3736_DRIVER_COUNT][IS31FL3736_PWM_REGISTER_COUNT];
bool g_pwm_buffer_update_required[IS31FL3736_DRIVER_COUNT] = {false};
typedef struct is31fl3736_driver_t {
uint8_t pwm_buffer[IS31FL3736_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t led_control_buffer[IS31FL3736_LED_CONTROL_REGISTER_COUNT];
bool led_control_buffer_dirty;
} PACKED is31fl3736_driver_t;
uint8_t g_led_control_registers[IS31FL3736_DRIVER_COUNT][IS31FL3736_LED_CONTROL_REGISTER_COUNT] = {0};
bool g_led_control_registers_update_required[IS31FL3736_DRIVER_COUNT] = {false};
void is31fl3736_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
i2c_transfer_buffer[0] = reg;
i2c_transfer_buffer[1] = data;
is31fl3736_driver_t driver_buffers[IS31FL3736_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.led_control_buffer = {0},
.led_control_buffer_dirty = false,
}};
void is31fl3736_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3736_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3736_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3736_I2C_TIMEOUT) == 0) break;
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3736_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3736_I2C_TIMEOUT);
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3736_I2C_TIMEOUT);
#endif
}
void is31fl3736_select_page(uint8_t addr, uint8_t page) {
is31fl3736_write_register(addr, IS31FL3736_REG_COMMAND_WRITE_LOCK, IS31FL3736_COMMAND_WRITE_LOCK_MAGIC);
is31fl3736_write_register(addr, IS31FL3736_REG_COMMAND, page);
void is31fl3736_select_page(uint8_t index, uint8_t page) {
is31fl3736_write_register(index, IS31FL3736_REG_COMMAND_WRITE_LOCK, IS31FL3736_COMMAND_WRITE_LOCK_MAGIC);
is31fl3736_write_register(index, IS31FL3736_REG_COMMAND, page);
}
void is31fl3736_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
// assumes page 1 is already selected
// transmit PWM registers in 12 transfers of 16 bytes
// i2c_transfer_buffer[] is 20 bytes
// iterate over the pwm_buffer contents at 16 byte intervals
for (int i = 0; i < IS31FL3736_PWM_REGISTER_COUNT; i += 16) {
i2c_transfer_buffer[0] = i;
// copy the data from i to i+15
// device will auto-increment register for data after the first byte
// thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer
memcpy(i2c_transfer_buffer + 1, pwm_buffer + i, 16);
void is31fl3736_write_pwm_buffer(uint8_t index) {
// Assumes page 1 is already selected.
// Transmit PWM registers in 12 transfers of 16 bytes.
// Iterate over the pwm_buffer contents at 16 byte intervals.
for (uint8_t i = 0; i < IS31FL3736_PWM_REGISTER_COUNT; i += 16) {
#if IS31FL3736_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3736_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3736_I2C_TIMEOUT) == 0) break;
for (uint8_t j = 0; j < IS31FL3736_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3736_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3736_I2C_TIMEOUT);
i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3736_I2C_TIMEOUT);
#endif
}
}
@ -106,64 +113,50 @@ void is31fl3736_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
void is31fl3736_init_drivers(void) {
i2c_init();
is31fl3736_init(IS31FL3736_I2C_ADDRESS_1);
#if defined(IS31FL3736_I2C_ADDRESS_2)
is31fl3736_init(IS31FL3736_I2C_ADDRESS_2);
# if defined(IS31FL3736_I2C_ADDRESS_3)
is31fl3736_init(IS31FL3736_I2C_ADDRESS_3);
# if defined(IS31FL3736_I2C_ADDRESS_4)
is31fl3736_init(IS31FL3736_I2C_ADDRESS_4);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3736_DRIVER_COUNT; i++) {
is31fl3736_init(i);
}
for (int i = 0; i < IS31FL3736_LED_COUNT; i++) {
is31fl3736_set_led_control_register(i, true, true, true);
}
is31fl3736_update_led_control_registers(IS31FL3736_I2C_ADDRESS_1, 0);
#if defined(IS31FL3736_I2C_ADDRESS_2)
is31fl3736_update_led_control_registers(IS31FL3736_I2C_ADDRESS_2, 1);
# if defined(IS31FL3736_I2C_ADDRESS_3)
is31fl3736_update_led_control_registers(IS31FL3736_I2C_ADDRESS_3, 2);
# if defined(IS31FL3736_I2C_ADDRESS_4)
is31fl3736_update_led_control_registers(IS31FL3736_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3736_DRIVER_COUNT; i++) {
is31fl3736_update_led_control_registers(i);
}
}
void is31fl3736_init(uint8_t addr) {
void is31fl3736_init(uint8_t index) {
// 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.
is31fl3736_select_page(addr, IS31FL3736_COMMAND_LED_CONTROL);
is31fl3736_select_page(index, IS31FL3736_COMMAND_LED_CONTROL);
// Turn off all LEDs.
for (int i = 0; i < IS31FL3736_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3736_write_register(addr, i, 0x00);
for (uint8_t i = 0; i < IS31FL3736_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3736_write_register(index, i, 0x00);
}
is31fl3736_select_page(addr, IS31FL3736_COMMAND_PWM);
is31fl3736_select_page(index, IS31FL3736_COMMAND_PWM);
// Set PWM on all LEDs to 0
// No need to setup Breath registers to PWM as that is the default.
for (int i = 0; i < IS31FL3736_PWM_REGISTER_COUNT; i++) {
is31fl3736_write_register(addr, i, 0x00);
for (uint8_t i = 0; i < IS31FL3736_PWM_REGISTER_COUNT; i++) {
is31fl3736_write_register(index, i, 0x00);
}
is31fl3736_select_page(addr, IS31FL3736_COMMAND_FUNCTION);
is31fl3736_select_page(index, IS31FL3736_COMMAND_FUNCTION);
// Set de-ghost pull-up resistors (SWx)
is31fl3736_write_register(addr, IS31FL3736_FUNCTION_REG_SW_PULLUP, IS31FL3736_SW_PULLUP);
is31fl3736_write_register(index, IS31FL3736_FUNCTION_REG_SW_PULLUP, IS31FL3736_SW_PULLUP);
// Set de-ghost pull-down resistors (CSx)
is31fl3736_write_register(addr, IS31FL3736_FUNCTION_REG_CS_PULLDOWN, IS31FL3736_CS_PULLDOWN);
is31fl3736_write_register(index, IS31FL3736_FUNCTION_REG_CS_PULLDOWN, IS31FL3736_CS_PULLDOWN);
// Set global current to maximum.
is31fl3736_write_register(addr, IS31FL3736_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3736_GLOBAL_CURRENT);
is31fl3736_write_register(index, IS31FL3736_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3736_GLOBAL_CURRENT);
// Disable software shutdown.
is31fl3736_write_register(addr, IS31FL3736_FUNCTION_REG_CONFIGURATION, ((IS31FL3736_PWM_FREQUENCY & 0b111) << 3) | 0x01);
is31fl3736_write_register(index, IS31FL3736_FUNCTION_REG_CONFIGURATION, ((IS31FL3736_PWM_FREQUENCY & 0b111) << 3) | 0x01);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
@ -171,16 +164,18 @@ void is31fl3736_init(uint8_t addr) {
void is31fl3736_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
is31fl3736_led_t led;
if (index >= 0 && index < IS31FL3736_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3736_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) {
if (driver_buffers[led.driver].pwm_buffer[led.r] == red && driver_buffers[led.driver].pwm_buffer[led.g] == green && driver_buffers[led.driver].pwm_buffer[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;
driver_buffers[led.driver].pwm_buffer[led.r] = red;
driver_buffers[led.driver].pwm_buffer[led.g] = green;
driver_buffers[led.driver].pwm_buffer[led.b] = blue;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
@ -209,53 +204,48 @@ void is31fl3736_set_led_control_register(uint8_t index, bool red, bool green, bo
uint8_t bit_b = led.b % 8;
if (red) {
g_led_control_registers[led.driver][control_register_r] |= (1 << bit_r);
driver_buffers[led.driver].led_control_buffer[control_register_r] |= (1 << bit_r);
} else {
g_led_control_registers[led.driver][control_register_r] &= ~(1 << bit_r);
driver_buffers[led.driver].led_control_buffer[control_register_r] &= ~(1 << bit_r);
}
if (green) {
g_led_control_registers[led.driver][control_register_g] |= (1 << bit_g);
driver_buffers[led.driver].led_control_buffer[control_register_g] |= (1 << bit_g);
} else {
g_led_control_registers[led.driver][control_register_g] &= ~(1 << bit_g);
driver_buffers[led.driver].led_control_buffer[control_register_g] &= ~(1 << bit_g);
}
if (blue) {
g_led_control_registers[led.driver][control_register_b] |= (1 << bit_b);
driver_buffers[led.driver].led_control_buffer[control_register_b] |= (1 << bit_b);
} else {
g_led_control_registers[led.driver][control_register_b] &= ~(1 << bit_b);
driver_buffers[led.driver].led_control_buffer[control_register_b] &= ~(1 << bit_b);
}
g_led_control_registers_update_required[led.driver] = true;
driver_buffers[led.driver].led_control_buffer_dirty = true;
}
void is31fl3736_update_pwm_buffers(uint8_t addr, uint8_t index) {
if (g_pwm_buffer_update_required[index]) {
is31fl3736_select_page(addr, IS31FL3736_COMMAND_PWM);
void is31fl3736_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3736_select_page(index, IS31FL3736_COMMAND_PWM);
is31fl3736_write_pwm_buffer(addr, g_pwm_buffer[index]);
g_pwm_buffer_update_required[index] = false;
is31fl3736_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void is31fl3736_update_led_control_registers(uint8_t addr, uint8_t index) {
if (g_led_control_registers_update_required[index]) {
is31fl3736_select_page(addr, IS31FL3736_COMMAND_LED_CONTROL);
void is31fl3736_update_led_control_registers(uint8_t index) {
if (driver_buffers[index].led_control_buffer_dirty) {
is31fl3736_select_page(index, IS31FL3736_COMMAND_LED_CONTROL);
for (int i = 0; i < IS31FL3736_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3736_write_register(addr, i, g_led_control_registers[index][i]);
for (uint8_t i = 0; i < IS31FL3736_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3736_write_register(index, i, driver_buffers[index].led_control_buffer[i]);
}
g_led_control_registers_update_required[index] = false;
driver_buffers[index].led_control_buffer_dirty = false;
}
}
void is31fl3736_flush(void) {
is31fl3736_update_pwm_buffers(IS31FL3736_I2C_ADDRESS_1, 0);
#if defined(IS31FL3736_I2C_ADDRESS_2)
is31fl3736_update_pwm_buffers(IS31FL3736_I2C_ADDRESS_2, 1);
# if defined(IS31FL3736_I2C_ADDRESS_3)
is31fl3736_update_pwm_buffers(IS31FL3736_I2C_ADDRESS_3, 2);
# if defined(IS31FL3736_I2C_ADDRESS_4)
is31fl3736_update_pwm_buffers(IS31FL3736_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3736_DRIVER_COUNT; i++) {
is31fl3736_update_pwm_buffers(i);
}
}

View File

@ -124,10 +124,9 @@ typedef struct is31fl3736_led_t {
extern const is31fl3736_led_t PROGMEM g_is31fl3736_leds[IS31FL3736_LED_COUNT];
void is31fl3736_init_drivers(void);
void is31fl3736_init(uint8_t addr);
void is31fl3736_write_register(uint8_t addr, uint8_t reg, uint8_t data);
void is31fl3736_select_page(uint8_t addr, uint8_t page);
void is31fl3736_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
void is31fl3736_init(uint8_t index);
void is31fl3736_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3736_select_page(uint8_t index, uint8_t page);
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);
@ -138,8 +137,8 @@ void is31fl3736_set_led_control_register(uint8_t index, bool red, bool green, bo
// (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 index);
void is31fl3736_update_led_control_registers(uint8_t index);
void is31fl3736_flush(void);
@ -167,110 +166,110 @@ void is31fl3736_flush(void);
#define IS31FL3736_PWM_FREQUENCY_2K1_HZ 0b011
#define IS31FL3736_PWM_FREQUENCY_1K05_HZ 0b100
#define A_1 0x00
#define A_2 0x02
#define A_3 0x04
#define A_4 0x06
#define A_5 0x08
#define A_6 0x0A
#define A_7 0x0C
#define A_8 0x0E
#define SW1_CS1 0x00
#define SW1_CS2 0x02
#define SW1_CS3 0x04
#define SW1_CS4 0x06
#define SW1_CS5 0x08
#define SW1_CS6 0x0A
#define SW1_CS7 0x0C
#define SW1_CS8 0x0E
#define B_1 0x10
#define B_2 0x12
#define B_3 0x14
#define B_4 0x16
#define B_5 0x18
#define B_6 0x1A
#define B_7 0x1C
#define B_8 0x1E
#define SW2_CS1 0x10
#define SW2_CS2 0x12
#define SW2_CS3 0x14
#define SW2_CS4 0x16
#define SW2_CS5 0x18
#define SW2_CS6 0x1A
#define SW2_CS7 0x1C
#define SW2_CS8 0x1E
#define C_1 0x20
#define C_2 0x22
#define C_3 0x24
#define C_4 0x26
#define C_5 0x28
#define C_6 0x2A
#define C_7 0x2C
#define C_8 0x2E
#define SW3_CS1 0x20
#define SW3_CS2 0x22
#define SW3_CS3 0x24
#define SW3_CS4 0x26
#define SW3_CS5 0x28
#define SW3_CS6 0x2A
#define SW3_CS7 0x2C
#define SW3_CS8 0x2E
#define D_1 0x30
#define D_2 0x32
#define D_3 0x34
#define D_4 0x36
#define D_5 0x38
#define D_6 0x3A
#define D_7 0x3C
#define D_8 0x3E
#define SW4_CS1 0x30
#define SW4_CS2 0x32
#define SW4_CS3 0x34
#define SW4_CS4 0x36
#define SW4_CS5 0x38
#define SW4_CS6 0x3A
#define SW4_CS7 0x3C
#define SW4_CS8 0x3E
#define E_1 0x40
#define E_2 0x42
#define E_3 0x44
#define E_4 0x46
#define E_5 0x48
#define E_6 0x4A
#define E_7 0x4C
#define E_8 0x4E
#define SW5_CS1 0x40
#define SW5_CS2 0x42
#define SW5_CS3 0x44
#define SW5_CS4 0x46
#define SW5_CS5 0x48
#define SW5_CS6 0x4A
#define SW5_CS7 0x4C
#define SW5_CS8 0x4E
#define F_1 0x50
#define F_2 0x52
#define F_3 0x54
#define F_4 0x56
#define F_5 0x58
#define F_6 0x5A
#define F_7 0x5C
#define F_8 0x5E
#define SW6_CS1 0x50
#define SW6_CS2 0x52
#define SW6_CS3 0x54
#define SW6_CS4 0x56
#define SW6_CS5 0x58
#define SW6_CS6 0x5A
#define SW6_CS7 0x5C
#define SW6_CS8 0x5E
#define G_1 0x60
#define G_2 0x62
#define G_3 0x64
#define G_4 0x66
#define G_5 0x68
#define G_6 0x6A
#define G_7 0x6C
#define G_8 0x6E
#define SW7_CS1 0x60
#define SW7_CS2 0x62
#define SW7_CS3 0x64
#define SW7_CS4 0x66
#define SW7_CS5 0x68
#define SW7_CS6 0x6A
#define SW7_CS7 0x6C
#define SW7_CS8 0x6E
#define H_1 0x70
#define H_2 0x72
#define H_3 0x74
#define H_4 0x76
#define H_5 0x78
#define H_6 0x7A
#define H_7 0x7C
#define H_8 0x7E
#define SW8_CS1 0x70
#define SW8_CS2 0x72
#define SW8_CS3 0x74
#define SW8_CS4 0x76
#define SW8_CS5 0x78
#define SW8_CS6 0x7A
#define SW8_CS7 0x7C
#define SW8_CS8 0x7E
#define I_1 0x80
#define I_2 0x82
#define I_3 0x84
#define I_4 0x86
#define I_5 0x88
#define I_6 0x8A
#define I_7 0x8C
#define I_8 0x8E
#define SW9_CS1 0x80
#define SW9_CS2 0x82
#define SW9_CS3 0x84
#define SW9_CS4 0x86
#define SW9_CS5 0x88
#define SW9_CS6 0x8A
#define SW9_CS7 0x8C
#define SW9_CS8 0x8E
#define J_1 0x90
#define J_2 0x92
#define J_3 0x94
#define J_4 0x96
#define J_5 0x98
#define J_6 0x9A
#define J_7 0x9C
#define J_8 0x9E
#define SW10_CS1 0x90
#define SW10_CS2 0x92
#define SW10_CS3 0x94
#define SW10_CS4 0x96
#define SW10_CS5 0x98
#define SW10_CS6 0x9A
#define SW10_CS7 0x9C
#define SW10_CS8 0x9E
#define K_1 0xA0
#define K_2 0xA2
#define K_3 0xA4
#define K_4 0xA6
#define K_5 0xA8
#define K_6 0xAA
#define K_7 0xAC
#define K_8 0xAE
#define SW11_CS1 0xA0
#define SW11_CS2 0xA2
#define SW11_CS3 0xA4
#define SW11_CS4 0xA6
#define SW11_CS5 0xA8
#define SW11_CS6 0xAA
#define SW11_CS7 0xAC
#define SW11_CS8 0xAE
#define L_1 0xB0
#define L_2 0xB2
#define L_3 0xB4
#define L_4 0xB6
#define L_5 0xB8
#define L_6 0xBA
#define L_7 0xBC
#define L_8 0xBE
#define SW12_CS1 0xB0
#define SW12_CS2 0xB2
#define SW12_CS3 0xB4
#define SW12_CS4 0xB6
#define SW12_CS5 0xB8
#define SW12_CS6 0xBA
#define SW12_CS7 0xBC
#define SW12_CS8 0xBE

View File

@ -0,0 +1,230 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2021 Doni Crosby
*
* 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 "is31fl3737-mono.h"
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3737_PWM_REGISTER_COUNT 192 // actually 144
#define IS31FL3737_LED_CONTROL_REGISTER_COUNT 24
#ifndef IS31FL3737_I2C_TIMEOUT
# define IS31FL3737_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3737_I2C_PERSISTENCE
# define IS31FL3737_I2C_PERSISTENCE 0
#endif
#ifndef IS31FL3737_PWM_FREQUENCY
# define IS31FL3737_PWM_FREQUENCY IS31FL3737_PWM_FREQUENCY_8K4_HZ // PFS - IS31FL3737B only
#endif
#ifndef IS31FL3737_SW_PULLUP
# define IS31FL3737_SW_PULLUP IS31FL3737_PUR_0_OHM
#endif
#ifndef IS31FL3737_CS_PULLDOWN
# define IS31FL3737_CS_PULLDOWN IS31FL3737_PDR_0_OHM
#endif
#ifndef IS31FL3737_GLOBAL_CURRENT
# define IS31FL3737_GLOBAL_CURRENT 0xFF
#endif
const uint8_t i2c_addresses[IS31FL3737_DRIVER_COUNT] = {
IS31FL3737_I2C_ADDRESS_1,
#ifdef IS31FL3737_I2C_ADDRESS_2
IS31FL3737_I2C_ADDRESS_2,
# ifdef IS31FL3737_I2C_ADDRESS_3
IS31FL3737_I2C_ADDRESS_3,
# ifdef IS31FL3737_I2C_ADDRESS_4
IS31FL3737_I2C_ADDRESS_4,
# endif
# endif
#endif
};
// These buffers match the IS31FL3737 PWM registers.
// The control buffers match the page 0 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
// probably not worth the extra complexity.
typedef struct is31fl3737_driver_t {
uint8_t pwm_buffer[IS31FL3737_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t led_control_buffer[IS31FL3737_LED_CONTROL_REGISTER_COUNT];
bool led_control_buffer_dirty;
} PACKED is31fl3737_driver_t;
is31fl3737_driver_t driver_buffers[IS31FL3737_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.led_control_buffer = {0},
.led_control_buffer_dirty = false,
}};
void is31fl3737_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3737_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3737_I2C_PERSISTENCE; i++) {
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3737_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3737_I2C_TIMEOUT);
#endif
}
void is31fl3737_select_page(uint8_t index, uint8_t page) {
is31fl3737_write_register(index, IS31FL3737_REG_COMMAND_WRITE_LOCK, IS31FL3737_COMMAND_WRITE_LOCK_MAGIC);
is31fl3737_write_register(index, IS31FL3737_REG_COMMAND, page);
}
void is31fl3737_write_pwm_buffer(uint8_t index) {
// Assumes page 1 is already selected.
// Transmit PWM registers in 12 transfers of 16 bytes.
// Iterate over the pwm_buffer contents at 16 byte intervals.
for (uint8_t i = 0; i < IS31FL3737_PWM_REGISTER_COUNT; i += 16) {
#if IS31FL3737_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < IS31FL3737_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3737_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3737_I2C_TIMEOUT);
#endif
}
}
void is31fl3737_init_drivers(void) {
i2c_init();
for (uint8_t i = 0; i < IS31FL3737_DRIVER_COUNT; i++) {
is31fl3737_init(i);
}
for (int i = 0; i < IS31FL3737_LED_COUNT; i++) {
is31fl3737_set_led_control_register(i, true);
}
for (uint8_t i = 0; i < IS31FL3737_DRIVER_COUNT; i++) {
is31fl3737_update_led_control_registers(i);
}
}
void is31fl3737_init(uint8_t index) {
// 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.
is31fl3737_select_page(index, IS31FL3737_COMMAND_LED_CONTROL);
// Turn off all LEDs.
for (uint8_t i = 0; i < IS31FL3737_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3737_write_register(index, i, 0x00);
}
is31fl3737_select_page(index, IS31FL3737_COMMAND_PWM);
// Set PWM on all LEDs to 0
// No need to setup Breath registers to PWM as that is the default.
for (uint8_t i = 0; i < IS31FL3737_PWM_REGISTER_COUNT; i++) {
is31fl3737_write_register(index, i, 0x00);
}
is31fl3737_select_page(index, IS31FL3737_COMMAND_FUNCTION);
// Set de-ghost pull-up resistors (SWx)
is31fl3737_write_register(index, IS31FL3737_FUNCTION_REG_SW_PULLUP, IS31FL3737_SW_PULLUP);
// Set de-ghost pull-down resistors (CSx)
is31fl3737_write_register(index, IS31FL3737_FUNCTION_REG_CS_PULLDOWN, IS31FL3737_CS_PULLDOWN);
// Set global current to maximum.
is31fl3737_write_register(index, IS31FL3737_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3737_GLOBAL_CURRENT);
// Disable software shutdown.
is31fl3737_write_register(index, IS31FL3737_FUNCTION_REG_CONFIGURATION, ((IS31FL3737_PWM_FREQUENCY & 0b111) << 3) | 0x01);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}
void is31fl3737_set_value(int index, uint8_t value) {
is31fl3737_led_t led;
if (index >= 0 && index < IS31FL3737_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3737_leds[index]), sizeof(led));
if (driver_buffers[led.driver].pwm_buffer[led.v] == value) {
return;
}
driver_buffers[led.driver].pwm_buffer[led.v] = value;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
void is31fl3737_set_value_all(uint8_t value) {
for (int i = 0; i < IS31FL3737_LED_COUNT; i++) {
is31fl3737_set_value(i, value);
}
}
void is31fl3737_set_led_control_register(uint8_t index, bool value) {
is31fl3737_led_t led;
memcpy_P(&led, (&g_is31fl3737_leds[index]), sizeof(led));
uint8_t control_register = led.v / 8;
uint8_t bit_value = led.v % 8;
if (value) {
driver_buffers[led.driver].led_control_buffer[control_register] |= (1 << bit_value);
} else {
driver_buffers[led.driver].led_control_buffer[control_register] &= ~(1 << bit_value);
}
driver_buffers[led.driver].led_control_buffer_dirty = true;
}
void is31fl3737_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3737_select_page(index, IS31FL3737_COMMAND_PWM);
is31fl3737_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void is31fl3737_update_led_control_registers(uint8_t index) {
if (driver_buffers[index].led_control_buffer_dirty) {
is31fl3737_select_page(index, IS31FL3737_COMMAND_LED_CONTROL);
for (uint8_t i = 0; i < IS31FL3737_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3737_write_register(index, i, driver_buffers[index].led_control_buffer[i]);
}
driver_buffers[index].led_control_buffer_dirty = false;
}
}
void is31fl3737_flush(void) {
for (uint8_t i = 0; i < IS31FL3737_DRIVER_COUNT; i++) {
is31fl3737_update_pwm_buffers(i);
}
}

View File

@ -0,0 +1,299 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2021 Doni Crosby
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
// ======== DEPRECATED DEFINES - DO NOT USE ========
#ifdef ISSI_TIMEOUT
# define IS31FL3737_I2C_TIMEOUT ISSI_TIMEOUT
#endif
#ifdef ISSI_PERSISTENCE
# define IS31FL3737_I2C_PERSISTENCE ISSI_PERSISTENCE
#endif
#ifdef ISSI_PWM_FREQUENCY
# define IS31FL3737_PWM_FREQUENCY ISSI_PWM_FREQUENCY
#endif
#ifdef ISSI_SWPULLUP
# define IS31FL3737_SW_PULLUP ISSI_SWPULLUP
#endif
#ifdef ISSI_CSPULLUP
# define IS31FL3737_CS_PULLDOWN ISSI_CSPULLUP
#endif
#ifdef ISSI_GLOBALCURRENT
# define IS31FL3737_GLOBAL_CURRENT ISSI_GLOBALCURRENT
#endif
#define PUR_0R IS31FL3737_PUR_0_OHM
#define PUR_05KR IS31FL3737_PUR_0K5_OHM
#define PUR_1KR IS31FL3737_PUR_1K_OHM
#define PUR_2KR IS31FL3737_PUR_2K_OHM
#define PUR_4KR IS31FL3737_PUR_4K_OHM
#define PUR_8KR IS31FL3737_PUR_8K_OHM
#define PUR_16KR IS31FL3737_PUR_16K_OHM
#define PUR_32KR IS31FL3737_PUR_32K_OHM
// ========
#define IS31FL3737_REG_INTERRUPT_MASK 0xF0
#define IS31FL3737_REG_INTERRUPT_STATUS 0xF1
#define IS31FL3737_REG_COMMAND 0xFD
#define IS31FL3737_COMMAND_LED_CONTROL 0x00
#define IS31FL3737_COMMAND_PWM 0x01
#define IS31FL3737_COMMAND_AUTO_BREATH 0x02
#define IS31FL3737_COMMAND_FUNCTION 0x03
#define IS31FL3737_FUNCTION_REG_CONFIGURATION 0x00
#define IS31FL3737_FUNCTION_REG_GLOBAL_CURRENT 0x01
#define IS31FL3737_FUNCTION_REG_SW_PULLUP 0x0F
#define IS31FL3737_FUNCTION_REG_CS_PULLDOWN 0x10
#define IS31FL3737_FUNCTION_REG_RESET 0x11
#define IS31FL3737_REG_COMMAND_WRITE_LOCK 0xFE
#define IS31FL3737_COMMAND_WRITE_LOCK_MAGIC 0xC5
#define IS31FL3737_I2C_ADDRESS_GND 0x50
#define IS31FL3737_I2C_ADDRESS_SCL 0x55
#define IS31FL3737_I2C_ADDRESS_SDA 0x5A
#define IS31FL3737_I2C_ADDRESS_VCC 0x5F
#if defined(LED_MATRIX_IS31FL3737)
# define IS31FL3737_LED_COUNT LED_MATRIX_LED_COUNT
#endif
#if defined(IS31FL3737_I2C_ADDRESS_4)
# define IS31FL3737_DRIVER_COUNT 4
#elif defined(IS31FL3737_I2C_ADDRESS_3)
# define IS31FL3737_DRIVER_COUNT 3
#elif defined(IS31FL3737_I2C_ADDRESS_2)
# define IS31FL3737_DRIVER_COUNT 2
#elif defined(IS31FL3737_I2C_ADDRESS_1)
# define IS31FL3737_DRIVER_COUNT 1
#endif
typedef struct is31fl3737_led_t {
uint8_t driver : 2;
uint8_t v;
} PACKED is31fl3737_led_t;
extern const is31fl3737_led_t PROGMEM g_is31fl3737_leds[IS31FL3737_LED_COUNT];
void is31fl3737_init_drivers(void);
void is31fl3737_init(uint8_t index);
void is31fl3737_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3737_select_page(uint8_t index, uint8_t page);
void is31fl3737_set_value(int index, uint8_t value);
void is31fl3737_set_value_all(uint8_t value);
void is31fl3737_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 is31fl3737_update_pwm_buffers(uint8_t index);
void is31fl3737_update_led_control_registers(uint8_t index);
void is31fl3737_flush(void);
#define IS31FL3737_PDR_0_OHM 0b000 // No pull-down resistor
#define IS31FL3737_PDR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3737_PDR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3737_PDR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3737_PDR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3737_PDR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3737_PDR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3737_PDR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3737_PUR_0_OHM 0b000 // No pull-up resistor
#define IS31FL3737_PUR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3737_PUR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3737_PUR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3737_PUR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3737_PUR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3737_PUR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3737_PUR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3737_PWM_FREQUENCY_8K4_HZ 0b000
#define IS31FL3737_PWM_FREQUENCY_4K2_HZ 0b001
#define IS31FL3737_PWM_FREQUENCY_26K7_HZ 0b010
#define IS31FL3737_PWM_FREQUENCY_2K1_HZ 0b011
#define IS31FL3737_PWM_FREQUENCY_1K05_HZ 0b100
#define SW1_CS1 0x00
#define SW1_CS2 0x01
#define SW1_CS3 0x02
#define SW1_CS4 0x03
#define SW1_CS5 0x04
#define SW1_CS6 0x05
#define SW1_CS7 0x08
#define SW1_CS8 0x09
#define SW1_CS9 0x0A
#define SW1_CS10 0x0B
#define SW1_CS11 0x0C
#define SW1_CS12 0x0D
#define SW2_CS1 0x10
#define SW2_CS2 0x11
#define SW2_CS3 0x12
#define SW2_CS4 0x13
#define SW2_CS5 0x14
#define SW2_CS6 0x15
#define SW2_CS7 0x18
#define SW2_CS8 0x19
#define SW2_CS9 0x1A
#define SW2_CS10 0x1B
#define SW2_CS11 0x1C
#define SW2_CS12 0x1D
#define SW3_CS1 0x20
#define SW3_CS2 0x21
#define SW3_CS3 0x22
#define SW3_CS4 0x23
#define SW3_CS5 0x24
#define SW3_CS6 0x25
#define SW3_CS7 0x28
#define SW3_CS8 0x29
#define SW3_CS9 0x2A
#define SW3_CS10 0x2B
#define SW3_CS11 0x2C
#define SW3_CS12 0x2D
#define SW4_CS1 0x30
#define SW4_CS2 0x31
#define SW4_CS3 0x32
#define SW4_CS4 0x33
#define SW4_CS5 0x34
#define SW4_CS6 0x35
#define SW4_CS7 0x38
#define SW4_CS8 0x39
#define SW4_CS9 0x3A
#define SW4_CS10 0x3B
#define SW4_CS11 0x3C
#define SW4_CS12 0x3D
#define SW5_CS1 0x40
#define SW5_CS2 0x41
#define SW5_CS3 0x42
#define SW5_CS4 0x43
#define SW5_CS5 0x44
#define SW5_CS6 0x45
#define SW5_CS7 0x48
#define SW5_CS8 0x49
#define SW5_CS9 0x4A
#define SW5_CS10 0x4B
#define SW5_CS11 0x4C
#define SW5_CS12 0x4D
#define SW6_CS1 0x50
#define SW6_CS2 0x51
#define SW6_CS3 0x52
#define SW6_CS4 0x53
#define SW6_CS5 0x54
#define SW6_CS6 0x55
#define SW6_CS7 0x58
#define SW6_CS8 0x59
#define SW6_CS9 0x5A
#define SW6_CS10 0x5B
#define SW6_CS11 0x5C
#define SW6_CS12 0x5D
#define SW7_CS1 0x60
#define SW7_CS2 0x61
#define SW7_CS3 0x62
#define SW7_CS4 0x63
#define SW7_CS5 0x64
#define SW7_CS6 0x65
#define SW7_CS7 0x68
#define SW7_CS8 0x69
#define SW7_CS9 0x6A
#define SW7_CS10 0x6B
#define SW7_CS11 0x6C
#define SW7_CS12 0x6D
#define SW8_CS1 0x70
#define SW8_CS2 0x71
#define SW8_CS3 0x72
#define SW8_CS4 0x73
#define SW8_CS5 0x74
#define SW8_CS6 0x75
#define SW8_CS7 0x78
#define SW8_CS8 0x79
#define SW8_CS9 0x7A
#define SW8_CS10 0x7B
#define SW8_CS11 0x7C
#define SW8_CS12 0x7D
#define SW9_CS1 0x80
#define SW9_CS2 0x81
#define SW9_CS3 0x82
#define SW9_CS4 0x83
#define SW9_CS5 0x84
#define SW9_CS6 0x85
#define SW9_CS7 0x88
#define SW9_CS8 0x89
#define SW9_CS9 0x8A
#define SW9_CS10 0x8B
#define SW9_CS11 0x8C
#define SW9_CS12 0x8D
#define SW10_CS1 0x90
#define SW10_CS2 0x91
#define SW10_CS3 0x92
#define SW10_CS4 0x93
#define SW10_CS5 0x94
#define SW10_CS6 0x95
#define SW10_CS7 0x98
#define SW10_CS8 0x99
#define SW10_CS9 0x9A
#define SW10_CS10 0x9B
#define SW10_CS11 0x9C
#define SW10_CS12 0x9D
#define SW11_CS1 0xA0
#define SW11_CS2 0xA1
#define SW11_CS3 0xA2
#define SW11_CS4 0xA3
#define SW11_CS5 0xA4
#define SW11_CS6 0xA5
#define SW11_CS7 0xA8
#define SW11_CS8 0xA9
#define SW11_CS9 0xAA
#define SW11_CS10 0xAB
#define SW11_CS11 0xAC
#define SW11_CS12 0xAD
#define SW12_CS1 0xB0
#define SW12_CS2 0xB1
#define SW12_CS3 0xB2
#define SW12_CS4 0xB3
#define SW12_CS5 0xB4
#define SW12_CS6 0xB5
#define SW12_CS7 0xB8
#define SW12_CS8 0xB9
#define SW12_CS9 0xBA
#define SW12_CS10 0xBB
#define SW12_CS11 0xBC
#define SW12_CS12 0xBD

View File

@ -1,241 +0,0 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2021 Doni Crosby
*
* 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 "is31fl3737-simple.h"
#include <string.h>
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3737_PWM_REGISTER_COUNT 192 // actually 144
#define IS31FL3737_LED_CONTROL_REGISTER_COUNT 24
#ifndef IS31FL3737_I2C_TIMEOUT
# define IS31FL3737_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3737_I2C_PERSISTENCE
# define IS31FL3737_I2C_PERSISTENCE 0
#endif
#ifndef IS31FL3737_PWM_FREQUENCY
# define IS31FL3737_PWM_FREQUENCY IS31FL3737_PWM_FREQUENCY_8K4_HZ // PFS - IS31FL3737B only
#endif
#ifndef IS31FL3737_SW_PULLUP
# define IS31FL3737_SW_PULLUP IS31FL3737_PUR_0_OHM
#endif
#ifndef IS31FL3737_CS_PULLDOWN
# define IS31FL3737_CS_PULLDOWN IS31FL3737_PDR_0_OHM
#endif
#ifndef IS31FL3737_GLOBAL_CURRENT
# define IS31FL3737_GLOBAL_CURRENT 0xFF
#endif
uint8_t i2c_transfer_buffer[20];
// These buffers match the IS31FL3737 PWM registers.
// The control buffers match the page 0 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
// probably not worth the extra complexity.
uint8_t g_pwm_buffer[IS31FL3737_DRIVER_COUNT][IS31FL3737_PWM_REGISTER_COUNT];
bool g_pwm_buffer_update_required[IS31FL3737_DRIVER_COUNT] = {false};
uint8_t g_led_control_registers[IS31FL3737_DRIVER_COUNT][IS31FL3737_LED_CONTROL_REGISTER_COUNT] = {0};
bool g_led_control_registers_update_required[IS31FL3737_DRIVER_COUNT] = {false};
void is31fl3737_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
i2c_transfer_buffer[0] = reg;
i2c_transfer_buffer[1] = data;
#if IS31FL3737_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3737_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3737_I2C_TIMEOUT) == 0) break;
}
#else
i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3737_I2C_TIMEOUT);
#endif
}
void is31fl3737_select_page(uint8_t addr, uint8_t page) {
is31fl3737_write_register(addr, IS31FL3737_REG_COMMAND_WRITE_LOCK, IS31FL3737_COMMAND_WRITE_LOCK_MAGIC);
is31fl3737_write_register(addr, IS31FL3737_REG_COMMAND, page);
}
void is31fl3737_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
// assumes page 1 is already selected
// transmit PWM registers in 12 transfers of 16 bytes
// i2c_transfer_buffer[] is 20 bytes
// iterate over the pwm_buffer contents at 16 byte intervals
for (int i = 0; i < IS31FL3737_PWM_REGISTER_COUNT; i += 16) {
i2c_transfer_buffer[0] = i;
// copy the data from i to i+15
// device will auto-increment register for data after the first byte
// thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer
memcpy(i2c_transfer_buffer + 1, pwm_buffer + i, 16);
#if IS31FL3737_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3737_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3737_I2C_TIMEOUT) == 0) break;
}
#else
i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3737_I2C_TIMEOUT);
#endif
}
}
void is31fl3737_init_drivers(void) {
i2c_init();
is31fl3737_init(IS31FL3737_I2C_ADDRESS_1);
#if defined(IS31FL3737_I2C_ADDRESS_2)
is31fl3737_init(IS31FL3737_I2C_ADDRESS_2);
# if defined(IS31FL3737_I2C_ADDRESS_3)
is31fl3737_init(IS31FL3737_I2C_ADDRESS_3);
# if defined(IS31FL3737_I2C_ADDRESS_4)
is31fl3737_init(IS31FL3737_I2C_ADDRESS_4);
# endif
# endif
#endif
for (int i = 0; i < IS31FL3737_LED_COUNT; i++) {
is31fl3737_set_led_control_register(i, true);
}
is31fl3737_update_led_control_registers(IS31FL3737_I2C_ADDRESS_1, 0);
#if defined(IS31FL3737_I2C_ADDRESS_2)
is31fl3737_update_led_control_registers(IS31FL3737_I2C_ADDRESS_2, 1);
# if defined(IS31FL3737_I2C_ADDRESS_3)
is31fl3737_update_led_control_registers(IS31FL3737_I2C_ADDRESS_3, 2);
# if defined(IS31FL3737_I2C_ADDRESS_4)
is31fl3737_update_led_control_registers(IS31FL3737_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
}
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.
is31fl3737_select_page(addr, IS31FL3737_COMMAND_LED_CONTROL);
// Turn off all LEDs.
for (int i = 0; i < IS31FL3737_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3737_write_register(addr, i, 0x00);
}
is31fl3737_select_page(addr, IS31FL3737_COMMAND_PWM);
// Set PWM on all LEDs to 0
// No need to setup Breath registers to PWM as that is the default.
for (int i = 0; i < IS31FL3737_PWM_REGISTER_COUNT; i++) {
is31fl3737_write_register(addr, i, 0x00);
}
is31fl3737_select_page(addr, IS31FL3737_COMMAND_FUNCTION);
// Set de-ghost pull-up resistors (SWx)
is31fl3737_write_register(addr, IS31FL3737_FUNCTION_REG_SW_PULLUP, IS31FL3737_SW_PULLUP);
// Set de-ghost pull-down resistors (CSx)
is31fl3737_write_register(addr, IS31FL3737_FUNCTION_REG_CS_PULLDOWN, IS31FL3737_CS_PULLDOWN);
// Set global current to maximum.
is31fl3737_write_register(addr, IS31FL3737_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3737_GLOBAL_CURRENT);
// Disable software shutdown.
is31fl3737_write_register(addr, IS31FL3737_FUNCTION_REG_CONFIGURATION, ((IS31FL3737_PWM_FREQUENCY & 0b111) << 3) | 0x01);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}
void is31fl3737_set_value(int index, uint8_t value) {
is31fl3737_led_t led;
if (index >= 0 && index < IS31FL3737_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3737_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 is31fl3737_set_value_all(uint8_t value) {
for (int i = 0; i < IS31FL3737_LED_COUNT; i++) {
is31fl3737_set_value(i, value);
}
}
void is31fl3737_set_led_control_register(uint8_t index, bool value) {
is31fl3737_led_t led;
memcpy_P(&led, (&g_is31fl3737_leds[index]), sizeof(led));
uint8_t control_register = led.v / 8;
uint8_t bit_value = led.v % 8;
if (value) {
g_led_control_registers[led.driver][control_register] |= (1 << bit_value);
} else {
g_led_control_registers[led.driver][control_register] &= ~(1 << bit_value);
}
g_led_control_registers_update_required[led.driver] = true;
}
void is31fl3737_update_pwm_buffers(uint8_t addr, uint8_t index) {
if (g_pwm_buffer_update_required[index]) {
is31fl3737_select_page(addr, IS31FL3737_COMMAND_PWM);
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) {
if (g_led_control_registers_update_required[index]) {
is31fl3737_select_page(addr, IS31FL3737_COMMAND_LED_CONTROL);
for (int i = 0; i < IS31FL3737_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3737_write_register(addr, i, g_led_control_registers[index][i]);
}
g_led_control_registers_update_required[index] = false;
}
}
void is31fl3737_flush(void) {
is31fl3737_update_pwm_buffers(IS31FL3737_I2C_ADDRESS_1, 0);
#if defined(IS31FL3737_I2C_ADDRESS_2)
is31fl3737_update_pwm_buffers(IS31FL3737_I2C_ADDRESS_2, 1);
# if defined(IS31FL3737_I2C_ADDRESS_3)
is31fl3737_update_pwm_buffers(IS31FL3737_I2C_ADDRESS_3, 2);
# if defined(IS31FL3737_I2C_ADDRESS_4)
is31fl3737_update_pwm_buffers(IS31FL3737_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
}

View File

@ -1,300 +0,0 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2021 Doni Crosby
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
// ======== DEPRECATED DEFINES - DO NOT USE ========
#ifdef ISSI_TIMEOUT
# define IS31FL3737_I2C_TIMEOUT ISSI_TIMEOUT
#endif
#ifdef ISSI_PERSISTENCE
# define IS31FL3737_I2C_PERSISTENCE ISSI_PERSISTENCE
#endif
#ifdef ISSI_PWM_FREQUENCY
# define IS31FL3737_PWM_FREQUENCY ISSI_PWM_FREQUENCY
#endif
#ifdef ISSI_SWPULLUP
# define IS31FL3737_SW_PULLUP ISSI_SWPULLUP
#endif
#ifdef ISSI_CSPULLUP
# define IS31FL3737_CS_PULLDOWN ISSI_CSPULLUP
#endif
#ifdef ISSI_GLOBALCURRENT
# define IS31FL3737_GLOBAL_CURRENT ISSI_GLOBALCURRENT
#endif
#define PUR_0R IS31FL3737_PUR_0_OHM
#define PUR_05KR IS31FL3737_PUR_0K5_OHM
#define PUR_1KR IS31FL3737_PUR_1K_OHM
#define PUR_2KR IS31FL3737_PUR_2K_OHM
#define PUR_4KR IS31FL3737_PUR_4K_OHM
#define PUR_8KR IS31FL3737_PUR_8K_OHM
#define PUR_16KR IS31FL3737_PUR_16K_OHM
#define PUR_32KR IS31FL3737_PUR_32K_OHM
// ========
#define IS31FL3737_REG_INTERRUPT_MASK 0xF0
#define IS31FL3737_REG_INTERRUPT_STATUS 0xF1
#define IS31FL3737_REG_COMMAND 0xFD
#define IS31FL3737_COMMAND_LED_CONTROL 0x00
#define IS31FL3737_COMMAND_PWM 0x01
#define IS31FL3737_COMMAND_AUTO_BREATH 0x02
#define IS31FL3737_COMMAND_FUNCTION 0x03
#define IS31FL3737_FUNCTION_REG_CONFIGURATION 0x00
#define IS31FL3737_FUNCTION_REG_GLOBAL_CURRENT 0x01
#define IS31FL3737_FUNCTION_REG_SW_PULLUP 0x0F
#define IS31FL3737_FUNCTION_REG_CS_PULLDOWN 0x10
#define IS31FL3737_FUNCTION_REG_RESET 0x11
#define IS31FL3737_REG_COMMAND_WRITE_LOCK 0xFE
#define IS31FL3737_COMMAND_WRITE_LOCK_MAGIC 0xC5
#define IS31FL3737_I2C_ADDRESS_GND 0x50
#define IS31FL3737_I2C_ADDRESS_SCL 0x55
#define IS31FL3737_I2C_ADDRESS_SDA 0x5A
#define IS31FL3737_I2C_ADDRESS_VCC 0x5F
#if defined(LED_MATRIX_IS31FL3737)
# define IS31FL3737_LED_COUNT LED_MATRIX_LED_COUNT
#endif
#if defined(IS31FL3737_I2C_ADDRESS_4)
# define IS31FL3737_DRIVER_COUNT 4
#elif defined(IS31FL3737_I2C_ADDRESS_3)
# define IS31FL3737_DRIVER_COUNT 3
#elif defined(IS31FL3737_I2C_ADDRESS_2)
# define IS31FL3737_DRIVER_COUNT 2
#elif defined(IS31FL3737_I2C_ADDRESS_1)
# define IS31FL3737_DRIVER_COUNT 1
#endif
typedef struct is31fl3737_led_t {
uint8_t driver : 2;
uint8_t v;
} PACKED is31fl3737_led_t;
extern const is31fl3737_led_t PROGMEM g_is31fl3737_leds[IS31FL3737_LED_COUNT];
void is31fl3737_init_drivers(void);
void is31fl3737_init(uint8_t addr);
void is31fl3737_write_register(uint8_t addr, uint8_t reg, uint8_t data);
void is31fl3737_select_page(uint8_t addr, uint8_t page);
void is31fl3737_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
void is31fl3737_set_value(int index, uint8_t value);
void is31fl3737_set_value_all(uint8_t value);
void is31fl3737_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 is31fl3737_update_pwm_buffers(uint8_t addr, uint8_t index);
void is31fl3737_update_led_control_registers(uint8_t addr, uint8_t index);
void is31fl3737_flush(void);
#define IS31FL3737_PDR_0_OHM 0b000 // No pull-down resistor
#define IS31FL3737_PDR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3737_PDR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3737_PDR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3737_PDR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3737_PDR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3737_PDR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3737_PDR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3737_PUR_0_OHM 0b000 // No pull-up resistor
#define IS31FL3737_PUR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3737_PUR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3737_PUR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3737_PUR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3737_PUR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3737_PUR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3737_PUR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3737_PWM_FREQUENCY_8K4_HZ 0b000
#define IS31FL3737_PWM_FREQUENCY_4K2_HZ 0b001
#define IS31FL3737_PWM_FREQUENCY_26K7_HZ 0b010
#define IS31FL3737_PWM_FREQUENCY_2K1_HZ 0b011
#define IS31FL3737_PWM_FREQUENCY_1K05_HZ 0b100
#define A_1 0x00
#define A_2 0x01
#define A_3 0x02
#define A_4 0x03
#define A_5 0x04
#define A_6 0x05
#define A_7 0x08
#define A_8 0x09
#define A_9 0x0A
#define A_10 0x0B
#define A_11 0x0C
#define A_12 0x0D
#define B_1 0x10
#define B_2 0x11
#define B_3 0x12
#define B_4 0x13
#define B_5 0x14
#define B_6 0x15
#define B_7 0x18
#define B_8 0x19
#define B_9 0x1A
#define B_10 0x1B
#define B_11 0x1C
#define B_12 0x1D
#define C_1 0x20
#define C_2 0x21
#define C_3 0x22
#define C_4 0x23
#define C_5 0x24
#define C_6 0x25
#define C_7 0x28
#define C_8 0x29
#define C_9 0x2A
#define C_10 0x2B
#define C_11 0x2C
#define C_12 0x2D
#define D_1 0x30
#define D_2 0x31
#define D_3 0x32
#define D_4 0x33
#define D_5 0x34
#define D_6 0x35
#define D_7 0x38
#define D_8 0x39
#define D_9 0x3A
#define D_10 0x3B
#define D_11 0x3C
#define D_12 0x3D
#define E_1 0x40
#define E_2 0x41
#define E_3 0x42
#define E_4 0x43
#define E_5 0x44
#define E_6 0x45
#define E_7 0x48
#define E_8 0x49
#define E_9 0x4A
#define E_10 0x4B
#define E_11 0x4C
#define E_12 0x4D
#define F_1 0x50
#define F_2 0x51
#define F_3 0x52
#define F_4 0x53
#define F_5 0x54
#define F_6 0x55
#define F_7 0x58
#define F_8 0x59
#define F_9 0x5A
#define F_10 0x5B
#define F_11 0x5C
#define F_12 0x5D
#define G_1 0x60
#define G_2 0x61
#define G_3 0x62
#define G_4 0x63
#define G_5 0x64
#define G_6 0x65
#define G_7 0x68
#define G_8 0x69
#define G_9 0x6A
#define G_10 0x6B
#define G_11 0x6C
#define G_12 0x6D
#define H_1 0x70
#define H_2 0x71
#define H_3 0x72
#define H_4 0x73
#define H_5 0x74
#define H_6 0x75
#define H_7 0x78
#define H_8 0x79
#define H_9 0x7A
#define H_10 0x7B
#define H_11 0x7C
#define H_12 0x7D
#define I_1 0x80
#define I_2 0x81
#define I_3 0x82
#define I_4 0x83
#define I_5 0x84
#define I_6 0x85
#define I_7 0x88
#define I_8 0x89
#define I_9 0x8A
#define I_10 0x8B
#define I_11 0x8C
#define I_12 0x8D
#define J_1 0x90
#define J_2 0x91
#define J_3 0x92
#define J_4 0x93
#define J_5 0x94
#define J_6 0x95
#define J_7 0x98
#define J_8 0x99
#define J_9 0x9A
#define J_10 0x9B
#define J_11 0x9C
#define J_12 0x9D
#define K_1 0xA0
#define K_2 0xA1
#define K_3 0xA2
#define K_4 0xA3
#define K_5 0xA4
#define K_6 0xA5
#define K_7 0xA8
#define K_8 0xA9
#define K_9 0xAA
#define K_10 0xAB
#define K_11 0xAC
#define K_12 0xAD
#define L_1 0xB0
#define L_2 0xB1
#define L_3 0xB2
#define L_4 0xB3
#define L_5 0xB4
#define L_6 0xB5
#define L_7 0xB8
#define L_8 0xB9
#define L_9 0xBA
#define L_10 0xBB
#define L_11 0xBC
#define L_12 0xBD

View File

@ -18,7 +18,6 @@
*/
#include "is31fl3737.h"
#include <string.h>
#include "i2c_master.h"
#include "wait.h"
@ -41,7 +40,7 @@
# define IS31FL3737_SW_PULLUP IS31FL3737_PUR_0_OHM
#endif
#ifndef IS31FL3737_CS_PULLDONW
#ifndef IS31FL3737_CS_PULLDOWN
# define IS31FL3737_CS_PULLDOWN IS31FL3737_PDR_0_OHM
#endif
@ -49,7 +48,18 @@
# define IS31FL3737_GLOBAL_CURRENT 0xFF
#endif
uint8_t i2c_transfer_buffer[20];
const uint8_t i2c_addresses[IS31FL3737_DRIVER_COUNT] = {
IS31FL3737_I2C_ADDRESS_1,
#ifdef IS31FL3737_I2C_ADDRESS_2
IS31FL3737_I2C_ADDRESS_2,
# ifdef IS31FL3737_I2C_ADDRESS_3
IS31FL3737_I2C_ADDRESS_3,
# ifdef IS31FL3737_I2C_ADDRESS_4
IS31FL3737_I2C_ADDRESS_4,
# endif
# endif
#endif
};
// These buffers match the IS31FL3737 PWM registers.
// The control buffers match the page 0 LED On/Off registers.
@ -57,51 +67,47 @@ uint8_t i2c_transfer_buffer[20];
// We could optimize this and take out the unused registers from these
// buffers and the transfers in is31fl3737_write_pwm_buffer() but it's
// probably not worth the extra complexity.
typedef struct is31fl3737_driver_t {
uint8_t pwm_buffer[IS31FL3737_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t led_control_buffer[IS31FL3737_LED_CONTROL_REGISTER_COUNT];
bool led_control_buffer_dirty;
} PACKED is31fl3737_driver_t;
uint8_t g_pwm_buffer[IS31FL3737_DRIVER_COUNT][IS31FL3737_PWM_REGISTER_COUNT];
bool g_pwm_buffer_update_required[IS31FL3737_DRIVER_COUNT] = {false};
uint8_t g_led_control_registers[IS31FL3737_DRIVER_COUNT][IS31FL3737_LED_CONTROL_REGISTER_COUNT] = {0};
bool g_led_control_registers_update_required[IS31FL3737_DRIVER_COUNT] = {false};
void is31fl3737_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
i2c_transfer_buffer[0] = reg;
i2c_transfer_buffer[1] = data;
is31fl3737_driver_t driver_buffers[IS31FL3737_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.led_control_buffer = {0},
.led_control_buffer_dirty = false,
}};
void is31fl3737_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3737_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3737_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3737_I2C_TIMEOUT) == 0) break;
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3737_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3737_I2C_TIMEOUT);
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3737_I2C_TIMEOUT);
#endif
}
void is31fl3737_select_page(uint8_t addr, uint8_t page) {
is31fl3737_write_register(addr, IS31FL3737_REG_COMMAND_WRITE_LOCK, IS31FL3737_COMMAND_WRITE_LOCK_MAGIC);
is31fl3737_write_register(addr, IS31FL3737_REG_COMMAND, page);
void is31fl3737_select_page(uint8_t index, uint8_t page) {
is31fl3737_write_register(index, IS31FL3737_REG_COMMAND_WRITE_LOCK, IS31FL3737_COMMAND_WRITE_LOCK_MAGIC);
is31fl3737_write_register(index, IS31FL3737_REG_COMMAND, page);
}
void is31fl3737_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
// assumes page 1 is already selected
// transmit PWM registers in 12 transfers of 16 bytes
// i2c_transfer_buffer[] is 20 bytes
// iterate over the pwm_buffer contents at 16 byte intervals
for (int i = 0; i < IS31FL3737_PWM_REGISTER_COUNT; i += 16) {
i2c_transfer_buffer[0] = i;
// copy the data from i to i+15
// device will auto-increment register for data after the first byte
// thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer
memcpy(i2c_transfer_buffer + 1, pwm_buffer + i, 16);
void is31fl3737_write_pwm_buffer(uint8_t index) {
// Assumes page 1 is already selected.
// Transmit PWM registers in 12 transfers of 16 bytes.
// Iterate over the pwm_buffer contents at 16 byte intervals.
for (uint8_t i = 0; i < IS31FL3737_PWM_REGISTER_COUNT; i += 16) {
#if IS31FL3737_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3737_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3737_I2C_TIMEOUT) == 0) break;
for (uint8_t j = 0; j < IS31FL3737_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3737_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_transmit(addr << 1, i2c_transfer_buffer, 17, IS31FL3737_I2C_TIMEOUT);
i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 16, IS31FL3737_I2C_TIMEOUT);
#endif
}
}
@ -109,64 +115,50 @@ void is31fl3737_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
void is31fl3737_init_drivers(void) {
i2c_init();
is31fl3737_init(IS31FL3737_I2C_ADDRESS_1);
#if defined(IS31FL3737_I2C_ADDRESS_2)
is31fl3737_init(IS31FL3737_I2C_ADDRESS_2);
# if defined(IS31FL3737_I2C_ADDRESS_3)
is31fl3737_init(IS31FL3737_I2C_ADDRESS_3);
# if defined(IS31FL3737_I2C_ADDRESS_4)
is31fl3737_init(IS31FL3737_I2C_ADDRESS_4);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3737_DRIVER_COUNT; i++) {
is31fl3737_init(i);
}
for (int i = 0; i < IS31FL3737_LED_COUNT; i++) {
is31fl3737_set_led_control_register(i, true, true, true);
}
is31fl3737_update_led_control_registers(IS31FL3737_I2C_ADDRESS_1, 0);
#if defined(IS31FL3737_I2C_ADDRESS_2)
is31fl3737_update_led_control_registers(IS31FL3737_I2C_ADDRESS_2, 1);
# if defined(IS31FL3737_I2C_ADDRESS_3)
is31fl3737_update_led_control_registers(IS31FL3737_I2C_ADDRESS_3, 2);
# if defined(IS31FL3737_I2C_ADDRESS_4)
is31fl3737_update_led_control_registers(IS31FL3737_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3737_DRIVER_COUNT; i++) {
is31fl3737_update_led_control_registers(i);
}
}
void is31fl3737_init(uint8_t addr) {
void is31fl3737_init(uint8_t index) {
// 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.
is31fl3737_select_page(addr, IS31FL3737_COMMAND_LED_CONTROL);
is31fl3737_select_page(index, IS31FL3737_COMMAND_LED_CONTROL);
// Turn off all LEDs.
for (int i = 0; i < IS31FL3737_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3737_write_register(addr, i, 0x00);
for (uint8_t i = 0; i < IS31FL3737_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3737_write_register(index, i, 0x00);
}
is31fl3737_select_page(addr, IS31FL3737_COMMAND_PWM);
is31fl3737_select_page(index, IS31FL3737_COMMAND_PWM);
// Set PWM on all LEDs to 0
// No need to setup Breath registers to PWM as that is the default.
for (int i = 0; i < IS31FL3737_PWM_REGISTER_COUNT; i++) {
is31fl3737_write_register(addr, i, 0x00);
for (uint8_t i = 0; i < IS31FL3737_PWM_REGISTER_COUNT; i++) {
is31fl3737_write_register(index, i, 0x00);
}
is31fl3737_select_page(addr, IS31FL3737_COMMAND_FUNCTION);
is31fl3737_select_page(index, IS31FL3737_COMMAND_FUNCTION);
// Set de-ghost pull-up resistors (SWx)
is31fl3737_write_register(addr, IS31FL3737_FUNCTION_REG_SW_PULLUP, IS31FL3737_SW_PULLUP);
is31fl3737_write_register(index, IS31FL3737_FUNCTION_REG_SW_PULLUP, IS31FL3737_SW_PULLUP);
// Set de-ghost pull-down resistors (CSx)
is31fl3737_write_register(addr, IS31FL3737_FUNCTION_REG_CS_PULLDOWN, IS31FL3737_CS_PULLDOWN);
is31fl3737_write_register(index, IS31FL3737_FUNCTION_REG_CS_PULLDOWN, IS31FL3737_CS_PULLDOWN);
// Set global current to maximum.
is31fl3737_write_register(addr, IS31FL3737_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3737_GLOBAL_CURRENT);
is31fl3737_write_register(index, IS31FL3737_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3737_GLOBAL_CURRENT);
// Disable software shutdown.
is31fl3737_write_register(addr, IS31FL3737_FUNCTION_REG_CONFIGURATION, ((IS31FL3737_PWM_FREQUENCY & 0b111) << 3) | 0x01);
is31fl3737_write_register(index, IS31FL3737_FUNCTION_REG_CONFIGURATION, ((IS31FL3737_PWM_FREQUENCY & 0b111) << 3) | 0x01);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
@ -174,16 +166,18 @@ void is31fl3737_init(uint8_t addr) {
void is31fl3737_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
is31fl3737_led_t led;
if (index >= 0 && index < IS31FL3737_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3737_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) {
if (driver_buffers[led.driver].pwm_buffer[led.r] == red && driver_buffers[led.driver].pwm_buffer[led.g] == green && driver_buffers[led.driver].pwm_buffer[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;
driver_buffers[led.driver].pwm_buffer[led.r] = red;
driver_buffers[led.driver].pwm_buffer[led.g] = green;
driver_buffers[led.driver].pwm_buffer[led.b] = blue;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
@ -205,53 +199,48 @@ void is31fl3737_set_led_control_register(uint8_t index, bool red, bool green, bo
uint8_t bit_b = led.b % 8;
if (red) {
g_led_control_registers[led.driver][control_register_r] |= (1 << bit_r);
driver_buffers[led.driver].led_control_buffer[control_register_r] |= (1 << bit_r);
} else {
g_led_control_registers[led.driver][control_register_r] &= ~(1 << bit_r);
driver_buffers[led.driver].led_control_buffer[control_register_r] &= ~(1 << bit_r);
}
if (green) {
g_led_control_registers[led.driver][control_register_g] |= (1 << bit_g);
driver_buffers[led.driver].led_control_buffer[control_register_g] |= (1 << bit_g);
} else {
g_led_control_registers[led.driver][control_register_g] &= ~(1 << bit_g);
driver_buffers[led.driver].led_control_buffer[control_register_g] &= ~(1 << bit_g);
}
if (blue) {
g_led_control_registers[led.driver][control_register_b] |= (1 << bit_b);
driver_buffers[led.driver].led_control_buffer[control_register_b] |= (1 << bit_b);
} else {
g_led_control_registers[led.driver][control_register_b] &= ~(1 << bit_b);
driver_buffers[led.driver].led_control_buffer[control_register_b] &= ~(1 << bit_b);
}
g_led_control_registers_update_required[led.driver] = true;
driver_buffers[led.driver].led_control_buffer_dirty = true;
}
void is31fl3737_update_pwm_buffers(uint8_t addr, uint8_t index) {
if (g_pwm_buffer_update_required[index]) {
is31fl3737_select_page(addr, IS31FL3737_COMMAND_PWM);
void is31fl3737_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3737_select_page(index, IS31FL3737_COMMAND_PWM);
is31fl3737_write_pwm_buffer(addr, g_pwm_buffer[index]);
g_pwm_buffer_update_required[index] = false;
is31fl3737_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void is31fl3737_update_led_control_registers(uint8_t addr, uint8_t index) {
if (g_led_control_registers_update_required[index]) {
is31fl3737_select_page(addr, IS31FL3737_COMMAND_LED_CONTROL);
void is31fl3737_update_led_control_registers(uint8_t index) {
if (driver_buffers[index].led_control_buffer_dirty) {
is31fl3737_select_page(index, IS31FL3737_COMMAND_LED_CONTROL);
for (int i = 0; i < IS31FL3737_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3737_write_register(addr, i, g_led_control_registers[index][i]);
for (uint8_t i = 0; i < IS31FL3737_LED_CONTROL_REGISTER_COUNT; i++) {
is31fl3737_write_register(index, i, driver_buffers[index].led_control_buffer[i]);
}
g_led_control_registers_update_required[index] = false;
driver_buffers[index].led_control_buffer_dirty = false;
}
}
void is31fl3737_flush(void) {
is31fl3737_update_pwm_buffers(IS31FL3737_I2C_ADDRESS_1, 0);
#if defined(IS31FL3737_I2C_ADDRESS_2)
is31fl3737_update_pwm_buffers(IS31FL3737_I2C_ADDRESS_2, 1);
# if defined(IS31FL3737_I2C_ADDRESS_3)
is31fl3737_update_pwm_buffers(IS31FL3737_I2C_ADDRESS_3, 2);
# if defined(IS31FL3737_I2C_ADDRESS_4)
is31fl3737_update_pwm_buffers(IS31FL3737_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3737_DRIVER_COUNT; i++) {
is31fl3737_update_pwm_buffers(i);
}
}

View File

@ -117,10 +117,9 @@ typedef struct is31fl3737_led_t {
extern const is31fl3737_led_t PROGMEM g_is31fl3737_leds[IS31FL3737_LED_COUNT];
void is31fl3737_init_drivers(void);
void is31fl3737_init(uint8_t addr);
void is31fl3737_write_register(uint8_t addr, uint8_t reg, uint8_t data);
void is31fl3737_select_page(uint8_t addr, uint8_t page);
void is31fl3737_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
void is31fl3737_init(uint8_t index);
void is31fl3737_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3737_select_page(uint8_t index, uint8_t page);
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);
@ -131,8 +130,8 @@ void is31fl3737_set_led_control_register(uint8_t index, bool red, bool green, bo
// (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 index);
void is31fl3737_update_led_control_registers(uint8_t index);
void is31fl3737_flush(void);
@ -160,158 +159,316 @@ void is31fl3737_flush(void);
#define IS31FL3737_PWM_FREQUENCY_2K1_HZ 0b011
#define IS31FL3737_PWM_FREQUENCY_1K05_HZ 0b100
#define A_1 0x00
#define A_2 0x01
#define A_3 0x02
#define A_4 0x03
#define A_5 0x04
#define A_6 0x05
#define A_7 0x08
#define A_8 0x09
#define A_9 0x0A
#define A_10 0x0B
#define A_11 0x0C
#define A_12 0x0D
#define SW1_CS1 0x00
#define SW1_CS2 0x01
#define SW1_CS3 0x02
#define SW1_CS4 0x03
#define SW1_CS5 0x04
#define SW1_CS6 0x05
#define SW1_CS7 0x08
#define SW1_CS8 0x09
#define SW1_CS9 0x0A
#define SW1_CS10 0x0B
#define SW1_CS11 0x0C
#define SW1_CS12 0x0D
#define B_1 0x10
#define B_2 0x11
#define B_3 0x12
#define B_4 0x13
#define B_5 0x14
#define B_6 0x15
#define B_7 0x18
#define B_8 0x19
#define B_9 0x1A
#define B_10 0x1B
#define B_11 0x1C
#define B_12 0x1D
#define SW2_CS1 0x10
#define SW2_CS2 0x11
#define SW2_CS3 0x12
#define SW2_CS4 0x13
#define SW2_CS5 0x14
#define SW2_CS6 0x15
#define SW2_CS7 0x18
#define SW2_CS8 0x19
#define SW2_CS9 0x1A
#define SW2_CS10 0x1B
#define SW2_CS11 0x1C
#define SW2_CS12 0x1D
#define C_1 0x20
#define C_2 0x21
#define C_3 0x22
#define C_4 0x23
#define C_5 0x24
#define C_6 0x25
#define C_7 0x28
#define C_8 0x29
#define C_9 0x2A
#define C_10 0x2B
#define C_11 0x2C
#define C_12 0x2D
#define SW3_CS1 0x20
#define SW3_CS2 0x21
#define SW3_CS3 0x22
#define SW3_CS4 0x23
#define SW3_CS5 0x24
#define SW3_CS6 0x25
#define SW3_CS7 0x28
#define SW3_CS8 0x29
#define SW3_CS9 0x2A
#define SW3_CS10 0x2B
#define SW3_CS11 0x2C
#define SW3_CS12 0x2D
#define D_1 0x30
#define D_2 0x31
#define D_3 0x32
#define D_4 0x33
#define D_5 0x34
#define D_6 0x35
#define D_7 0x38
#define D_8 0x39
#define D_9 0x3A
#define D_10 0x3B
#define D_11 0x3C
#define D_12 0x3D
#define SW4_CS1 0x30
#define SW4_CS2 0x31
#define SW4_CS3 0x32
#define SW4_CS4 0x33
#define SW4_CS5 0x34
#define SW4_CS6 0x35
#define SW4_CS7 0x38
#define SW4_CS8 0x39
#define SW4_CS9 0x3A
#define SW4_CS10 0x3B
#define SW4_CS11 0x3C
#define SW4_CS12 0x3D
#define E_1 0x40
#define E_2 0x41
#define E_3 0x42
#define E_4 0x43
#define E_5 0x44
#define E_6 0x45
#define E_7 0x48
#define E_8 0x49
#define E_9 0x4A
#define E_10 0x4B
#define E_11 0x4C
#define E_12 0x4D
#define SW5_CS1 0x40
#define SW5_CS2 0x41
#define SW5_CS3 0x42
#define SW5_CS4 0x43
#define SW5_CS5 0x44
#define SW5_CS6 0x45
#define SW5_CS7 0x48
#define SW5_CS8 0x49
#define SW5_CS9 0x4A
#define SW5_CS10 0x4B
#define SW5_CS11 0x4C
#define SW5_CS12 0x4D
#define F_1 0x50
#define F_2 0x51
#define F_3 0x52
#define F_4 0x53
#define F_5 0x54
#define F_6 0x55
#define F_7 0x58
#define F_8 0x59
#define F_9 0x5A
#define F_10 0x5B
#define F_11 0x5C
#define F_12 0x5D
#define SW6_CS1 0x50
#define SW6_CS2 0x51
#define SW6_CS3 0x52
#define SW6_CS4 0x53
#define SW6_CS5 0x54
#define SW6_CS6 0x55
#define SW6_CS7 0x58
#define SW6_CS8 0x59
#define SW6_CS9 0x5A
#define SW6_CS10 0x5B
#define SW6_CS11 0x5C
#define SW6_CS12 0x5D
#define G_1 0x60
#define G_2 0x61
#define G_3 0x62
#define G_4 0x63
#define G_5 0x64
#define G_6 0x65
#define G_7 0x68
#define G_8 0x69
#define G_9 0x6A
#define G_10 0x6B
#define G_11 0x6C
#define G_12 0x6D
#define SW7_CS1 0x60
#define SW7_CS2 0x61
#define SW7_CS3 0x62
#define SW7_CS4 0x63
#define SW7_CS5 0x64
#define SW7_CS6 0x65
#define SW7_CS7 0x68
#define SW7_CS8 0x69
#define SW7_CS9 0x6A
#define SW7_CS10 0x6B
#define SW7_CS11 0x6C
#define SW7_CS12 0x6D
#define H_1 0x70
#define H_2 0x71
#define H_3 0x72
#define H_4 0x73
#define H_5 0x74
#define H_6 0x75
#define H_7 0x78
#define H_8 0x79
#define H_9 0x7A
#define H_10 0x7B
#define H_11 0x7C
#define H_12 0x7D
#define SW8_CS1 0x70
#define SW8_CS2 0x71
#define SW8_CS3 0x72
#define SW8_CS4 0x73
#define SW8_CS5 0x74
#define SW8_CS6 0x75
#define SW8_CS7 0x78
#define SW8_CS8 0x79
#define SW8_CS9 0x7A
#define SW8_CS10 0x7B
#define SW8_CS11 0x7C
#define SW8_CS12 0x7D
#define I_1 0x80
#define I_2 0x81
#define I_3 0x82
#define I_4 0x83
#define I_5 0x84
#define I_6 0x85
#define I_7 0x88
#define I_8 0x89
#define I_9 0x8A
#define I_10 0x8B
#define I_11 0x8C
#define I_12 0x8D
#define SW9_CS1 0x80
#define SW9_CS2 0x81
#define SW9_CS3 0x82
#define SW9_CS4 0x83
#define SW9_CS5 0x84
#define SW9_CS6 0x85
#define SW9_CS7 0x88
#define SW9_CS8 0x89
#define SW9_CS9 0x8A
#define SW9_CS10 0x8B
#define SW9_CS11 0x8C
#define SW9_CS12 0x8D
#define J_1 0x90
#define J_2 0x91
#define J_3 0x92
#define J_4 0x93
#define J_5 0x94
#define J_6 0x95
#define J_7 0x98
#define J_8 0x99
#define J_9 0x9A
#define J_10 0x9B
#define J_11 0x9C
#define J_12 0x9D
#define SW10_CS1 0x90
#define SW10_CS2 0x91
#define SW10_CS3 0x92
#define SW10_CS4 0x93
#define SW10_CS5 0x94
#define SW10_CS6 0x95
#define SW10_CS7 0x98
#define SW10_CS8 0x99
#define SW10_CS9 0x9A
#define SW10_CS10 0x9B
#define SW10_CS11 0x9C
#define SW10_CS12 0x9D
#define K_1 0xA0
#define K_2 0xA1
#define K_3 0xA2
#define K_4 0xA3
#define K_5 0xA4
#define K_6 0xA5
#define K_7 0xA8
#define K_8 0xA9
#define K_9 0xAA
#define K_10 0xAB
#define K_11 0xAC
#define K_12 0xAD
#define SW11_CS1 0xA0
#define SW11_CS2 0xA1
#define SW11_CS3 0xA2
#define SW11_CS4 0xA3
#define SW11_CS5 0xA4
#define SW11_CS6 0xA5
#define SW11_CS7 0xA8
#define SW11_CS8 0xA9
#define SW11_CS9 0xAA
#define SW11_CS10 0xAB
#define SW11_CS11 0xAC
#define SW11_CS12 0xAD
#define L_1 0xB0
#define L_2 0xB1
#define L_3 0xB2
#define L_4 0xB3
#define L_5 0xB4
#define L_6 0xB5
#define L_7 0xB8
#define L_8 0xB9
#define L_9 0xBA
#define L_10 0xBB
#define L_11 0xBC
#define L_12 0xBD
#define SW12_CS1 0xB0
#define SW12_CS2 0xB1
#define SW12_CS3 0xB2
#define SW12_CS4 0xB3
#define SW12_CS5 0xB4
#define SW12_CS6 0xB5
#define SW12_CS7 0xB8
#define SW12_CS8 0xB9
#define SW12_CS9 0xBA
#define SW12_CS10 0xBB
#define SW12_CS11 0xBC
#define SW12_CS12 0xBD
// DEPRECATED - DO NOT USE
#define A_1 SW1_CS1
#define A_2 SW1_CS2
#define A_3 SW1_CS3
#define A_4 SW1_CS4
#define A_5 SW1_CS5
#define A_6 SW1_CS6
#define A_7 SW1_CS7
#define A_8 SW1_CS8
#define A_9 SW1_CS9
#define A_10 SW1_CS10
#define A_11 SW1_CS11
#define A_12 SW1_CS12
#define B_1 SW2_CS1
#define B_2 SW2_CS2
#define B_3 SW2_CS3
#define B_4 SW2_CS4
#define B_5 SW2_CS5
#define B_6 SW2_CS6
#define B_7 SW2_CS7
#define B_8 SW2_CS8
#define B_9 SW2_CS9
#define B_10 SW2_CS10
#define B_11 SW2_CS11
#define B_12 SW2_CS12
#define C_1 SW3_CS1
#define C_2 SW3_CS2
#define C_3 SW3_CS3
#define C_4 SW3_CS4
#define C_5 SW3_CS5
#define C_6 SW3_CS6
#define C_7 SW3_CS7
#define C_8 SW3_CS8
#define C_9 SW3_CS9
#define C_10 SW3_CS10
#define C_11 SW3_CS11
#define C_12 SW3_CS12
#define D_1 SW4_CS1
#define D_2 SW4_CS2
#define D_3 SW4_CS3
#define D_4 SW4_CS4
#define D_5 SW4_CS5
#define D_6 SW4_CS6
#define D_7 SW4_CS7
#define D_8 SW4_CS8
#define D_9 SW4_CS9
#define D_10 SW4_CS10
#define D_11 SW4_CS11
#define D_12 SW4_CS12
#define E_1 SW5_CS1
#define E_2 SW5_CS2
#define E_3 SW5_CS3
#define E_4 SW5_CS4
#define E_5 SW5_CS5
#define E_6 SW5_CS6
#define E_7 SW5_CS7
#define E_8 SW5_CS8
#define E_9 SW5_CS9
#define E_10 SW5_CS10
#define E_11 SW5_CS11
#define E_12 SW5_CS12
#define F_1 SW6_CS1
#define F_2 SW6_CS2
#define F_3 SW6_CS3
#define F_4 SW6_CS4
#define F_5 SW6_CS5
#define F_6 SW6_CS6
#define F_7 SW6_CS7
#define F_8 SW6_CS8
#define F_9 SW6_CS9
#define F_10 SW6_CS10
#define F_11 SW6_CS11
#define F_12 SW6_CS12
#define G_1 SW7_CS1
#define G_2 SW7_CS2
#define G_3 SW7_CS3
#define G_4 SW7_CS4
#define G_5 SW7_CS5
#define G_6 SW7_CS6
#define G_7 SW7_CS7
#define G_8 SW7_CS8
#define G_9 SW7_CS9
#define G_10 SW7_CS10
#define G_11 SW7_CS11
#define G_12 SW7_CS12
#define H_1 SW8_CS1
#define H_2 SW8_CS2
#define H_3 SW8_CS3
#define H_4 SW8_CS4
#define H_5 SW8_CS5
#define H_6 SW8_CS6
#define H_7 SW8_CS7
#define H_8 SW8_CS8
#define H_9 SW8_CS9
#define H_10 SW8_CS10
#define H_11 SW8_CS11
#define H_12 SW8_CS12
#define I_1 SW9_CS1
#define I_2 SW9_CS2
#define I_3 SW9_CS3
#define I_4 SW9_CS4
#define I_5 SW9_CS5
#define I_6 SW9_CS6
#define I_7 SW9_CS7
#define I_8 SW9_CS8
#define I_9 SW9_CS9
#define I_10 SW9_CS10
#define I_11 SW9_CS11
#define I_12 SW9_CS12
#define J_1 SW10_CS1
#define J_2 SW10_CS2
#define J_3 SW10_CS3
#define J_4 SW10_CS4
#define J_5 SW10_CS5
#define J_6 SW10_CS6
#define J_7 SW10_CS7
#define J_8 SW10_CS8
#define J_9 SW10_CS9
#define J_10 SW10_CS10
#define J_11 SW10_CS11
#define J_12 SW10_CS12
#define K_1 SW11_CS1
#define K_2 SW11_CS2
#define K_3 SW11_CS3
#define K_4 SW11_CS4
#define K_5 SW11_CS5
#define K_6 SW11_CS6
#define K_7 SW11_CS7
#define K_8 SW11_CS8
#define K_9 SW11_CS9
#define K_10 SW11_CS10
#define K_11 SW11_CS11
#define K_12 SW11_CS12
#define L_1 SW12_CS1
#define L_2 SW12_CS2
#define L_3 SW12_CS3
#define L_4 SW12_CS4
#define L_5 SW12_CS5
#define L_6 SW12_CS6
#define L_7 SW12_CS7
#define L_8 SW12_CS8
#define L_9 SW12_CS9
#define L_10 SW12_CS10
#define L_11 SW12_CS11
#define L_12 SW12_CS12

View File

@ -0,0 +1,276 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
*
* 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 "is31fl3741-mono.h"
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3741_PWM_0_REGISTER_COUNT 180
#define IS31FL3741_PWM_1_REGISTER_COUNT 171
#define IS31FL3741_SCALING_0_REGISTER_COUNT 180
#define IS31FL3741_SCALING_1_REGISTER_COUNT 171
#ifndef IS31FL3741_I2C_TIMEOUT
# define IS31FL3741_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3741_I2C_PERSISTENCE
# define IS31FL3741_I2C_PERSISTENCE 0
#endif
#ifndef IS31FL3741_CONFIGURATION
# define IS31FL3741_CONFIGURATION 0x01
#endif
#ifndef IS31FL3741_PWM_FREQUENCY
# define IS31FL3741_PWM_FREQUENCY IS31FL3741_PWM_FREQUENCY_29K_HZ
#endif
#ifndef IS31FL3741_SW_PULLUP
# define IS31FL3741_SW_PULLUP IS31FL3741_PUR_32K_OHM
#endif
#ifndef IS31FL3741_CS_PULLDOWN
# define IS31FL3741_CS_PULLDOWN IS31FL3741_PDR_32K_OHM
#endif
#ifndef IS31FL3741_GLOBAL_CURRENT
# define IS31FL3741_GLOBAL_CURRENT 0xFF
#endif
const uint8_t i2c_addresses[IS31FL3741_DRIVER_COUNT] = {
IS31FL3741_I2C_ADDRESS_1,
#ifdef IS31FL3741_I2C_ADDRESS_2
IS31FL3741_I2C_ADDRESS_2,
# ifdef IS31FL3741_I2C_ADDRESS_3
IS31FL3741_I2C_ADDRESS_3,
# ifdef IS31FL3741_I2C_ADDRESS_4
IS31FL3741_I2C_ADDRESS_4,
# endif
# endif
#endif
};
// These buffers match the IS31FL3741 and IS31FL3741A PWM registers.
// The scaling buffers match the page 2 and 3 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
// probably not worth the extra complexity.
typedef struct is31fl3741_driver_t {
uint8_t pwm_buffer_0[IS31FL3741_PWM_0_REGISTER_COUNT];
uint8_t pwm_buffer_1[IS31FL3741_PWM_1_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t scaling_buffer_0[IS31FL3741_SCALING_0_REGISTER_COUNT];
uint8_t scaling_buffer_1[IS31FL3741_SCALING_1_REGISTER_COUNT];
bool scaling_buffer_dirty;
} PACKED is31fl3741_driver_t;
is31fl3741_driver_t driver_buffers[IS31FL3741_DRIVER_COUNT] = {{
.pwm_buffer_0 = {0},
.pwm_buffer_1 = {0},
.pwm_buffer_dirty = false,
.scaling_buffer_0 = {0},
.scaling_buffer_1 = {0},
.scaling_buffer_dirty = false,
}};
void is31fl3741_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3741_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3741_I2C_PERSISTENCE; i++) {
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3741_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3741_I2C_TIMEOUT);
#endif
}
void is31fl3741_select_page(uint8_t index, uint8_t page) {
is31fl3741_write_register(index, IS31FL3741_REG_COMMAND_WRITE_LOCK, IS31FL3741_COMMAND_WRITE_LOCK_MAGIC);
is31fl3741_write_register(index, IS31FL3741_REG_COMMAND, page);
}
void is31fl3741_write_pwm_buffer(uint8_t index) {
is31fl3741_select_page(index, IS31FL3741_COMMAND_PWM_0);
// Transmit PWM0 registers in 6 transfers of 30 bytes.
// Iterate over the pwm_buffer_0 contents at 30 byte intervals.
for (uint8_t i = 0; i < IS31FL3741_PWM_0_REGISTER_COUNT; i += 30) {
#if IS31FL3741_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < IS31FL3741_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer_0 + i, 30, IS31FL3741_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer_0 + i, 30, IS31FL3741_I2C_TIMEOUT);
#endif
}
is31fl3741_select_page(index, IS31FL3741_COMMAND_PWM_1);
// Transmit PWM1 registers in 9 transfers of 19 bytes.
// Iterate over the pwm_buffer_1 contents at 19 byte intervals.
for (uint8_t i = 0; i < IS31FL3741_PWM_1_REGISTER_COUNT; i += 19) {
#if IS31FL3741_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3741_I2C_PERSISTENCE; i++) {
if (i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer_1 + i, 19, IS31FL3741_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer_1 + i, 19, IS31FL3741_I2C_TIMEOUT);
#endif
}
}
void is31fl3741_init_drivers(void) {
i2c_init();
for (uint8_t i = 0; i < IS31FL3741_DRIVER_COUNT; i++) {
is31fl3741_init(i);
}
for (int i = 0; i < IS31FL3741_LED_COUNT; i++) {
is31fl3741_set_led_control_register(i, true);
}
for (uint8_t i = 0; i < IS31FL3741_DRIVER_COUNT; i++) {
is31fl3741_update_led_control_registers(i);
}
}
void is31fl3741_init(uint8_t index) {
// 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.
is31fl3741_select_page(index, IS31FL3741_COMMAND_FUNCTION);
// Set to Normal operation
is31fl3741_write_register(index, IS31FL3741_FUNCTION_REG_CONFIGURATION, IS31FL3741_CONFIGURATION);
// Set Golbal Current Control Register
is31fl3741_write_register(index, IS31FL3741_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3741_GLOBAL_CURRENT);
// Set Pull up & Down for SWx CSy
is31fl3741_write_register(index, IS31FL3741_FUNCTION_REG_PULLDOWNUP, ((IS31FL3741_CS_PULLDOWN << 4) | IS31FL3741_SW_PULLUP));
// Set PWM frequency
is31fl3741_write_register(index, IS31FL3741_FUNCTION_REG_PWM_FREQUENCY, (IS31FL3741_PWM_FREQUENCY & 0b1111));
// is31fl3741_update_led_scaling_registers(index, 0xFF, 0xFF, 0xFF);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}
uint8_t get_pwm_value(uint8_t driver, uint16_t reg) {
if (reg & 0x100) {
return driver_buffers[driver].pwm_buffer_1[reg & 0xFF];
} else {
return driver_buffers[driver].pwm_buffer_0[reg];
}
}
void set_pwm_value(uint8_t driver, uint16_t reg, uint8_t value) {
if (reg & 0x100) {
driver_buffers[driver].pwm_buffer_1[reg & 0xFF] = value;
} else {
driver_buffers[driver].pwm_buffer_0[reg] = value;
}
}
void is31fl3741_set_value(int index, uint8_t value) {
is31fl3741_led_t led;
if (index >= 0 && index < IS31FL3741_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3741_leds[index]), sizeof(led));
if (get_pwm_value(led.driver, led.v) == value) {
return;
}
set_pwm_value(led.driver, led.v, value);
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
void is31fl3741_set_value_all(uint8_t value) {
for (int i = 0; i < IS31FL3741_LED_COUNT; i++) {
is31fl3741_set_value(i, value);
}
}
void set_scaling_value(uint8_t driver, uint16_t reg, uint8_t value) {
if (reg & 0x100) {
driver_buffers[driver].scaling_buffer_1[reg & 0xFF] = value;
} else {
driver_buffers[driver].scaling_buffer_0[reg] = value;
}
}
void is31fl3741_set_led_control_register(uint8_t index, bool value) {
is31fl3741_led_t led;
memcpy_P(&led, (&g_is31fl3741_leds[index]), sizeof(led));
set_scaling_value(led.driver, led.v, value ? 0xFF : 0x00);
driver_buffers[led.driver].scaling_buffer_dirty = true;
}
void is31fl3741_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3741_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void is31fl3741_set_pwm_buffer(const is31fl3741_led_t *pled, uint8_t value) {
set_pwm_value(pled->driver, pled->v, value);
driver_buffers[pled->driver].pwm_buffer_dirty = true;
}
void is31fl3741_update_led_control_registers(uint8_t index) {
if (driver_buffers[index].scaling_buffer_dirty) {
is31fl3741_select_page(index, IS31FL3741_COMMAND_SCALING_0);
for (uint8_t i = 0; i < IS31FL3741_SCALING_0_REGISTER_COUNT; i++) {
is31fl3741_write_register(index, i, driver_buffers[index].scaling_buffer_0[i]);
}
is31fl3741_select_page(index, IS31FL3741_COMMAND_SCALING_1);
for (uint8_t i = 0; i < IS31FL3741_SCALING_1_REGISTER_COUNT; i++) {
is31fl3741_write_register(index, i, driver_buffers[index].scaling_buffer_1[i]);
}
driver_buffers[index].scaling_buffer_dirty = false;
}
}
void is31fl3741_set_scaling_registers(const is31fl3741_led_t *pled, uint8_t value) {
set_scaling_value(pled->driver, pled->v, value);
driver_buffers[pled->driver].scaling_buffer_dirty = true;
}
void is31fl3741_flush(void) {
for (uint8_t i = 0; i < IS31FL3741_DRIVER_COUNT; i++) {
is31fl3741_update_pwm_buffers(i);
}
}

View File

@ -0,0 +1,887 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
// ======== DEPRECATED DEFINES - DO NOT USE ========
#ifdef ISSI_TIMEOUT
# define IS31FL3741_I2C_TIMEOUT ISSI_TIMEOUT
#endif
#ifdef ISSI_PERSISTENCE
# define IS31FL3741_I2C_PERSISTENCE ISSI_PERSISTENCE
#endif
#ifdef ISSI_CONFIGURATION
# define IS31FL3741_CONFIGURATION ISSI_CONFIGURATION
#endif
#ifdef ISSI_SWPULLUP
# define IS31FL3741_SW_PULLUP ISSI_SWPULLUP
#endif
#ifdef ISSI_CSPULLUP
# define IS31FL3741_CS_PULLDOWN ISSI_CSPULLUP
#endif
#ifdef ISSI_GLOBALCURRENT
# define IS31FL3741_GLOBAL_CURRENT ISSI_GLOBALCURRENT
#endif
#define PUR_0R IS31FL3741_PUR_0_OHM
#define PUR_05KR IS31FL3741_PUR_0K5_OHM
#define PUR_1KR IS31FL3741_PUR_1K_OHM
#define PUR_2KR IS31FL3741_PUR_2K_OHM
#define PUR_4KR IS31FL3741_PUR_4K_OHM
#define PUR_8KR IS31FL3741_PUR_8K_OHM
#define PUR_16KR IS31FL3741_PUR_16K_OHM
#define PUR_32KR IS31FL3741_PUR_32K_OHM
// ========
#define IS31FL3741_REG_INTERRUPT_MASK 0xF0
#define IS31FL3741_REG_INTERRUPT_STATUS 0xF1
#define IS31FL3741_REG_ID 0xFC
#define IS31FL3741_REG_COMMAND 0xFD
#define IS31FL3741_COMMAND_PWM_0 0x00
#define IS31FL3741_COMMAND_PWM_1 0x01
#define IS31FL3741_COMMAND_SCALING_0 0x02
#define IS31FL3741_COMMAND_SCALING_1 0x03
#define IS31FL3741_COMMAND_FUNCTION 0x04
#define IS31FL3741_FUNCTION_REG_CONFIGURATION 0x00
#define IS31FL3741_FUNCTION_REG_GLOBAL_CURRENT 0x01
#define IS31FL3741_FUNCTION_REG_PULLDOWNUP 0x02
#define IS31FL3741_FUNCTION_REG_PWM_FREQUENCY 0x36
#define IS31FL3741_FUNCTION_REG_RESET 0x3F
#define IS31FL3741_REG_COMMAND_WRITE_LOCK 0xFE
#define IS31FL3741_COMMAND_WRITE_LOCK_MAGIC 0xC5
#define IS31FL3741_I2C_ADDRESS_GND 0x30
#define IS31FL3741_I2C_ADDRESS_SCL 0x31
#define IS31FL3741_I2C_ADDRESS_SDA 0x32
#define IS31FL3741_I2C_ADDRESS_VCC 0x33
#if defined(LED_MATRIX_IS31FL3741)
# define IS31FL3741_LED_COUNT LED_MATRIX_LED_COUNT
#endif
#if defined(IS31FL3741_I2C_ADDRESS_4)
# define IS31FL3741_DRIVER_COUNT 4
#elif defined(IS31FL3741_I2C_ADDRESS_3)
# define IS31FL3741_DRIVER_COUNT 3
#elif defined(IS31FL3741_I2C_ADDRESS_2)
# define IS31FL3741_DRIVER_COUNT 2
#elif defined(IS31FL3741_I2C_ADDRESS_1)
# define IS31FL3741_DRIVER_COUNT 1
#endif
typedef struct is31fl3741_led_t {
uint8_t driver : 2;
uint16_t v : 9;
} PACKED is31fl3741_led_t;
extern const is31fl3741_led_t PROGMEM g_is31fl3741_leds[IS31FL3741_LED_COUNT];
void is31fl3741_init_drivers(void);
void is31fl3741_init(uint8_t index);
void is31fl3741_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3741_select_page(uint8_t index, uint8_t page);
void is31fl3741_set_value(int index, uint8_t value);
void is31fl3741_set_value_all(uint8_t value);
void is31fl3741_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 is31fl3741_update_pwm_buffers(uint8_t index);
void is31fl3741_update_led_control_registers(uint8_t index);
void is31fl3741_set_scaling_registers(const is31fl3741_led_t *pled, uint8_t value);
void is31fl3741_set_pwm_buffer(const is31fl3741_led_t *pled, uint8_t value);
void is31fl3741_flush(void);
#define IS31FL3741_PDR_0_OHM 0b000 // No pull-down resistor
#define IS31FL3741_PDR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3741_PDR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3741_PDR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3741_PDR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3741_PDR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3741_PDR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3741_PDR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3741_PUR_0_OHM 0b000 // No pull-up resistor
#define IS31FL3741_PUR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3741_PUR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3741_PUR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3741_PUR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3741_PUR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3741_PUR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3741_PUR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3741_PWM_FREQUENCY_29K_HZ 0b0000
#define IS31FL3741_PWM_FREQUENCY_3K6_HZ 0b0011
#define IS31FL3741_PWM_FREQUENCY_1K8_HZ 0b0111
#define IS31FL3741_PWM_FREQUENCY_900_HZ 0b1011
#define SW1_CS1 0x00
#define SW1_CS2 0x01
#define SW1_CS3 0x02
#define SW1_CS4 0x03
#define SW1_CS5 0x04
#define SW1_CS6 0x05
#define SW1_CS7 0x06
#define SW1_CS8 0x07
#define SW1_CS9 0x08
#define SW1_CS10 0x09
#define SW1_CS11 0x0A
#define SW1_CS12 0x0B
#define SW1_CS13 0x0C
#define SW1_CS14 0x0D
#define SW1_CS15 0x0E
#define SW1_CS16 0x0F
#define SW1_CS17 0x10
#define SW1_CS18 0x11
#define SW1_CS19 0x12
#define SW1_CS20 0x13
#define SW1_CS21 0x14
#define SW1_CS22 0x15
#define SW1_CS23 0x16
#define SW1_CS24 0x17
#define SW1_CS25 0x18
#define SW1_CS26 0x19
#define SW1_CS27 0x1A
#define SW1_CS28 0x1B
#define SW1_CS29 0x1C
#define SW1_CS30 0x1D
#define SW2_CS1 0x1E
#define SW2_CS2 0x1F
#define SW2_CS3 0x20
#define SW2_CS4 0x21
#define SW2_CS5 0x22
#define SW2_CS6 0x23
#define SW2_CS7 0x24
#define SW2_CS8 0x25
#define SW2_CS9 0x26
#define SW2_CS10 0x27
#define SW2_CS11 0x28
#define SW2_CS12 0x29
#define SW2_CS13 0x2A
#define SW2_CS14 0x2B
#define SW2_CS15 0x2C
#define SW2_CS16 0x2D
#define SW2_CS17 0x2E
#define SW2_CS18 0x2F
#define SW2_CS19 0x30
#define SW2_CS20 0x31
#define SW2_CS21 0x32
#define SW2_CS22 0x33
#define SW2_CS23 0x34
#define SW2_CS24 0x35
#define SW2_CS25 0x36
#define SW2_CS26 0x37
#define SW2_CS27 0x38
#define SW2_CS28 0x39
#define SW2_CS29 0x3A
#define SW2_CS30 0x3B
#define SW3_CS1 0x3C
#define SW3_CS2 0x3D
#define SW3_CS3 0x3E
#define SW3_CS4 0x3F
#define SW3_CS5 0x40
#define SW3_CS6 0x41
#define SW3_CS7 0x42
#define SW3_CS8 0x43
#define SW3_CS9 0x44
#define SW3_CS10 0x45
#define SW3_CS11 0x46
#define SW3_CS12 0x47
#define SW3_CS13 0x48
#define SW3_CS14 0x49
#define SW3_CS15 0x4A
#define SW3_CS16 0x4B
#define SW3_CS17 0x4C
#define SW3_CS18 0x4D
#define SW3_CS19 0x4E
#define SW3_CS20 0x4F
#define SW3_CS21 0x50
#define SW3_CS22 0x51
#define SW3_CS23 0x52
#define SW3_CS24 0x53
#define SW3_CS25 0x54
#define SW3_CS26 0x55
#define SW3_CS27 0x56
#define SW3_CS28 0x57
#define SW3_CS29 0x58
#define SW3_CS30 0x59
#define SW4_CS1 0x5A
#define SW4_CS2 0x5B
#define SW4_CS3 0x5C
#define SW4_CS4 0x5D
#define SW4_CS5 0x5E
#define SW4_CS6 0x5F
#define SW4_CS7 0x60
#define SW4_CS8 0x61
#define SW4_CS9 0x62
#define SW4_CS10 0x63
#define SW4_CS11 0x64
#define SW4_CS12 0x65
#define SW4_CS13 0x66
#define SW4_CS14 0x67
#define SW4_CS15 0x68
#define SW4_CS16 0x69
#define SW4_CS17 0x6A
#define SW4_CS18 0x6B
#define SW4_CS19 0x6C
#define SW4_CS20 0x6D
#define SW4_CS21 0x6E
#define SW4_CS22 0x6F
#define SW4_CS23 0x70
#define SW4_CS24 0x71
#define SW4_CS25 0x72
#define SW4_CS26 0x73
#define SW4_CS27 0x74
#define SW4_CS28 0x75
#define SW4_CS29 0x76
#define SW4_CS30 0x77
#define SW5_CS1 0x78
#define SW5_CS2 0x79
#define SW5_CS3 0x7A
#define SW5_CS4 0x7B
#define SW5_CS5 0x7C
#define SW5_CS6 0x7D
#define SW5_CS7 0x7E
#define SW5_CS8 0x7F
#define SW5_CS9 0x80
#define SW5_CS10 0x81
#define SW5_CS11 0x82
#define SW5_CS12 0x83
#define SW5_CS13 0x84
#define SW5_CS14 0x85
#define SW5_CS15 0x86
#define SW5_CS16 0x87
#define SW5_CS17 0x88
#define SW5_CS18 0x89
#define SW5_CS19 0x8A
#define SW5_CS20 0x8B
#define SW5_CS21 0x8C
#define SW5_CS22 0x8D
#define SW5_CS23 0x8E
#define SW5_CS24 0x8F
#define SW5_CS25 0x90
#define SW5_CS26 0x91
#define SW5_CS27 0x92
#define SW5_CS28 0x93
#define SW5_CS29 0x94
#define SW5_CS30 0x95
#define SW6_CS1 0x96
#define SW6_CS2 0x97
#define SW6_CS3 0x98
#define SW6_CS4 0x99
#define SW6_CS5 0x9A
#define SW6_CS6 0x9B
#define SW6_CS7 0x9C
#define SW6_CS8 0x9D
#define SW6_CS9 0x9E
#define SW6_CS10 0x9F
#define SW6_CS11 0xA0
#define SW6_CS12 0xA1
#define SW6_CS13 0xA2
#define SW6_CS14 0xA3
#define SW6_CS15 0xA4
#define SW6_CS16 0xA5
#define SW6_CS17 0xA6
#define SW6_CS18 0xA7
#define SW6_CS19 0xA8
#define SW6_CS20 0xA9
#define SW6_CS21 0xAA
#define SW6_CS22 0xAB
#define SW6_CS23 0xAC
#define SW6_CS24 0xAD
#define SW6_CS25 0xAE
#define SW6_CS26 0xAF
#define SW6_CS27 0xB0
#define SW6_CS28 0xB1
#define SW6_CS29 0xB2
#define SW6_CS30 0xB3
#define SW7_CS1 0x100
#define SW7_CS2 0x101
#define SW7_CS3 0x102
#define SW7_CS4 0x103
#define SW7_CS5 0x104
#define SW7_CS6 0x105
#define SW7_CS7 0x106
#define SW7_CS8 0x107
#define SW7_CS9 0x108
#define SW7_CS10 0x109
#define SW7_CS11 0x10A
#define SW7_CS12 0x10B
#define SW7_CS13 0x10C
#define SW7_CS14 0x10D
#define SW7_CS15 0x10E
#define SW7_CS16 0x10F
#define SW7_CS17 0x110
#define SW7_CS18 0x111
#define SW7_CS19 0x112
#define SW7_CS20 0x113
#define SW7_CS21 0x114
#define SW7_CS22 0x115
#define SW7_CS23 0x116
#define SW7_CS24 0x117
#define SW7_CS25 0x118
#define SW7_CS26 0x119
#define SW7_CS27 0x11A
#define SW7_CS28 0x11B
#define SW7_CS29 0x11C
#define SW7_CS30 0x11D
#define SW8_CS1 0x11E
#define SW8_CS2 0x11F
#define SW8_CS3 0x120
#define SW8_CS4 0x121
#define SW8_CS5 0x122
#define SW8_CS6 0x123
#define SW8_CS7 0x124
#define SW8_CS8 0x125
#define SW8_CS9 0x126
#define SW8_CS10 0x127
#define SW8_CS11 0x128
#define SW8_CS12 0x129
#define SW8_CS13 0x12A
#define SW8_CS14 0x12B
#define SW8_CS15 0x12C
#define SW8_CS16 0x12D
#define SW8_CS17 0x12E
#define SW8_CS18 0x12F
#define SW8_CS19 0x130
#define SW8_CS20 0x131
#define SW8_CS21 0x132
#define SW8_CS22 0x133
#define SW8_CS23 0x134
#define SW8_CS24 0x135
#define SW8_CS25 0x136
#define SW8_CS26 0x137
#define SW8_CS27 0x138
#define SW8_CS28 0x139
#define SW8_CS29 0x13A
#define SW8_CS30 0x13B
#define SW9_CS1 0x13C
#define SW9_CS2 0x13D
#define SW9_CS3 0x13E
#define SW9_CS4 0x13F
#define SW9_CS5 0x140
#define SW9_CS6 0x141
#define SW9_CS7 0x142
#define SW9_CS8 0x143
#define SW9_CS9 0x144
#define SW9_CS10 0x145
#define SW9_CS11 0x146
#define SW9_CS12 0x147
#define SW9_CS13 0x148
#define SW9_CS14 0x149
#define SW9_CS15 0x14A
#define SW9_CS16 0x14B
#define SW9_CS17 0x14C
#define SW9_CS18 0x14D
#define SW9_CS19 0x14E
#define SW9_CS20 0x14F
#define SW9_CS21 0x150
#define SW9_CS22 0x151
#define SW9_CS23 0x152
#define SW9_CS24 0x153
#define SW9_CS25 0x154
#define SW9_CS26 0x155
#define SW9_CS27 0x156
#define SW9_CS28 0x157
#define SW9_CS29 0x158
#define SW9_CS30 0x159
#define SW1_CS31 0x15A
#define SW1_CS32 0x15B
#define SW1_CS33 0x15C
#define SW1_CS34 0x15D
#define SW1_CS35 0x15E
#define SW1_CS36 0x15F
#define SW1_CS37 0x160
#define SW1_CS38 0x161
#define SW1_CS39 0x162
#define SW2_CS31 0x163
#define SW2_CS32 0x164
#define SW2_CS33 0x165
#define SW2_CS34 0x166
#define SW2_CS35 0x167
#define SW2_CS36 0x168
#define SW2_CS37 0x169
#define SW2_CS38 0x16A
#define SW2_CS39 0x16B
#define SW3_CS31 0x16C
#define SW3_CS32 0x16D
#define SW3_CS33 0x16E
#define SW3_CS34 0x16F
#define SW3_CS35 0x170
#define SW3_CS36 0x171
#define SW3_CS37 0x172
#define SW3_CS38 0x173
#define SW3_CS39 0x174
#define SW4_CS31 0x175
#define SW4_CS32 0x176
#define SW4_CS33 0x177
#define SW4_CS34 0x178
#define SW4_CS35 0x179
#define SW4_CS36 0x17A
#define SW4_CS37 0x17B
#define SW4_CS38 0x17C
#define SW4_CS39 0x17D
#define SW5_CS31 0x17E
#define SW5_CS32 0x17F
#define SW5_CS33 0x180
#define SW5_CS34 0x181
#define SW5_CS35 0x182
#define SW5_CS36 0x183
#define SW5_CS37 0x184
#define SW5_CS38 0x185
#define SW5_CS39 0x186
#define SW6_CS31 0x187
#define SW6_CS32 0x188
#define SW6_CS33 0x189
#define SW6_CS34 0x18A
#define SW6_CS35 0x18B
#define SW6_CS36 0x18C
#define SW6_CS37 0x18D
#define SW6_CS38 0x18E
#define SW6_CS39 0x18F
#define SW7_CS31 0x190
#define SW7_CS32 0x191
#define SW7_CS33 0x192
#define SW7_CS34 0x193
#define SW7_CS35 0x194
#define SW7_CS36 0x195
#define SW7_CS37 0x196
#define SW7_CS38 0x197
#define SW7_CS39 0x198
#define SW8_CS31 0x199
#define SW8_CS32 0x19A
#define SW8_CS33 0x19B
#define SW8_CS34 0x19C
#define SW8_CS35 0x19D
#define SW8_CS36 0x19E
#define SW8_CS37 0x19F
#define SW8_CS38 0x1A0
#define SW8_CS39 0x1A1
#define SW9_CS31 0x1A2
#define SW9_CS32 0x1A3
#define SW9_CS33 0x1A4
#define SW9_CS34 0x1A5
#define SW9_CS35 0x1A6
#define SW9_CS36 0x1A7
#define SW9_CS37 0x1A8
#define SW9_CS38 0x1A9
#define SW9_CS39 0x1AA
// DEPRECATED - DO NOT USE
#define CS1_SW1 SW1_CS1
#define CS2_SW1 SW1_CS2
#define CS3_SW1 SW1_CS3
#define CS4_SW1 SW1_CS4
#define CS5_SW1 SW1_CS5
#define CS6_SW1 SW1_CS6
#define CS7_SW1 SW1_CS7
#define CS8_SW1 SW1_CS8
#define CS9_SW1 SW1_CS9
#define CS10_SW1 SW1_CS10
#define CS11_SW1 SW1_CS11
#define CS12_SW1 SW1_CS12
#define CS13_SW1 SW1_CS13
#define CS14_SW1 SW1_CS14
#define CS15_SW1 SW1_CS15
#define CS16_SW1 SW1_CS16
#define CS17_SW1 SW1_CS17
#define CS18_SW1 SW1_CS18
#define CS19_SW1 SW1_CS19
#define CS20_SW1 SW1_CS20
#define CS21_SW1 SW1_CS21
#define CS22_SW1 SW1_CS22
#define CS23_SW1 SW1_CS23
#define CS24_SW1 SW1_CS24
#define CS25_SW1 SW1_CS25
#define CS26_SW1 SW1_CS26
#define CS27_SW1 SW1_CS27
#define CS28_SW1 SW1_CS28
#define CS29_SW1 SW1_CS29
#define CS30_SW1 SW1_CS30
#define CS1_SW2 SW2_CS1
#define CS2_SW2 SW2_CS2
#define CS3_SW2 SW2_CS3
#define CS4_SW2 SW2_CS4
#define CS5_SW2 SW2_CS5
#define CS6_SW2 SW2_CS6
#define CS7_SW2 SW2_CS7
#define CS8_SW2 SW2_CS8
#define CS9_SW2 SW2_CS9
#define CS10_SW2 SW2_CS10
#define CS11_SW2 SW2_CS11
#define CS12_SW2 SW2_CS12
#define CS13_SW2 SW2_CS13
#define CS14_SW2 SW2_CS14
#define CS15_SW2 SW2_CS15
#define CS16_SW2 SW2_CS16
#define CS17_SW2 SW2_CS17
#define CS18_SW2 SW2_CS18
#define CS19_SW2 SW2_CS19
#define CS20_SW2 SW2_CS20
#define CS21_SW2 SW2_CS21
#define CS22_SW2 SW2_CS22
#define CS23_SW2 SW2_CS23
#define CS24_SW2 SW2_CS24
#define CS25_SW2 SW2_CS25
#define CS26_SW2 SW2_CS26
#define CS27_SW2 SW2_CS27
#define CS28_SW2 SW2_CS28
#define CS29_SW2 SW2_CS29
#define CS30_SW2 SW2_CS30
#define CS1_SW3 SW3_CS1
#define CS2_SW3 SW3_CS2
#define CS3_SW3 SW3_CS3
#define CS4_SW3 SW3_CS4
#define CS5_SW3 SW3_CS5
#define CS6_SW3 SW3_CS6
#define CS7_SW3 SW3_CS7
#define CS8_SW3 SW3_CS8
#define CS9_SW3 SW3_CS9
#define CS10_SW3 SW3_CS10
#define CS11_SW3 SW3_CS11
#define CS12_SW3 SW3_CS12
#define CS13_SW3 SW3_CS13
#define CS14_SW3 SW3_CS14
#define CS15_SW3 SW3_CS15
#define CS16_SW3 SW3_CS16
#define CS17_SW3 SW3_CS17
#define CS18_SW3 SW3_CS18
#define CS19_SW3 SW3_CS19
#define CS20_SW3 SW3_CS20
#define CS21_SW3 SW3_CS21
#define CS22_SW3 SW3_CS22
#define CS23_SW3 SW3_CS23
#define CS24_SW3 SW3_CS24
#define CS25_SW3 SW3_CS25
#define CS26_SW3 SW3_CS26
#define CS27_SW3 SW3_CS27
#define CS28_SW3 SW3_CS28
#define CS29_SW3 SW3_CS29
#define CS30_SW3 SW3_CS30
#define CS1_SW4 SW4_CS1
#define CS2_SW4 SW4_CS2
#define CS3_SW4 SW4_CS3
#define CS4_SW4 SW4_CS4
#define CS5_SW4 SW4_CS5
#define CS6_SW4 SW4_CS6
#define CS7_SW4 SW4_CS7
#define CS8_SW4 SW4_CS8
#define CS9_SW4 SW4_CS9
#define CS10_SW4 SW4_CS10
#define CS11_SW4 SW4_CS11
#define CS12_SW4 SW4_CS12
#define CS13_SW4 SW4_CS13
#define CS14_SW4 SW4_CS14
#define CS15_SW4 SW4_CS15
#define CS16_SW4 SW4_CS16
#define CS17_SW4 SW4_CS17
#define CS18_SW4 SW4_CS18
#define CS19_SW4 SW4_CS19
#define CS20_SW4 SW4_CS20
#define CS21_SW4 SW4_CS21
#define CS22_SW4 SW4_CS22
#define CS23_SW4 SW4_CS23
#define CS24_SW4 SW4_CS24
#define CS25_SW4 SW4_CS25
#define CS26_SW4 SW4_CS26
#define CS27_SW4 SW4_CS27
#define CS28_SW4 SW4_CS28
#define CS29_SW4 SW4_CS29
#define CS30_SW4 SW4_CS30
#define CS1_SW5 SW5_CS1
#define CS2_SW5 SW5_CS2
#define CS3_SW5 SW5_CS3
#define CS4_SW5 SW5_CS4
#define CS5_SW5 SW5_CS5
#define CS6_SW5 SW5_CS6
#define CS7_SW5 SW5_CS7
#define CS8_SW5 SW5_CS8
#define CS9_SW5 SW5_CS9
#define CS10_SW5 SW5_CS10
#define CS11_SW5 SW5_CS11
#define CS12_SW5 SW5_CS12
#define CS13_SW5 SW5_CS13
#define CS14_SW5 SW5_CS14
#define CS15_SW5 SW5_CS15
#define CS16_SW5 SW5_CS16
#define CS17_SW5 SW5_CS17
#define CS18_SW5 SW5_CS18
#define CS19_SW5 SW5_CS19
#define CS20_SW5 SW5_CS20
#define CS21_SW5 SW5_CS21
#define CS22_SW5 SW5_CS22
#define CS23_SW5 SW5_CS23
#define CS24_SW5 SW5_CS24
#define CS25_SW5 SW5_CS25
#define CS26_SW5 SW5_CS26
#define CS27_SW5 SW5_CS27
#define CS28_SW5 SW5_CS28
#define CS29_SW5 SW5_CS29
#define CS30_SW5 SW5_CS30
#define CS1_SW6 SW6_CS1
#define CS2_SW6 SW6_CS2
#define CS3_SW6 SW6_CS3
#define CS4_SW6 SW6_CS4
#define CS5_SW6 SW6_CS5
#define CS6_SW6 SW6_CS6
#define CS7_SW6 SW6_CS7
#define CS8_SW6 SW6_CS8
#define CS9_SW6 SW6_CS9
#define CS10_SW6 SW6_CS10
#define CS11_SW6 SW6_CS11
#define CS12_SW6 SW6_CS12
#define CS13_SW6 SW6_CS13
#define CS14_SW6 SW6_CS14
#define CS15_SW6 SW6_CS15
#define CS16_SW6 SW6_CS16
#define CS17_SW6 SW6_CS17
#define CS18_SW6 SW6_CS18
#define CS19_SW6 SW6_CS19
#define CS20_SW6 SW6_CS20
#define CS21_SW6 SW6_CS21
#define CS22_SW6 SW6_CS22
#define CS23_SW6 SW6_CS23
#define CS24_SW6 SW6_CS24
#define CS25_SW6 SW6_CS25
#define CS26_SW6 SW6_CS26
#define CS27_SW6 SW6_CS27
#define CS28_SW6 SW6_CS28
#define CS29_SW6 SW6_CS29
#define CS30_SW6 SW6_CS30
#define CS1_SW7 SW7_CS1
#define CS2_SW7 SW7_CS2
#define CS3_SW7 SW7_CS3
#define CS4_SW7 SW7_CS4
#define CS5_SW7 SW7_CS5
#define CS6_SW7 SW7_CS6
#define CS7_SW7 SW7_CS7
#define CS8_SW7 SW7_CS8
#define CS9_SW7 SW7_CS9
#define CS10_SW7 SW7_CS10
#define CS11_SW7 SW7_CS11
#define CS12_SW7 SW7_CS12
#define CS13_SW7 SW7_CS13
#define CS14_SW7 SW7_CS14
#define CS15_SW7 SW7_CS15
#define CS16_SW7 SW7_CS16
#define CS17_SW7 SW7_CS17
#define CS18_SW7 SW7_CS18
#define CS19_SW7 SW7_CS19
#define CS20_SW7 SW7_CS20
#define CS21_SW7 SW7_CS21
#define CS22_SW7 SW7_CS22
#define CS23_SW7 SW7_CS23
#define CS24_SW7 SW7_CS24
#define CS25_SW7 SW7_CS25
#define CS26_SW7 SW7_CS26
#define CS27_SW7 SW7_CS27
#define CS28_SW7 SW7_CS28
#define CS29_SW7 SW7_CS29
#define CS30_SW7 SW7_CS30
#define CS1_SW8 SW8_CS1
#define CS2_SW8 SW8_CS2
#define CS3_SW8 SW8_CS3
#define CS4_SW8 SW8_CS4
#define CS5_SW8 SW8_CS5
#define CS6_SW8 SW8_CS6
#define CS7_SW8 SW8_CS7
#define CS8_SW8 SW8_CS8
#define CS9_SW8 SW8_CS9
#define CS10_SW8 SW8_CS10
#define CS11_SW8 SW8_CS11
#define CS12_SW8 SW8_CS12
#define CS13_SW8 SW8_CS13
#define CS14_SW8 SW8_CS14
#define CS15_SW8 SW8_CS15
#define CS16_SW8 SW8_CS16
#define CS17_SW8 SW8_CS17
#define CS18_SW8 SW8_CS18
#define CS19_SW8 SW8_CS19
#define CS20_SW8 SW8_CS20
#define CS21_SW8 SW8_CS21
#define CS22_SW8 SW8_CS22
#define CS23_SW8 SW8_CS23
#define CS24_SW8 SW8_CS24
#define CS25_SW8 SW8_CS25
#define CS26_SW8 SW8_CS26
#define CS27_SW8 SW8_CS27
#define CS28_SW8 SW8_CS28
#define CS29_SW8 SW8_CS29
#define CS30_SW8 SW8_CS30
#define CS1_SW9 SW9_CS1
#define CS2_SW9 SW9_CS2
#define CS3_SW9 SW9_CS3
#define CS4_SW9 SW9_CS4
#define CS5_SW9 SW9_CS5
#define CS6_SW9 SW9_CS6
#define CS7_SW9 SW9_CS7
#define CS8_SW9 SW9_CS8
#define CS9_SW9 SW9_CS9
#define CS10_SW9 SW9_CS10
#define CS11_SW9 SW9_CS11
#define CS12_SW9 SW9_CS12
#define CS13_SW9 SW9_CS13
#define CS14_SW9 SW9_CS14
#define CS15_SW9 SW9_CS15
#define CS16_SW9 SW9_CS16
#define CS17_SW9 SW9_CS17
#define CS18_SW9 SW9_CS18
#define CS19_SW9 SW9_CS19
#define CS20_SW9 SW9_CS20
#define CS21_SW9 SW9_CS21
#define CS22_SW9 SW9_CS22
#define CS23_SW9 SW9_CS23
#define CS24_SW9 SW9_CS24
#define CS25_SW9 SW9_CS25
#define CS26_SW9 SW9_CS26
#define CS27_SW9 SW9_CS27
#define CS28_SW9 SW9_CS28
#define CS29_SW9 SW9_CS29
#define CS30_SW9 SW9_CS30
#define CS31_SW1 SW1_CS31
#define CS32_SW1 SW1_CS32
#define CS33_SW1 SW1_CS33
#define CS34_SW1 SW1_CS34
#define CS35_SW1 SW1_CS35
#define CS36_SW1 SW1_CS36
#define CS37_SW1 SW1_CS37
#define CS38_SW1 SW1_CS38
#define CS39_SW1 SW1_CS39
#define CS31_SW2 SW2_CS31
#define CS32_SW2 SW2_CS32
#define CS33_SW2 SW2_CS33
#define CS34_SW2 SW2_CS34
#define CS35_SW2 SW2_CS35
#define CS36_SW2 SW2_CS36
#define CS37_SW2 SW2_CS37
#define CS38_SW2 SW2_CS38
#define CS39_SW2 SW2_CS39
#define CS31_SW3 SW3_CS31
#define CS32_SW3 SW3_CS32
#define CS33_SW3 SW3_CS33
#define CS34_SW3 SW3_CS34
#define CS35_SW3 SW3_CS35
#define CS36_SW3 SW3_CS36
#define CS37_SW3 SW3_CS37
#define CS38_SW3 SW3_CS38
#define CS39_SW3 SW3_CS39
#define CS31_SW4 SW4_CS31
#define CS32_SW4 SW4_CS32
#define CS33_SW4 SW4_CS33
#define CS34_SW4 SW4_CS34
#define CS35_SW4 SW4_CS35
#define CS36_SW4 SW4_CS36
#define CS37_SW4 SW4_CS37
#define CS38_SW4 SW4_CS38
#define CS39_SW4 SW4_CS39
#define CS31_SW5 SW5_CS31
#define CS32_SW5 SW5_CS32
#define CS33_SW5 SW5_CS33
#define CS34_SW5 SW5_CS34
#define CS35_SW5 SW5_CS35
#define CS36_SW5 SW5_CS36
#define CS37_SW5 SW5_CS37
#define CS38_SW5 SW5_CS38
#define CS39_SW5 SW5_CS39
#define CS31_SW6 SW6_CS31
#define CS32_SW6 SW6_CS32
#define CS33_SW6 SW6_CS33
#define CS34_SW6 SW6_CS34
#define CS35_SW6 SW6_CS35
#define CS36_SW6 SW6_CS36
#define CS37_SW6 SW6_CS37
#define CS38_SW6 SW6_CS38
#define CS39_SW6 SW6_CS39
#define CS31_SW7 SW7_CS31
#define CS32_SW7 SW7_CS32
#define CS33_SW7 SW7_CS33
#define CS34_SW7 SW7_CS34
#define CS35_SW7 SW7_CS35
#define CS36_SW7 SW7_CS36
#define CS37_SW7 SW7_CS37
#define CS38_SW7 SW7_CS38
#define CS39_SW7 SW7_CS39
#define CS31_SW8 SW8_CS31
#define CS32_SW8 SW8_CS32
#define CS33_SW8 SW8_CS33
#define CS34_SW8 SW8_CS34
#define CS35_SW8 SW8_CS35
#define CS36_SW8 SW8_CS36
#define CS37_SW8 SW8_CS37
#define CS38_SW8 SW8_CS38
#define CS39_SW8 SW8_CS39
#define CS31_SW9 SW9_CS31
#define CS32_SW9 SW9_CS32
#define CS33_SW9 SW9_CS33
#define CS34_SW9 SW9_CS34
#define CS35_SW9 SW9_CS35
#define CS36_SW9 SW9_CS36
#define CS37_SW9 SW9_CS37
#define CS38_SW9 SW9_CS38
#define CS39_SW9 SW9_CS39

View File

@ -1,271 +0,0 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
*
* 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 "is31fl3741-simple.h"
#include <string.h>
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3741_PWM_REGISTER_COUNT 351
#define IS31FL3741_SCALING_REGISTER_COUNT 351
#ifndef IS31FL3741_I2C_TIMEOUT
# define IS31FL3741_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3741_I2C_PERSISTENCE
# define IS31FL3741_I2C_PERSISTENCE 0
#endif
#ifndef IS31FL3741_CONFIGURATION
# define IS31FL3741_CONFIGURATION 0x01
#endif
#ifndef IS31FL3741_PWM_FREQUENCY
# define IS31FL3741_PWM_FREQUENCY IS31FL3741_PWM_FREQUENCY_29K_HZ
#endif
#ifndef IS31FL3741_SW_PULLUP
# define IS31FL3741_SW_PULLUP IS31FL3741_PUR_32K_OHM
#endif
#ifndef IS31FL3741_CS_PULLDOWN
# define IS31FL3741_CS_PULLDOWN IS31FL3741_PDR_32K_OHM
#endif
#ifndef IS31FL3741_GLOBAL_CURRENT
# define IS31FL3741_GLOBAL_CURRENT 0xFF
#endif
uint8_t i2c_transfer_buffer[20] = {0xFF};
// These buffers match the IS31FL3741 and IS31FL3741A PWM registers.
// The scaling buffers match the page 2 and 3 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
// probably not worth the extra complexity.
uint8_t g_pwm_buffer[IS31FL3741_DRIVER_COUNT][IS31FL3741_PWM_REGISTER_COUNT];
bool g_pwm_buffer_update_required[IS31FL3741_DRIVER_COUNT] = {false};
bool g_scaling_registers_update_required[IS31FL3741_DRIVER_COUNT] = {false};
uint8_t g_scaling_registers[IS31FL3741_DRIVER_COUNT][IS31FL3741_SCALING_REGISTER_COUNT];
void is31fl3741_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
i2c_transfer_buffer[0] = reg;
i2c_transfer_buffer[1] = data;
#if IS31FL3741_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3741_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3741_I2C_TIMEOUT) == 0) break;
}
#else
i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3741_I2C_TIMEOUT);
#endif
}
void is31fl3741_select_page(uint8_t addr, uint8_t page) {
is31fl3741_write_register(addr, IS31FL3741_REG_COMMAND_WRITE_LOCK, IS31FL3741_COMMAND_WRITE_LOCK_MAGIC);
is31fl3741_write_register(addr, IS31FL3741_REG_COMMAND, page);
}
bool is31fl3741_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
// Assume page 0 is already selected
for (int i = 0; i < 342; i += 18) {
if (i == 180) {
is31fl3741_select_page(addr, IS31FL3741_COMMAND_PWM_1);
}
i2c_transfer_buffer[0] = i % 180;
memcpy(i2c_transfer_buffer + 1, pwm_buffer + i, 18);
#if IS31FL3741_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3741_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 19, IS31FL3741_I2C_TIMEOUT) != 0) {
return false;
}
}
#else
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 19, IS31FL3741_I2C_TIMEOUT) != 0) {
return false;
}
#endif
}
// transfer the left cause the total number is 351
i2c_transfer_buffer[0] = 162;
memcpy(i2c_transfer_buffer + 1, pwm_buffer + 342, 9);
#if IS31FL3741_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3741_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 10, IS31FL3741_I2C_TIMEOUT) != 0) {
return false;
}
}
#else
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 10, IS31FL3741_I2C_TIMEOUT) != 0) {
return false;
}
#endif
return true;
}
void is31fl3741_init_drivers(void) {
i2c_init();
is31fl3741_init(IS31FL3741_I2C_ADDRESS_1);
#if defined(IS31FL3741_I2C_ADDRESS_2)
is31fl3741_init(IS31FL3741_I2C_ADDRESS_2);
# if defined(IS31FL3741_I2C_ADDRESS_3)
is31fl3741_init(IS31FL3741_I2C_ADDRESS_3);
# if defined(IS31FL3741_I2C_ADDRESS_4)
is31fl3741_init(IS31FL3741_I2C_ADDRESS_4);
# endif
# endif
#endif
for (int i = 0; i < IS31FL3741_LED_COUNT; i++) {
is31fl3741_set_led_control_register(i, true);
}
is31fl3741_update_led_control_registers(IS31FL3741_I2C_ADDRESS_1, 0);
#if defined(IS31FL3741_I2C_ADDRESS_2)
is31fl3741_update_led_control_registers(IS31FL3741_I2C_ADDRESS_2, 1);
# if defined(IS31FL3741_I2C_ADDRESS_3)
is31fl3741_update_led_control_registers(IS31FL3741_I2C_ADDRESS_3, 2);
# if defined(IS31FL3741_I2C_ADDRESS_4)
is31fl3741_update_led_control_registers(IS31FL3741_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
}
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,
// then disable software shutdown.
// Unlock the command register.
is31fl3741_select_page(addr, IS31FL3741_COMMAND_FUNCTION);
// Set to Normal operation
is31fl3741_write_register(addr, IS31FL3741_FUNCTION_REG_CONFIGURATION, IS31FL3741_CONFIGURATION);
// Set Golbal Current Control Register
is31fl3741_write_register(addr, IS31FL3741_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3741_GLOBAL_CURRENT);
// Set Pull up & Down for SWx CSy
is31fl3741_write_register(addr, IS31FL3741_FUNCTION_REG_PULLDOWNUP, ((IS31FL3741_CS_PULLDOWN << 4) | IS31FL3741_SW_PULLUP));
// Set PWM frequency
is31fl3741_write_register(addr, IS31FL3741_FUNCTION_REG_PWM_FREQUENCY, (IS31FL3741_PWM_FREQUENCY & 0b1111));
// is31fl3741_update_led_scaling_registers(addr, 0xFF, 0xFF, 0xFF);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}
void is31fl3741_set_value(int index, uint8_t value) {
is31fl3741_led_t led;
if (index >= 0 && index < IS31FL3741_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3741_leds[index]), sizeof(led));
if (g_pwm_buffer[led.driver][led.v] == value) {
return;
}
g_pwm_buffer_update_required[led.driver] = true;
g_pwm_buffer[led.driver][led.v] = value;
}
}
void is31fl3741_set_value_all(uint8_t value) {
for (int i = 0; i < IS31FL3741_LED_COUNT; i++) {
is31fl3741_set_value(i, value);
}
}
void is31fl3741_set_led_control_register(uint8_t index, bool value) {
is31fl3741_led_t led;
memcpy_P(&led, (&g_is31fl3741_leds[index]), sizeof(led));
if (value) {
g_scaling_registers[led.driver][led.v] = 0xFF;
} else {
g_scaling_registers[led.driver][led.v] = 0x00;
}
g_scaling_registers_update_required[led.driver] = true;
}
void is31fl3741_update_pwm_buffers(uint8_t addr, uint8_t index) {
if (g_pwm_buffer_update_required[index]) {
is31fl3741_select_page(addr, IS31FL3741_COMMAND_PWM_0);
is31fl3741_write_pwm_buffer(addr, g_pwm_buffer[index]);
}
g_pwm_buffer_update_required[index] = false;
}
void is31fl3741_set_pwm_buffer(const is31fl3741_led_t *pled, uint8_t value) {
g_pwm_buffer[pled->driver][pled->v] = value;
g_pwm_buffer_update_required[pled->driver] = true;
}
void is31fl3741_update_led_control_registers(uint8_t addr, uint8_t index) {
if (g_scaling_registers_update_required[index]) {
is31fl3741_select_page(addr, IS31FL3741_COMMAND_SCALING_0);
// CS1_SW1 to CS30_SW6 are on page 2
for (int i = CS1_SW1; i <= CS30_SW6; ++i) {
is31fl3741_write_register(addr, i, g_scaling_registers[index][i]);
}
is31fl3741_select_page(addr, IS31FL3741_COMMAND_SCALING_1);
// CS1_SW7 to CS39_SW9 are on page 3
for (int i = CS1_SW7; i <= CS39_SW9; ++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 is31fl3741_led_t *pled, uint8_t value) {
g_scaling_registers[pled->driver][pled->v] = value;
g_scaling_registers_update_required[pled->driver] = true;
}
void is31fl3741_flush(void) {
is31fl3741_update_pwm_buffers(IS31FL3741_I2C_ADDRESS_1, 0);
#if defined(IS31FL3741_I2C_ADDRESS_2)
is31fl3741_update_pwm_buffers(IS31FL3741_I2C_ADDRESS_2, 1);
# if defined(IS31FL3741_I2C_ADDRESS_3)
is31fl3741_update_pwm_buffers(IS31FL3741_I2C_ADDRESS_3, 2);
# if defined(IS31FL3741_I2C_ADDRESS_4)
is31fl3741_update_pwm_buffers(IS31FL3741_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
}

View File

@ -1,517 +0,0 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
// ======== DEPRECATED DEFINES - DO NOT USE ========
#ifdef ISSI_TIMEOUT
# define IS31FL3741_I2C_TIMEOUT ISSI_TIMEOUT
#endif
#ifdef ISSI_PERSISTENCE
# define IS31FL3741_I2C_PERSISTENCE ISSI_PERSISTENCE
#endif
#ifdef ISSI_CONFIGURATION
# define IS31FL3741_CONFIGURATION ISSI_CONFIGURATION
#endif
#ifdef ISSI_SWPULLUP
# define IS31FL3741_SW_PULLUP ISSI_SWPULLUP
#endif
#ifdef ISSI_CSPULLUP
# define IS31FL3741_CS_PULLDOWN ISSI_CSPULLUP
#endif
#ifdef ISSI_GLOBALCURRENT
# define IS31FL3741_GLOBAL_CURRENT ISSI_GLOBALCURRENT
#endif
#define PUR_0R IS31FL3741_PUR_0_OHM
#define PUR_05KR IS31FL3741_PUR_0K5_OHM
#define PUR_1KR IS31FL3741_PUR_1K_OHM
#define PUR_2KR IS31FL3741_PUR_2K_OHM
#define PUR_4KR IS31FL3741_PUR_4K_OHM
#define PUR_8KR IS31FL3741_PUR_8K_OHM
#define PUR_16KR IS31FL3741_PUR_16K_OHM
#define PUR_32KR IS31FL3741_PUR_32K_OHM
// ========
#define IS31FL3741_REG_INTERRUPT_MASK 0xF0
#define IS31FL3741_REG_INTERRUPT_STATUS 0xF1
#define IS31FL3741_REG_ID 0xFC
#define IS31FL3741_REG_COMMAND 0xFD
#define IS31FL3741_COMMAND_PWM_0 0x00
#define IS31FL3741_COMMAND_PWM_1 0x01
#define IS31FL3741_COMMAND_SCALING_0 0x02
#define IS31FL3741_COMMAND_SCALING_1 0x03
#define IS31FL3741_COMMAND_FUNCTION 0x04
#define IS31FL3741_FUNCTION_REG_CONFIGURATION 0x00
#define IS31FL3741_FUNCTION_REG_GLOBAL_CURRENT 0x01
#define IS31FL3741_FUNCTION_REG_PULLDOWNUP 0x02
#define IS31FL3741_FUNCTION_REG_PWM_FREQUENCY 0x36
#define IS31FL3741_FUNCTION_REG_RESET 0x3F
#define IS31FL3741_REG_COMMAND_WRITE_LOCK 0xFE
#define IS31FL3741_COMMAND_WRITE_LOCK_MAGIC 0xC5
#define IS31FL3741_I2C_ADDRESS_GND 0x30
#define IS31FL3741_I2C_ADDRESS_SCL 0x31
#define IS31FL3741_I2C_ADDRESS_SDA 0x32
#define IS31FL3741_I2C_ADDRESS_VCC 0x33
#if defined(LED_MATRIX_IS31FL3741)
# define IS31FL3741_LED_COUNT LED_MATRIX_LED_COUNT
#endif
#if defined(IS31FL3741_I2C_ADDRESS_4)
# define IS31FL3741_DRIVER_COUNT 4
#elif defined(IS31FL3741_I2C_ADDRESS_3)
# define IS31FL3741_DRIVER_COUNT 3
#elif defined(IS31FL3741_I2C_ADDRESS_2)
# define IS31FL3741_DRIVER_COUNT 2
#elif defined(IS31FL3741_I2C_ADDRESS_1)
# define IS31FL3741_DRIVER_COUNT 1
#endif
typedef struct is31fl3741_led_t {
uint8_t driver : 2;
uint16_t v : 9;
} PACKED is31fl3741_led_t;
extern const is31fl3741_led_t PROGMEM g_is31fl3741_leds[IS31FL3741_LED_COUNT];
void is31fl3741_init_drivers(void);
void is31fl3741_init(uint8_t addr);
void is31fl3741_write_register(uint8_t addr, uint8_t reg, uint8_t data);
void is31fl3741_select_page(uint8_t addr, uint8_t page);
bool is31fl3741_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
void is31fl3741_set_value(int index, uint8_t value);
void is31fl3741_set_value_all(uint8_t value);
void is31fl3741_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 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 is31fl3741_led_t *pled, uint8_t value);
void is31fl3741_set_pwm_buffer(const is31fl3741_led *pled, uint8_t value);
void is31fl3741_flush(void);
#define IS31FL3741_PDR_0_OHM 0b000 // No pull-down resistor
#define IS31FL3741_PDR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3741_PDR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3741_PDR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3741_PDR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3741_PDR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3741_PDR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3741_PDR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3741_PUR_0_OHM 0b000 // No pull-up resistor
#define IS31FL3741_PUR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3741_PUR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3741_PUR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3741_PUR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3741_PUR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3741_PUR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3741_PUR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3741_PWM_FREQUENCY_29K_HZ 0b0000
#define IS31FL3741_PWM_FREQUENCY_3K6_HZ 0b0011
#define IS31FL3741_PWM_FREQUENCY_1K8_HZ 0b0111
#define IS31FL3741_PWM_FREQUENCY_900_HZ 0b1011
#define CS1_SW1 0x00
#define CS2_SW1 0x01
#define CS3_SW1 0x02
#define CS4_SW1 0x03
#define CS5_SW1 0x04
#define CS6_SW1 0x05
#define CS7_SW1 0x06
#define CS8_SW1 0x07
#define CS9_SW1 0x08
#define CS10_SW1 0x09
#define CS11_SW1 0x0A
#define CS12_SW1 0x0B
#define CS13_SW1 0x0C
#define CS14_SW1 0x0D
#define CS15_SW1 0x0E
#define CS16_SW1 0x0F
#define CS17_SW1 0x10
#define CS18_SW1 0x11
#define CS19_SW1 0x12
#define CS20_SW1 0x13
#define CS21_SW1 0x14
#define CS22_SW1 0x15
#define CS23_SW1 0x16
#define CS24_SW1 0x17
#define CS25_SW1 0x18
#define CS26_SW1 0x19
#define CS27_SW1 0x1A
#define CS28_SW1 0x1B
#define CS29_SW1 0x1C
#define CS30_SW1 0x1D
#define CS1_SW2 0x1E
#define CS2_SW2 0x1F
#define CS3_SW2 0x20
#define CS4_SW2 0x21
#define CS5_SW2 0x22
#define CS6_SW2 0x23
#define CS7_SW2 0x24
#define CS8_SW2 0x25
#define CS9_SW2 0x26
#define CS10_SW2 0x27
#define CS11_SW2 0x28
#define CS12_SW2 0x29
#define CS13_SW2 0x2A
#define CS14_SW2 0x2B
#define CS15_SW2 0x2C
#define CS16_SW2 0x2D
#define CS17_SW2 0x2E
#define CS18_SW2 0x2F
#define CS19_SW2 0x30
#define CS20_SW2 0x31
#define CS21_SW2 0x32
#define CS22_SW2 0x33
#define CS23_SW2 0x34
#define CS24_SW2 0x35
#define CS25_SW2 0x36
#define CS26_SW2 0x37
#define CS27_SW2 0x38
#define CS28_SW2 0x39
#define CS29_SW2 0x3A
#define CS30_SW2 0x3B
#define CS1_SW3 0x3C
#define CS2_SW3 0x3D
#define CS3_SW3 0x3E
#define CS4_SW3 0x3F
#define CS5_SW3 0x40
#define CS6_SW3 0x41
#define CS7_SW3 0x42
#define CS8_SW3 0x43
#define CS9_SW3 0x44
#define CS10_SW3 0x45
#define CS11_SW3 0x46
#define CS12_SW3 0x47
#define CS13_SW3 0x48
#define CS14_SW3 0x49
#define CS15_SW3 0x4A
#define CS16_SW3 0x4B
#define CS17_SW3 0x4C
#define CS18_SW3 0x4D
#define CS19_SW3 0x4E
#define CS20_SW3 0x4F
#define CS21_SW3 0x50
#define CS22_SW3 0x51
#define CS23_SW3 0x52
#define CS24_SW3 0x53
#define CS25_SW3 0x54
#define CS26_SW3 0x55
#define CS27_SW3 0x56
#define CS28_SW3 0x57
#define CS29_SW3 0x58
#define CS30_SW3 0x59
#define CS1_SW4 0x5A
#define CS2_SW4 0x5B
#define CS3_SW4 0x5C
#define CS4_SW4 0x5D
#define CS5_SW4 0x5E
#define CS6_SW4 0x5F
#define CS7_SW4 0x60
#define CS8_SW4 0x61
#define CS9_SW4 0x62
#define CS10_SW4 0x63
#define CS11_SW4 0x64
#define CS12_SW4 0x65
#define CS13_SW4 0x66
#define CS14_SW4 0x67
#define CS15_SW4 0x68
#define CS16_SW4 0x69
#define CS17_SW4 0x6A
#define CS18_SW4 0x6B
#define CS19_SW4 0x6C
#define CS20_SW4 0x6D
#define CS21_SW4 0x6E
#define CS22_SW4 0x6F
#define CS23_SW4 0x70
#define CS24_SW4 0x71
#define CS25_SW4 0x72
#define CS26_SW4 0x73
#define CS27_SW4 0x74
#define CS28_SW4 0x75
#define CS29_SW4 0x76
#define CS30_SW4 0x77
#define CS1_SW5 0x78
#define CS2_SW5 0x79
#define CS3_SW5 0x7A
#define CS4_SW5 0x7B
#define CS5_SW5 0x7C
#define CS6_SW5 0x7D
#define CS7_SW5 0x7E
#define CS8_SW5 0x7F
#define CS9_SW5 0x80
#define CS10_SW5 0x81
#define CS11_SW5 0x82
#define CS12_SW5 0x83
#define CS13_SW5 0x84
#define CS14_SW5 0x85
#define CS15_SW5 0x86
#define CS16_SW5 0x87
#define CS17_SW5 0x88
#define CS18_SW5 0x89
#define CS19_SW5 0x8A
#define CS20_SW5 0x8B
#define CS21_SW5 0x8C
#define CS22_SW5 0x8D
#define CS23_SW5 0x8E
#define CS24_SW5 0x8F
#define CS25_SW5 0x90
#define CS26_SW5 0x91
#define CS27_SW5 0x92
#define CS28_SW5 0x93
#define CS29_SW5 0x94
#define CS30_SW5 0x95
#define CS1_SW6 0x96
#define CS2_SW6 0x97
#define CS3_SW6 0x98
#define CS4_SW6 0x99
#define CS5_SW6 0x9A
#define CS6_SW6 0x9B
#define CS7_SW6 0x9C
#define CS8_SW6 0x9D
#define CS9_SW6 0x9E
#define CS10_SW6 0x9F
#define CS11_SW6 0xA0
#define CS12_SW6 0xA1
#define CS13_SW6 0xA2
#define CS14_SW6 0xA3
#define CS15_SW6 0xA4
#define CS16_SW6 0xA5
#define CS17_SW6 0xA6
#define CS18_SW6 0xA7
#define CS19_SW6 0xA8
#define CS20_SW6 0xA9
#define CS21_SW6 0xAA
#define CS22_SW6 0xAB
#define CS23_SW6 0xAC
#define CS24_SW6 0xAD
#define CS25_SW6 0xAE
#define CS26_SW6 0xAF
#define CS27_SW6 0xB0
#define CS28_SW6 0xB1
#define CS29_SW6 0xB2
#define CS30_SW6 0xB3
#define CS1_SW7 0xB4
#define CS2_SW7 0xB5
#define CS3_SW7 0xB6
#define CS4_SW7 0xB7
#define CS5_SW7 0xB8
#define CS6_SW7 0xB9
#define CS7_SW7 0xBA
#define CS8_SW7 0xBB
#define CS9_SW7 0xBC
#define CS10_SW7 0xBD
#define CS11_SW7 0xBE
#define CS12_SW7 0xBF
#define CS13_SW7 0xC0
#define CS14_SW7 0xC1
#define CS15_SW7 0xC2
#define CS16_SW7 0xC3
#define CS17_SW7 0xC4
#define CS18_SW7 0xC5
#define CS19_SW7 0xC6
#define CS20_SW7 0xC7
#define CS21_SW7 0xC8
#define CS22_SW7 0xC9
#define CS23_SW7 0xCA
#define CS24_SW7 0xCB
#define CS25_SW7 0xCC
#define CS26_SW7 0xCD
#define CS27_SW7 0xCE
#define CS28_SW7 0xCF
#define CS29_SW7 0xD0
#define CS30_SW7 0xD1
#define CS1_SW8 0xD2
#define CS2_SW8 0xD3
#define CS3_SW8 0xD4
#define CS4_SW8 0xD5
#define CS5_SW8 0xD6
#define CS6_SW8 0xD7
#define CS7_SW8 0xD8
#define CS8_SW8 0xD9
#define CS9_SW8 0xDA
#define CS10_SW8 0xDB
#define CS11_SW8 0xDC
#define CS12_SW8 0xDD
#define CS13_SW8 0xDE
#define CS14_SW8 0xDF
#define CS15_SW8 0xE0
#define CS16_SW8 0xE1
#define CS17_SW8 0xE2
#define CS18_SW8 0xE3
#define CS19_SW8 0xE4
#define CS20_SW8 0xE5
#define CS21_SW8 0xE6
#define CS22_SW8 0xE7
#define CS23_SW8 0xE8
#define CS24_SW8 0xE9
#define CS25_SW8 0xEA
#define CS26_SW8 0xEB
#define CS27_SW8 0xEC
#define CS28_SW8 0xED
#define CS29_SW8 0xEE
#define CS30_SW8 0xEF
#define CS1_SW9 0xF0
#define CS2_SW9 0xF1
#define CS3_SW9 0xF2
#define CS4_SW9 0xF3
#define CS5_SW9 0xF4
#define CS6_SW9 0xF5
#define CS7_SW9 0xF6
#define CS8_SW9 0xF7
#define CS9_SW9 0xF8
#define CS10_SW9 0xF9
#define CS11_SW9 0xFA
#define CS12_SW9 0xFB
#define CS13_SW9 0xFC
#define CS14_SW9 0xFD
#define CS15_SW9 0xFE
#define CS16_SW9 0xFF
#define CS17_SW9 0x100
#define CS18_SW9 0x101
#define CS19_SW9 0x102
#define CS20_SW9 0x103
#define CS21_SW9 0x104
#define CS22_SW9 0x105
#define CS23_SW9 0x106
#define CS24_SW9 0x107
#define CS25_SW9 0x108
#define CS26_SW9 0x109
#define CS27_SW9 0x10A
#define CS28_SW9 0x10B
#define CS29_SW9 0x10C
#define CS30_SW9 0x10D
#define CS31_SW1 0x10E
#define CS32_SW1 0x10F
#define CS33_SW1 0x110
#define CS34_SW1 0x111
#define CS35_SW1 0x112
#define CS36_SW1 0x113
#define CS37_SW1 0x114
#define CS38_SW1 0x115
#define CS39_SW1 0x116
#define CS31_SW2 0x117
#define CS32_SW2 0x118
#define CS33_SW2 0x119
#define CS34_SW2 0x11A
#define CS35_SW2 0x11B
#define CS36_SW2 0x11C
#define CS37_SW2 0x11D
#define CS38_SW2 0x11E
#define CS39_SW2 0x11F
#define CS31_SW3 0x120
#define CS32_SW3 0x121
#define CS33_SW3 0x122
#define CS34_SW3 0x123
#define CS35_SW3 0x124
#define CS36_SW3 0x125
#define CS37_SW3 0x126
#define CS38_SW3 0x127
#define CS39_SW3 0x128
#define CS31_SW4 0x129
#define CS32_SW4 0x12A
#define CS33_SW4 0x12B
#define CS34_SW4 0x12C
#define CS35_SW4 0x12D
#define CS36_SW4 0x12E
#define CS37_SW4 0x12F
#define CS38_SW4 0x130
#define CS39_SW4 0x131
#define CS31_SW5 0x132
#define CS32_SW5 0x133
#define CS33_SW5 0x134
#define CS34_SW5 0x135
#define CS35_SW5 0x136
#define CS36_SW5 0x137
#define CS37_SW5 0x138
#define CS38_SW5 0x139
#define CS39_SW5 0x13A
#define CS31_SW6 0x13B
#define CS32_SW6 0x13C
#define CS33_SW6 0x13D
#define CS34_SW6 0x13E
#define CS35_SW6 0x13F
#define CS36_SW6 0x140
#define CS37_SW6 0x141
#define CS38_SW6 0x142
#define CS39_SW6 0x143
#define CS31_SW7 0x144
#define CS32_SW7 0x145
#define CS33_SW7 0x146
#define CS34_SW7 0x147
#define CS35_SW7 0x148
#define CS36_SW7 0x149
#define CS37_SW7 0x14A
#define CS38_SW7 0x14B
#define CS39_SW7 0x14C
#define CS31_SW8 0x14D
#define CS32_SW8 0x14E
#define CS33_SW8 0x14F
#define CS34_SW8 0x150
#define CS35_SW8 0x151
#define CS36_SW8 0x152
#define CS37_SW8 0x153
#define CS38_SW8 0x154
#define CS39_SW8 0x155
#define CS31_SW9 0x156
#define CS32_SW9 0x157
#define CS33_SW9 0x158
#define CS34_SW9 0x159
#define CS35_SW9 0x15A
#define CS36_SW9 0x15B
#define CS37_SW9 0x15C
#define CS38_SW9 0x15D
#define CS39_SW9 0x15E

View File

@ -18,12 +18,13 @@
*/
#include "is31fl3741.h"
#include <string.h>
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3741_PWM_REGISTER_COUNT 351
#define IS31FL3741_SCALING_REGISTER_COUNT 351
#define IS31FL3741_PWM_0_REGISTER_COUNT 180
#define IS31FL3741_PWM_1_REGISTER_COUNT 171
#define IS31FL3741_SCALING_0_REGISTER_COUNT 180
#define IS31FL3741_SCALING_1_REGISTER_COUNT 171
#ifndef IS31FL3741_I2C_TIMEOUT
# define IS31FL3741_I2C_TIMEOUT 100
@ -53,7 +54,18 @@
# define IS31FL3741_GLOBAL_CURRENT 0xFF
#endif
uint8_t i2c_transfer_buffer[20] = {0xFF};
const uint8_t i2c_addresses[IS31FL3741_DRIVER_COUNT] = {
IS31FL3741_I2C_ADDRESS_1,
#ifdef IS31FL3741_I2C_ADDRESS_2
IS31FL3741_I2C_ADDRESS_2,
# ifdef IS31FL3741_I2C_ADDRESS_3
IS31FL3741_I2C_ADDRESS_3,
# ifdef IS31FL3741_I2C_ADDRESS_4
IS31FL3741_I2C_ADDRESS_4,
# endif
# endif
#endif
};
// These buffers match the IS31FL3741 and IS31FL3741A PWM registers.
// The scaling buffers match the page 2 and 3 LED On/Off registers.
@ -61,140 +73,142 @@ uint8_t i2c_transfer_buffer[20] = {0xFF};
// We could optimize this and take out the unused registers from these
// buffers and the transfers in is31fl3741_write_pwm_buffer() but it's
// probably not worth the extra complexity.
uint8_t g_pwm_buffer[IS31FL3741_DRIVER_COUNT][IS31FL3741_PWM_REGISTER_COUNT];
bool g_pwm_buffer_update_required[IS31FL3741_DRIVER_COUNT] = {false};
bool g_scaling_registers_update_required[IS31FL3741_DRIVER_COUNT] = {false};
typedef struct is31fl3741_driver_t {
uint8_t pwm_buffer_0[IS31FL3741_PWM_0_REGISTER_COUNT];
uint8_t pwm_buffer_1[IS31FL3741_PWM_1_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t scaling_buffer_0[IS31FL3741_SCALING_0_REGISTER_COUNT];
uint8_t scaling_buffer_1[IS31FL3741_SCALING_1_REGISTER_COUNT];
bool scaling_buffer_dirty;
} PACKED is31fl3741_driver_t;
uint8_t g_scaling_registers[IS31FL3741_DRIVER_COUNT][IS31FL3741_SCALING_REGISTER_COUNT];
void is31fl3741_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
i2c_transfer_buffer[0] = reg;
i2c_transfer_buffer[1] = data;
is31fl3741_driver_t driver_buffers[IS31FL3741_DRIVER_COUNT] = {{
.pwm_buffer_0 = {0},
.pwm_buffer_1 = {0},
.pwm_buffer_dirty = false,
.scaling_buffer_0 = {0},
.scaling_buffer_1 = {0},
.scaling_buffer_dirty = false,
}};
void is31fl3741_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3741_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3741_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3741_I2C_TIMEOUT) == 0) break;
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3741_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_transmit(addr << 1, i2c_transfer_buffer, 2, IS31FL3741_I2C_TIMEOUT);
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3741_I2C_TIMEOUT);
#endif
}
void is31fl3741_select_page(uint8_t addr, uint8_t page) {
is31fl3741_write_register(addr, IS31FL3741_REG_COMMAND_WRITE_LOCK, IS31FL3741_COMMAND_WRITE_LOCK_MAGIC);
is31fl3741_write_register(addr, IS31FL3741_REG_COMMAND, page);
void is31fl3741_select_page(uint8_t index, uint8_t page) {
is31fl3741_write_register(index, IS31FL3741_REG_COMMAND_WRITE_LOCK, IS31FL3741_COMMAND_WRITE_LOCK_MAGIC);
is31fl3741_write_register(index, IS31FL3741_REG_COMMAND, page);
}
bool is31fl3741_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
// Assume page 0 is already selected
void is31fl3741_write_pwm_buffer(uint8_t index) {
is31fl3741_select_page(index, IS31FL3741_COMMAND_PWM_0);
for (int i = 0; i < 342; i += 18) {
if (i == 180) {
is31fl3741_select_page(addr, IS31FL3741_COMMAND_PWM_1);
// Transmit PWM0 registers in 6 transfers of 30 bytes.
// Iterate over the pwm_buffer_0 contents at 30 byte intervals.
for (uint8_t i = 0; i < IS31FL3741_PWM_0_REGISTER_COUNT; i += 30) {
#if IS31FL3741_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < IS31FL3741_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer_0 + i, 30, IS31FL3741_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer_0 + i, 30, IS31FL3741_I2C_TIMEOUT);
#endif
}
i2c_transfer_buffer[0] = i % 180;
memcpy(i2c_transfer_buffer + 1, pwm_buffer + i, 18);
is31fl3741_select_page(index, IS31FL3741_COMMAND_PWM_1);
// Transmit PWM1 registers in 9 transfers of 19 bytes.
// Iterate over the pwm_buffer_1 contents at 19 byte intervals.
for (uint8_t i = 0; i < IS31FL3741_PWM_1_REGISTER_COUNT; i += 19) {
#if IS31FL3741_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3741_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 19, IS31FL3741_I2C_TIMEOUT) != 0) {
return false;
}
if (i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer_1 + i, 19, IS31FL3741_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 19, IS31FL3741_I2C_TIMEOUT) != 0) {
return false;
}
i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer_1 + i, 19, IS31FL3741_I2C_TIMEOUT);
#endif
}
// transfer the left cause the total number is 351
i2c_transfer_buffer[0] = 162;
memcpy(i2c_transfer_buffer + 1, pwm_buffer + 342, 9);
#if IS31FL3741_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3741_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 10, IS31FL3741_I2C_TIMEOUT) != 0) {
return false;
}
}
#else
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 10, IS31FL3741_I2C_TIMEOUT) != 0) {
return false;
}
#endif
return true;
}
void is31fl3741_init_drivers(void) {
i2c_init();
is31fl3741_init(IS31FL3741_I2C_ADDRESS_1);
#if defined(IS31FL3741_I2C_ADDRESS_2)
is31fl3741_init(IS31FL3741_I2C_ADDRESS_2);
# if defined(IS31FL3741_I2C_ADDRESS_3)
is31fl3741_init(IS31FL3741_I2C_ADDRESS_3);
# if defined(IS31FL3741_I2C_ADDRESS_4)
is31fl3741_init(IS31FL3741_I2C_ADDRESS_4);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3741_DRIVER_COUNT; i++) {
is31fl3741_init(i);
}
for (int i = 0; i < IS31FL3741_LED_COUNT; i++) {
is31fl3741_set_led_control_register(i, true, true, true);
}
is31fl3741_update_led_control_registers(IS31FL3741_I2C_ADDRESS_1, 0);
#if defined(IS31FL3741_I2C_ADDRESS_2)
is31fl3741_update_led_control_registers(IS31FL3741_I2C_ADDRESS_2, 1);
# if defined(IS31FL3741_I2C_ADDRESS_3)
is31fl3741_update_led_control_registers(IS31FL3741_I2C_ADDRESS_3, 2);
# if defined(IS31FL3741_I2C_ADDRESS_4)
is31fl3741_update_led_control_registers(IS31FL3741_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3741_DRIVER_COUNT; i++) {
is31fl3741_update_led_control_registers(i);
}
}
void is31fl3741_init(uint8_t addr) {
void is31fl3741_init(uint8_t index) {
// 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.
is31fl3741_select_page(addr, IS31FL3741_COMMAND_FUNCTION);
is31fl3741_select_page(index, IS31FL3741_COMMAND_FUNCTION);
// Set to Normal operation
is31fl3741_write_register(addr, IS31FL3741_FUNCTION_REG_CONFIGURATION, IS31FL3741_CONFIGURATION);
is31fl3741_write_register(index, IS31FL3741_FUNCTION_REG_CONFIGURATION, IS31FL3741_CONFIGURATION);
// Set Golbal Current Control Register
is31fl3741_write_register(addr, IS31FL3741_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3741_GLOBAL_CURRENT);
is31fl3741_write_register(index, IS31FL3741_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3741_GLOBAL_CURRENT);
// Set Pull up & Down for SWx CSy
is31fl3741_write_register(addr, IS31FL3741_FUNCTION_REG_PULLDOWNUP, ((IS31FL3741_CS_PULLDOWN << 4) | IS31FL3741_SW_PULLUP));
is31fl3741_write_register(index, IS31FL3741_FUNCTION_REG_PULLDOWNUP, ((IS31FL3741_CS_PULLDOWN << 4) | IS31FL3741_SW_PULLUP));
// Set PWM frequency
is31fl3741_write_register(addr, IS31FL3741_FUNCTION_REG_PWM_FREQUENCY, (IS31FL3741_PWM_FREQUENCY & 0b1111));
is31fl3741_write_register(index, IS31FL3741_FUNCTION_REG_PWM_FREQUENCY, (IS31FL3741_PWM_FREQUENCY & 0b1111));
// is31fl3741_update_led_scaling_registers(addr, 0xFF, 0xFF, 0xFF);
// is31fl3741_update_led_scaling_registers(index, 0xFF, 0xFF, 0xFF);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}
uint8_t get_pwm_value(uint8_t driver, uint16_t reg) {
if (reg & 0x100) {
return driver_buffers[driver].pwm_buffer_1[reg & 0xFF];
} else {
return driver_buffers[driver].pwm_buffer_0[reg];
}
}
void set_pwm_value(uint8_t driver, uint16_t reg, uint8_t value) {
if (reg & 0x100) {
driver_buffers[driver].pwm_buffer_1[reg & 0xFF] = value;
} else {
driver_buffers[driver].pwm_buffer_0[reg] = value;
}
}
void is31fl3741_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
is31fl3741_led_t led;
if (index >= 0 && index < IS31FL3741_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3741_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) {
if (get_pwm_value(led.driver, led.r) == red && get_pwm_value(led.driver, led.g) == green && get_pwm_value(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;
set_pwm_value(led.driver, led.r, red);
set_pwm_value(led.driver, led.g, green);
set_pwm_value(led.driver, led.b, blue);
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
@ -204,86 +218,67 @@ void is31fl3741_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
}
}
void set_scaling_value(uint8_t driver, uint16_t reg, uint8_t value) {
if (reg & 0x100) {
driver_buffers[driver].scaling_buffer_1[reg & 0xFF] = value;
} else {
driver_buffers[driver].scaling_buffer_0[reg] = value;
}
}
void is31fl3741_set_led_control_register(uint8_t index, bool red, bool green, bool blue) {
is31fl3741_led_t led;
memcpy_P(&led, (&g_is31fl3741_leds[index]), sizeof(led));
if (red) {
g_scaling_registers[led.driver][led.r] = 0xFF;
} else {
g_scaling_registers[led.driver][led.r] = 0x00;
}
set_scaling_value(led.driver, led.r, red ? 0xFF : 0x00);
set_scaling_value(led.driver, led.g, green ? 0xFF : 0x00);
set_scaling_value(led.driver, led.b, blue ? 0xFF : 0x00);
if (green) {
g_scaling_registers[led.driver][led.g] = 0xFF;
} else {
g_scaling_registers[led.driver][led.g] = 0x00;
}
if (blue) {
g_scaling_registers[led.driver][led.b] = 0xFF;
} else {
g_scaling_registers[led.driver][led.b] = 0x00;
}
g_scaling_registers_update_required[led.driver] = true;
driver_buffers[led.driver].scaling_buffer_dirty = true;
}
void is31fl3741_update_pwm_buffers(uint8_t addr, uint8_t index) {
if (g_pwm_buffer_update_required[index]) {
is31fl3741_select_page(addr, IS31FL3741_COMMAND_PWM_0);
void is31fl3741_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3741_write_pwm_buffer(index);
is31fl3741_write_pwm_buffer(addr, g_pwm_buffer[index]);
driver_buffers[index].pwm_buffer_dirty = false;
}
g_pwm_buffer_update_required[index] = false;
}
void is31fl3741_set_pwm_buffer(const is31fl3741_led_t *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;
g_pwm_buffer_update_required[pled->driver] = true;
set_pwm_value(pled->driver, pled->r, red);
set_pwm_value(pled->driver, pled->g, green);
set_pwm_value(pled->driver, pled->b, blue);
driver_buffers[pled->driver].pwm_buffer_dirty = true;
}
void is31fl3741_update_led_control_registers(uint8_t addr, uint8_t index) {
if (g_scaling_registers_update_required[index]) {
is31fl3741_select_page(addr, IS31FL3741_COMMAND_SCALING_0);
void is31fl3741_update_led_control_registers(uint8_t index) {
if (driver_buffers[index].scaling_buffer_dirty) {
is31fl3741_select_page(index, IS31FL3741_COMMAND_SCALING_0);
// CS1_SW1 to CS30_SW6 are on page 2
for (int i = CS1_SW1; i <= CS30_SW6; ++i) {
is31fl3741_write_register(addr, i, g_scaling_registers[index][i]);
for (uint8_t i = 0; i < IS31FL3741_SCALING_0_REGISTER_COUNT; i++) {
is31fl3741_write_register(index, i, driver_buffers[index].scaling_buffer_0[i]);
}
is31fl3741_select_page(addr, IS31FL3741_COMMAND_SCALING_1);
is31fl3741_select_page(index, IS31FL3741_COMMAND_SCALING_1);
// CS1_SW7 to CS39_SW9 are on page 3
for (int i = CS1_SW7; i <= CS39_SW9; ++i) {
is31fl3741_write_register(addr, i - CS1_SW7, g_scaling_registers[index][i]);
for (uint8_t i = 0; i < IS31FL3741_SCALING_1_REGISTER_COUNT; i++) {
is31fl3741_write_register(index, i, driver_buffers[index].scaling_buffer_1[i]);
}
g_scaling_registers_update_required[index] = false;
driver_buffers[index].scaling_buffer_dirty = false;
}
}
void is31fl3741_set_scaling_registers(const is31fl3741_led_t *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;
g_scaling_registers_update_required[pled->driver] = true;
set_scaling_value(pled->driver, pled->r, red);
set_scaling_value(pled->driver, pled->g, green);
set_scaling_value(pled->driver, pled->b, blue);
driver_buffers[pled->driver].scaling_buffer_dirty = true;
}
void is31fl3741_flush(void) {
is31fl3741_update_pwm_buffers(IS31FL3741_I2C_ADDRESS_1, 0);
#if defined(IS31FL3741_I2C_ADDRESS_2)
is31fl3741_update_pwm_buffers(IS31FL3741_I2C_ADDRESS_2, 1);
# if defined(IS31FL3741_I2C_ADDRESS_3)
is31fl3741_update_pwm_buffers(IS31FL3741_I2C_ADDRESS_3, 2);
# if defined(IS31FL3741_I2C_ADDRESS_4)
is31fl3741_update_pwm_buffers(IS31FL3741_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
for (uint8_t i = 0; i < IS31FL3741_DRIVER_COUNT; i++) {
is31fl3741_update_pwm_buffers(i);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,299 +0,0 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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
// This is a 7-bit address, that gets left-shifted and bit 0
// set to 0 for write, 1 for read (as per I2C protocol)
// The address will vary depending on your wiring:
// 00 <-> GND
// 01 <-> SCL
// 10 <-> SDA
// 11 <-> VCC
// ADDR represents A1:A0 of the 7-bit address.
// The result is: 0b01100(ADDR)
#ifndef DRIVER_ADDR_1
# define DRIVER_ADDR_1 0b0110000
#endif
// Command Registers
#define ISSI_COMMANDREGISTER_WRITELOCK 0xFE
#define ISSI_COMMANDREGISTER 0xFD
#define ISSI_IDREGISTER 0xFC
#define ISSI_REGISTER_UNLOCK 0xC5
// Response Registers
#define ISSI_PAGE_PWM 0x00
#define ISSI_PAGE_SCALING 0x02
#define ISSI_PAGE_FUNCTION 0x04
// Registers under Function Register
#define ISSI_REG_CONFIGURATION 0x00
#define ISSI_REG_GLOBALCURRENT 0x01
#define ISSI_REG_PULLDOWNUP 0x02
#define ISSI_REG_SSR 0x41
#define ISSI_REG_RESET 0x3F
#define ISSI_REG_PWM_SET 0x36
// Set defaults for Function Registers
#ifndef ISSI_CONFIGURATION
# define ISSI_CONFIGURATION 0x31
#endif
#ifndef ISSI_GLOBALCURRENT
# define ISSI_GLOBALCURRENT 0xFF
#endif
#ifndef ISSI_PULLDOWNUP
# define ISSI_PULLDOWNUP 0x55
#endif
#ifndef ISSI_PWM_SET
# define ISSI_PWM_SET 0x00
#endif
// Set defaults for Spread Spectrum Register
#ifndef ISSI_SSR_1
# define ISSI_SSR_1 0x00
#endif
#ifndef ISSI_SSR_2
# define ISSI_SSR_2 0x00
#endif
#ifndef ISSI_SSR_3
# define ISSI_SSR_3 0x00
#endif
#ifndef ISSI_SSR_4
# define ISSI_SSR_4 0x00
#endif
// Set defaults for Scaling registers
#ifndef ISSI_SCAL_RED
# define ISSI_SCAL_RED 0xFF
#endif
#ifndef ISSI_SCAL_BLUE
# define ISSI_SCAL_BLUE 0xFF
#endif
#ifndef ISSI_SCAL_GREEN
# define ISSI_SCAL_GREEN 0xFF
#endif
#define ISSI_SCAL_RED_OFF 0x00
#define ISSI_SCAL_GREEN_OFF 0x00
#define ISSI_SCAL_BLUE_OFF 0x00
#ifndef ISSI_SCAL_LED
# define ISSI_SCAL_LED 0xFF
#endif
#define ISSI_SCAL_LED_OFF 0x00
// Set buffer sizes
#define ISSI_MAX_LEDS 180
#define ISSI_SCALING_SIZE 180
#define ISSI_PWM_TRF_SIZE 18
#define ISSI_SCALING_TRF_SIZE 18
// Location of 1st bit for PWM and Scaling registers
#define ISSI_PWM_REG_1ST 0x00
#define ISSI_SCL_REG_1ST 0x00
// Map CS SW locations to order in PWM / Scaling buffers
// This matches the ORDER in the Datasheet Register not the POSITION
// It will always count from 0x00 to (ISSI_MAX_LEDS - 1)
#define CS1_SW1 0x00
#define CS2_SW1 0x01
#define CS3_SW1 0x02
#define CS4_SW1 0x03
#define CS5_SW1 0x04
#define CS6_SW1 0x05
#define CS7_SW1 0x06
#define CS8_SW1 0x07
#define CS9_SW1 0x08
#define CS10_SW1 0x09
#define CS11_SW1 0x0A
#define CS12_SW1 0x0B
#define CS13_SW1 0x0C
#define CS14_SW1 0x0D
#define CS15_SW1 0x0E
#define CS16_SW1 0x0F
#define CS17_SW1 0x10
#define CS18_SW1 0x11
#define CS19_SW1 0x12
#define CS20_SW1 0x13
#define CS21_SW1 0x14
#define CS22_SW1 0x15
#define CS23_SW1 0x16
#define CS24_SW1 0x17
#define CS25_SW1 0x18
#define CS26_SW1 0x19
#define CS27_SW1 0x1A
#define CS28_SW1 0x1B
#define CS29_SW1 0x1C
#define CS30_SW1 0x1D
#define CS1_SW2 0x1E
#define CS2_SW2 0x1F
#define CS3_SW2 0x20
#define CS4_SW2 0x21
#define CS5_SW2 0x22
#define CS6_SW2 0x23
#define CS7_SW2 0x24
#define CS8_SW2 0x25
#define CS9_SW2 0x26
#define CS10_SW2 0x27
#define CS11_SW2 0x28
#define CS12_SW2 0x29
#define CS13_SW2 0x2A
#define CS14_SW2 0x2B
#define CS15_SW2 0x2C
#define CS16_SW2 0x2D
#define CS17_SW2 0x2E
#define CS18_SW2 0x2F
#define CS19_SW2 0x30
#define CS20_SW2 0x31
#define CS21_SW2 0x32
#define CS22_SW2 0x33
#define CS23_SW2 0x34
#define CS24_SW2 0x35
#define CS25_SW2 0x36
#define CS26_SW2 0x37
#define CS27_SW2 0x38
#define CS28_SW2 0x39
#define CS29_SW2 0x3A
#define CS30_SW2 0x3B
#define CS1_SW3 0x3C
#define CS2_SW3 0x3D
#define CS3_SW3 0x3E
#define CS4_SW3 0x3F
#define CS5_SW3 0x40
#define CS6_SW3 0x41
#define CS7_SW3 0x42
#define CS8_SW3 0x43
#define CS9_SW3 0x44
#define CS10_SW3 0x45
#define CS11_SW3 0x46
#define CS12_SW3 0x47
#define CS13_SW3 0x48
#define CS14_SW3 0x49
#define CS15_SW3 0x4A
#define CS16_SW3 0x4B
#define CS17_SW3 0x4C
#define CS18_SW3 0x4D
#define CS19_SW3 0x4E
#define CS20_SW3 0x4F
#define CS21_SW3 0x50
#define CS22_SW3 0x51
#define CS23_SW3 0x52
#define CS24_SW3 0x53
#define CS25_SW3 0x54
#define CS26_SW3 0x55
#define CS27_SW3 0x56
#define CS28_SW3 0x57
#define CS29_SW3 0x58
#define CS30_SW3 0x59
#define CS1_SW4 0x5A
#define CS2_SW4 0x5B
#define CS3_SW4 0x5C
#define CS4_SW4 0x5D
#define CS5_SW4 0x5E
#define CS6_SW4 0x5F
#define CS7_SW4 0x60
#define CS8_SW4 0x61
#define CS9_SW4 0x62
#define CS10_SW4 0x63
#define CS11_SW4 0x64
#define CS12_SW4 0x65
#define CS13_SW4 0x66
#define CS14_SW4 0x67
#define CS15_SW4 0x68
#define CS16_SW4 0x69
#define CS17_SW4 0x6A
#define CS18_SW4 0x6B
#define CS19_SW4 0x6C
#define CS20_SW4 0x6D
#define CS21_SW4 0x6E
#define CS22_SW4 0x6F
#define CS23_SW4 0x70
#define CS24_SW4 0x71
#define CS25_SW4 0x72
#define CS26_SW4 0x73
#define CS27_SW4 0x74
#define CS28_SW4 0x75
#define CS29_SW4 0x76
#define CS30_SW4 0x77
#define CS1_SW5 0x78
#define CS2_SW5 0x79
#define CS3_SW5 0x7A
#define CS4_SW5 0x7B
#define CS5_SW5 0x7C
#define CS6_SW5 0x7D
#define CS7_SW5 0x7E
#define CS8_SW5 0x7F
#define CS9_SW5 0x80
#define CS10_SW5 0x81
#define CS11_SW5 0x82
#define CS12_SW5 0x83
#define CS13_SW5 0x84
#define CS14_SW5 0x85
#define CS15_SW5 0x86
#define CS16_SW5 0x87
#define CS17_SW5 0x88
#define CS18_SW5 0x89
#define CS19_SW5 0x8A
#define CS20_SW5 0x8B
#define CS21_SW5 0x8C
#define CS22_SW5 0x8D
#define CS23_SW5 0x8E
#define CS24_SW5 0x8F
#define CS25_SW5 0x90
#define CS26_SW5 0x91
#define CS27_SW5 0x92
#define CS28_SW5 0x93
#define CS29_SW5 0x94
#define CS30_SW5 0x95
#define CS1_SW6 0x96
#define CS2_SW6 0x97
#define CS3_SW6 0x98
#define CS4_SW6 0x99
#define CS5_SW6 0x9A
#define CS6_SW6 0x9B
#define CS7_SW6 0x9C
#define CS8_SW6 0x9D
#define CS9_SW6 0x9E
#define CS10_SW6 0x9F
#define CS11_SW6 0xA0
#define CS12_SW6 0xA1
#define CS13_SW6 0xA2
#define CS14_SW6 0xA3
#define CS15_SW6 0xA4
#define CS16_SW6 0xA5
#define CS17_SW6 0xA6
#define CS18_SW6 0xA7
#define CS19_SW6 0xA8
#define CS20_SW6 0xA9
#define CS21_SW6 0xAA
#define CS22_SW6 0xAB
#define CS23_SW6 0xAC
#define CS24_SW6 0xAD
#define CS25_SW6 0xAE
#define CS26_SW6 0xAF
#define CS27_SW6 0xB0
#define CS28_SW6 0xB1
#define CS29_SW6 0xB2
#define CS30_SW6 0xB3

View File

@ -0,0 +1,215 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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 "is31fl3742a-mono.h"
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3742A_PWM_REGISTER_COUNT 180
#define IS31FL3742A_SCALING_REGISTER_COUNT 180
#ifndef IS31FL3742A_I2C_TIMEOUT
# define IS31FL3742A_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3742A_I2C_PERSISTENCE
# define IS31FL3742A_I2C_PERSISTENCE 0
#endif
#ifndef IS31FL3742A_CONFIGURATION
# define IS31FL3742A_CONFIGURATION 0x31
#endif
#ifndef IS31FL3742A_PWM_FREQUENCY
# define IS31FL3742A_PWM_FREQUENCY IS31FL3742A_PWM_FREQUENCY_29K_HZ
#endif
#ifndef IS31FL3742A_SW_PULLDOWN
# define IS31FL3742A_SW_PULLDOWN IS31FL3742A_PDR_8K_OHM
#endif
#ifndef IS31FL3742A_CS_PULLUP
# define IS31FL3742A_CS_PULLUP IS31FL3742A_PUR_8K_OHM
#endif
#ifndef IS31FL3742A_GLOBAL_CURRENT
# define IS31FL3742A_GLOBAL_CURRENT 0xFF
#endif
const uint8_t i2c_addresses[IS31FL3742A_DRIVER_COUNT] = {
IS31FL3742A_I2C_ADDRESS_1,
#ifdef IS31FL3742A_I2C_ADDRESS_2
IS31FL3742A_I2C_ADDRESS_2,
# ifdef IS31FL3742A_I2C_ADDRESS_3
IS31FL3742A_I2C_ADDRESS_3,
# ifdef IS31FL3742A_I2C_ADDRESS_4
IS31FL3742A_I2C_ADDRESS_4,
# endif
# endif
#endif
};
typedef struct is31fl3742a_driver_t {
uint8_t pwm_buffer[IS31FL3742A_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t scaling_buffer[IS31FL3742A_SCALING_REGISTER_COUNT];
bool scaling_buffer_dirty;
} PACKED is31fl3742a_driver_t;
is31fl3742a_driver_t driver_buffers[IS31FL3742A_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.scaling_buffer = {0},
.scaling_buffer_dirty = false,
}};
void is31fl3742a_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3742A_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3742A_I2C_PERSISTENCE; i++) {
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3742A_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3742A_I2C_TIMEOUT);
#endif
}
void is31fl3742a_select_page(uint8_t index, uint8_t page) {
is31fl3742a_write_register(index, IS31FL3742A_REG_COMMAND_WRITE_LOCK, IS31FL3742A_COMMAND_WRITE_LOCK_MAGIC);
is31fl3742a_write_register(index, IS31FL3742A_REG_COMMAND, page);
}
void is31fl3742a_write_pwm_buffer(uint8_t index) {
// Assumes page 0 is already selected.
// Transmit PWM registers in 6 transfers of 30 bytes.
// Iterate over the pwm_buffer contents at 30 byte intervals.
for (uint8_t i = 0; i < IS31FL3742A_PWM_REGISTER_COUNT; i += 30) {
#if IS31FL3742A_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < IS31FL3742A_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 30, IS31FL3742A_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 30, IS31FL3742A_I2C_TIMEOUT);
#endif
}
}
void is31fl3742a_init_drivers(void) {
i2c_init();
for (uint8_t i = 0; i < IS31FL3742A_DRIVER_COUNT; i++) {
is31fl3742a_init(i);
}
for (int i = 0; i < IS31FL3742A_LED_COUNT; i++) {
is31fl3742a_set_scaling_register(i, 0xFF);
}
for (uint8_t i = 0; i < IS31FL3742A_DRIVER_COUNT; i++) {
is31fl3742a_update_scaling_registers(i);
}
}
void is31fl3742a_init(uint8_t index) {
// 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.
is31fl3742a_select_page(index, IS31FL3742A_COMMAND_SCALING);
// Turn off all LEDs.
for (uint8_t i = 0; i < IS31FL3742A_SCALING_REGISTER_COUNT; i++) {
is31fl3742a_write_register(index, i, 0x00);
}
is31fl3742a_select_page(index, IS31FL3742A_COMMAND_PWM);
for (uint8_t i = 0; i < IS31FL3742A_PWM_REGISTER_COUNT; i++) {
is31fl3742a_write_register(index, i, 0x00);
}
is31fl3742a_select_page(index, IS31FL3742A_COMMAND_FUNCTION);
is31fl3742a_write_register(index, IS31FL3742A_FUNCTION_REG_PULLDOWNUP, (IS31FL3742A_SW_PULLDOWN << 4) | IS31FL3742A_CS_PULLUP);
is31fl3742a_write_register(index, IS31FL3742A_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3742A_GLOBAL_CURRENT);
is31fl3742a_write_register(index, IS31FL3742A_FUNCTION_REG_PWM_FREQUENCY, (IS31FL3742A_PWM_FREQUENCY & 0b0111));
is31fl3742a_write_register(index, IS31FL3742A_FUNCTION_REG_CONFIGURATION, IS31FL3742A_CONFIGURATION);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}
void is31fl3742a_set_value(int index, uint8_t value) {
is31fl3742a_led_t led;
if (index >= 0 && index < IS31FL3742A_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3742a_leds[index]), sizeof(led));
if (driver_buffers[led.driver].pwm_buffer[led.v] == value) {
return;
}
driver_buffers[led.driver].pwm_buffer[led.v] = value;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
void is31fl3742a_set_value_all(uint8_t value) {
for (int i = 0; i < IS31FL3742A_LED_COUNT; i++) {
is31fl3742a_set_value(i, value);
}
}
void is31fl3742a_set_scaling_register(uint8_t index, uint8_t value) {
is31fl3742a_led_t led;
memcpy_P(&led, (&g_is31fl3742a_leds[index]), sizeof(led));
driver_buffers[led.driver].scaling_buffer[led.v] = value;
driver_buffers[led.driver].scaling_buffer_dirty = true;
}
void is31fl3742a_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3742a_select_page(index, IS31FL3742A_COMMAND_PWM);
is31fl3742a_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void is31fl3742a_update_scaling_registers(uint8_t index) {
if (driver_buffers[index].scaling_buffer_dirty) {
is31fl3742a_select_page(index, IS31FL3742A_COMMAND_SCALING);
for (uint8_t i = 0; i < IS31FL3742A_SCALING_REGISTER_COUNT; i++) {
is31fl3742a_write_register(index, i, driver_buffers[index].scaling_buffer[i]);
}
driver_buffers[index].scaling_buffer_dirty = false;
}
}
void is31fl3742a_flush(void) {
for (uint8_t i = 0; i < IS31FL3742A_DRIVER_COUNT; i++) {
is31fl3742a_update_pwm_buffers(i);
}
}

View File

@ -0,0 +1,296 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
#define IS31FL3742A_REG_INTERRUPT_MASK 0xF0
#define IS31FL3742A_REG_INTERRUPT_STATUS 0xF1
#define IS31FL3742A_REG_ID 0xFC
#define IS31FL3742A_REG_COMMAND 0xFD
#define IS31FL3742A_COMMAND_PWM 0x00
#define IS31FL3742A_COMMAND_SCALING 0x02
#define IS31FL3742A_COMMAND_FUNCTION 0x04
#define IS31FL3742A_FUNCTION_REG_CONFIGURATION 0x00
#define IS31FL3742A_FUNCTION_REG_GLOBAL_CURRENT 0x01
#define IS31FL3742A_FUNCTION_REG_PULLDOWNUP 0x02
#define IS31FL3742A_FUNCTION_REG_PWM_FREQUENCY 0x36
#define IS31FL3742A_FUNCTION_REG_RESET 0x3F
#define IS31FL3742A_FUNCTION_REG_SPREAD_SPECTRUM 0x41
#define IS31FL3742A_REG_COMMAND_WRITE_LOCK 0xFE
#define IS31FL3742A_COMMAND_WRITE_LOCK_MAGIC 0xC5
#define IS31FL3742A_I2C_ADDRESS_GND 0x30
#define IS31FL3742A_I2C_ADDRESS_SCL 0x31
#define IS31FL3742A_I2C_ADDRESS_SDA 0x32
#define IS31FL3742A_I2C_ADDRESS_VCC 0x33
#if defined(LED_MATRIX_IS31FL3742A)
# define IS31FL3742A_LED_COUNT LED_MATRIX_LED_COUNT
#endif
#if defined(IS31FL3742A_I2C_ADDRESS_4)
# define IS31FL3742A_DRIVER_COUNT 4
#elif defined(IS31FL3742A_I2C_ADDRESS_3)
# define IS31FL3742A_DRIVER_COUNT 3
#elif defined(IS31FL3742A_I2C_ADDRESS_2)
# define IS31FL3742A_DRIVER_COUNT 2
#elif defined(IS31FL3742A_I2C_ADDRESS_1)
# define IS31FL3742A_DRIVER_COUNT 1
#endif
typedef struct is31fl3742a_led_t {
uint8_t driver : 2;
uint8_t v;
} PACKED is31fl3742a_led_t;
extern const is31fl3742a_led_t PROGMEM g_is31fl3742a_leds[IS31FL3742A_LED_COUNT];
void is31fl3742a_init_drivers(void);
void is31fl3742a_init(uint8_t index);
void is31fl3742a_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3742a_select_page(uint8_t index, uint8_t page);
void is31fl3742a_set_value(int index, uint8_t value);
void is31fl3742a_set_value_all(uint8_t value);
void is31fl3742a_set_scaling_register(uint8_t index, uint8_t value);
void is31fl3742a_update_pwm_buffers(uint8_t index);
void is31fl3742a_update_scaling_registers(uint8_t index);
void is31fl3742a_flush(void);
#define IS31FL3742A_PDR_0_OHM 0b000 // No pull-down resistor
#define IS31FL3742A_PDR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3742A_PDR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3742A_PDR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3742A_PDR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3742A_PDR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3742A_PDR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3742A_PDR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3742A_PUR_0_OHM 0b000 // No pull-up resistor
#define IS31FL3742A_PUR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3742A_PUR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3742A_PUR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3742A_PUR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3742A_PUR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3742A_PUR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3742A_PUR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3742A_PWM_FREQUENCY_29K_HZ 0b0000
#define IS31FL3742A_PWM_FREQUENCY_3K6_HZ 0b0011
#define IS31FL3742A_PWM_FREQUENCY_1K8_HZ 0b0111
#define IS31FL3742A_PWM_FREQUENCY_900_HZ 0b1011
#define SW1_CS1 0x00
#define SW1_CS2 0x01
#define SW1_CS3 0x02
#define SW1_CS4 0x03
#define SW1_CS5 0x04
#define SW1_CS6 0x05
#define SW1_CS7 0x06
#define SW1_CS8 0x07
#define SW1_CS9 0x08
#define SW1_CS10 0x09
#define SW1_CS11 0x0A
#define SW1_CS12 0x0B
#define SW1_CS13 0x0C
#define SW1_CS14 0x0D
#define SW1_CS15 0x0E
#define SW1_CS16 0x0F
#define SW1_CS17 0x10
#define SW1_CS18 0x11
#define SW1_CS19 0x12
#define SW1_CS20 0x13
#define SW1_CS21 0x14
#define SW1_CS22 0x15
#define SW1_CS23 0x16
#define SW1_CS24 0x17
#define SW1_CS25 0x18
#define SW1_CS26 0x19
#define SW1_CS27 0x1A
#define SW1_CS28 0x1B
#define SW1_CS29 0x1C
#define SW1_CS30 0x1D
#define SW2_CS1 0x1E
#define SW2_CS2 0x1F
#define SW2_CS3 0x20
#define SW2_CS4 0x21
#define SW2_CS5 0x22
#define SW2_CS6 0x23
#define SW2_CS7 0x24
#define SW2_CS8 0x25
#define SW2_CS9 0x26
#define SW2_CS10 0x27
#define SW2_CS11 0x28
#define SW2_CS12 0x29
#define SW2_CS13 0x2A
#define SW2_CS14 0x2B
#define SW2_CS15 0x2C
#define SW2_CS16 0x2D
#define SW2_CS17 0x2E
#define SW2_CS18 0x2F
#define SW2_CS19 0x30
#define SW2_CS20 0x31
#define SW2_CS21 0x32
#define SW2_CS22 0x33
#define SW2_CS23 0x34
#define SW2_CS24 0x35
#define SW2_CS25 0x36
#define SW2_CS26 0x37
#define SW2_CS27 0x38
#define SW2_CS28 0x39
#define SW2_CS29 0x3A
#define SW2_CS30 0x3B
#define SW3_CS1 0x3C
#define SW3_CS2 0x3D
#define SW3_CS3 0x3E
#define SW3_CS4 0x3F
#define SW3_CS5 0x40
#define SW3_CS6 0x41
#define SW3_CS7 0x42
#define SW3_CS8 0x43
#define SW3_CS9 0x44
#define SW3_CS10 0x45
#define SW3_CS11 0x46
#define SW3_CS12 0x47
#define SW3_CS13 0x48
#define SW3_CS14 0x49
#define SW3_CS15 0x4A
#define SW3_CS16 0x4B
#define SW3_CS17 0x4C
#define SW3_CS18 0x4D
#define SW3_CS19 0x4E
#define SW3_CS20 0x4F
#define SW3_CS21 0x50
#define SW3_CS22 0x51
#define SW3_CS23 0x52
#define SW3_CS24 0x53
#define SW3_CS25 0x54
#define SW3_CS26 0x55
#define SW3_CS27 0x56
#define SW3_CS28 0x57
#define SW3_CS29 0x58
#define SW3_CS30 0x59
#define SW4_CS1 0x5A
#define SW4_CS2 0x5B
#define SW4_CS3 0x5C
#define SW4_CS4 0x5D
#define SW4_CS5 0x5E
#define SW4_CS6 0x5F
#define SW4_CS7 0x60
#define SW4_CS8 0x61
#define SW4_CS9 0x62
#define SW4_CS10 0x63
#define SW4_CS11 0x64
#define SW4_CS12 0x65
#define SW4_CS13 0x66
#define SW4_CS14 0x67
#define SW4_CS15 0x68
#define SW4_CS16 0x69
#define SW4_CS17 0x6A
#define SW4_CS18 0x6B
#define SW4_CS19 0x6C
#define SW4_CS20 0x6D
#define SW4_CS21 0x6E
#define SW4_CS22 0x6F
#define SW4_CS23 0x70
#define SW4_CS24 0x71
#define SW4_CS25 0x72
#define SW4_CS26 0x73
#define SW4_CS27 0x74
#define SW4_CS28 0x75
#define SW4_CS29 0x76
#define SW4_CS30 0x77
#define SW5_CS1 0x78
#define SW5_CS2 0x79
#define SW5_CS3 0x7A
#define SW5_CS4 0x7B
#define SW5_CS5 0x7C
#define SW5_CS6 0x7D
#define SW5_CS7 0x7E
#define SW5_CS8 0x7F
#define SW5_CS9 0x80
#define SW5_CS10 0x81
#define SW5_CS11 0x82
#define SW5_CS12 0x83
#define SW5_CS13 0x84
#define SW5_CS14 0x85
#define SW5_CS15 0x86
#define SW5_CS16 0x87
#define SW5_CS17 0x88
#define SW5_CS18 0x89
#define SW5_CS19 0x8A
#define SW5_CS20 0x8B
#define SW5_CS21 0x8C
#define SW5_CS22 0x8D
#define SW5_CS23 0x8E
#define SW5_CS24 0x8F
#define SW5_CS25 0x90
#define SW5_CS26 0x91
#define SW5_CS27 0x92
#define SW5_CS28 0x93
#define SW5_CS29 0x94
#define SW5_CS30 0x95
#define SW6_CS1 0x96
#define SW6_CS2 0x97
#define SW6_CS3 0x98
#define SW6_CS4 0x99
#define SW6_CS5 0x9A
#define SW6_CS6 0x9B
#define SW6_CS7 0x9C
#define SW6_CS8 0x9D
#define SW6_CS9 0x9E
#define SW6_CS10 0x9F
#define SW6_CS11 0xA0
#define SW6_CS12 0xA1
#define SW6_CS13 0xA2
#define SW6_CS14 0xA3
#define SW6_CS15 0xA4
#define SW6_CS16 0xA5
#define SW6_CS17 0xA6
#define SW6_CS18 0xA7
#define SW6_CS19 0xA8
#define SW6_CS20 0xA9
#define SW6_CS21 0xAA
#define SW6_CS22 0xAB
#define SW6_CS23 0xAC
#define SW6_CS24 0xAD
#define SW6_CS25 0xAE
#define SW6_CS26 0xAF
#define SW6_CS27 0xB0
#define SW6_CS28 0xB1
#define SW6_CS29 0xB2
#define SW6_CS30 0xB3

View File

@ -0,0 +1,219 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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 "is31fl3742a.h"
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3742A_PWM_REGISTER_COUNT 180
#define IS31FL3742A_SCALING_REGISTER_COUNT 180
#ifndef IS31FL3742A_I2C_TIMEOUT
# define IS31FL3742A_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3742A_I2C_PERSISTENCE
# define IS31FL3742A_I2C_PERSISTENCE 0
#endif
#ifndef IS31FL3742A_CONFIGURATION
# define IS31FL3742A_CONFIGURATION 0x31
#endif
#ifndef IS31FL3742A_PWM_FREQUENCY
# define IS31FL3742A_PWM_FREQUENCY IS31FL3742A_PWM_FREQUENCY_29K_HZ
#endif
#ifndef IS31FL3742A_SW_PULLDOWN
# define IS31FL3742A_SW_PULLDOWN IS31FL3742A_PDR_8K_OHM
#endif
#ifndef IS31FL3742A_CS_PULLUP
# define IS31FL3742A_CS_PULLUP IS31FL3742A_PUR_8K_OHM
#endif
#ifndef IS31FL3742A_GLOBAL_CURRENT
# define IS31FL3742A_GLOBAL_CURRENT 0xFF
#endif
const uint8_t i2c_addresses[IS31FL3742A_DRIVER_COUNT] = {
IS31FL3742A_I2C_ADDRESS_1,
#ifdef IS31FL3742A_I2C_ADDRESS_2
IS31FL3742A_I2C_ADDRESS_2,
# ifdef IS31FL3742A_I2C_ADDRESS_3
IS31FL3742A_I2C_ADDRESS_3,
# ifdef IS31FL3742A_I2C_ADDRESS_4
IS31FL3742A_I2C_ADDRESS_4,
# endif
# endif
#endif
};
typedef struct is31fl3742a_driver_t {
uint8_t pwm_buffer[IS31FL3742A_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t scaling_buffer[IS31FL3742A_SCALING_REGISTER_COUNT];
bool scaling_buffer_dirty;
} PACKED is31fl3742a_driver_t;
is31fl3742a_driver_t driver_buffers[IS31FL3742A_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.scaling_buffer = {0},
.scaling_buffer_dirty = false,
}};
void is31fl3742a_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3742A_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3742A_I2C_PERSISTENCE; i++) {
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3742A_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3742A_I2C_TIMEOUT);
#endif
}
void is31fl3742a_select_page(uint8_t index, uint8_t page) {
is31fl3742a_write_register(index, IS31FL3742A_REG_COMMAND_WRITE_LOCK, IS31FL3742A_COMMAND_WRITE_LOCK_MAGIC);
is31fl3742a_write_register(index, IS31FL3742A_REG_COMMAND, page);
}
void is31fl3742a_write_pwm_buffer(uint8_t index) {
// Assumes page 0 is already selected.
// Transmit PWM registers in 6 transfers of 30 bytes.
// Iterate over the pwm_buffer contents at 30 byte intervals.
for (uint8_t i = 0; i < IS31FL3742A_PWM_REGISTER_COUNT; i += 30) {
#if IS31FL3742A_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < IS31FL3742A_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 30, IS31FL3742A_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 30, IS31FL3742A_I2C_TIMEOUT);
#endif
}
}
void is31fl3742a_init_drivers(void) {
i2c_init();
for (uint8_t i = 0; i < IS31FL3742A_DRIVER_COUNT; i++) {
is31fl3742a_init(i);
}
for (int i = 0; i < IS31FL3742A_LED_COUNT; i++) {
is31fl3742a_set_scaling_register(i, 0xFF, 0xFF, 0xFF);
}
for (uint8_t i = 0; i < IS31FL3742A_DRIVER_COUNT; i++) {
is31fl3742a_update_scaling_registers(i);
}
}
void is31fl3742a_init(uint8_t index) {
// 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.
is31fl3742a_select_page(index, IS31FL3742A_COMMAND_SCALING);
// Turn off all LEDs.
for (uint8_t i = 0; i < IS31FL3742A_SCALING_REGISTER_COUNT; i++) {
is31fl3742a_write_register(index, i, 0x00);
}
is31fl3742a_select_page(index, IS31FL3742A_COMMAND_PWM);
for (uint8_t i = 0; i < IS31FL3742A_PWM_REGISTER_COUNT; i++) {
is31fl3742a_write_register(index, i, 0x00);
}
is31fl3742a_select_page(index, IS31FL3742A_COMMAND_FUNCTION);
is31fl3742a_write_register(index, IS31FL3742A_FUNCTION_REG_PULLDOWNUP, (IS31FL3742A_SW_PULLDOWN << 4) | IS31FL3742A_CS_PULLUP);
is31fl3742a_write_register(index, IS31FL3742A_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3742A_GLOBAL_CURRENT);
is31fl3742a_write_register(index, IS31FL3742A_FUNCTION_REG_PWM_FREQUENCY, (IS31FL3742A_PWM_FREQUENCY & 0b0111));
is31fl3742a_write_register(index, IS31FL3742A_FUNCTION_REG_CONFIGURATION, IS31FL3742A_CONFIGURATION);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}
void is31fl3742a_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
is31fl3742a_led_t led;
if (index >= 0 && index < IS31FL3742A_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3742a_leds[index]), sizeof(led));
if (driver_buffers[led.driver].pwm_buffer[led.r] == red && driver_buffers[led.driver].pwm_buffer[led.g] == green && driver_buffers[led.driver].pwm_buffer[led.b] == blue) {
return;
}
driver_buffers[led.driver].pwm_buffer[led.r] = red;
driver_buffers[led.driver].pwm_buffer[led.g] = green;
driver_buffers[led.driver].pwm_buffer[led.b] = blue;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
void is31fl3742a_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
for (int i = 0; i < IS31FL3742A_LED_COUNT; i++) {
is31fl3742a_set_color(i, red, green, blue);
}
}
void is31fl3742a_set_scaling_register(uint8_t index, uint8_t red, uint8_t green, uint8_t blue) {
is31fl3742a_led_t led;
memcpy_P(&led, (&g_is31fl3742a_leds[index]), sizeof(led));
driver_buffers[led.driver].scaling_buffer[led.r] = red;
driver_buffers[led.driver].scaling_buffer[led.g] = green;
driver_buffers[led.driver].scaling_buffer[led.b] = blue;
driver_buffers[led.driver].scaling_buffer_dirty = true;
}
void is31fl3742a_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3742a_select_page(index, IS31FL3742A_COMMAND_PWM);
is31fl3742a_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void is31fl3742a_update_scaling_registers(uint8_t index) {
if (driver_buffers[index].scaling_buffer_dirty) {
is31fl3742a_select_page(index, IS31FL3742A_COMMAND_SCALING);
for (uint8_t i = 0; i < IS31FL3742A_SCALING_REGISTER_COUNT; i++) {
is31fl3742a_write_register(index, i, driver_buffers[index].scaling_buffer[i]);
}
driver_buffers[index].scaling_buffer_dirty = false;
}
}
void is31fl3742a_flush(void) {
for (uint8_t i = 0; i < IS31FL3742A_DRIVER_COUNT; i++) {
is31fl3742a_update_pwm_buffers(i);
}
}

View File

@ -0,0 +1,298 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
#define IS31FL3742A_REG_INTERRUPT_MASK 0xF0
#define IS31FL3742A_REG_INTERRUPT_STATUS 0xF1
#define IS31FL3742A_REG_ID 0xFC
#define IS31FL3742A_REG_COMMAND 0xFD
#define IS31FL3742A_COMMAND_PWM 0x00
#define IS31FL3742A_COMMAND_SCALING 0x02
#define IS31FL3742A_COMMAND_FUNCTION 0x04
#define IS31FL3742A_FUNCTION_REG_CONFIGURATION 0x00
#define IS31FL3742A_FUNCTION_REG_GLOBAL_CURRENT 0x01
#define IS31FL3742A_FUNCTION_REG_PULLDOWNUP 0x02
#define IS31FL3742A_FUNCTION_REG_PWM_FREQUENCY 0x36
#define IS31FL3742A_FUNCTION_REG_RESET 0x3F
#define IS31FL3742A_FUNCTION_REG_SPREAD_SPECTRUM 0x41
#define IS31FL3742A_REG_COMMAND_WRITE_LOCK 0xFE
#define IS31FL3742A_COMMAND_WRITE_LOCK_MAGIC 0xC5
#define IS31FL3742A_I2C_ADDRESS_GND 0x30
#define IS31FL3742A_I2C_ADDRESS_SCL 0x31
#define IS31FL3742A_I2C_ADDRESS_SDA 0x32
#define IS31FL3742A_I2C_ADDRESS_VCC 0x33
#if defined(RGB_MATRIX_IS31FL3742A)
# define IS31FL3742A_LED_COUNT RGB_MATRIX_LED_COUNT
#endif
#if defined(IS31FL3742A_I2C_ADDRESS_4)
# define IS31FL3742A_DRIVER_COUNT 4
#elif defined(IS31FL3742A_I2C_ADDRESS_3)
# define IS31FL3742A_DRIVER_COUNT 3
#elif defined(IS31FL3742A_I2C_ADDRESS_2)
# define IS31FL3742A_DRIVER_COUNT 2
#elif defined(IS31FL3742A_I2C_ADDRESS_1)
# define IS31FL3742A_DRIVER_COUNT 1
#endif
typedef struct is31fl3742a_led_t {
uint8_t driver : 2;
uint8_t r;
uint8_t g;
uint8_t b;
} PACKED is31fl3742a_led_t;
extern const is31fl3742a_led_t PROGMEM g_is31fl3742a_leds[IS31FL3742A_LED_COUNT];
void is31fl3742a_init_drivers(void);
void is31fl3742a_init(uint8_t index);
void is31fl3742a_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3742a_select_page(uint8_t index, uint8_t page);
void is31fl3742a_set_color(int index, uint8_t red, uint8_t green, uint8_t blue);
void is31fl3742a_set_color_all(uint8_t red, uint8_t green, uint8_t blue);
void is31fl3742a_set_scaling_register(uint8_t index, uint8_t red, uint8_t green, uint8_t blue);
void is31fl3742a_update_pwm_buffers(uint8_t index);
void is31fl3742a_update_scaling_registers(uint8_t index);
void is31fl3742a_flush(void);
#define IS31FL3742A_PDR_0_OHM 0b000 // No pull-down resistor
#define IS31FL3742A_PDR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3742A_PDR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3742A_PDR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3742A_PDR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3742A_PDR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3742A_PDR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3742A_PDR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3742A_PUR_0_OHM 0b000 // No pull-up resistor
#define IS31FL3742A_PUR_0K5_OHM 0b001 // 0.5 kOhm resistor
#define IS31FL3742A_PUR_1K_OHM 0b010 // 1 kOhm resistor
#define IS31FL3742A_PUR_2K_OHM 0b011 // 2 kOhm resistor
#define IS31FL3742A_PUR_4K_OHM 0b100 // 4 kOhm resistor
#define IS31FL3742A_PUR_8K_OHM 0b101 // 8 kOhm resistor
#define IS31FL3742A_PUR_16K_OHM 0b110 // 16 kOhm resistor
#define IS31FL3742A_PUR_32K_OHM 0b111 // 32 kOhm resistor
#define IS31FL3742A_PWM_FREQUENCY_29K_HZ 0b0000
#define IS31FL3742A_PWM_FREQUENCY_3K6_HZ 0b0011
#define IS31FL3742A_PWM_FREQUENCY_1K8_HZ 0b0111
#define IS31FL3742A_PWM_FREQUENCY_900_HZ 0b1011
#define SW1_CS1 0x00
#define SW1_CS2 0x01
#define SW1_CS3 0x02
#define SW1_CS4 0x03
#define SW1_CS5 0x04
#define SW1_CS6 0x05
#define SW1_CS7 0x06
#define SW1_CS8 0x07
#define SW1_CS9 0x08
#define SW1_CS10 0x09
#define SW1_CS11 0x0A
#define SW1_CS12 0x0B
#define SW1_CS13 0x0C
#define SW1_CS14 0x0D
#define SW1_CS15 0x0E
#define SW1_CS16 0x0F
#define SW1_CS17 0x10
#define SW1_CS18 0x11
#define SW1_CS19 0x12
#define SW1_CS20 0x13
#define SW1_CS21 0x14
#define SW1_CS22 0x15
#define SW1_CS23 0x16
#define SW1_CS24 0x17
#define SW1_CS25 0x18
#define SW1_CS26 0x19
#define SW1_CS27 0x1A
#define SW1_CS28 0x1B
#define SW1_CS29 0x1C
#define SW1_CS30 0x1D
#define SW2_CS1 0x1E
#define SW2_CS2 0x1F
#define SW2_CS3 0x20
#define SW2_CS4 0x21
#define SW2_CS5 0x22
#define SW2_CS6 0x23
#define SW2_CS7 0x24
#define SW2_CS8 0x25
#define SW2_CS9 0x26
#define SW2_CS10 0x27
#define SW2_CS11 0x28
#define SW2_CS12 0x29
#define SW2_CS13 0x2A
#define SW2_CS14 0x2B
#define SW2_CS15 0x2C
#define SW2_CS16 0x2D
#define SW2_CS17 0x2E
#define SW2_CS18 0x2F
#define SW2_CS19 0x30
#define SW2_CS20 0x31
#define SW2_CS21 0x32
#define SW2_CS22 0x33
#define SW2_CS23 0x34
#define SW2_CS24 0x35
#define SW2_CS25 0x36
#define SW2_CS26 0x37
#define SW2_CS27 0x38
#define SW2_CS28 0x39
#define SW2_CS29 0x3A
#define SW2_CS30 0x3B
#define SW3_CS1 0x3C
#define SW3_CS2 0x3D
#define SW3_CS3 0x3E
#define SW3_CS4 0x3F
#define SW3_CS5 0x40
#define SW3_CS6 0x41
#define SW3_CS7 0x42
#define SW3_CS8 0x43
#define SW3_CS9 0x44
#define SW3_CS10 0x45
#define SW3_CS11 0x46
#define SW3_CS12 0x47
#define SW3_CS13 0x48
#define SW3_CS14 0x49
#define SW3_CS15 0x4A
#define SW3_CS16 0x4B
#define SW3_CS17 0x4C
#define SW3_CS18 0x4D
#define SW3_CS19 0x4E
#define SW3_CS20 0x4F
#define SW3_CS21 0x50
#define SW3_CS22 0x51
#define SW3_CS23 0x52
#define SW3_CS24 0x53
#define SW3_CS25 0x54
#define SW3_CS26 0x55
#define SW3_CS27 0x56
#define SW3_CS28 0x57
#define SW3_CS29 0x58
#define SW3_CS30 0x59
#define SW4_CS1 0x5A
#define SW4_CS2 0x5B
#define SW4_CS3 0x5C
#define SW4_CS4 0x5D
#define SW4_CS5 0x5E
#define SW4_CS6 0x5F
#define SW4_CS7 0x60
#define SW4_CS8 0x61
#define SW4_CS9 0x62
#define SW4_CS10 0x63
#define SW4_CS11 0x64
#define SW4_CS12 0x65
#define SW4_CS13 0x66
#define SW4_CS14 0x67
#define SW4_CS15 0x68
#define SW4_CS16 0x69
#define SW4_CS17 0x6A
#define SW4_CS18 0x6B
#define SW4_CS19 0x6C
#define SW4_CS20 0x6D
#define SW4_CS21 0x6E
#define SW4_CS22 0x6F
#define SW4_CS23 0x70
#define SW4_CS24 0x71
#define SW4_CS25 0x72
#define SW4_CS26 0x73
#define SW4_CS27 0x74
#define SW4_CS28 0x75
#define SW4_CS29 0x76
#define SW4_CS30 0x77
#define SW5_CS1 0x78
#define SW5_CS2 0x79
#define SW5_CS3 0x7A
#define SW5_CS4 0x7B
#define SW5_CS5 0x7C
#define SW5_CS6 0x7D
#define SW5_CS7 0x7E
#define SW5_CS8 0x7F
#define SW5_CS9 0x80
#define SW5_CS10 0x81
#define SW5_CS11 0x82
#define SW5_CS12 0x83
#define SW5_CS13 0x84
#define SW5_CS14 0x85
#define SW5_CS15 0x86
#define SW5_CS16 0x87
#define SW5_CS17 0x88
#define SW5_CS18 0x89
#define SW5_CS19 0x8A
#define SW5_CS20 0x8B
#define SW5_CS21 0x8C
#define SW5_CS22 0x8D
#define SW5_CS23 0x8E
#define SW5_CS24 0x8F
#define SW5_CS25 0x90
#define SW5_CS26 0x91
#define SW5_CS27 0x92
#define SW5_CS28 0x93
#define SW5_CS29 0x94
#define SW5_CS30 0x95
#define SW6_CS1 0x96
#define SW6_CS2 0x97
#define SW6_CS3 0x98
#define SW6_CS4 0x99
#define SW6_CS5 0x9A
#define SW6_CS6 0x9B
#define SW6_CS7 0x9C
#define SW6_CS8 0x9D
#define SW6_CS9 0x9E
#define SW6_CS10 0x9F
#define SW6_CS11 0xA0
#define SW6_CS12 0xA1
#define SW6_CS13 0xA2
#define SW6_CS14 0xA3
#define SW6_CS15 0xA4
#define SW6_CS16 0xA5
#define SW6_CS17 0xA6
#define SW6_CS18 0xA7
#define SW6_CS19 0xA8
#define SW6_CS20 0xA9
#define SW6_CS21 0xAA
#define SW6_CS22 0xAB
#define SW6_CS23 0xAC
#define SW6_CS24 0xAD
#define SW6_CS25 0xAE
#define SW6_CS26 0xAF
#define SW6_CS27 0xB0
#define SW6_CS28 0xB1
#define SW6_CS29 0xB2
#define SW6_CS30 0xB3

View File

@ -1,327 +0,0 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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
// This is a 7-bit address, that gets left-shifted and bit 0
// set to 0 for write, 1 for read (as per I2C protocol)
// The address will vary depending on your wiring:
// 00 <-> GND
// 01 <-> SCL
// 10 <-> SDA
// 11 <-> VCC
// ADDR1 represents A1:A0 of the 7-bit address.
// ADDR2 represents A3:A2 of the 7-bit address.
// The result is: 0b010(ADDR2)(ADDR1)
#ifndef DRIVER_ADDR_1
# define DRIVER_ADDR_1 0b0100000
#endif
// Set defaults for Spread Spectrum Register
#ifndef ISSI_SSR_1
# ifndef DRIVER_ADDR_2
# define ISSI_SSR_1 0x00
# else
# define ISSI_SSR_1 0xC0
# endif
#endif
#ifndef ISSI_SSR_2
# define ISSI_SSR_2 0x80
#endif
#ifndef ISSI_SSR_3
# define ISSI_SSR_3 0x80
#endif
#ifndef ISSI_SSR_4
# define ISSI_SSR_4 0x80
#endif
// Command Registers
#define ISSI_COMMANDREGISTER_WRITELOCK 0xFE
#define ISSI_COMMANDREGISTER 0xFD
#define ISSI_IDREGISTER 0xFC
#define ISSI_REGISTER_UNLOCK 0xC5
// Response Registers
#define ISSI_PAGE_PWM 0x00
#define ISSI_PAGE_SCALING 0x01
#define ISSI_PAGE_FUNCTION 0x02
// Registers under Function Register
#define ISSI_REG_CONFIGURATION 0x00
#define ISSI_REG_GLOBALCURRENT 0x01
#define ISSI_REG_PULLDOWNUP 0x02
#define ISSI_REG_TEMP 0x24
#define ISSI_REG_SSR 0x25
#define ISSI_REG_RESET 0x2F
// Set defaults for Function Registers
#ifndef ISSI_CONFIGURATION
# define ISSI_CONFIGURATION 0x01
#endif
#ifndef ISSI_GLOBALCURRENT
# define ISSI_GLOBALCURRENT 0xFF
#endif
#ifndef ISSI_PULLDOWNUP
# define ISSI_PULLDOWNUP 0x33
#endif
#ifndef ISSI_TEMP
# define ISSI_TEMP 0x00
#endif
// Set defaults for Scaling registers
#ifndef ISSI_SCAL_RED
# define ISSI_SCAL_RED 0xFF
#endif
#ifndef ISSI_SCAL_BLUE
# define ISSI_SCAL_BLUE 0xFF
#endif
#ifndef ISSI_SCAL_GREEN
# define ISSI_SCAL_GREEN 0xFF
#endif
#define ISSI_SCAL_RED_OFF 0x00
#define ISSI_SCAL_GREEN_OFF 0x00
#define ISSI_SCAL_BLUE_OFF 0x00
#ifndef ISSI_SCAL_LED
# define ISSI_SCAL_LED 0xFF
#endif
#define ISSI_SCAL_LED_OFF 0x00
// Set buffer sizes
#define ISSI_MAX_LEDS 198
#define ISSI_SCALING_SIZE 198
#define ISSI_PWM_TRF_SIZE 18
#define ISSI_SCALING_TRF_SIZE 18
// Location of 1st bit for PWM and Scaling registers
#define ISSI_PWM_REG_1ST 0x01
#define ISSI_SCL_REG_1ST 0x01
// Map CS SW locations to order in PWM / Scaling buffers
// This matches the ORDER in the Datasheet Register not the POSITION
// It will always count from 0x00 to (ISSI_MAX_LEDS - 1)
#define CS1_SW1 0x00
#define CS2_SW1 0x01
#define CS3_SW1 0x02
#define CS4_SW1 0x03
#define CS5_SW1 0x04
#define CS6_SW1 0x05
#define CS7_SW1 0x06
#define CS8_SW1 0x07
#define CS9_SW1 0x08
#define CS10_SW1 0x09
#define CS11_SW1 0x0A
#define CS12_SW1 0x0B
#define CS13_SW1 0x0C
#define CS14_SW1 0x0D
#define CS15_SW1 0x0E
#define CS16_SW1 0x0F
#define CS17_SW1 0x10
#define CS18_SW1 0x11
#define CS1_SW2 0x12
#define CS2_SW2 0x13
#define CS3_SW2 0x14
#define CS4_SW2 0x15
#define CS5_SW2 0x16
#define CS6_SW2 0x17
#define CS7_SW2 0x18
#define CS8_SW2 0x19
#define CS9_SW2 0x1A
#define CS10_SW2 0x1B
#define CS11_SW2 0x1C
#define CS12_SW2 0x1D
#define CS13_SW2 0x1E
#define CS14_SW2 0x1F
#define CS15_SW2 0x20
#define CS16_SW2 0x21
#define CS17_SW2 0x22
#define CS18_SW2 0x23
#define CS1_SW3 0x24
#define CS2_SW3 0x25
#define CS3_SW3 0x26
#define CS4_SW3 0x27
#define CS5_SW3 0x28
#define CS6_SW3 0x29
#define CS7_SW3 0x2A
#define CS8_SW3 0x2B
#define CS9_SW3 0x2C
#define CS10_SW3 0x2D
#define CS11_SW3 0x2E
#define CS12_SW3 0x2F
#define CS13_SW3 0x30
#define CS14_SW3 0x31
#define CS15_SW3 0x32
#define CS16_SW3 0x33
#define CS17_SW3 0x34
#define CS18_SW3 0x35
#define CS1_SW4 0x36
#define CS2_SW4 0x37
#define CS3_SW4 0x38
#define CS4_SW4 0x39
#define CS5_SW4 0x3A
#define CS6_SW4 0x3B
#define CS7_SW4 0x3C
#define CS8_SW4 0x3D
#define CS9_SW4 0x3E
#define CS10_SW4 0x3F
#define CS11_SW4 0x40
#define CS12_SW4 0x41
#define CS13_SW4 0x42
#define CS14_SW4 0x43
#define CS15_SW4 0x44
#define CS16_SW4 0x45
#define CS17_SW4 0x46
#define CS18_SW4 0x47
#define CS1_SW5 0x48
#define CS2_SW5 0x49
#define CS3_SW5 0x4A
#define CS4_SW5 0x4B
#define CS5_SW5 0x4C
#define CS6_SW5 0x4D
#define CS7_SW5 0x4E
#define CS8_SW5 0x4F
#define CS9_SW5 0x50
#define CS10_SW5 0x51
#define CS11_SW5 0x52
#define CS12_SW5 0x53
#define CS13_SW5 0x54
#define CS14_SW5 0x55
#define CS15_SW5 0x56
#define CS16_SW5 0x57
#define CS17_SW5 0x58
#define CS18_SW5 0x59
#define CS1_SW6 0x5A
#define CS2_SW6 0x5B
#define CS3_SW6 0x5C
#define CS4_SW6 0x5D
#define CS5_SW6 0x5E
#define CS6_SW6 0x5F
#define CS7_SW6 0x60
#define CS8_SW6 0x61
#define CS9_SW6 0x62
#define CS10_SW6 0x63
#define CS11_SW6 0x64
#define CS12_SW6 0x65
#define CS13_SW6 0x66
#define CS14_SW6 0x67
#define CS15_SW6 0x68
#define CS16_SW6 0x69
#define CS17_SW6 0x6A
#define CS18_SW6 0x6B
#define CS1_SW7 0x6C
#define CS2_SW7 0x6D
#define CS3_SW7 0x6E
#define CS4_SW7 0x6F
#define CS5_SW7 0x70
#define CS6_SW7 0x71
#define CS7_SW7 0x72
#define CS8_SW7 0x73
#define CS9_SW7 0x74
#define CS10_SW7 0x75
#define CS11_SW7 0x76
#define CS12_SW7 0x77
#define CS13_SW7 0x78
#define CS14_SW7 0x79
#define CS15_SW7 0x7A
#define CS16_SW7 0x7B
#define CS17_SW7 0x7C
#define CS18_SW7 0x7D
#define CS1_SW8 0x7E
#define CS2_SW8 0x7F
#define CS3_SW8 0x80
#define CS4_SW8 0x81
#define CS5_SW8 0x82
#define CS6_SW8 0x83
#define CS7_SW8 0x84
#define CS8_SW8 0x85
#define CS9_SW8 0x86
#define CS10_SW8 0x87
#define CS11_SW8 0x88
#define CS12_SW8 0x89
#define CS13_SW8 0x8A
#define CS14_SW8 0x8B
#define CS15_SW8 0x8C
#define CS16_SW8 0x8D
#define CS17_SW8 0x8E
#define CS18_SW8 0x8F
#define CS1_SW9 0x90
#define CS2_SW9 0x91
#define CS3_SW9 0x92
#define CS4_SW9 0x93
#define CS5_SW9 0x94
#define CS6_SW9 0x95
#define CS7_SW9 0x96
#define CS8_SW9 0x97
#define CS9_SW9 0x98
#define CS10_SW9 0x99
#define CS11_SW9 0x9A
#define CS12_SW9 0x9B
#define CS13_SW9 0x9C
#define CS14_SW9 0x9D
#define CS15_SW9 0x9E
#define CS16_SW9 0x9F
#define CS17_SW9 0xA0
#define CS18_SW9 0xA1
#define CS1_SW10 0xA2
#define CS2_SW10 0xA3
#define CS3_SW10 0xA4
#define CS4_SW10 0xA5
#define CS5_SW10 0xA6
#define CS6_SW10 0xA7
#define CS7_SW10 0xA8
#define CS8_SW10 0xA9
#define CS9_SW10 0xAA
#define CS10_SW10 0xAB
#define CS11_SW10 0xAC
#define CS12_SW10 0xAD
#define CS13_SW10 0xAE
#define CS14_SW10 0xAF
#define CS15_SW10 0xB0
#define CS16_SW10 0xB1
#define CS17_SW10 0xB2
#define CS18_SW10 0xB3
#define CS1_SW11 0xB4
#define CS2_SW11 0xB5
#define CS3_SW11 0xB6
#define CS4_SW11 0xB7
#define CS5_SW11 0xB8
#define CS6_SW11 0xB9
#define CS7_SW11 0xBA
#define CS8_SW11 0xBB
#define CS9_SW11 0xBC
#define CS10_SW11 0xBD
#define CS11_SW11 0xBE
#define CS12_SW11 0xBF
#define CS13_SW11 0xC0
#define CS14_SW11 0xC1
#define CS15_SW11 0xC2
#define CS16_SW11 0xC3
#define CS17_SW11 0xC4
#define CS18_SW11 0xC5

View File

@ -0,0 +1,239 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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 "is31fl3743a-mono.h"
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3743A_PWM_REGISTER_COUNT 198
#define IS31FL3743A_SCALING_REGISTER_COUNT 198
#ifndef IS31FL3743A_I2C_TIMEOUT
# define IS31FL3743A_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3743A_I2C_PERSISTENCE
# define IS31FL3743A_I2C_PERSISTENCE 0
#endif
#ifndef IS31FL3743A_CONFIGURATION
# define IS31FL3743A_CONFIGURATION 0x01
#endif
#ifndef IS31FL3743A_SW_PULLDOWN
# define IS31FL3743A_SW_PULLDOWN IS31FL3743A_PDR_2K_OHM_SW_OFF
#endif
#ifndef IS31FL3743A_CS_PULLUP
# define IS31FL3743A_CS_PULLUP IS31FL3743A_PUR_2K_OHM_CS_OFF
#endif
#ifndef IS31FL3743A_GLOBAL_CURRENT
# define IS31FL3743A_GLOBAL_CURRENT 0xFF
#endif
#ifndef IS31FL3743A_SYNC_1
# define IS31FL3743A_SYNC_1 IS31FL3743A_SYNC_NONE
#endif
#ifndef IS31FL3743A_SYNC_2
# define IS31FL3743A_SYNC_2 IS31FL3743A_SYNC_NONE
#endif
#ifndef IS31FL3743A_SYNC_3
# define IS31FL3743A_SYNC_3 IS31FL3743A_SYNC_NONE
#endif
#ifndef IS31FL3743A_SYNC_4
# define IS31FL3743A_SYNC_4 IS31FL3743A_SYNC_NONE
#endif
const uint8_t i2c_addresses[IS31FL3743A_DRIVER_COUNT] = {
IS31FL3743A_I2C_ADDRESS_1,
#ifdef IS31FL3743A_I2C_ADDRESS_2
IS31FL3743A_I2C_ADDRESS_2,
# ifdef IS31FL3743A_I2C_ADDRESS_3
IS31FL3743A_I2C_ADDRESS_3,
# ifdef IS31FL3743A_I2C_ADDRESS_4
IS31FL3743A_I2C_ADDRESS_4,
# endif
# endif
#endif
};
const uint8_t driver_sync[IS31FL3743A_DRIVER_COUNT] = {
IS31FL3743A_SYNC_1,
#ifdef IS31FL3743A_I2C_ADDRESS_2
IS31FL3743A_SYNC_2,
# ifdef IS31FL3743A_I2C_ADDRESS_3
IS31FL3743A_SYNC_3,
# ifdef IS31FL3743A_I2C_ADDRESS_4
IS31FL3743A_SYNC_4,
# endif
# endif
#endif
};
typedef struct is31fl3743a_driver_t {
uint8_t pwm_buffer[IS31FL3743A_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t scaling_buffer[IS31FL3743A_SCALING_REGISTER_COUNT];
bool scaling_buffer_dirty;
} PACKED is31fl3743a_driver_t;
is31fl3743a_driver_t driver_buffers[IS31FL3743A_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.scaling_buffer = {0},
.scaling_buffer_dirty = false,
}};
void is31fl3743a_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3743A_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3743A_I2C_PERSISTENCE; i++) {
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3743A_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3743A_I2C_TIMEOUT);
#endif
}
void is31fl3743a_select_page(uint8_t index, uint8_t page) {
is31fl3743a_write_register(index, IS31FL3743A_REG_COMMAND_WRITE_LOCK, IS31FL3743A_COMMAND_WRITE_LOCK_MAGIC);
is31fl3743a_write_register(index, IS31FL3743A_REG_COMMAND, page);
}
void is31fl3743a_write_pwm_buffer(uint8_t index) {
// Assumes page 0 is already selected.
// Transmit PWM registers in 11 transfers of 18 bytes.
// Iterate over the pwm_buffer contents at 18 byte intervals.
for (uint8_t i = 0; i < IS31FL3743A_PWM_REGISTER_COUNT; i += 18) {
#if IS31FL3743A_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < IS31FL3743A_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i + 1, driver_buffers[index].pwm_buffer + i, 18, IS31FL3743A_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, i + 1, driver_buffers[index].pwm_buffer + i, 18, IS31FL3743A_I2C_TIMEOUT);
#endif
}
}
void is31fl3743a_init_drivers(void) {
i2c_init();
for (uint8_t i = 0; i < IS31FL3743A_DRIVER_COUNT; i++) {
is31fl3743a_init(i);
}
for (int i = 0; i < IS31FL3743A_LED_COUNT; i++) {
is31fl3743a_set_scaling_register(i, 0xFF);
}
for (uint8_t i = 0; i < IS31FL3743A_DRIVER_COUNT; i++) {
is31fl3743a_update_scaling_registers(i);
}
}
void is31fl3743a_init(uint8_t index) {
// 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.
is31fl3743a_select_page(index, IS31FL3743A_COMMAND_SCALING);
// Turn off all LEDs.
for (uint8_t i = 0; i < IS31FL3743A_SCALING_REGISTER_COUNT; i++) {
is31fl3743a_write_register(index, i + 1, 0x00);
}
is31fl3743a_select_page(index, IS31FL3743A_COMMAND_PWM);
for (uint8_t i = 0; i < IS31FL3743A_PWM_REGISTER_COUNT; i++) {
is31fl3743a_write_register(index, i + 1, 0x00);
}
is31fl3743a_select_page(index, IS31FL3743A_COMMAND_FUNCTION);
uint8_t sync = driver_sync[index];
is31fl3743a_write_register(index, IS31FL3743A_FUNCTION_REG_PULLDOWNUP, (IS31FL3743A_SW_PULLDOWN << 4) | IS31FL3743A_CS_PULLUP);
is31fl3743a_write_register(index, IS31FL3743A_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3743A_GLOBAL_CURRENT);
is31fl3743a_write_register(index, IS31FL3743A_FUNCTION_REG_SPREAD_SPECTRUM, (sync & 0b11) << 6);
is31fl3743a_write_register(index, IS31FL3743A_FUNCTION_REG_CONFIGURATION, IS31FL3743A_CONFIGURATION);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}
void is31fl3743a_set_value(int index, uint8_t value) {
is31fl3743a_led_t led;
if (index >= 0 && index < IS31FL3743A_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3743a_leds[index]), sizeof(led));
if (driver_buffers[led.driver].pwm_buffer[led.v] == value) {
return;
}
driver_buffers[led.driver].pwm_buffer[led.v] = value;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
void is31fl3743a_set_value_all(uint8_t value) {
for (int i = 0; i < IS31FL3743A_LED_COUNT; i++) {
is31fl3743a_set_value(i, value);
}
}
void is31fl3743a_set_scaling_register(uint8_t index, uint8_t value) {
is31fl3743a_led_t led;
memcpy_P(&led, (&g_is31fl3743a_leds[index]), sizeof(led));
driver_buffers[led.driver].scaling_buffer[led.v] = value;
driver_buffers[led.driver].scaling_buffer_dirty = true;
}
void is31fl3743a_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3743a_select_page(index, IS31FL3743A_COMMAND_PWM);
is31fl3743a_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void is31fl3743a_update_scaling_registers(uint8_t index) {
if (driver_buffers[index].scaling_buffer_dirty) {
is31fl3743a_select_page(index, IS31FL3743A_COMMAND_SCALING);
for (uint8_t i = 0; i < IS31FL3743A_SCALING_REGISTER_COUNT; i++) {
is31fl3743a_write_register(index, i + 1, driver_buffers[index].scaling_buffer[i]);
}
driver_buffers[index].scaling_buffer_dirty = false;
}
}
void is31fl3743a_flush(void) {
for (uint8_t i = 0; i < IS31FL3743A_DRIVER_COUNT; i++) {
is31fl3743a_update_pwm_buffers(i);
}
}

View File

@ -0,0 +1,328 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
#define IS31FL3743A_REG_ID 0xFC
#define IS31FL3743A_REG_COMMAND 0xFD
#define IS31FL3743A_COMMAND_PWM 0x00
#define IS31FL3743A_COMMAND_SCALING 0x01
#define IS31FL3743A_COMMAND_FUNCTION 0x02
#define IS31FL3743A_FUNCTION_REG_CONFIGURATION 0x00
#define IS31FL3743A_FUNCTION_REG_GLOBAL_CURRENT 0x01
#define IS31FL3743A_FUNCTION_REG_PULLDOWNUP 0x02
#define IS31FL3743A_FUNCTION_REG_TEMPERATURE 0x24
#define IS31FL3743A_FUNCTION_REG_SPREAD_SPECTRUM 0x25
#define IS31FL3743A_FUNCTION_REG_RESET 0x2F
#define IS31FL3743A_REG_COMMAND_WRITE_LOCK 0xFE
#define IS31FL3743A_COMMAND_WRITE_LOCK_MAGIC 0xC5
#define IS31FL3743A_I2C_ADDRESS_GND_GND 0x20
#define IS31FL3743A_I2C_ADDRESS_GND_SCL 0x21
#define IS31FL3743A_I2C_ADDRESS_GND_SDA 0x22
#define IS31FL3743A_I2C_ADDRESS_GND_VCC 0x23
#define IS31FL3743A_I2C_ADDRESS_SCL_GND 0x24
#define IS31FL3743A_I2C_ADDRESS_SCL_SCL 0x25
#define IS31FL3743A_I2C_ADDRESS_SCL_SDA 0x26
#define IS31FL3743A_I2C_ADDRESS_SCL_VCC 0x27
#define IS31FL3743A_I2C_ADDRESS_SDA_GND 0x28
#define IS31FL3743A_I2C_ADDRESS_SDA_SCL 0x29
#define IS31FL3743A_I2C_ADDRESS_SDA_SDA 0x2A
#define IS31FL3743A_I2C_ADDRESS_SDA_VCC 0x2B
#define IS31FL3743A_I2C_ADDRESS_VCC_GND 0x2C
#define IS31FL3743A_I2C_ADDRESS_VCC_SCL 0x2D
#define IS31FL3743A_I2C_ADDRESS_VCC_SDA 0x2E
#define IS31FL3743A_I2C_ADDRESS_VCC_VCC 0x2F
#if defined(LED_MATRIX_IS31FL3743A)
# define IS31FL3743A_LED_COUNT LED_MATRIX_LED_COUNT
#endif
#if defined(IS31FL3743A_I2C_ADDRESS_4)
# define IS31FL3743A_DRIVER_COUNT 4
#elif defined(IS31FL3743A_I2C_ADDRESS_3)
# define IS31FL3743A_DRIVER_COUNT 3
#elif defined(IS31FL3743A_I2C_ADDRESS_2)
# define IS31FL3743A_DRIVER_COUNT 2
#elif defined(IS31FL3743A_I2C_ADDRESS_1)
# define IS31FL3743A_DRIVER_COUNT 1
#endif
typedef struct is31fl3743a_led_t {
uint8_t driver : 2;
uint8_t v;
} PACKED is31fl3743a_led_t;
extern const is31fl3743a_led_t PROGMEM g_is31fl3743a_leds[IS31FL3743A_LED_COUNT];
void is31fl3743a_init_drivers(void);
void is31fl3743a_init(uint8_t index);
void is31fl3743a_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3743a_select_page(uint8_t index, uint8_t page);
void is31fl3743a_set_value(int index, uint8_t value);
void is31fl3743a_set_value_all(uint8_t value);
void is31fl3743a_set_scaling_register(uint8_t index, uint8_t value);
void is31fl3743a_update_pwm_buffers(uint8_t index);
void is31fl3743a_update_scaling_registers(uint8_t index);
void is31fl3743a_flush(void);
#define IS31FL3743A_PDR_0_OHM 0b000 // No pull-down resistor
#define IS31FL3743A_PDR_0K5_OHM_SW_OFF 0b001 // 0.5 kOhm resistor in SWx off time
#define IS31FL3743A_PDR_1K_OHM_SW_OFF 0b010 // 1 kOhm resistor in SWx off time
#define IS31FL3743A_PDR_2K_OHM_SW_OFF 0b011 // 2 kOhm resistor in SWx off time
#define IS31FL3743A_PDR_1K_OHM 0b100 // 1 kOhm resistor
#define IS31FL3743A_PDR_2K_OHM 0b101 // 2 kOhm resistor
#define IS31FL3743A_PDR_4K_OHM 0b110 // 4 kOhm resistor
#define IS31FL3743A_PDR_8K_OHM 0b111 // 8 kOhm resistor
#define IS31FL3743A_PUR_0_OHM 0b000 // No pull-up resistor
#define IS31FL3743A_PUR_0K5_OHM_CS_OFF 0b001 // 0.5 kOhm resistor in CSy off time
#define IS31FL3743A_PUR_1K_OHM_CS_OFF 0b010 // 1 kOhm resistor in CSy off time
#define IS31FL3743A_PUR_2K_OHM_CS_OFF 0b011 // 2 kOhm resistor in CSy off time
#define IS31FL3743A_PUR_1K_OHM 0b100 // 1 kOhm resistor
#define IS31FL3743A_PUR_2K_OHM 0b101 // 2 kOhm resistor
#define IS31FL3743A_PUR_4K_OHM 0b110 // 4 kOhm resistor
#define IS31FL3743A_PUR_8K_OHM 0b111 // 8 kOhm resistor
#define IS31FL3743A_SYNC_NONE 0b00
#define IS31FL3743A_SYNC_SLAVE 0b10
#define IS31FL3743A_SYNC_MASTER 0b11
#define SW1_CS1 0x00
#define SW1_CS2 0x01
#define SW1_CS3 0x02
#define SW1_CS4 0x03
#define SW1_CS5 0x04
#define SW1_CS6 0x05
#define SW1_CS7 0x06
#define SW1_CS8 0x07
#define SW1_CS9 0x08
#define SW1_CS10 0x09
#define SW1_CS11 0x0A
#define SW1_CS12 0x0B
#define SW1_CS13 0x0C
#define SW1_CS14 0x0D
#define SW1_CS15 0x0E
#define SW1_CS16 0x0F
#define SW1_CS17 0x10
#define SW1_CS18 0x11
#define SW2_CS1 0x12
#define SW2_CS2 0x13
#define SW2_CS3 0x14
#define SW2_CS4 0x15
#define SW2_CS5 0x16
#define SW2_CS6 0x17
#define SW2_CS7 0x18
#define SW2_CS8 0x19
#define SW2_CS9 0x1A
#define SW2_CS10 0x1B
#define SW2_CS11 0x1C
#define SW2_CS12 0x1D
#define SW2_CS13 0x1E
#define SW2_CS14 0x1F
#define SW2_CS15 0x20
#define SW2_CS16 0x21
#define SW2_CS17 0x22
#define SW2_CS18 0x23
#define SW3_CS1 0x24
#define SW3_CS2 0x25
#define SW3_CS3 0x26
#define SW3_CS4 0x27
#define SW3_CS5 0x28
#define SW3_CS6 0x29
#define SW3_CS7 0x2A
#define SW3_CS8 0x2B
#define SW3_CS9 0x2C
#define SW3_CS10 0x2D
#define SW3_CS11 0x2E
#define SW3_CS12 0x2F
#define SW3_CS13 0x30
#define SW3_CS14 0x31
#define SW3_CS15 0x32
#define SW3_CS16 0x33
#define SW3_CS17 0x34
#define SW3_CS18 0x35
#define SW4_CS1 0x36
#define SW4_CS2 0x37
#define SW4_CS3 0x38
#define SW4_CS4 0x39
#define SW4_CS5 0x3A
#define SW4_CS6 0x3B
#define SW4_CS7 0x3C
#define SW4_CS8 0x3D
#define SW4_CS9 0x3E
#define SW4_CS10 0x3F
#define SW4_CS11 0x40
#define SW4_CS12 0x41
#define SW4_CS13 0x42
#define SW4_CS14 0x43
#define SW4_CS15 0x44
#define SW4_CS16 0x45
#define SW4_CS17 0x46
#define SW4_CS18 0x47
#define SW5_CS1 0x48
#define SW5_CS2 0x49
#define SW5_CS3 0x4A
#define SW5_CS4 0x4B
#define SW5_CS5 0x4C
#define SW5_CS6 0x4D
#define SW5_CS7 0x4E
#define SW5_CS8 0x4F
#define SW5_CS9 0x50
#define SW5_CS10 0x51
#define SW5_CS11 0x52
#define SW5_CS12 0x53
#define SW5_CS13 0x54
#define SW5_CS14 0x55
#define SW5_CS15 0x56
#define SW5_CS16 0x57
#define SW5_CS17 0x58
#define SW5_CS18 0x59
#define SW6_CS1 0x5A
#define SW6_CS2 0x5B
#define SW6_CS3 0x5C
#define SW6_CS4 0x5D
#define SW6_CS5 0x5E
#define SW6_CS6 0x5F
#define SW6_CS7 0x60
#define SW6_CS8 0x61
#define SW6_CS9 0x62
#define SW6_CS10 0x63
#define SW6_CS11 0x64
#define SW6_CS12 0x65
#define SW6_CS13 0x66
#define SW6_CS14 0x67
#define SW6_CS15 0x68
#define SW6_CS16 0x69
#define SW6_CS17 0x6A
#define SW6_CS18 0x6B
#define SW7_CS1 0x6C
#define SW7_CS2 0x6D
#define SW7_CS3 0x6E
#define SW7_CS4 0x6F
#define SW7_CS5 0x70
#define SW7_CS6 0x71
#define SW7_CS7 0x72
#define SW7_CS8 0x73
#define SW7_CS9 0x74
#define SW7_CS10 0x75
#define SW7_CS11 0x76
#define SW7_CS12 0x77
#define SW7_CS13 0x78
#define SW7_CS14 0x79
#define SW7_CS15 0x7A
#define SW7_CS16 0x7B
#define SW7_CS17 0x7C
#define SW7_CS18 0x7D
#define SW8_CS1 0x7E
#define SW8_CS2 0x7F
#define SW8_CS3 0x80
#define SW8_CS4 0x81
#define SW8_CS5 0x82
#define SW8_CS6 0x83
#define SW8_CS7 0x84
#define SW8_CS8 0x85
#define SW8_CS9 0x86
#define SW8_CS10 0x87
#define SW8_CS11 0x88
#define SW8_CS12 0x89
#define SW8_CS13 0x8A
#define SW8_CS14 0x8B
#define SW8_CS15 0x8C
#define SW8_CS16 0x8D
#define SW8_CS17 0x8E
#define SW8_CS18 0x8F
#define SW9_CS1 0x90
#define SW9_CS2 0x91
#define SW9_CS3 0x92
#define SW9_CS4 0x93
#define SW9_CS5 0x94
#define SW9_CS6 0x95
#define SW9_CS7 0x96
#define SW9_CS8 0x97
#define SW9_CS9 0x98
#define SW9_CS10 0x99
#define SW9_CS11 0x9A
#define SW9_CS12 0x9B
#define SW9_CS13 0x9C
#define SW9_CS14 0x9D
#define SW9_CS15 0x9E
#define SW9_CS16 0x9F
#define SW9_CS17 0xA0
#define SW9_CS18 0xA1
#define SW10_CS1 0xA2
#define SW10_CS2 0xA3
#define SW10_CS3 0xA4
#define SW10_CS4 0xA5
#define SW10_CS5 0xA6
#define SW10_CS6 0xA7
#define SW10_CS7 0xA8
#define SW10_CS8 0xA9
#define SW10_CS9 0xAA
#define SW10_CS10 0xAB
#define SW10_CS11 0xAC
#define SW10_CS12 0xAD
#define SW10_CS13 0xAE
#define SW10_CS14 0xAF
#define SW10_CS15 0xB0
#define SW10_CS16 0xB1
#define SW10_CS17 0xB2
#define SW10_CS18 0xB3
#define SW11_CS1 0xB4
#define SW11_CS2 0xB5
#define SW11_CS3 0xB6
#define SW11_CS4 0xB7
#define SW11_CS5 0xB8
#define SW11_CS6 0xB9
#define SW11_CS7 0xBA
#define SW11_CS8 0xBB
#define SW11_CS9 0xBC
#define SW11_CS10 0xBD
#define SW11_CS11 0xBE
#define SW11_CS12 0xBF
#define SW11_CS13 0xC0
#define SW11_CS14 0xC1
#define SW11_CS15 0xC2
#define SW11_CS16 0xC3
#define SW11_CS17 0xC4
#define SW11_CS18 0xC5

View File

@ -0,0 +1,243 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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 "is31fl3743a.h"
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3743A_PWM_REGISTER_COUNT 198
#define IS31FL3743A_SCALING_REGISTER_COUNT 198
#ifndef IS31FL3743A_I2C_TIMEOUT
# define IS31FL3743A_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3743A_I2C_PERSISTENCE
# define IS31FL3743A_I2C_PERSISTENCE 0
#endif
#ifndef IS31FL3743A_CONFIGURATION
# define IS31FL3743A_CONFIGURATION 0x01
#endif
#ifndef IS31FL3743A_SW_PULLDOWN
# define IS31FL3743A_SW_PULLDOWN IS31FL3743A_PDR_2K_OHM_SW_OFF
#endif
#ifndef IS31FL3743A_CS_PULLUP
# define IS31FL3743A_CS_PULLUP IS31FL3743A_PUR_2K_OHM_CS_OFF
#endif
#ifndef IS31FL3743A_GLOBAL_CURRENT
# define IS31FL3743A_GLOBAL_CURRENT 0xFF
#endif
#ifndef IS31FL3743A_SYNC_1
# define IS31FL3743A_SYNC_1 IS31FL3743A_SYNC_NONE
#endif
#ifndef IS31FL3743A_SYNC_2
# define IS31FL3743A_SYNC_2 IS31FL3743A_SYNC_NONE
#endif
#ifndef IS31FL3743A_SYNC_3
# define IS31FL3743A_SYNC_3 IS31FL3743A_SYNC_NONE
#endif
#ifndef IS31FL3743A_SYNC_4
# define IS31FL3743A_SYNC_4 IS31FL3743A_SYNC_NONE
#endif
const uint8_t i2c_addresses[IS31FL3743A_DRIVER_COUNT] = {
IS31FL3743A_I2C_ADDRESS_1,
#ifdef IS31FL3743A_I2C_ADDRESS_2
IS31FL3743A_I2C_ADDRESS_2,
# ifdef IS31FL3743A_I2C_ADDRESS_3
IS31FL3743A_I2C_ADDRESS_3,
# ifdef IS31FL3743A_I2C_ADDRESS_4
IS31FL3743A_I2C_ADDRESS_4,
# endif
# endif
#endif
};
const uint8_t driver_sync[IS31FL3743A_DRIVER_COUNT] = {
IS31FL3743A_SYNC_1,
#ifdef IS31FL3743A_I2C_ADDRESS_2
IS31FL3743A_SYNC_2,
# ifdef IS31FL3743A_I2C_ADDRESS_3
IS31FL3743A_SYNC_3,
# ifdef IS31FL3743A_I2C_ADDRESS_4
IS31FL3743A_SYNC_4,
# endif
# endif
#endif
};
typedef struct is31fl3743a_driver_t {
uint8_t pwm_buffer[IS31FL3743A_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t scaling_buffer[IS31FL3743A_SCALING_REGISTER_COUNT];
bool scaling_buffer_dirty;
} PACKED is31fl3743a_driver_t;
is31fl3743a_driver_t driver_buffers[IS31FL3743A_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.scaling_buffer = {0},
.scaling_buffer_dirty = false,
}};
void is31fl3743a_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3743A_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3743A_I2C_PERSISTENCE; i++) {
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3743A_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3743A_I2C_TIMEOUT);
#endif
}
void is31fl3743a_select_page(uint8_t index, uint8_t page) {
is31fl3743a_write_register(index, IS31FL3743A_REG_COMMAND_WRITE_LOCK, IS31FL3743A_COMMAND_WRITE_LOCK_MAGIC);
is31fl3743a_write_register(index, IS31FL3743A_REG_COMMAND, page);
}
void is31fl3743a_write_pwm_buffer(uint8_t index) {
// Assumes page 0 is already selected.
// Transmit PWM registers in 11 transfers of 18 bytes.
// Iterate over the pwm_buffer contents at 18 byte intervals.
for (uint8_t i = 0; i < IS31FL3743A_PWM_REGISTER_COUNT; i += 18) {
#if IS31FL3743A_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < IS31FL3743A_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i + 1, driver_buffers[index].pwm_buffer + i, 18, IS31FL3743A_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, i + 1, driver_buffers[index].pwm_buffer + i, 18, IS31FL3743A_I2C_TIMEOUT);
#endif
}
}
void is31fl3743a_init_drivers(void) {
i2c_init();
for (uint8_t i = 0; i < IS31FL3743A_DRIVER_COUNT; i++) {
is31fl3743a_init(i);
}
for (int i = 0; i < IS31FL3743A_LED_COUNT; i++) {
is31fl3743a_set_scaling_register(i, 0xFF, 0xFF, 0xFF);
}
for (uint8_t i = 0; i < IS31FL3743A_DRIVER_COUNT; i++) {
is31fl3743a_update_scaling_registers(i);
}
}
void is31fl3743a_init(uint8_t index) {
// 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.
is31fl3743a_select_page(index, IS31FL3743A_COMMAND_SCALING);
// Turn off all LEDs.
for (uint8_t i = 0; i < IS31FL3743A_SCALING_REGISTER_COUNT; i++) {
is31fl3743a_write_register(index, i + 1, 0x00);
}
is31fl3743a_select_page(index, IS31FL3743A_COMMAND_PWM);
for (uint8_t i = 0; i < IS31FL3743A_PWM_REGISTER_COUNT; i++) {
is31fl3743a_write_register(index, i + 1, 0x00);
}
is31fl3743a_select_page(index, IS31FL3743A_COMMAND_FUNCTION);
uint8_t sync = driver_sync[index];
is31fl3743a_write_register(index, IS31FL3743A_FUNCTION_REG_PULLDOWNUP, (IS31FL3743A_SW_PULLDOWN << 4) | IS31FL3743A_CS_PULLUP);
is31fl3743a_write_register(index, IS31FL3743A_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3743A_GLOBAL_CURRENT);
is31fl3743a_write_register(index, IS31FL3743A_FUNCTION_REG_SPREAD_SPECTRUM, (sync & 0b11) << 6);
is31fl3743a_write_register(index, IS31FL3743A_FUNCTION_REG_CONFIGURATION, IS31FL3743A_CONFIGURATION);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}
void is31fl3743a_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
is31fl3743a_led_t led;
if (index >= 0 && index < IS31FL3743A_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3743a_leds[index]), sizeof(led));
if (driver_buffers[led.driver].pwm_buffer[led.r] == red && driver_buffers[led.driver].pwm_buffer[led.g] == green && driver_buffers[led.driver].pwm_buffer[led.b] == blue) {
return;
}
driver_buffers[led.driver].pwm_buffer[led.r] = red;
driver_buffers[led.driver].pwm_buffer[led.g] = green;
driver_buffers[led.driver].pwm_buffer[led.b] = blue;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
void is31fl3743a_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
for (int i = 0; i < IS31FL3743A_LED_COUNT; i++) {
is31fl3743a_set_color(i, red, green, blue);
}
}
void is31fl3743a_set_scaling_register(uint8_t index, uint8_t red, uint8_t green, uint8_t blue) {
is31fl3743a_led_t led;
memcpy_P(&led, (&g_is31fl3743a_leds[index]), sizeof(led));
driver_buffers[led.driver].scaling_buffer[led.r] = red;
driver_buffers[led.driver].scaling_buffer[led.g] = green;
driver_buffers[led.driver].scaling_buffer[led.b] = blue;
driver_buffers[led.driver].scaling_buffer_dirty = true;
}
void is31fl3743a_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3743a_select_page(index, IS31FL3743A_COMMAND_PWM);
is31fl3743a_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void is31fl3743a_update_scaling_registers(uint8_t index) {
if (driver_buffers[index].scaling_buffer_dirty) {
is31fl3743a_select_page(index, IS31FL3743A_COMMAND_SCALING);
for (uint8_t i = 0; i < IS31FL3743A_SCALING_REGISTER_COUNT; i++) {
is31fl3743a_write_register(index, i + 1, driver_buffers[index].scaling_buffer[i]);
}
driver_buffers[index].scaling_buffer_dirty = false;
}
}
void is31fl3743a_flush(void) {
for (uint8_t i = 0; i < IS31FL3743A_DRIVER_COUNT; i++) {
is31fl3743a_update_pwm_buffers(i);
}
}

View File

@ -0,0 +1,541 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
#define IS31FL3743A_REG_ID 0xFC
#define IS31FL3743A_REG_COMMAND 0xFD
#define IS31FL3743A_COMMAND_PWM 0x00
#define IS31FL3743A_COMMAND_SCALING 0x01
#define IS31FL3743A_COMMAND_FUNCTION 0x02
#define IS31FL3743A_FUNCTION_REG_CONFIGURATION 0x00
#define IS31FL3743A_FUNCTION_REG_GLOBAL_CURRENT 0x01
#define IS31FL3743A_FUNCTION_REG_PULLDOWNUP 0x02
#define IS31FL3743A_FUNCTION_REG_TEMPERATURE 0x24
#define IS31FL3743A_FUNCTION_REG_SPREAD_SPECTRUM 0x25
#define IS31FL3743A_FUNCTION_REG_RESET 0x2F
#define IS31FL3743A_REG_COMMAND_WRITE_LOCK 0xFE
#define IS31FL3743A_COMMAND_WRITE_LOCK_MAGIC 0xC5
#define IS31FL3743A_I2C_ADDRESS_GND_GND 0x20
#define IS31FL3743A_I2C_ADDRESS_GND_SCL 0x21
#define IS31FL3743A_I2C_ADDRESS_GND_SDA 0x22
#define IS31FL3743A_I2C_ADDRESS_GND_VCC 0x23
#define IS31FL3743A_I2C_ADDRESS_SCL_GND 0x24
#define IS31FL3743A_I2C_ADDRESS_SCL_SCL 0x25
#define IS31FL3743A_I2C_ADDRESS_SCL_SDA 0x26
#define IS31FL3743A_I2C_ADDRESS_SCL_VCC 0x27
#define IS31FL3743A_I2C_ADDRESS_SDA_GND 0x28
#define IS31FL3743A_I2C_ADDRESS_SDA_SCL 0x29
#define IS31FL3743A_I2C_ADDRESS_SDA_SDA 0x2A
#define IS31FL3743A_I2C_ADDRESS_SDA_VCC 0x2B
#define IS31FL3743A_I2C_ADDRESS_VCC_GND 0x2C
#define IS31FL3743A_I2C_ADDRESS_VCC_SCL 0x2D
#define IS31FL3743A_I2C_ADDRESS_VCC_SDA 0x2E
#define IS31FL3743A_I2C_ADDRESS_VCC_VCC 0x2F
#if defined(RGB_MATRIX_IS31FL3743A)
# define IS31FL3743A_LED_COUNT RGB_MATRIX_LED_COUNT
#endif
#if defined(IS31FL3743A_I2C_ADDRESS_4)
# define IS31FL3743A_DRIVER_COUNT 4
#elif defined(IS31FL3743A_I2C_ADDRESS_3)
# define IS31FL3743A_DRIVER_COUNT 3
#elif defined(IS31FL3743A_I2C_ADDRESS_2)
# define IS31FL3743A_DRIVER_COUNT 2
#elif defined(IS31FL3743A_I2C_ADDRESS_1)
# define IS31FL3743A_DRIVER_COUNT 1
#endif
typedef struct is31fl3743a_led_t {
uint8_t driver : 2;
uint8_t r;
uint8_t g;
uint8_t b;
} PACKED is31fl3743a_led_t;
extern const is31fl3743a_led_t PROGMEM g_is31fl3743a_leds[IS31FL3743A_LED_COUNT];
void is31fl3743a_init_drivers(void);
void is31fl3743a_init(uint8_t index);
void is31fl3743a_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3743a_select_page(uint8_t index, uint8_t page);
void is31fl3743a_set_color(int index, uint8_t red, uint8_t green, uint8_t blue);
void is31fl3743a_set_color_all(uint8_t red, uint8_t green, uint8_t blue);
void is31fl3743a_set_scaling_register(uint8_t index, uint8_t red, uint8_t green, uint8_t blue);
void is31fl3743a_update_pwm_buffers(uint8_t index);
void is31fl3743a_update_scaling_registers(uint8_t index);
void is31fl3743a_flush(void);
#define IS31FL3743A_PDR_0_OHM 0b000 // No pull-down resistor
#define IS31FL3743A_PDR_0K5_OHM_SW_OFF 0b001 // 0.5 kOhm resistor in SWx off time
#define IS31FL3743A_PDR_1K_OHM_SW_OFF 0b010 // 1 kOhm resistor in SWx off time
#define IS31FL3743A_PDR_2K_OHM_SW_OFF 0b011 // 2 kOhm resistor in SWx off time
#define IS31FL3743A_PDR_1K_OHM 0b100 // 1 kOhm resistor
#define IS31FL3743A_PDR_2K_OHM 0b101 // 2 kOhm resistor
#define IS31FL3743A_PDR_4K_OHM 0b110 // 4 kOhm resistor
#define IS31FL3743A_PDR_8K_OHM 0b111 // 8 kOhm resistor
#define IS31FL3743A_PUR_0_OHM 0b000 // No pull-up resistor
#define IS31FL3743A_PUR_0K5_OHM_CS_OFF 0b001 // 0.5 kOhm resistor in CSy off time
#define IS31FL3743A_PUR_1K_OHM_CS_OFF 0b010 // 1 kOhm resistor in CSy off time
#define IS31FL3743A_PUR_2K_OHM_CS_OFF 0b011 // 2 kOhm resistor in CSy off time
#define IS31FL3743A_PUR_1K_OHM 0b100 // 1 kOhm resistor
#define IS31FL3743A_PUR_2K_OHM 0b101 // 2 kOhm resistor
#define IS31FL3743A_PUR_4K_OHM 0b110 // 4 kOhm resistor
#define IS31FL3743A_PUR_8K_OHM 0b111 // 8 kOhm resistor
#define IS31FL3743A_SYNC_NONE 0b00
#define IS31FL3743A_SYNC_SLAVE 0b10
#define IS31FL3743A_SYNC_MASTER 0b11
#define SW1_CS1 0x00
#define SW1_CS2 0x01
#define SW1_CS3 0x02
#define SW1_CS4 0x03
#define SW1_CS5 0x04
#define SW1_CS6 0x05
#define SW1_CS7 0x06
#define SW1_CS8 0x07
#define SW1_CS9 0x08
#define SW1_CS10 0x09
#define SW1_CS11 0x0A
#define SW1_CS12 0x0B
#define SW1_CS13 0x0C
#define SW1_CS14 0x0D
#define SW1_CS15 0x0E
#define SW1_CS16 0x0F
#define SW1_CS17 0x10
#define SW1_CS18 0x11
#define SW2_CS1 0x12
#define SW2_CS2 0x13
#define SW2_CS3 0x14
#define SW2_CS4 0x15
#define SW2_CS5 0x16
#define SW2_CS6 0x17
#define SW2_CS7 0x18
#define SW2_CS8 0x19
#define SW2_CS9 0x1A
#define SW2_CS10 0x1B
#define SW2_CS11 0x1C
#define SW2_CS12 0x1D
#define SW2_CS13 0x1E
#define SW2_CS14 0x1F
#define SW2_CS15 0x20
#define SW2_CS16 0x21
#define SW2_CS17 0x22
#define SW2_CS18 0x23
#define SW3_CS1 0x24
#define SW3_CS2 0x25
#define SW3_CS3 0x26
#define SW3_CS4 0x27
#define SW3_CS5 0x28
#define SW3_CS6 0x29
#define SW3_CS7 0x2A
#define SW3_CS8 0x2B
#define SW3_CS9 0x2C
#define SW3_CS10 0x2D
#define SW3_CS11 0x2E
#define SW3_CS12 0x2F
#define SW3_CS13 0x30
#define SW3_CS14 0x31
#define SW3_CS15 0x32
#define SW3_CS16 0x33
#define SW3_CS17 0x34
#define SW3_CS18 0x35
#define SW4_CS1 0x36
#define SW4_CS2 0x37
#define SW4_CS3 0x38
#define SW4_CS4 0x39
#define SW4_CS5 0x3A
#define SW4_CS6 0x3B
#define SW4_CS7 0x3C
#define SW4_CS8 0x3D
#define SW4_CS9 0x3E
#define SW4_CS10 0x3F
#define SW4_CS11 0x40
#define SW4_CS12 0x41
#define SW4_CS13 0x42
#define SW4_CS14 0x43
#define SW4_CS15 0x44
#define SW4_CS16 0x45
#define SW4_CS17 0x46
#define SW4_CS18 0x47
#define SW5_CS1 0x48
#define SW5_CS2 0x49
#define SW5_CS3 0x4A
#define SW5_CS4 0x4B
#define SW5_CS5 0x4C
#define SW5_CS6 0x4D
#define SW5_CS7 0x4E
#define SW5_CS8 0x4F
#define SW5_CS9 0x50
#define SW5_CS10 0x51
#define SW5_CS11 0x52
#define SW5_CS12 0x53
#define SW5_CS13 0x54
#define SW5_CS14 0x55
#define SW5_CS15 0x56
#define SW5_CS16 0x57
#define SW5_CS17 0x58
#define SW5_CS18 0x59
#define SW6_CS1 0x5A
#define SW6_CS2 0x5B
#define SW6_CS3 0x5C
#define SW6_CS4 0x5D
#define SW6_CS5 0x5E
#define SW6_CS6 0x5F
#define SW6_CS7 0x60
#define SW6_CS8 0x61
#define SW6_CS9 0x62
#define SW6_CS10 0x63
#define SW6_CS11 0x64
#define SW6_CS12 0x65
#define SW6_CS13 0x66
#define SW6_CS14 0x67
#define SW6_CS15 0x68
#define SW6_CS16 0x69
#define SW6_CS17 0x6A
#define SW6_CS18 0x6B
#define SW7_CS1 0x6C
#define SW7_CS2 0x6D
#define SW7_CS3 0x6E
#define SW7_CS4 0x6F
#define SW7_CS5 0x70
#define SW7_CS6 0x71
#define SW7_CS7 0x72
#define SW7_CS8 0x73
#define SW7_CS9 0x74
#define SW7_CS10 0x75
#define SW7_CS11 0x76
#define SW7_CS12 0x77
#define SW7_CS13 0x78
#define SW7_CS14 0x79
#define SW7_CS15 0x7A
#define SW7_CS16 0x7B
#define SW7_CS17 0x7C
#define SW7_CS18 0x7D
#define SW8_CS1 0x7E
#define SW8_CS2 0x7F
#define SW8_CS3 0x80
#define SW8_CS4 0x81
#define SW8_CS5 0x82
#define SW8_CS6 0x83
#define SW8_CS7 0x84
#define SW8_CS8 0x85
#define SW8_CS9 0x86
#define SW8_CS10 0x87
#define SW8_CS11 0x88
#define SW8_CS12 0x89
#define SW8_CS13 0x8A
#define SW8_CS14 0x8B
#define SW8_CS15 0x8C
#define SW8_CS16 0x8D
#define SW8_CS17 0x8E
#define SW8_CS18 0x8F
#define SW9_CS1 0x90
#define SW9_CS2 0x91
#define SW9_CS3 0x92
#define SW9_CS4 0x93
#define SW9_CS5 0x94
#define SW9_CS6 0x95
#define SW9_CS7 0x96
#define SW9_CS8 0x97
#define SW9_CS9 0x98
#define SW9_CS10 0x99
#define SW9_CS11 0x9A
#define SW9_CS12 0x9B
#define SW9_CS13 0x9C
#define SW9_CS14 0x9D
#define SW9_CS15 0x9E
#define SW9_CS16 0x9F
#define SW9_CS17 0xA0
#define SW9_CS18 0xA1
#define SW10_CS1 0xA2
#define SW10_CS2 0xA3
#define SW10_CS3 0xA4
#define SW10_CS4 0xA5
#define SW10_CS5 0xA6
#define SW10_CS6 0xA7
#define SW10_CS7 0xA8
#define SW10_CS8 0xA9
#define SW10_CS9 0xAA
#define SW10_CS10 0xAB
#define SW10_CS11 0xAC
#define SW10_CS12 0xAD
#define SW10_CS13 0xAE
#define SW10_CS14 0xAF
#define SW10_CS15 0xB0
#define SW10_CS16 0xB1
#define SW10_CS17 0xB2
#define SW10_CS18 0xB3
#define SW11_CS1 0xB4
#define SW11_CS2 0xB5
#define SW11_CS3 0xB6
#define SW11_CS4 0xB7
#define SW11_CS5 0xB8
#define SW11_CS6 0xB9
#define SW11_CS7 0xBA
#define SW11_CS8 0xBB
#define SW11_CS9 0xBC
#define SW11_CS10 0xBD
#define SW11_CS11 0xBE
#define SW11_CS12 0xBF
#define SW11_CS13 0xC0
#define SW11_CS14 0xC1
#define SW11_CS15 0xC2
#define SW11_CS16 0xC3
#define SW11_CS17 0xC4
#define SW11_CS18 0xC5
// DEPRECATED - DO NOT USE
#define CS1_SW1 SW1_CS1
#define CS2_SW1 SW1_CS2
#define CS3_SW1 SW1_CS3
#define CS4_SW1 SW1_CS4
#define CS5_SW1 SW1_CS5
#define CS6_SW1 SW1_CS6
#define CS7_SW1 SW1_CS7
#define CS8_SW1 SW1_CS8
#define CS9_SW1 SW1_CS9
#define CS10_SW1 SW1_CS10
#define CS11_SW1 SW1_CS11
#define CS12_SW1 SW1_CS12
#define CS13_SW1 SW1_CS13
#define CS14_SW1 SW1_CS14
#define CS15_SW1 SW1_CS15
#define CS16_SW1 SW1_CS16
#define CS17_SW1 SW1_CS17
#define CS18_SW1 SW1_CS18
#define CS1_SW2 SW2_CS1
#define CS2_SW2 SW2_CS2
#define CS3_SW2 SW2_CS3
#define CS4_SW2 SW2_CS4
#define CS5_SW2 SW2_CS5
#define CS6_SW2 SW2_CS6
#define CS7_SW2 SW2_CS7
#define CS8_SW2 SW2_CS8
#define CS9_SW2 SW2_CS9
#define CS10_SW2 SW2_CS10
#define CS11_SW2 SW2_CS11
#define CS12_SW2 SW2_CS12
#define CS13_SW2 SW2_CS13
#define CS14_SW2 SW2_CS14
#define CS15_SW2 SW2_CS15
#define CS16_SW2 SW2_CS16
#define CS17_SW2 SW2_CS17
#define CS18_SW2 SW2_CS18
#define CS1_SW3 SW3_CS1
#define CS2_SW3 SW3_CS2
#define CS3_SW3 SW3_CS3
#define CS4_SW3 SW3_CS4
#define CS5_SW3 SW3_CS5
#define CS6_SW3 SW3_CS6
#define CS7_SW3 SW3_CS7
#define CS8_SW3 SW3_CS8
#define CS9_SW3 SW3_CS9
#define CS10_SW3 SW3_CS10
#define CS11_SW3 SW3_CS11
#define CS12_SW3 SW3_CS12
#define CS13_SW3 SW3_CS13
#define CS14_SW3 SW3_CS14
#define CS15_SW3 SW3_CS15
#define CS16_SW3 SW3_CS16
#define CS17_SW3 SW3_CS17
#define CS18_SW3 SW3_CS18
#define CS1_SW4 SW4_CS1
#define CS2_SW4 SW4_CS2
#define CS3_SW4 SW4_CS3
#define CS4_SW4 SW4_CS4
#define CS5_SW4 SW4_CS5
#define CS6_SW4 SW4_CS6
#define CS7_SW4 SW4_CS7
#define CS8_SW4 SW4_CS8
#define CS9_SW4 SW4_CS9
#define CS10_SW4 SW4_CS10
#define CS11_SW4 SW4_CS11
#define CS12_SW4 SW4_CS12
#define CS13_SW4 SW4_CS13
#define CS14_SW4 SW4_CS14
#define CS15_SW4 SW4_CS15
#define CS16_SW4 SW4_CS16
#define CS17_SW4 SW4_CS17
#define CS18_SW4 SW4_CS18
#define CS1_SW5 SW5_CS1
#define CS2_SW5 SW5_CS2
#define CS3_SW5 SW5_CS3
#define CS4_SW5 SW5_CS4
#define CS5_SW5 SW5_CS5
#define CS6_SW5 SW5_CS6
#define CS7_SW5 SW5_CS7
#define CS8_SW5 SW5_CS8
#define CS9_SW5 SW5_CS9
#define CS10_SW5 SW5_CS10
#define CS11_SW5 SW5_CS11
#define CS12_SW5 SW5_CS12
#define CS13_SW5 SW5_CS13
#define CS14_SW5 SW5_CS14
#define CS15_SW5 SW5_CS15
#define CS16_SW5 SW5_CS16
#define CS17_SW5 SW5_CS17
#define CS18_SW5 SW5_CS18
#define CS1_SW6 SW6_CS1
#define CS2_SW6 SW6_CS2
#define CS3_SW6 SW6_CS3
#define CS4_SW6 SW6_CS4
#define CS5_SW6 SW6_CS5
#define CS6_SW6 SW6_CS6
#define CS7_SW6 SW6_CS7
#define CS8_SW6 SW6_CS8
#define CS9_SW6 SW6_CS9
#define CS10_SW6 SW6_CS10
#define CS11_SW6 SW6_CS11
#define CS12_SW6 SW6_CS12
#define CS13_SW6 SW6_CS13
#define CS14_SW6 SW6_CS14
#define CS15_SW6 SW6_CS15
#define CS16_SW6 SW6_CS16
#define CS17_SW6 SW6_CS17
#define CS18_SW6 SW6_CS18
#define CS1_SW7 SW7_CS1
#define CS2_SW7 SW7_CS2
#define CS3_SW7 SW7_CS3
#define CS4_SW7 SW7_CS4
#define CS5_SW7 SW7_CS5
#define CS6_SW7 SW7_CS6
#define CS7_SW7 SW7_CS7
#define CS8_SW7 SW7_CS8
#define CS9_SW7 SW7_CS9
#define CS10_SW7 SW7_CS10
#define CS11_SW7 SW7_CS11
#define CS12_SW7 SW7_CS12
#define CS13_SW7 SW7_CS13
#define CS14_SW7 SW7_CS14
#define CS15_SW7 SW7_CS15
#define CS16_SW7 SW7_CS16
#define CS17_SW7 SW7_CS17
#define CS18_SW7 SW7_CS18
#define CS1_SW8 SW8_CS1
#define CS2_SW8 SW8_CS2
#define CS3_SW8 SW8_CS3
#define CS4_SW8 SW8_CS4
#define CS5_SW8 SW8_CS5
#define CS6_SW8 SW8_CS6
#define CS7_SW8 SW8_CS7
#define CS8_SW8 SW8_CS8
#define CS9_SW8 SW8_CS9
#define CS10_SW8 SW8_CS10
#define CS11_SW8 SW8_CS11
#define CS12_SW8 SW8_CS12
#define CS13_SW8 SW8_CS13
#define CS14_SW8 SW8_CS14
#define CS15_SW8 SW8_CS15
#define CS16_SW8 SW8_CS16
#define CS17_SW8 SW8_CS17
#define CS18_SW8 SW8_CS18
#define CS1_SW9 SW9_CS1
#define CS2_SW9 SW9_CS2
#define CS3_SW9 SW9_CS3
#define CS4_SW9 SW9_CS4
#define CS5_SW9 SW9_CS5
#define CS6_SW9 SW9_CS6
#define CS7_SW9 SW9_CS7
#define CS8_SW9 SW9_CS8
#define CS9_SW9 SW9_CS9
#define CS10_SW9 SW9_CS10
#define CS11_SW9 SW9_CS11
#define CS12_SW9 SW9_CS12
#define CS13_SW9 SW9_CS13
#define CS14_SW9 SW9_CS14
#define CS15_SW9 SW9_CS15
#define CS16_SW9 SW9_CS16
#define CS17_SW9 SW9_CS17
#define CS18_SW9 SW9_CS18
#define CS1_SW10 SW10_CS1
#define CS2_SW10 SW10_CS2
#define CS3_SW10 SW10_CS3
#define CS4_SW10 SW10_CS4
#define CS5_SW10 SW10_CS5
#define CS6_SW10 SW10_CS6
#define CS7_SW10 SW10_CS7
#define CS8_SW10 SW10_CS8
#define CS9_SW10 SW10_CS9
#define CS10_SW10 SW10_CS10
#define CS11_SW10 SW10_CS11
#define CS12_SW10 SW10_CS12
#define CS13_SW10 SW10_CS13
#define CS14_SW10 SW10_CS14
#define CS15_SW10 SW10_CS15
#define CS16_SW10 SW10_CS16
#define CS17_SW10 SW10_CS17
#define CS18_SW10 SW10_CS18
#define CS1_SW11 SW11_CS1
#define CS2_SW11 SW11_CS2
#define CS3_SW11 SW11_CS3
#define CS4_SW11 SW11_CS4
#define CS5_SW11 SW11_CS5
#define CS6_SW11 SW11_CS6
#define CS7_SW11 SW11_CS7
#define CS8_SW11 SW11_CS8
#define CS9_SW11 SW11_CS9
#define CS10_SW11 SW11_CS10
#define CS11_SW11 SW11_CS11
#define CS12_SW11 SW11_CS12
#define CS13_SW11 SW11_CS13
#define CS14_SW11 SW11_CS14
#define CS15_SW11 SW11_CS15
#define CS16_SW11 SW11_CS16
#define CS17_SW11 SW11_CS17
#define CS18_SW11 SW11_CS18

View File

@ -0,0 +1,239 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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 "is31fl3745-mono.h"
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3745_PWM_REGISTER_COUNT 144
#define IS31FL3745_SCALING_REGISTER_COUNT 144
#ifndef IS31FL3745_I2C_TIMEOUT
# define IS31FL3745_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3745_I2C_PERSISTENCE
# define IS31FL3745_I2C_PERSISTENCE 0
#endif
#ifndef IS31FL3745_CONFIGURATION
# define IS31FL3745_CONFIGURATION 0x31
#endif
#ifndef IS31FL3745_SW_PULLDOWN
# define IS31FL3745_SW_PULLDOWN IS31FL3745_PDR_2K_OHM_SW_OFF
#endif
#ifndef IS31FL3745_CS_PULLUP
# define IS31FL3745_CS_PULLUP IS31FL3745_PUR_2K_OHM_CS_OFF
#endif
#ifndef IS31FL3745_GLOBAL_CURRENT
# define IS31FL3745_GLOBAL_CURRENT 0xFF
#endif
#ifndef IS31FL3745_SYNC_1
# define IS31FL3745_SYNC_1 IS31FL3745_SYNC_NONE
#endif
#ifndef IS31FL3745_SYNC_2
# define IS31FL3745_SYNC_2 IS31FL3745_SYNC_NONE
#endif
#ifndef IS31FL3745_SYNC_3
# define IS31FL3745_SYNC_3 IS31FL3745_SYNC_NONE
#endif
#ifndef IS31FL3745_SYNC_4
# define IS31FL3745_SYNC_4 IS31FL3745_SYNC_NONE
#endif
const uint8_t i2c_addresses[IS31FL3745_DRIVER_COUNT] = {
IS31FL3745_I2C_ADDRESS_1,
#ifdef IS31FL3745_I2C_ADDRESS_2
IS31FL3745_I2C_ADDRESS_2,
# ifdef IS31FL3745_I2C_ADDRESS_3
IS31FL3745_I2C_ADDRESS_3,
# ifdef IS31FL3745_I2C_ADDRESS_4
IS31FL3745_I2C_ADDRESS_4,
# endif
# endif
#endif
};
const uint8_t driver_sync[IS31FL3745_DRIVER_COUNT] = {
IS31FL3745_SYNC_1,
#ifdef IS31FL3745_I2C_ADDRESS_2
IS31FL3745_SYNC_2,
# ifdef IS31FL3745_I2C_ADDRESS_3
IS31FL3745_SYNC_3,
# ifdef IS31FL3745_I2C_ADDRESS_4
IS31FL3745_SYNC_4,
# endif
# endif
#endif
};
typedef struct is31fl3745_driver_t {
uint8_t pwm_buffer[IS31FL3745_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t scaling_buffer[IS31FL3745_SCALING_REGISTER_COUNT];
bool scaling_buffer_dirty;
} PACKED is31fl3745_driver_t;
is31fl3745_driver_t driver_buffers[IS31FL3745_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.scaling_buffer = {0},
.scaling_buffer_dirty = false,
}};
void is31fl3745_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3745_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3745_I2C_PERSISTENCE; i++) {
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3745_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3745_I2C_TIMEOUT);
#endif
}
void is31fl3745_select_page(uint8_t index, uint8_t page) {
is31fl3745_write_register(index, IS31FL3745_REG_COMMAND_WRITE_LOCK, IS31FL3745_COMMAND_WRITE_LOCK_MAGIC);
is31fl3745_write_register(index, IS31FL3745_REG_COMMAND, page);
}
void is31fl3745_write_pwm_buffer(uint8_t index) {
// Assumes page 0 is already selected.
// Transmit PWM registers in 8 transfers of 18 bytes.
// Iterate over the pwm_buffer contents at 18 byte intervals.
for (uint8_t i = 0; i < IS31FL3745_PWM_REGISTER_COUNT; i += 18) {
#if IS31FL3745_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < IS31FL3745_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i + 1, driver_buffers[index].pwm_buffer + i, 18, IS31FL3745_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, i + 1, driver_buffers[index].pwm_buffer + i, 18, IS31FL3745_I2C_TIMEOUT);
#endif
}
}
void is31fl3745_init_drivers(void) {
i2c_init();
for (uint8_t i = 0; i < IS31FL3745_DRIVER_COUNT; i++) {
is31fl3745_init(i);
}
for (int i = 0; i < IS31FL3745_LED_COUNT; i++) {
is31fl3745_set_scaling_register(i, 0xFF);
}
for (uint8_t i = 0; i < IS31FL3745_DRIVER_COUNT; i++) {
is31fl3745_update_scaling_registers(i);
}
}
void is31fl3745_init(uint8_t index) {
// 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.
is31fl3745_select_page(index, IS31FL3745_COMMAND_SCALING);
// Turn off all LEDs.
for (uint8_t i = 0; i < IS31FL3745_SCALING_REGISTER_COUNT; i++) {
is31fl3745_write_register(index, i + 1, 0x00);
}
is31fl3745_select_page(index, IS31FL3745_COMMAND_PWM);
for (uint8_t i = 0; i < IS31FL3745_PWM_REGISTER_COUNT; i++) {
is31fl3745_write_register(index, i + 1, 0x00);
}
is31fl3745_select_page(index, IS31FL3745_COMMAND_FUNCTION);
uint8_t sync = driver_sync[index];
is31fl3745_write_register(index, IS31FL3745_FUNCTION_REG_PULLDOWNUP, (IS31FL3745_SW_PULLDOWN << 4) | IS31FL3745_CS_PULLUP);
is31fl3745_write_register(index, IS31FL3745_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3745_GLOBAL_CURRENT);
is31fl3745_write_register(index, IS31FL3745_FUNCTION_REG_SPREAD_SPECTRUM, (sync & 0b11) << 6);
is31fl3745_write_register(index, IS31FL3745_FUNCTION_REG_CONFIGURATION, IS31FL3745_CONFIGURATION);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}
void is31fl3745_set_value(int index, uint8_t value) {
is31fl3745_led_t led;
if (index >= 0 && index < IS31FL3745_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3745_leds[index]), sizeof(led));
if (driver_buffers[led.driver].pwm_buffer[led.v] == value) {
return;
}
driver_buffers[led.driver].pwm_buffer[led.v] = value;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
void is31fl3745_set_value_all(uint8_t value) {
for (int i = 0; i < IS31FL3745_LED_COUNT; i++) {
is31fl3745_set_value(i, value);
}
}
void is31fl3745_set_scaling_register(uint8_t index, uint8_t value) {
is31fl3745_led_t led;
memcpy_P(&led, (&g_is31fl3745_leds[index]), sizeof(led));
driver_buffers[led.driver].scaling_buffer[led.v] = value;
driver_buffers[led.driver].scaling_buffer_dirty = true;
}
void is31fl3745_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3745_select_page(index, IS31FL3745_COMMAND_PWM);
is31fl3745_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void is31fl3745_update_scaling_registers(uint8_t index) {
if (driver_buffers[index].scaling_buffer_dirty) {
is31fl3745_select_page(index, IS31FL3745_COMMAND_SCALING);
for (uint8_t i = 0; i < IS31FL3745_SCALING_REGISTER_COUNT; i++) {
is31fl3745_write_register(index, i + 1, driver_buffers[index].scaling_buffer[i]);
}
driver_buffers[index].scaling_buffer_dirty = false;
}
}
void is31fl3745_flush(void) {
for (uint8_t i = 0; i < IS31FL3745_DRIVER_COUNT; i++) {
is31fl3745_update_pwm_buffers(i);
}
}

View File

@ -0,0 +1,271 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
#define IS31FL3745_REG_ID 0xFC
#define IS31FL3745_REG_COMMAND 0xFD
#define IS31FL3745_COMMAND_PWM 0x00
#define IS31FL3745_COMMAND_SCALING 0x01
#define IS31FL3745_COMMAND_FUNCTION 0x02
#define IS31FL3745_FUNCTION_REG_CONFIGURATION 0x00
#define IS31FL3745_FUNCTION_REG_GLOBAL_CURRENT 0x01
#define IS31FL3745_FUNCTION_REG_PULLDOWNUP 0x02
#define IS31FL3745_FUNCTION_REG_TEMPERATURE 0x24
#define IS31FL3745_FUNCTION_REG_SPREAD_SPECTRUM 0x25
#define IS31FL3745_FUNCTION_REG_RESET 0x2F
#define IS31FL3745_REG_COMMAND_WRITE_LOCK 0xFE
#define IS31FL3745_COMMAND_WRITE_LOCK_MAGIC 0xC5
#define IS31FL3745_I2C_ADDRESS_GND_GND 0x20
#define IS31FL3745_I2C_ADDRESS_GND_SCL 0x21
#define IS31FL3745_I2C_ADDRESS_GND_SDA 0x22
#define IS31FL3745_I2C_ADDRESS_GND_VCC 0x23
#define IS31FL3745_I2C_ADDRESS_SCL_GND 0x24
#define IS31FL3745_I2C_ADDRESS_SCL_SCL 0x25
#define IS31FL3745_I2C_ADDRESS_SCL_SDA 0x26
#define IS31FL3745_I2C_ADDRESS_SCL_VCC 0x27
#define IS31FL3745_I2C_ADDRESS_SDA_GND 0x28
#define IS31FL3745_I2C_ADDRESS_SDA_SCL 0x29
#define IS31FL3745_I2C_ADDRESS_SDA_SDA 0x2A
#define IS31FL3745_I2C_ADDRESS_SDA_VCC 0x2B
#define IS31FL3745_I2C_ADDRESS_VCC_GND 0x2C
#define IS31FL3745_I2C_ADDRESS_VCC_SCL 0x2D
#define IS31FL3745_I2C_ADDRESS_VCC_SDA 0x2E
#define IS31FL3745_I2C_ADDRESS_VCC_VCC 0x2F
#if defined(LED_MATRIX_IS31FL3745)
# define IS31FL3745_LED_COUNT LED_MATRIX_LED_COUNT
#endif
#if defined(IS31FL3745_I2C_ADDRESS_4)
# define IS31FL3745_DRIVER_COUNT 4
#elif defined(IS31FL3745_I2C_ADDRESS_3)
# define IS31FL3745_DRIVER_COUNT 3
#elif defined(IS31FL3745_I2C_ADDRESS_2)
# define IS31FL3745_DRIVER_COUNT 2
#elif defined(IS31FL3745_I2C_ADDRESS_1)
# define IS31FL3745_DRIVER_COUNT 1
#endif
typedef struct is31fl3745_led_t {
uint8_t driver : 2;
uint8_t v;
} PACKED is31fl3745_led_t;
extern const is31fl3745_led_t PROGMEM g_is31fl3745_leds[IS31FL3745_LED_COUNT];
void is31fl3745_init_drivers(void);
void is31fl3745_init(uint8_t index);
void is31fl3745_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3745_select_page(uint8_t index, uint8_t page);
void is31fl3745_set_value(int index, uint8_t value);
void is31fl3745_set_value_all(uint8_t value);
void is31fl3745_set_scaling_register(uint8_t index, uint8_t value);
void is31fl3745_update_pwm_buffers(uint8_t index);
void is31fl3745_update_scaling_registers(uint8_t index);
void is31fl3745_flush(void);
#define IS31FL3745_PDR_0_OHM 0b000 // No pull-down resistor
#define IS31FL3745_PDR_0K5_OHM_SW_OFF 0b001 // 0.5 kOhm resistor in SWx off time
#define IS31FL3745_PDR_1K_OHM_SW_OFF 0b010 // 1 kOhm resistor in SWx off time
#define IS31FL3745_PDR_2K_OHM_SW_OFF 0b011 // 2 kOhm resistor in SWx off time
#define IS31FL3745_PDR_1K_OHM 0b100 // 1 kOhm resistor
#define IS31FL3745_PDR_2K_OHM 0b101 // 2 kOhm resistor
#define IS31FL3745_PDR_4K_OHM 0b110 // 4 kOhm resistor
#define IS31FL3745_PDR_8K_OHM 0b111 // 8 kOhm resistor
#define IS31FL3745_PUR_0_OHM 0b000 // No pull-up resistor
#define IS31FL3745_PUR_0K5_OHM_CS_OFF 0b001 // 0.5 kOhm resistor in CSy off time
#define IS31FL3745_PUR_1K_OHM_CS_OFF 0b010 // 1 kOhm resistor in CSy off time
#define IS31FL3745_PUR_2K_OHM_CS_OFF 0b011 // 2 kOhm resistor in CSy off time
#define IS31FL3745_PUR_1K_OHM 0b100 // 1 kOhm resistor
#define IS31FL3745_PUR_2K_OHM 0b101 // 2 kOhm resistor
#define IS31FL3745_PUR_4K_OHM 0b110 // 4 kOhm resistor
#define IS31FL3745_PUR_8K_OHM 0b111 // 8 kOhm resistor
#define IS31FL3745_SYNC_NONE 0b00
#define IS31FL3745_SYNC_SLAVE 0b10
#define IS31FL3745_SYNC_MASTER 0b11
#define SW1_CS1 0x00
#define SW1_CS2 0x01
#define SW1_CS3 0x02
#define SW1_CS4 0x03
#define SW1_CS5 0x04
#define SW1_CS6 0x05
#define SW1_CS7 0x06
#define SW1_CS8 0x07
#define SW1_CS9 0x08
#define SW1_CS10 0x09
#define SW1_CS11 0x0A
#define SW1_CS12 0x0B
#define SW1_CS13 0x0C
#define SW1_CS14 0x0D
#define SW1_CS15 0x0E
#define SW1_CS16 0x0F
#define SW1_CS17 0x10
#define SW1_CS18 0x11
#define SW2_CS1 0x12
#define SW2_CS2 0x13
#define SW2_CS3 0x14
#define SW2_CS4 0x15
#define SW2_CS5 0x16
#define SW2_CS6 0x17
#define SW2_CS7 0x18
#define SW2_CS8 0x19
#define SW2_CS9 0x1A
#define SW2_CS10 0x1B
#define SW2_CS11 0x1C
#define SW2_CS12 0x1D
#define SW2_CS13 0x1E
#define SW2_CS14 0x1F
#define SW2_CS15 0x20
#define SW2_CS16 0x21
#define SW2_CS17 0x22
#define SW2_CS18 0x23
#define SW3_CS1 0x24
#define SW3_CS2 0x25
#define SW3_CS3 0x26
#define SW3_CS4 0x27
#define SW3_CS5 0x28
#define SW3_CS6 0x29
#define SW3_CS7 0x2A
#define SW3_CS8 0x2B
#define SW3_CS9 0x2C
#define SW3_CS10 0x2D
#define SW3_CS11 0x2E
#define SW3_CS12 0x2F
#define SW3_CS13 0x30
#define SW3_CS14 0x31
#define SW3_CS15 0x32
#define SW3_CS16 0x33
#define SW3_CS17 0x34
#define SW3_CS18 0x35
#define SW4_CS1 0x36
#define SW4_CS2 0x37
#define SW4_CS3 0x38
#define SW4_CS4 0x39
#define SW4_CS5 0x3A
#define SW4_CS6 0x3B
#define SW4_CS7 0x3C
#define SW4_CS8 0x3D
#define SW4_CS9 0x3E
#define SW4_CS10 0x3F
#define SW4_CS11 0x40
#define SW4_CS12 0x41
#define SW4_CS13 0x42
#define SW4_CS14 0x43
#define SW4_CS15 0x44
#define SW4_CS16 0x45
#define SW4_CS17 0x46
#define SW4_CS18 0x47
#define SW5_CS1 0x48
#define SW5_CS2 0x49
#define SW5_CS3 0x4A
#define SW5_CS4 0x4B
#define SW5_CS5 0x4C
#define SW5_CS6 0x4D
#define SW5_CS7 0x4E
#define SW5_CS8 0x4F
#define SW5_CS9 0x50
#define SW5_CS10 0x51
#define SW5_CS11 0x52
#define SW5_CS12 0x53
#define SW5_CS13 0x54
#define SW5_CS14 0x55
#define SW5_CS15 0x56
#define SW5_CS16 0x57
#define SW5_CS17 0x58
#define SW5_CS18 0x59
#define SW6_CS1 0x5A
#define SW6_CS2 0x5B
#define SW6_CS3 0x5C
#define SW6_CS4 0x5D
#define SW6_CS5 0x5E
#define SW6_CS6 0x5F
#define SW6_CS7 0x60
#define SW6_CS8 0x61
#define SW6_CS9 0x62
#define SW6_CS10 0x63
#define SW6_CS11 0x64
#define SW6_CS12 0x65
#define SW6_CS13 0x66
#define SW6_CS14 0x67
#define SW6_CS15 0x68
#define SW6_CS16 0x69
#define SW6_CS17 0x6A
#define SW6_CS18 0x6B
#define SW7_CS1 0x6C
#define SW7_CS2 0x6D
#define SW7_CS3 0x6E
#define SW7_CS4 0x6F
#define SW7_CS5 0x70
#define SW7_CS6 0x71
#define SW7_CS7 0x72
#define SW7_CS8 0x73
#define SW7_CS9 0x74
#define SW7_CS10 0x75
#define SW7_CS11 0x76
#define SW7_CS12 0x77
#define SW7_CS13 0x78
#define SW7_CS14 0x79
#define SW7_CS15 0x7A
#define SW7_CS16 0x7B
#define SW7_CS17 0x7C
#define SW7_CS18 0x7D
#define SW8_CS1 0x7E
#define SW8_CS2 0x7F
#define SW8_CS3 0x80
#define SW8_CS4 0x81
#define SW8_CS5 0x82
#define SW8_CS6 0x83
#define SW8_CS7 0x84
#define SW8_CS8 0x85
#define SW8_CS9 0x86
#define SW8_CS10 0x87
#define SW8_CS11 0x88
#define SW8_CS12 0x89
#define SW8_CS13 0x8A
#define SW8_CS14 0x8B
#define SW8_CS15 0x8C
#define SW8_CS16 0x8D
#define SW8_CS17 0x8E
#define SW8_CS18 0x8F

View File

@ -0,0 +1,243 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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 "is31fl3745.h"
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3745_PWM_REGISTER_COUNT 144
#define IS31FL3745_SCALING_REGISTER_COUNT 144
#ifndef IS31FL3745_I2C_TIMEOUT
# define IS31FL3745_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3745_I2C_PERSISTENCE
# define IS31FL3745_I2C_PERSISTENCE 0
#endif
#ifndef IS31FL3745_CONFIGURATION
# define IS31FL3745_CONFIGURATION 0x31
#endif
#ifndef IS31FL3745_SW_PULLDOWN
# define IS31FL3745_SW_PULLDOWN IS31FL3745_PDR_2K_OHM_SW_OFF
#endif
#ifndef IS31FL3745_CS_PULLUP
# define IS31FL3745_CS_PULLUP IS31FL3745_PUR_2K_OHM_CS_OFF
#endif
#ifndef IS31FL3745_GLOBAL_CURRENT
# define IS31FL3745_GLOBAL_CURRENT 0xFF
#endif
#ifndef IS31FL3745_SYNC_1
# define IS31FL3745_SYNC_1 IS31FL3745_SYNC_NONE
#endif
#ifndef IS31FL3745_SYNC_2
# define IS31FL3745_SYNC_2 IS31FL3745_SYNC_NONE
#endif
#ifndef IS31FL3745_SYNC_3
# define IS31FL3745_SYNC_3 IS31FL3745_SYNC_NONE
#endif
#ifndef IS31FL3745_SYNC_4
# define IS31FL3745_SYNC_4 IS31FL3745_SYNC_NONE
#endif
const uint8_t i2c_addresses[IS31FL3745_DRIVER_COUNT] = {
IS31FL3745_I2C_ADDRESS_1,
#ifdef IS31FL3745_I2C_ADDRESS_2
IS31FL3745_I2C_ADDRESS_2,
# ifdef IS31FL3745_I2C_ADDRESS_3
IS31FL3745_I2C_ADDRESS_3,
# ifdef IS31FL3745_I2C_ADDRESS_4
IS31FL3745_I2C_ADDRESS_4,
# endif
# endif
#endif
};
const uint8_t driver_sync[IS31FL3745_DRIVER_COUNT] = {
IS31FL3745_SYNC_1,
#ifdef IS31FL3745_I2C_ADDRESS_2
IS31FL3745_SYNC_2,
# ifdef IS31FL3745_I2C_ADDRESS_3
IS31FL3745_SYNC_3,
# ifdef IS31FL3745_I2C_ADDRESS_4
IS31FL3745_SYNC_4,
# endif
# endif
#endif
};
typedef struct is31fl3745_driver_t {
uint8_t pwm_buffer[IS31FL3745_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t scaling_buffer[IS31FL3745_SCALING_REGISTER_COUNT];
bool scaling_buffer_dirty;
} PACKED is31fl3745_driver_t;
is31fl3745_driver_t driver_buffers[IS31FL3745_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.scaling_buffer = {0},
.scaling_buffer_dirty = false,
}};
void is31fl3745_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3745_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3745_I2C_PERSISTENCE; i++) {
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3745_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3745_I2C_TIMEOUT);
#endif
}
void is31fl3745_select_page(uint8_t index, uint8_t page) {
is31fl3745_write_register(index, IS31FL3745_REG_COMMAND_WRITE_LOCK, IS31FL3745_COMMAND_WRITE_LOCK_MAGIC);
is31fl3745_write_register(index, IS31FL3745_REG_COMMAND, page);
}
void is31fl3745_write_pwm_buffer(uint8_t index) {
// Assumes page 0 is already selected.
// Transmit PWM registers in 8 transfers of 18 bytes.
// Iterate over the pwm_buffer contents at 18 byte intervals.
for (uint8_t i = 0; i < IS31FL3745_PWM_REGISTER_COUNT; i += 18) {
#if IS31FL3745_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < IS31FL3745_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i + 1, driver_buffers[index].pwm_buffer + i, 18, IS31FL3745_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, i + 1, driver_buffers[index].pwm_buffer + i, 18, IS31FL3745_I2C_TIMEOUT);
#endif
}
}
void is31fl3745_init_drivers(void) {
i2c_init();
for (uint8_t i = 0; i < IS31FL3745_DRIVER_COUNT; i++) {
is31fl3745_init(i);
}
for (int i = 0; i < IS31FL3745_LED_COUNT; i++) {
is31fl3745_set_scaling_register(i, 0xFF, 0xFF, 0xFF);
}
for (uint8_t i = 0; i < IS31FL3745_DRIVER_COUNT; i++) {
is31fl3745_update_scaling_registers(i);
}
}
void is31fl3745_init(uint8_t index) {
// 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.
is31fl3745_select_page(index, IS31FL3745_COMMAND_SCALING);
// Turn off all LEDs.
for (uint8_t i = 0; i < IS31FL3745_SCALING_REGISTER_COUNT; i++) {
is31fl3745_write_register(index, i + 1, 0x00);
}
is31fl3745_select_page(index, IS31FL3745_COMMAND_PWM);
for (uint8_t i = 0; i < IS31FL3745_PWM_REGISTER_COUNT; i++) {
is31fl3745_write_register(index, i + 1, 0x00);
}
is31fl3745_select_page(index, IS31FL3745_COMMAND_FUNCTION);
uint8_t sync = driver_sync[index];
is31fl3745_write_register(index, IS31FL3745_FUNCTION_REG_PULLDOWNUP, (IS31FL3745_SW_PULLDOWN << 4) | IS31FL3745_CS_PULLUP);
is31fl3745_write_register(index, IS31FL3745_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3745_GLOBAL_CURRENT);
is31fl3745_write_register(index, IS31FL3745_FUNCTION_REG_SPREAD_SPECTRUM, (sync & 0b11) << 6);
is31fl3745_write_register(index, IS31FL3745_FUNCTION_REG_CONFIGURATION, IS31FL3745_CONFIGURATION);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}
void is31fl3745_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
is31fl3745_led_t led;
if (index >= 0 && index < IS31FL3745_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3745_leds[index]), sizeof(led));
if (driver_buffers[led.driver].pwm_buffer[led.r] == red && driver_buffers[led.driver].pwm_buffer[led.g] == green && driver_buffers[led.driver].pwm_buffer[led.b] == blue) {
return;
}
driver_buffers[led.driver].pwm_buffer[led.r] = red;
driver_buffers[led.driver].pwm_buffer[led.g] = green;
driver_buffers[led.driver].pwm_buffer[led.b] = blue;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
void is31fl3745_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
for (int i = 0; i < IS31FL3745_LED_COUNT; i++) {
is31fl3745_set_color(i, red, green, blue);
}
}
void is31fl3745_set_scaling_register(uint8_t index, uint8_t red, uint8_t green, uint8_t blue) {
is31fl3745_led_t led;
memcpy_P(&led, (&g_is31fl3745_leds[index]), sizeof(led));
driver_buffers[led.driver].scaling_buffer[led.r] = red;
driver_buffers[led.driver].scaling_buffer[led.g] = green;
driver_buffers[led.driver].scaling_buffer[led.b] = blue;
driver_buffers[led.driver].scaling_buffer_dirty = true;
}
void is31fl3745_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3745_select_page(index, IS31FL3745_COMMAND_PWM);
is31fl3745_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void is31fl3745_update_scaling_registers(uint8_t index) {
if (driver_buffers[index].scaling_buffer_dirty) {
is31fl3745_select_page(index, IS31FL3745_COMMAND_SCALING);
for (uint8_t i = 0; i < IS31FL3745_SCALING_REGISTER_COUNT; i++) {
is31fl3745_write_register(index, i + 1, driver_buffers[index].scaling_buffer[i]);
}
driver_buffers[index].scaling_buffer_dirty = false;
}
}
void is31fl3745_flush(void) {
for (uint8_t i = 0; i < IS31FL3745_DRIVER_COUNT; i++) {
is31fl3745_update_pwm_buffers(i);
}
}

View File

@ -20,251 +20,254 @@
#pragma once
// This is a 7-bit address, that gets left-shifted and bit 0
// set to 0 for write, 1 for read (as per I2C protocol)
// The address will vary depending on your wiring:
// 00 <-> GND
// 01 <-> SCL
// 10 <-> SDA
// 11 <-> VCC
// ADDR1 represents A1:A0 of the 7-bit address.
// ADDR2 represents A3:A2 of the 7-bit address.
// The result is: 0b010(ADDR2)(ADDR1)
#ifndef DRIVER_ADDR_1
# define DRIVER_ADDR_1 0b0100000
#include <stdint.h>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
#define IS31FL3745_REG_ID 0xFC
#define IS31FL3745_REG_COMMAND 0xFD
#define IS31FL3745_COMMAND_PWM 0x00
#define IS31FL3745_COMMAND_SCALING 0x01
#define IS31FL3745_COMMAND_FUNCTION 0x02
#define IS31FL3745_FUNCTION_REG_CONFIGURATION 0x00
#define IS31FL3745_FUNCTION_REG_GLOBAL_CURRENT 0x01
#define IS31FL3745_FUNCTION_REG_PULLDOWNUP 0x02
#define IS31FL3745_FUNCTION_REG_TEMPERATURE 0x24
#define IS31FL3745_FUNCTION_REG_SPREAD_SPECTRUM 0x25
#define IS31FL3745_FUNCTION_REG_RESET 0x2F
#define IS31FL3745_REG_COMMAND_WRITE_LOCK 0xFE
#define IS31FL3745_COMMAND_WRITE_LOCK_MAGIC 0xC5
#define IS31FL3745_I2C_ADDRESS_GND_GND 0x20
#define IS31FL3745_I2C_ADDRESS_GND_SCL 0x21
#define IS31FL3745_I2C_ADDRESS_GND_SDA 0x22
#define IS31FL3745_I2C_ADDRESS_GND_VCC 0x23
#define IS31FL3745_I2C_ADDRESS_SCL_GND 0x24
#define IS31FL3745_I2C_ADDRESS_SCL_SCL 0x25
#define IS31FL3745_I2C_ADDRESS_SCL_SDA 0x26
#define IS31FL3745_I2C_ADDRESS_SCL_VCC 0x27
#define IS31FL3745_I2C_ADDRESS_SDA_GND 0x28
#define IS31FL3745_I2C_ADDRESS_SDA_SCL 0x29
#define IS31FL3745_I2C_ADDRESS_SDA_SDA 0x2A
#define IS31FL3745_I2C_ADDRESS_SDA_VCC 0x2B
#define IS31FL3745_I2C_ADDRESS_VCC_GND 0x2C
#define IS31FL3745_I2C_ADDRESS_VCC_SCL 0x2D
#define IS31FL3745_I2C_ADDRESS_VCC_SDA 0x2E
#define IS31FL3745_I2C_ADDRESS_VCC_VCC 0x2F
#if defined(RGB_MATRIX_IS31FL3745)
# define IS31FL3745_LED_COUNT RGB_MATRIX_LED_COUNT
#endif
// Set defaults for Spread Spectrum Register
#ifndef ISSI_SSR_1
# ifndef DRIVER_ADDR_2
# define ISSI_SSR_1 0x00
# else
# define ISSI_SSR_1 0xC0
# endif
#endif
#ifndef ISSI_SSR_2
# define ISSI_SSR_2 0x80
#endif
#ifndef ISSI_SSR_3
# define ISSI_SSR_3 0x80
#endif
#ifndef ISSI_SSR_4
# define ISSI_SSR_4 0x80
#if defined(IS31FL3745_I2C_ADDRESS_4)
# define IS31FL3745_DRIVER_COUNT 4
#elif defined(IS31FL3745_I2C_ADDRESS_3)
# define IS31FL3745_DRIVER_COUNT 3
#elif defined(IS31FL3745_I2C_ADDRESS_2)
# define IS31FL3745_DRIVER_COUNT 2
#elif defined(IS31FL3745_I2C_ADDRESS_1)
# define IS31FL3745_DRIVER_COUNT 1
#endif
// Command Registers
#define ISSI_COMMANDREGISTER_WRITELOCK 0xFE
#define ISSI_COMMANDREGISTER 0xFD
#define ISSI_IDREGISTER 0xFC
#define ISSI_REGISTER_UNLOCK 0xC5
typedef struct is31fl3745_led_t {
uint8_t driver : 2;
uint8_t r;
uint8_t g;
uint8_t b;
} PACKED is31fl3745_led_t;
// Response Registers
#define ISSI_PAGE_PWM 0x00
#define ISSI_PAGE_SCALING 0x01
#define ISSI_PAGE_FUNCTION 0x02
extern const is31fl3745_led_t PROGMEM g_is31fl3745_leds[IS31FL3745_LED_COUNT];
// Registers under Function Register
#define ISSI_REG_CONFIGURATION 0x00
#define ISSI_REG_GLOBALCURRENT 0x01
#define ISSI_REG_PULLDOWNUP 0x02
#define ISSI_REG_TEMP 0x24
#define ISSI_REG_SSR 0x25
#define ISSI_REG_RESET 0x2F
void is31fl3745_init_drivers(void);
void is31fl3745_init(uint8_t index);
void is31fl3745_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3745_select_page(uint8_t index, uint8_t page);
// Set defaults for Function Registers
#ifndef ISSI_CONFIGURATION
# define ISSI_CONFIGURATION 0x31
#endif
#ifndef ISSI_GLOBALCURRENT
# define ISSI_GLOBALCURRENT 0xFF
#endif
#ifndef ISSI_PULLDOWNUP
# define ISSI_PULLDOWNUP 0x33
#endif
#ifndef ISSI_TEMP
# define ISSI_TEMP 0x00
#endif
void is31fl3745_set_color(int index, uint8_t red, uint8_t green, uint8_t blue);
void is31fl3745_set_color_all(uint8_t red, uint8_t green, uint8_t blue);
// Set defaults for Scaling registers
#ifndef ISSI_SCAL_RED
# define ISSI_SCAL_RED 0xFF
#endif
#ifndef ISSI_SCAL_BLUE
# define ISSI_SCAL_BLUE 0xFF
#endif
#ifndef ISSI_SCAL_GREEN
# define ISSI_SCAL_GREEN 0xFF
#endif
#define ISSI_SCAL_RED_OFF 0x00
#define ISSI_SCAL_GREEN_OFF 0x00
#define ISSI_SCAL_BLUE_OFF 0x00
void is31fl3745_set_scaling_register(uint8_t index, uint8_t red, uint8_t green, uint8_t blue);
#ifndef ISSI_SCAL_LED
# define ISSI_SCAL_LED 0xFF
#endif
#define ISSI_SCAL_LED_OFF 0x00
void is31fl3745_update_pwm_buffers(uint8_t index);
void is31fl3745_update_scaling_registers(uint8_t index);
// Set buffer sizes
#define ISSI_MAX_LEDS 144
#define ISSI_SCALING_SIZE 144
#define ISSI_PWM_TRF_SIZE 18
#define ISSI_SCALING_TRF_SIZE 18
void is31fl3745_flush(void);
// Location of 1st bit for PWM and Scaling registers
#define ISSI_PWM_REG_1ST 0x01
#define ISSI_SCL_REG_1ST 0x01
#define IS31FL3745_PDR_0_OHM 0b000 // No pull-down resistor
#define IS31FL3745_PDR_0K5_OHM_SW_OFF 0b001 // 0.5 kOhm resistor in SWx off time
#define IS31FL3745_PDR_1K_OHM_SW_OFF 0b010 // 1 kOhm resistor in SWx off time
#define IS31FL3745_PDR_2K_OHM_SW_OFF 0b011 // 2 kOhm resistor in SWx off time
#define IS31FL3745_PDR_1K_OHM 0b100 // 1 kOhm resistor
#define IS31FL3745_PDR_2K_OHM 0b101 // 2 kOhm resistor
#define IS31FL3745_PDR_4K_OHM 0b110 // 4 kOhm resistor
#define IS31FL3745_PDR_8K_OHM 0b111 // 8 kOhm resistor
// Map CS SW locations to order in PWM / Scaling buffers
// This matches the ORDER in the Datasheet Register not the POSITION
// It will always count from 0x00 to (ISSI_MAX_LEDS - 1)
#define CS1_SW1 0x00
#define CS2_SW1 0x01
#define CS3_SW1 0x02
#define CS4_SW1 0x03
#define CS5_SW1 0x04
#define CS6_SW1 0x05
#define CS7_SW1 0x06
#define CS8_SW1 0x07
#define CS9_SW1 0x08
#define CS10_SW1 0x09
#define CS11_SW1 0x0A
#define CS12_SW1 0x0B
#define CS13_SW1 0x0C
#define CS14_SW1 0x0D
#define CS15_SW1 0x0E
#define CS16_SW1 0x0F
#define CS17_SW1 0x10
#define CS18_SW1 0x11
#define IS31FL3745_PUR_0_OHM 0b000 // No pull-up resistor
#define IS31FL3745_PUR_0K5_OHM_CS_OFF 0b001 // 0.5 kOhm resistor in CSy off time
#define IS31FL3745_PUR_1K_OHM_CS_OFF 0b010 // 1 kOhm resistor in CSy off time
#define IS31FL3745_PUR_2K_OHM_CS_OFF 0b011 // 2 kOhm resistor in CSy off time
#define IS31FL3745_PUR_1K_OHM 0b100 // 1 kOhm resistor
#define IS31FL3745_PUR_2K_OHM 0b101 // 2 kOhm resistor
#define IS31FL3745_PUR_4K_OHM 0b110 // 4 kOhm resistor
#define IS31FL3745_PUR_8K_OHM 0b111 // 8 kOhm resistor
#define CS1_SW2 0x12
#define CS2_SW2 0x13
#define CS3_SW2 0x14
#define CS4_SW2 0x15
#define CS5_SW2 0x16
#define CS6_SW2 0x17
#define CS7_SW2 0x18
#define CS8_SW2 0x19
#define CS9_SW2 0x1A
#define CS10_SW2 0x1B
#define CS11_SW2 0x1C
#define CS12_SW2 0x1D
#define CS13_SW2 0x1E
#define CS14_SW2 0x1F
#define CS15_SW2 0x20
#define CS16_SW2 0x21
#define CS17_SW2 0x22
#define CS18_SW2 0x23
#define IS31FL3745_SYNC_NONE 0b00
#define IS31FL3745_SYNC_SLAVE 0b10
#define IS31FL3745_SYNC_MASTER 0b11
#define CS1_SW3 0x24
#define CS2_SW3 0x25
#define CS3_SW3 0x26
#define CS4_SW3 0x27
#define CS5_SW3 0x28
#define CS6_SW3 0x29
#define CS7_SW3 0x2A
#define CS8_SW3 0x2B
#define CS9_SW3 0x2C
#define CS10_SW3 0x2D
#define CS11_SW3 0x2E
#define CS12_SW3 0x2F
#define CS13_SW3 0x30
#define CS14_SW3 0x31
#define CS15_SW3 0x32
#define CS16_SW3 0x33
#define CS17_SW3 0x34
#define CS18_SW3 0x35
#define SW1_CS1 0x00
#define SW1_CS2 0x01
#define SW1_CS3 0x02
#define SW1_CS4 0x03
#define SW1_CS5 0x04
#define SW1_CS6 0x05
#define SW1_CS7 0x06
#define SW1_CS8 0x07
#define SW1_CS9 0x08
#define SW1_CS10 0x09
#define SW1_CS11 0x0A
#define SW1_CS12 0x0B
#define SW1_CS13 0x0C
#define SW1_CS14 0x0D
#define SW1_CS15 0x0E
#define SW1_CS16 0x0F
#define SW1_CS17 0x10
#define SW1_CS18 0x11
#define CS1_SW4 0x36
#define CS2_SW4 0x37
#define CS3_SW4 0x38
#define CS4_SW4 0x39
#define CS5_SW4 0x3A
#define CS6_SW4 0x3B
#define CS7_SW4 0x3C
#define CS8_SW4 0x3D
#define CS9_SW4 0x3E
#define CS10_SW4 0x3F
#define CS11_SW4 0x40
#define CS12_SW4 0x41
#define CS13_SW4 0x42
#define CS14_SW4 0x43
#define CS15_SW4 0x44
#define CS16_SW4 0x45
#define CS17_SW4 0x46
#define CS18_SW4 0x47
#define SW2_CS1 0x12
#define SW2_CS2 0x13
#define SW2_CS3 0x14
#define SW2_CS4 0x15
#define SW2_CS5 0x16
#define SW2_CS6 0x17
#define SW2_CS7 0x18
#define SW2_CS8 0x19
#define SW2_CS9 0x1A
#define SW2_CS10 0x1B
#define SW2_CS11 0x1C
#define SW2_CS12 0x1D
#define SW2_CS13 0x1E
#define SW2_CS14 0x1F
#define SW2_CS15 0x20
#define SW2_CS16 0x21
#define SW2_CS17 0x22
#define SW2_CS18 0x23
#define CS1_SW5 0x48
#define CS2_SW5 0x49
#define CS3_SW5 0x4A
#define CS4_SW5 0x4B
#define CS5_SW5 0x4C
#define CS6_SW5 0x4D
#define CS7_SW5 0x4E
#define CS8_SW5 0x4F
#define CS9_SW5 0x50
#define CS10_SW5 0x51
#define CS11_SW5 0x52
#define CS12_SW5 0x53
#define CS13_SW5 0x54
#define CS14_SW5 0x55
#define CS15_SW5 0x56
#define CS16_SW5 0x57
#define CS17_SW5 0x58
#define CS18_SW5 0x59
#define SW3_CS1 0x24
#define SW3_CS2 0x25
#define SW3_CS3 0x26
#define SW3_CS4 0x27
#define SW3_CS5 0x28
#define SW3_CS6 0x29
#define SW3_CS7 0x2A
#define SW3_CS8 0x2B
#define SW3_CS9 0x2C
#define SW3_CS10 0x2D
#define SW3_CS11 0x2E
#define SW3_CS12 0x2F
#define SW3_CS13 0x30
#define SW3_CS14 0x31
#define SW3_CS15 0x32
#define SW3_CS16 0x33
#define SW3_CS17 0x34
#define SW3_CS18 0x35
#define CS1_SW6 0x5A
#define CS2_SW6 0x5B
#define CS3_SW6 0x5C
#define CS4_SW6 0x5D
#define CS5_SW6 0x5E
#define CS6_SW6 0x5F
#define CS7_SW6 0x60
#define CS8_SW6 0x61
#define CS9_SW6 0x62
#define CS10_SW6 0x63
#define CS11_SW6 0x64
#define CS12_SW6 0x65
#define CS13_SW6 0x66
#define CS14_SW6 0x67
#define CS15_SW6 0x68
#define CS16_SW6 0x69
#define CS17_SW6 0x6A
#define CS18_SW6 0x6B
#define SW4_CS1 0x36
#define SW4_CS2 0x37
#define SW4_CS3 0x38
#define SW4_CS4 0x39
#define SW4_CS5 0x3A
#define SW4_CS6 0x3B
#define SW4_CS7 0x3C
#define SW4_CS8 0x3D
#define SW4_CS9 0x3E
#define SW4_CS10 0x3F
#define SW4_CS11 0x40
#define SW4_CS12 0x41
#define SW4_CS13 0x42
#define SW4_CS14 0x43
#define SW4_CS15 0x44
#define SW4_CS16 0x45
#define SW4_CS17 0x46
#define SW4_CS18 0x47
#define CS1_SW7 0x6C
#define CS2_SW7 0x6D
#define CS3_SW7 0x6E
#define CS4_SW7 0x6F
#define CS5_SW7 0x70
#define CS6_SW7 0x71
#define CS7_SW7 0x72
#define CS8_SW7 0x73
#define CS9_SW7 0x74
#define CS10_SW7 0x75
#define CS11_SW7 0x76
#define CS12_SW7 0x77
#define CS13_SW7 0x78
#define CS14_SW7 0x79
#define CS15_SW7 0x7A
#define CS16_SW7 0x7B
#define CS17_SW7 0x7C
#define CS18_SW7 0x7D
#define SW5_CS1 0x48
#define SW5_CS2 0x49
#define SW5_CS3 0x4A
#define SW5_CS4 0x4B
#define SW5_CS5 0x4C
#define SW5_CS6 0x4D
#define SW5_CS7 0x4E
#define SW5_CS8 0x4F
#define SW5_CS9 0x50
#define SW5_CS10 0x51
#define SW5_CS11 0x52
#define SW5_CS12 0x53
#define SW5_CS13 0x54
#define SW5_CS14 0x55
#define SW5_CS15 0x56
#define SW5_CS16 0x57
#define SW5_CS17 0x58
#define SW5_CS18 0x59
#define CS1_SW8 0x7E
#define CS2_SW8 0x7F
#define CS3_SW8 0x80
#define CS4_SW8 0x81
#define CS5_SW8 0x82
#define CS6_SW8 0x83
#define CS7_SW8 0x84
#define CS8_SW8 0x85
#define CS9_SW8 0x86
#define CS10_SW8 0x87
#define CS11_SW8 0x88
#define CS12_SW8 0x89
#define CS13_SW8 0x8A
#define CS14_SW8 0x8B
#define CS15_SW8 0x8C
#define CS16_SW8 0x8D
#define CS17_SW8 0x8E
#define CS18_SW8 0x8F
#define SW6_CS1 0x5A
#define SW6_CS2 0x5B
#define SW6_CS3 0x5C
#define SW6_CS4 0x5D
#define SW6_CS5 0x5E
#define SW6_CS6 0x5F
#define SW6_CS7 0x60
#define SW6_CS8 0x61
#define SW6_CS9 0x62
#define SW6_CS10 0x63
#define SW6_CS11 0x64
#define SW6_CS12 0x65
#define SW6_CS13 0x66
#define SW6_CS14 0x67
#define SW6_CS15 0x68
#define SW6_CS16 0x69
#define SW6_CS17 0x6A
#define SW6_CS18 0x6B
#define SW7_CS1 0x6C
#define SW7_CS2 0x6D
#define SW7_CS3 0x6E
#define SW7_CS4 0x6F
#define SW7_CS5 0x70
#define SW7_CS6 0x71
#define SW7_CS7 0x72
#define SW7_CS8 0x73
#define SW7_CS9 0x74
#define SW7_CS10 0x75
#define SW7_CS11 0x76
#define SW7_CS12 0x77
#define SW7_CS13 0x78
#define SW7_CS14 0x79
#define SW7_CS15 0x7A
#define SW7_CS16 0x7B
#define SW7_CS17 0x7C
#define SW7_CS18 0x7D
#define SW8_CS1 0x7E
#define SW8_CS2 0x7F
#define SW8_CS3 0x80
#define SW8_CS4 0x81
#define SW8_CS5 0x82
#define SW8_CS6 0x83
#define SW8_CS7 0x84
#define SW8_CS8 0x85
#define SW8_CS9 0x86
#define SW8_CS10 0x87
#define SW8_CS11 0x88
#define SW8_CS12 0x89
#define SW8_CS13 0x8A
#define SW8_CS14 0x8B
#define SW8_CS15 0x8C
#define SW8_CS16 0x8D
#define SW8_CS17 0x8E
#define SW8_CS18 0x8F

View File

@ -1,198 +0,0 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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
// This is a 7-bit address, that gets left-shifted and bit 0
// set to 0 for write, 1 for read (as per I2C protocol)
// The address will vary depending on your wiring:
// 00 <-> GND
// 01 <-> SCL
// 10 <-> SDA
// 11 <-> VCC
// ADDR1 represents A1:A0 of the 7-bit address.
// ADDR2 represents A3:A2 of the 7-bit address.
// The result is: 0b110(ADDR2)(ADDR1)
#ifndef DRIVER_ADDR_1
# define DRIVER_ADDR_1 0b1100000
#endif
// Set defaults for Spread Spectrum Register
#ifndef ISSI_SSR_1
# define ISSI_SSR_1 0x00
#endif
#ifndef ISSI_SSR_2
# define ISSI_SSR_2 0x00
#endif
#ifndef ISSI_SSR_3
# define ISSI_SSR_3 0x00
#endif
#ifndef ISSI_SSR_4
# define ISSI_SSR_4 0x00
#endif
// Command Registers
#define ISSI_COMMANDREGISTER_WRITELOCK 0xFE
#define ISSI_COMMANDREGISTER 0xFD
#define ISSI_IDREGISTER 0xFC
#define ISSI_REGISTER_UNLOCK 0xC5
// Response Registers
#define ISSI_PAGE_PWM 0x00
#define ISSI_PAGE_SCALING 0x01
#define ISSI_PAGE_FUNCTION 0x01
// Registers under Function Register
#define ISSI_REG_CONFIGURATION 0x50
#define ISSI_REG_GLOBALCURRENT 0x51
#define ISSI_REG_PULLDOWNUP 0x52
#define ISSI_REG_TEMP 0x5F
#define ISSI_REG_SSR 0x60
#define ISSI_REG_RESET 0x8F
#define ISSI_REG_PWM_ENABLE 0xE0
#define ISSI_REG_PWM_SET 0xE2
// Set defaults for Function Registers
#ifndef ISSI_CONFIGURATION
# define ISSI_CONFIGURATION 0x01
#endif
#ifndef ISSI_GLOBALCURRENT
# define ISSI_GLOBALCURRENT 0xFF
#endif
#ifndef ISSI_PULLDOWNUP
# define ISSI_PULLDOWNUP 0x33
#endif
#ifndef ISSI_TEMP
# define ISSI_TEMP 0x00
#endif
#ifndef ISSI_PWM_ENABLE
# define ISSI_PWM_ENABLE 0x00
#endif
#ifndef ISSI_PWM_SET
# define ISSI_PWM_SET 0x00
#endif
// Set defaults for Scaling registers
#ifndef ISSI_SCAL_RED
# define ISSI_SCAL_RED 0xFF
#endif
#ifndef ISSI_SCAL_BLUE
# define ISSI_SCAL_BLUE 0xFF
#endif
#ifndef ISSI_SCAL_GREEN
# define ISSI_SCAL_GREEN 0xFF
#endif
#define ISSI_SCAL_RED_OFF 0x00
#define ISSI_SCAL_GREEN_OFF 0x00
#define ISSI_SCAL_BLUE_OFF 0x00
#ifndef ISSI_SCAL_LED
# define ISSI_SCAL_LED 0xFF
#endif
#define ISSI_SCAL_LED_OFF 0x00
// Set buffer sizes
#define ISSI_MAX_LEDS 72
#define ISSI_SCALING_SIZE 72
#define ISSI_PWM_TRF_SIZE 18
#define ISSI_SCALING_TRF_SIZE 18
// Location of 1st bit for PWM and Scaling registers
#define ISSI_PWM_REG_1ST 0x01
#define ISSI_SCL_REG_1ST 0x01
// Map CS SW locations to order in PWM / Scaling buffers
// This matches the ORDER in the Datasheet Register not the POSITION
// It will always count from 0x00 to (ISSI_MAX_LEDS - 1)
#define CS1_SW1 0x00
#define CS2_SW1 0x01
#define CS3_SW1 0x02
#define CS4_SW1 0x03
#define CS5_SW1 0x04
#define CS6_SW1 0x05
#define CS7_SW1 0x06
#define CS8_SW1 0x07
#define CS9_SW1 0x08
#define CS10_SW1 0x09
#define CS11_SW1 0x0A
#define CS12_SW1 0x0B
#define CS13_SW1 0x0C
#define CS14_SW1 0x0D
#define CS15_SW1 0x0E
#define CS16_SW1 0x0F
#define CS17_SW1 0x10
#define CS18_SW1 0x11
#define CS1_SW2 0x12
#define CS2_SW2 0x13
#define CS3_SW2 0x14
#define CS4_SW2 0x15
#define CS5_SW2 0x16
#define CS6_SW2 0x17
#define CS7_SW2 0x18
#define CS8_SW2 0x19
#define CS9_SW2 0x1A
#define CS10_SW2 0x1B
#define CS11_SW2 0x1C
#define CS12_SW2 0x1D
#define CS13_SW2 0x1E
#define CS14_SW2 0x1F
#define CS15_SW2 0x20
#define CS16_SW2 0x21
#define CS17_SW2 0x22
#define CS18_SW2 0x23
#define CS1_SW3 0x24
#define CS2_SW3 0x25
#define CS3_SW3 0x26
#define CS4_SW3 0x27
#define CS5_SW3 0x28
#define CS6_SW3 0x29
#define CS7_SW3 0x2A
#define CS8_SW3 0x2B
#define CS9_SW3 0x2C
#define CS10_SW3 0x2D
#define CS11_SW3 0x2E
#define CS12_SW3 0x2F
#define CS13_SW3 0x30
#define CS14_SW3 0x31
#define CS15_SW3 0x32
#define CS16_SW3 0x33
#define CS17_SW3 0x34
#define CS18_SW3 0x35
#define CS1_SW4 0x36
#define CS2_SW4 0x37
#define CS3_SW4 0x38
#define CS4_SW4 0x39
#define CS5_SW4 0x3A
#define CS6_SW4 0x3B
#define CS7_SW4 0x3C
#define CS8_SW4 0x3D
#define CS9_SW4 0x3E
#define CS10_SW4 0x3F
#define CS11_SW4 0x40
#define CS12_SW4 0x41
#define CS13_SW4 0x42
#define CS14_SW4 0x43
#define CS15_SW4 0x44
#define CS16_SW4 0x45
#define CS17_SW4 0x46
#define CS18_SW4 0x47

View File

@ -0,0 +1,216 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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 "is31fl3746a-mono.h"
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3746A_PWM_REGISTER_COUNT 72
#define IS31FL3746A_SCALING_REGISTER_COUNT 72
#ifndef IS31FL3746A_I2C_TIMEOUT
# define IS31FL3746A_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3746A_I2C_PERSISTENCE
# define IS31FL3746A_I2C_PERSISTENCE 0
#endif
#ifndef IS31FL3746A_CONFIGURATION
# define IS31FL3746A_CONFIGURATION 0x01
#endif
#ifndef IS31FL3746A_PWM_FREQUENCY
# define IS31FL3746A_PWM_FREQUENCY IS31FL3746A_PWM_FREQUENCY_29K_HZ
#endif
#ifndef IS31FL3746A_SW_PULLDOWN
# define IS31FL3746A_SW_PULLDOWN IS31FL3746A_PDR_2K_OHM_SW_OFF
#endif
#ifndef IS31FL3746A_CS_PULLUP
# define IS31FL3746A_CS_PULLUP IS31FL3746A_PUR_2K_OHM_CS_OFF
#endif
#ifndef IS31FL3746A_GLOBAL_CURRENT
# define IS31FL3746A_GLOBAL_CURRENT 0xFF
#endif
const uint8_t i2c_addresses[IS31FL3746A_DRIVER_COUNT] = {
IS31FL3746A_I2C_ADDRESS_1,
#ifdef IS31FL3746A_I2C_ADDRESS_2
IS31FL3746A_I2C_ADDRESS_2,
# ifdef IS31FL3746A_I2C_ADDRESS_3
IS31FL3746A_I2C_ADDRESS_3,
# ifdef IS31FL3746A_I2C_ADDRESS_4
IS31FL3746A_I2C_ADDRESS_4,
# endif
# endif
#endif
};
typedef struct is31fl3746a_driver_t {
uint8_t pwm_buffer[IS31FL3746A_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t scaling_buffer[IS31FL3746A_SCALING_REGISTER_COUNT];
bool scaling_buffer_dirty;
} PACKED is31fl3746a_driver_t;
is31fl3746a_driver_t driver_buffers[IS31FL3746A_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.scaling_buffer = {0},
.scaling_buffer_dirty = false,
}};
void is31fl3746a_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3746A_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3746A_I2C_PERSISTENCE; i++) {
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3746A_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3746A_I2C_TIMEOUT);
#endif
}
void is31fl3746a_select_page(uint8_t index, uint8_t page) {
is31fl3746a_write_register(index, IS31FL3746A_REG_COMMAND_WRITE_LOCK, IS31FL3746A_COMMAND_WRITE_LOCK_MAGIC);
is31fl3746a_write_register(index, IS31FL3746A_REG_COMMAND, page);
}
void is31fl3746a_write_pwm_buffer(uint8_t index) {
// Assumes page 0 is already selected.
// Transmit PWM registers in 4 transfers of 18 bytes.
// Iterate over the pwm_buffer contents at 18 byte intervals.
for (uint8_t i = 0; i < IS31FL3746A_PWM_REGISTER_COUNT; i += 18) {
#if IS31FL3746A_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < IS31FL3746A_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i + 1, driver_buffers[index].pwm_buffer + i, 18, IS31FL3746A_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, i + 1, driver_buffers[index].pwm_buffer + i, 18, IS31FL3746A_I2C_TIMEOUT);
#endif
}
}
void is31fl3746a_init_drivers(void) {
i2c_init();
for (uint8_t i = 0; i < IS31FL3746A_DRIVER_COUNT; i++) {
is31fl3746a_init(i);
}
for (int i = 0; i < IS31FL3746A_LED_COUNT; i++) {
is31fl3746a_set_scaling_register(i, 0xFF);
}
for (uint8_t i = 0; i < IS31FL3746A_DRIVER_COUNT; i++) {
is31fl3746a_update_scaling_registers(i);
}
}
void is31fl3746a_init(uint8_t index) {
// 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.
is31fl3746a_select_page(index, IS31FL3746A_COMMAND_SCALING);
// Turn off all LEDs.
for (uint8_t i = 0; i < IS31FL3746A_SCALING_REGISTER_COUNT; i++) {
is31fl3746a_write_register(index, i + 1, 0x00);
}
is31fl3746a_select_page(index, IS31FL3746A_COMMAND_PWM);
for (uint8_t i = 0; i < IS31FL3746A_PWM_REGISTER_COUNT; i++) {
is31fl3746a_write_register(index, i + 1, 0x00);
}
is31fl3746a_select_page(index, IS31FL3746A_COMMAND_FUNCTION);
is31fl3746a_write_register(index, IS31FL3746A_FUNCTION_REG_PULLDOWNUP, (IS31FL3746A_SW_PULLDOWN << 4) | IS31FL3746A_CS_PULLUP);
is31fl3746a_write_register(index, IS31FL3746A_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3746A_GLOBAL_CURRENT);
is31fl3746a_write_register(index, IS31FL3746A_FUNCTION_REG_PWM_ENABLE, 0x01);
is31fl3746a_write_register(index, IS31FL3746A_FUNCTION_REG_PWM_FREQUENCY, IS31FL3746A_PWM_FREQUENCY);
is31fl3746a_write_register(index, IS31FL3746A_FUNCTION_REG_CONFIGURATION, IS31FL3746A_CONFIGURATION);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}
void is31fl3746a_set_value(int index, uint8_t value) {
is31fl3746a_led_t led;
if (index >= 0 && index < IS31FL3746A_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3746a_leds[index]), sizeof(led));
if (driver_buffers[led.driver].pwm_buffer[led.v] == value) {
return;
}
driver_buffers[led.driver].pwm_buffer[led.v] = value;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
void is31fl3746a_set_value_all(uint8_t value) {
for (int i = 0; i < IS31FL3746A_LED_COUNT; i++) {
is31fl3746a_set_value(i, value);
}
}
void is31fl3746a_set_scaling_register(uint8_t index, uint8_t value) {
is31fl3746a_led_t led;
memcpy_P(&led, (&g_is31fl3746a_leds[index]), sizeof(led));
driver_buffers[led.driver].scaling_buffer[led.v] = value;
driver_buffers[led.driver].scaling_buffer_dirty = true;
}
void is31fl3746a_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3746a_select_page(index, IS31FL3746A_COMMAND_PWM);
is31fl3746a_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void is31fl3746a_update_scaling_registers(uint8_t index) {
if (driver_buffers[index].scaling_buffer_dirty) {
is31fl3746a_select_page(index, IS31FL3746A_COMMAND_SCALING);
for (uint8_t i = 0; i < IS31FL3746A_SCALING_REGISTER_COUNT; i++) {
is31fl3746a_write_register(index, i + 1, driver_buffers[index].scaling_buffer[i]);
}
driver_buffers[index].scaling_buffer_dirty = false;
}
}
void is31fl3746a_flush(void) {
for (uint8_t i = 0; i < IS31FL3746A_DRIVER_COUNT; i++) {
is31fl3746a_update_pwm_buffers(i);
}
}

View File

@ -0,0 +1,201 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
#define IS31FL3746A_REG_ID 0xFC
#define IS31FL3746A_REG_COMMAND 0xFD
#define IS31FL3746A_COMMAND_PWM 0x00
#define IS31FL3746A_COMMAND_SCALING 0x01
#define IS31FL3746A_COMMAND_FUNCTION 0x01
#define IS31FL3746A_FUNCTION_REG_CONFIGURATION 0x50
#define IS31FL3746A_FUNCTION_REG_GLOBAL_CURRENT 0x51
#define IS31FL3746A_FUNCTION_REG_PULLDOWNUP 0x52
#define IS31FL3746A_FUNCTION_REG_TEMPERATURE 0x5F
#define IS31FL3746A_FUNCTION_REG_SPREAD_SPECTRUM 0x60
#define IS31FL3746A_FUNCTION_REG_RESET 0x8F
#define IS31FL3746A_FUNCTION_REG_PWM_ENABLE 0xE0
#define IS31FL3746A_FUNCTION_REG_PWM_FREQUENCY 0xE2
#define IS31FL3746A_REG_COMMAND_WRITE_LOCK 0xFE
#define IS31FL3746A_COMMAND_WRITE_LOCK_MAGIC 0xC5
#define IS31FL3746A_I2C_ADDRESS_GND_GND 0x60
#define IS31FL3746A_I2C_ADDRESS_GND_SCL 0x61
#define IS31FL3746A_I2C_ADDRESS_GND_SDA 0x62
#define IS31FL3746A_I2C_ADDRESS_GND_VCC 0x63
#define IS31FL3746A_I2C_ADDRESS_SCL_GND 0x64
#define IS31FL3746A_I2C_ADDRESS_SCL_SCL 0x65
#define IS31FL3746A_I2C_ADDRESS_SCL_SDA 0x66
#define IS31FL3746A_I2C_ADDRESS_SCL_VCC 0x67
#define IS31FL3746A_I2C_ADDRESS_SDA_GND 0x68
#define IS31FL3746A_I2C_ADDRESS_SDA_SCL 0x69
#define IS31FL3746A_I2C_ADDRESS_SDA_SDA 0x6A
#define IS31FL3746A_I2C_ADDRESS_SDA_VCC 0x6B
#define IS31FL3746A_I2C_ADDRESS_VCC_GND 0x6C
#define IS31FL3746A_I2C_ADDRESS_VCC_SCL 0x6D
#define IS31FL3746A_I2C_ADDRESS_VCC_SDA 0x6E
#define IS31FL3746A_I2C_ADDRESS_VCC_VCC 0x6F
#if defined(LED_MATRIX_IS31FL3746A)
# define IS31FL3746A_LED_COUNT LED_MATRIX_LED_COUNT
#endif
#if defined(IS31FL3746A_I2C_ADDRESS_4)
# define IS31FL3746A_DRIVER_COUNT 4
#elif defined(IS31FL3746A_I2C_ADDRESS_3)
# define IS31FL3746A_DRIVER_COUNT 3
#elif defined(IS31FL3746A_I2C_ADDRESS_2)
# define IS31FL3746A_DRIVER_COUNT 2
#elif defined(IS31FL3746A_I2C_ADDRESS_1)
# define IS31FL3746A_DRIVER_COUNT 1
#endif
typedef struct is31fl3746a_led_t {
uint8_t driver : 2;
uint8_t v;
} PACKED is31fl3746a_led_t;
extern const is31fl3746a_led_t PROGMEM g_is31fl3746a_leds[IS31FL3746A_LED_COUNT];
void is31fl3746a_init_drivers(void);
void is31fl3746a_init(uint8_t index);
void is31fl3746a_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3746a_select_page(uint8_t index, uint8_t page);
void is31fl3746a_set_value(int index, uint8_t value);
void is31fl3746a_set_value_all(uint8_t value);
void is31fl3746a_set_scaling_register(uint8_t index, uint8_t value);
void is31fl3746a_update_pwm_buffers(uint8_t index);
void is31fl3746a_update_scaling_registers(uint8_t index);
void is31fl3746a_flush(void);
#define IS31FL3746A_PDR_0_OHM 0b000 // No pull-down resistor
#define IS31FL3746A_PDR_0K5_OHM_SW_OFF 0b001 // 0.5 kOhm resistor in SWx off time
#define IS31FL3746A_PDR_1K_OHM_SW_OFF 0b010 // 1 kOhm resistor in SWx off time
#define IS31FL3746A_PDR_2K_OHM_SW_OFF 0b011 // 2 kOhm resistor in SWx off time
#define IS31FL3746A_PDR_1K_OHM 0b100 // 1 kOhm resistor
#define IS31FL3746A_PDR_2K_OHM 0b101 // 2 kOhm resistor
#define IS31FL3746A_PDR_4K_OHM 0b110 // 4 kOhm resistor
#define IS31FL3746A_PDR_8K_OHM 0b111 // 8 kOhm resistor
#define IS31FL3746A_PUR_0_OHM 0b000 // No pull-up resistor
#define IS31FL3746A_PUR_0K5_OHM_CS_OFF 0b001 // 0.5 kOhm resistor in CSy off time
#define IS31FL3746A_PUR_1K_OHM_CS_OFF 0b010 // 1 kOhm resistor in CSy off time
#define IS31FL3746A_PUR_2K_OHM_CS_OFF 0b011 // 2 kOhm resistor in CSy off time
#define IS31FL3746A_PUR_1K_OHM 0b100 // 1 kOhm resistor
#define IS31FL3746A_PUR_2K_OHM 0b101 // 2 kOhm resistor
#define IS31FL3746A_PUR_4K_OHM 0b110 // 4 kOhm resistor
#define IS31FL3746A_PUR_8K_OHM 0b111 // 8 kOhm resistor
#define IS31FL3746A_PWM_FREQUENCY_29K_HZ 0b000
#define IS31FL3746A_PWM_FREQUENCY_14K5_HZ 0b001
#define IS31FL3746A_PWM_FREQUENCY_7K25_HZ 0b010
#define IS31FL3746A_PWM_FREQUENCY_3K63_HZ 0b011
#define IS31FL3746A_PWM_FREQUENCY_1K81_HZ 0b100
#define IS31FL3746A_PWM_FREQUENCY_906_HZ 0b101
#define IS31FL3746A_PWM_FREQUENCY_453_HZ 0b110
#define SW1_CS1 0x00
#define SW1_CS2 0x01
#define SW1_CS3 0x02
#define SW1_CS4 0x03
#define SW1_CS5 0x04
#define SW1_CS6 0x05
#define SW1_CS7 0x06
#define SW1_CS8 0x07
#define SW1_CS9 0x08
#define SW1_CS10 0x09
#define SW1_CS11 0x0A
#define SW1_CS12 0x0B
#define SW1_CS13 0x0C
#define SW1_CS14 0x0D
#define SW1_CS15 0x0E
#define SW1_CS16 0x0F
#define SW1_CS17 0x10
#define SW1_CS18 0x11
#define SW2_CS1 0x12
#define SW2_CS2 0x13
#define SW2_CS3 0x14
#define SW2_CS4 0x15
#define SW2_CS5 0x16
#define SW2_CS6 0x17
#define SW2_CS7 0x18
#define SW2_CS8 0x19
#define SW2_CS9 0x1A
#define SW2_CS10 0x1B
#define SW2_CS11 0x1C
#define SW2_CS12 0x1D
#define SW2_CS13 0x1E
#define SW2_CS14 0x1F
#define SW2_CS15 0x20
#define SW2_CS16 0x21
#define SW2_CS17 0x22
#define SW2_CS18 0x23
#define SW3_CS1 0x24
#define SW3_CS2 0x25
#define SW3_CS3 0x26
#define SW3_CS4 0x27
#define SW3_CS5 0x28
#define SW3_CS6 0x29
#define SW3_CS7 0x2A
#define SW3_CS8 0x2B
#define SW3_CS9 0x2C
#define SW3_CS10 0x2D
#define SW3_CS11 0x2E
#define SW3_CS12 0x2F
#define SW3_CS13 0x30
#define SW3_CS14 0x31
#define SW3_CS15 0x32
#define SW3_CS16 0x33
#define SW3_CS17 0x34
#define SW3_CS18 0x35
#define SW4_CS1 0x36
#define SW4_CS2 0x37
#define SW4_CS3 0x38
#define SW4_CS4 0x39
#define SW4_CS5 0x3A
#define SW4_CS6 0x3B
#define SW4_CS7 0x3C
#define SW4_CS8 0x3D
#define SW4_CS9 0x3E
#define SW4_CS10 0x3F
#define SW4_CS11 0x40
#define SW4_CS12 0x41
#define SW4_CS13 0x42
#define SW4_CS14 0x43
#define SW4_CS15 0x44
#define SW4_CS16 0x45
#define SW4_CS17 0x46
#define SW4_CS18 0x47

View File

@ -0,0 +1,220 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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 "is31fl3746a.h"
#include "i2c_master.h"
#include "wait.h"
#define IS31FL3746A_PWM_REGISTER_COUNT 72
#define IS31FL3746A_SCALING_REGISTER_COUNT 72
#ifndef IS31FL3746A_I2C_TIMEOUT
# define IS31FL3746A_I2C_TIMEOUT 100
#endif
#ifndef IS31FL3746A_I2C_PERSISTENCE
# define IS31FL3746A_I2C_PERSISTENCE 0
#endif
#ifndef IS31FL3746A_CONFIGURATION
# define IS31FL3746A_CONFIGURATION 0x01
#endif
#ifndef IS31FL3746A_PWM_FREQUENCY
# define IS31FL3746A_PWM_FREQUENCY IS31FL3746A_PWM_FREQUENCY_29K_HZ
#endif
#ifndef IS31FL3746A_SW_PULLDOWN
# define IS31FL3746A_SW_PULLDOWN IS31FL3746A_PDR_2K_OHM_SW_OFF
#endif
#ifndef IS31FL3746A_CS_PULLUP
# define IS31FL3746A_CS_PULLUP IS31FL3746A_PUR_2K_OHM_CS_OFF
#endif
#ifndef IS31FL3746A_GLOBAL_CURRENT
# define IS31FL3746A_GLOBAL_CURRENT 0xFF
#endif
const uint8_t i2c_addresses[IS31FL3746A_DRIVER_COUNT] = {
IS31FL3746A_I2C_ADDRESS_1,
#ifdef IS31FL3746A_I2C_ADDRESS_2
IS31FL3746A_I2C_ADDRESS_2,
# ifdef IS31FL3746A_I2C_ADDRESS_3
IS31FL3746A_I2C_ADDRESS_3,
# ifdef IS31FL3746A_I2C_ADDRESS_4
IS31FL3746A_I2C_ADDRESS_4,
# endif
# endif
#endif
};
typedef struct is31fl3746a_driver_t {
uint8_t pwm_buffer[IS31FL3746A_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t scaling_buffer[IS31FL3746A_SCALING_REGISTER_COUNT];
bool scaling_buffer_dirty;
} PACKED is31fl3746a_driver_t;
is31fl3746a_driver_t driver_buffers[IS31FL3746A_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.scaling_buffer = {0},
.scaling_buffer_dirty = false,
}};
void is31fl3746a_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if IS31FL3746A_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < IS31FL3746A_I2C_PERSISTENCE; i++) {
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3746A_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, IS31FL3746A_I2C_TIMEOUT);
#endif
}
void is31fl3746a_select_page(uint8_t index, uint8_t page) {
is31fl3746a_write_register(index, IS31FL3746A_REG_COMMAND_WRITE_LOCK, IS31FL3746A_COMMAND_WRITE_LOCK_MAGIC);
is31fl3746a_write_register(index, IS31FL3746A_REG_COMMAND, page);
}
void is31fl3746a_write_pwm_buffer(uint8_t index) {
// Assumes page 0 is already selected.
// Transmit PWM registers in 4 transfers of 18 bytes.
// Iterate over the pwm_buffer contents at 18 byte intervals.
for (uint8_t i = 0; i < IS31FL3746A_PWM_REGISTER_COUNT; i += 18) {
#if IS31FL3746A_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < IS31FL3746A_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i + 1, driver_buffers[index].pwm_buffer + i, 18, IS31FL3746A_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, i + 1, driver_buffers[index].pwm_buffer + i, 18, IS31FL3746A_I2C_TIMEOUT);
#endif
}
}
void is31fl3746a_init_drivers(void) {
i2c_init();
for (uint8_t i = 0; i < IS31FL3746A_DRIVER_COUNT; i++) {
is31fl3746a_init(i);
}
for (int i = 0; i < IS31FL3746A_LED_COUNT; i++) {
is31fl3746a_set_scaling_register(i, 0xFF, 0xFF, 0xFF);
}
for (uint8_t i = 0; i < IS31FL3746A_DRIVER_COUNT; i++) {
is31fl3746a_update_scaling_registers(i);
}
}
void is31fl3746a_init(uint8_t index) {
// 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.
is31fl3746a_select_page(index, IS31FL3746A_COMMAND_SCALING);
// Turn off all LEDs.
for (uint8_t i = 0; i < IS31FL3746A_SCALING_REGISTER_COUNT; i++) {
is31fl3746a_write_register(index, i + 1, 0x00);
}
is31fl3746a_select_page(index, IS31FL3746A_COMMAND_PWM);
for (uint8_t i = 0; i < IS31FL3746A_PWM_REGISTER_COUNT; i++) {
is31fl3746a_write_register(index, i + 1, 0x00);
}
is31fl3746a_select_page(index, IS31FL3746A_COMMAND_FUNCTION);
is31fl3746a_write_register(index, IS31FL3746A_FUNCTION_REG_PULLDOWNUP, (IS31FL3746A_SW_PULLDOWN << 4) | IS31FL3746A_CS_PULLUP);
is31fl3746a_write_register(index, IS31FL3746A_FUNCTION_REG_GLOBAL_CURRENT, IS31FL3746A_GLOBAL_CURRENT);
is31fl3746a_write_register(index, IS31FL3746A_FUNCTION_REG_PWM_ENABLE, 0x01);
is31fl3746a_write_register(index, IS31FL3746A_FUNCTION_REG_PWM_FREQUENCY, IS31FL3746A_PWM_FREQUENCY);
is31fl3746a_write_register(index, IS31FL3746A_FUNCTION_REG_CONFIGURATION, IS31FL3746A_CONFIGURATION);
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}
void is31fl3746a_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
is31fl3746a_led_t led;
if (index >= 0 && index < IS31FL3746A_LED_COUNT) {
memcpy_P(&led, (&g_is31fl3746a_leds[index]), sizeof(led));
if (driver_buffers[led.driver].pwm_buffer[led.r] == red && driver_buffers[led.driver].pwm_buffer[led.g] == green && driver_buffers[led.driver].pwm_buffer[led.b] == blue) {
return;
}
driver_buffers[led.driver].pwm_buffer[led.r] = red;
driver_buffers[led.driver].pwm_buffer[led.g] = green;
driver_buffers[led.driver].pwm_buffer[led.b] = blue;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
void is31fl3746a_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
for (int i = 0; i < IS31FL3746A_LED_COUNT; i++) {
is31fl3746a_set_color(i, red, green, blue);
}
}
void is31fl3746a_set_scaling_register(uint8_t index, uint8_t red, uint8_t green, uint8_t blue) {
is31fl3746a_led_t led;
memcpy_P(&led, (&g_is31fl3746a_leds[index]), sizeof(led));
driver_buffers[led.driver].scaling_buffer[led.r] = red;
driver_buffers[led.driver].scaling_buffer[led.g] = green;
driver_buffers[led.driver].scaling_buffer[led.b] = blue;
driver_buffers[led.driver].scaling_buffer_dirty = true;
}
void is31fl3746a_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
is31fl3746a_select_page(index, IS31FL3746A_COMMAND_PWM);
is31fl3746a_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void is31fl3746a_update_scaling_registers(uint8_t index) {
if (driver_buffers[index].scaling_buffer_dirty) {
is31fl3746a_select_page(index, IS31FL3746A_COMMAND_SCALING);
for (uint8_t i = 0; i < IS31FL3746A_SCALING_REGISTER_COUNT; i++) {
is31fl3746a_write_register(index, i + 1, driver_buffers[index].scaling_buffer[i]);
}
driver_buffers[index].scaling_buffer_dirty = false;
}
}
void is31fl3746a_flush(void) {
for (uint8_t i = 0; i < IS31FL3746A_DRIVER_COUNT; i++) {
is31fl3746a_update_pwm_buffers(i);
}
}

View File

@ -0,0 +1,203 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
#define IS31FL3746A_REG_ID 0xFC
#define IS31FL3746A_REG_COMMAND 0xFD
#define IS31FL3746A_COMMAND_PWM 0x00
#define IS31FL3746A_COMMAND_SCALING 0x01
#define IS31FL3746A_COMMAND_FUNCTION 0x01
#define IS31FL3746A_FUNCTION_REG_CONFIGURATION 0x50
#define IS31FL3746A_FUNCTION_REG_GLOBAL_CURRENT 0x51
#define IS31FL3746A_FUNCTION_REG_PULLDOWNUP 0x52
#define IS31FL3746A_FUNCTION_REG_TEMPERATURE 0x5F
#define IS31FL3746A_FUNCTION_REG_SPREAD_SPECTRUM 0x60
#define IS31FL3746A_FUNCTION_REG_RESET 0x8F
#define IS31FL3746A_FUNCTION_REG_PWM_ENABLE 0xE0
#define IS31FL3746A_FUNCTION_REG_PWM_FREQUENCY 0xE2
#define IS31FL3746A_REG_COMMAND_WRITE_LOCK 0xFE
#define IS31FL3746A_COMMAND_WRITE_LOCK_MAGIC 0xC5
#define IS31FL3746A_I2C_ADDRESS_GND_GND 0x60
#define IS31FL3746A_I2C_ADDRESS_GND_SCL 0x61
#define IS31FL3746A_I2C_ADDRESS_GND_SDA 0x62
#define IS31FL3746A_I2C_ADDRESS_GND_VCC 0x63
#define IS31FL3746A_I2C_ADDRESS_SCL_GND 0x64
#define IS31FL3746A_I2C_ADDRESS_SCL_SCL 0x65
#define IS31FL3746A_I2C_ADDRESS_SCL_SDA 0x66
#define IS31FL3746A_I2C_ADDRESS_SCL_VCC 0x67
#define IS31FL3746A_I2C_ADDRESS_SDA_GND 0x68
#define IS31FL3746A_I2C_ADDRESS_SDA_SCL 0x69
#define IS31FL3746A_I2C_ADDRESS_SDA_SDA 0x6A
#define IS31FL3746A_I2C_ADDRESS_SDA_VCC 0x6B
#define IS31FL3746A_I2C_ADDRESS_VCC_GND 0x6C
#define IS31FL3746A_I2C_ADDRESS_VCC_SCL 0x6D
#define IS31FL3746A_I2C_ADDRESS_VCC_SDA 0x6E
#define IS31FL3746A_I2C_ADDRESS_VCC_VCC 0x6F
#if defined(RGB_MATRIX_IS31FL3746A)
# define IS31FL3746A_LED_COUNT RGB_MATRIX_LED_COUNT
#endif
#if defined(IS31FL3746A_I2C_ADDRESS_4)
# define IS31FL3746A_DRIVER_COUNT 4
#elif defined(IS31FL3746A_I2C_ADDRESS_3)
# define IS31FL3746A_DRIVER_COUNT 3
#elif defined(IS31FL3746A_I2C_ADDRESS_2)
# define IS31FL3746A_DRIVER_COUNT 2
#elif defined(IS31FL3746A_I2C_ADDRESS_1)
# define IS31FL3746A_DRIVER_COUNT 1
#endif
typedef struct is31fl3746a_led_t {
uint8_t driver : 2;
uint8_t r;
uint8_t g;
uint8_t b;
} PACKED is31fl3746a_led_t;
extern const is31fl3746a_led_t PROGMEM g_is31fl3746a_leds[IS31FL3746A_LED_COUNT];
void is31fl3746a_init_drivers(void);
void is31fl3746a_init(uint8_t index);
void is31fl3746a_write_register(uint8_t index, uint8_t reg, uint8_t data);
void is31fl3746a_select_page(uint8_t index, uint8_t page);
void is31fl3746a_set_color(int index, uint8_t red, uint8_t green, uint8_t blue);
void is31fl3746a_set_color_all(uint8_t red, uint8_t green, uint8_t blue);
void is31fl3746a_set_scaling_register(uint8_t index, uint8_t red, uint8_t green, uint8_t blue);
void is31fl3746a_update_pwm_buffers(uint8_t index);
void is31fl3746a_update_scaling_registers(uint8_t index);
void is31fl3746a_flush(void);
#define IS31FL3746A_PDR_0_OHM 0b000 // No pull-down resistor
#define IS31FL3746A_PDR_0K5_OHM_SW_OFF 0b001 // 0.5 kOhm resistor in SWx off time
#define IS31FL3746A_PDR_1K_OHM_SW_OFF 0b010 // 1 kOhm resistor in SWx off time
#define IS31FL3746A_PDR_2K_OHM_SW_OFF 0b011 // 2 kOhm resistor in SWx off time
#define IS31FL3746A_PDR_1K_OHM 0b100 // 1 kOhm resistor
#define IS31FL3746A_PDR_2K_OHM 0b101 // 2 kOhm resistor
#define IS31FL3746A_PDR_4K_OHM 0b110 // 4 kOhm resistor
#define IS31FL3746A_PDR_8K_OHM 0b111 // 8 kOhm resistor
#define IS31FL3746A_PUR_0_OHM 0b000 // No pull-up resistor
#define IS31FL3746A_PUR_0K5_OHM_CS_OFF 0b001 // 0.5 kOhm resistor in CSy off time
#define IS31FL3746A_PUR_1K_OHM_CS_OFF 0b010 // 1 kOhm resistor in CSy off time
#define IS31FL3746A_PUR_2K_OHM_CS_OFF 0b011 // 2 kOhm resistor in CSy off time
#define IS31FL3746A_PUR_1K_OHM 0b100 // 1 kOhm resistor
#define IS31FL3746A_PUR_2K_OHM 0b101 // 2 kOhm resistor
#define IS31FL3746A_PUR_4K_OHM 0b110 // 4 kOhm resistor
#define IS31FL3746A_PUR_8K_OHM 0b111 // 8 kOhm resistor
#define IS31FL3746A_PWM_FREQUENCY_29K_HZ 0b000
#define IS31FL3746A_PWM_FREQUENCY_14K5_HZ 0b001
#define IS31FL3746A_PWM_FREQUENCY_7K25_HZ 0b010
#define IS31FL3746A_PWM_FREQUENCY_3K63_HZ 0b011
#define IS31FL3746A_PWM_FREQUENCY_1K81_HZ 0b100
#define IS31FL3746A_PWM_FREQUENCY_906_HZ 0b101
#define IS31FL3746A_PWM_FREQUENCY_453_HZ 0b110
#define SW1_CS1 0x00
#define SW1_CS2 0x01
#define SW1_CS3 0x02
#define SW1_CS4 0x03
#define SW1_CS5 0x04
#define SW1_CS6 0x05
#define SW1_CS7 0x06
#define SW1_CS8 0x07
#define SW1_CS9 0x08
#define SW1_CS10 0x09
#define SW1_CS11 0x0A
#define SW1_CS12 0x0B
#define SW1_CS13 0x0C
#define SW1_CS14 0x0D
#define SW1_CS15 0x0E
#define SW1_CS16 0x0F
#define SW1_CS17 0x10
#define SW1_CS18 0x11
#define SW2_CS1 0x12
#define SW2_CS2 0x13
#define SW2_CS3 0x14
#define SW2_CS4 0x15
#define SW2_CS5 0x16
#define SW2_CS6 0x17
#define SW2_CS7 0x18
#define SW2_CS8 0x19
#define SW2_CS9 0x1A
#define SW2_CS10 0x1B
#define SW2_CS11 0x1C
#define SW2_CS12 0x1D
#define SW2_CS13 0x1E
#define SW2_CS14 0x1F
#define SW2_CS15 0x20
#define SW2_CS16 0x21
#define SW2_CS17 0x22
#define SW2_CS18 0x23
#define SW3_CS1 0x24
#define SW3_CS2 0x25
#define SW3_CS3 0x26
#define SW3_CS4 0x27
#define SW3_CS5 0x28
#define SW3_CS6 0x29
#define SW3_CS7 0x2A
#define SW3_CS8 0x2B
#define SW3_CS9 0x2C
#define SW3_CS10 0x2D
#define SW3_CS11 0x2E
#define SW3_CS12 0x2F
#define SW3_CS13 0x30
#define SW3_CS14 0x31
#define SW3_CS15 0x32
#define SW3_CS16 0x33
#define SW3_CS17 0x34
#define SW3_CS18 0x35
#define SW4_CS1 0x36
#define SW4_CS2 0x37
#define SW4_CS3 0x38
#define SW4_CS4 0x39
#define SW4_CS5 0x3A
#define SW4_CS6 0x3B
#define SW4_CS7 0x3C
#define SW4_CS8 0x3D
#define SW4_CS9 0x3E
#define SW4_CS10 0x3F
#define SW4_CS11 0x40
#define SW4_CS12 0x41
#define SW4_CS13 0x42
#define SW4_CS14 0x43
#define SW4_CS15 0x44
#define SW4_CS16 0x45
#define SW4_CS17 0x46
#define SW4_CS18 0x47

View File

@ -1,329 +0,0 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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 "is31flcommon.h"
#include "i2c_master.h"
#include "wait.h"
#include <string.h>
// Set defaults for Timeout and Persistence
#ifndef ISSI_TIMEOUT
# define ISSI_TIMEOUT 100
#endif
#ifndef ISSI_PERSISTENCE
# define ISSI_PERSISTENCE 0
#endif
uint8_t i2c_transfer_buffer[20];
// These buffers match the PWM & scaling registers.
// Storing them like this is optimal for I2C transfers to the registers.
uint8_t g_pwm_buffer[DRIVER_COUNT][ISSI_MAX_LEDS];
bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false};
uint8_t g_scaling_buffer[DRIVER_COUNT][ISSI_SCALING_SIZE];
bool g_scaling_buffer_update_required[DRIVER_COUNT] = {false};
// For writing of single register entry
void IS31FL_write_single_register(uint8_t addr, uint8_t reg, uint8_t data) {
// Set register address and register data ready to write
i2c_transfer_buffer[0] = reg;
i2c_transfer_buffer[1] = data;
#if ISSI_PERSISTENCE > 0
for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, ISSI_TIMEOUT) == 0) break;
}
#else
i2c_transmit(addr << 1, i2c_transfer_buffer, 2, ISSI_TIMEOUT);
#endif
}
// For writing of mulitple register entries to make use of address auto increment
// Once the controller has been called and we have written the first bit of data
// the controller will move to the next register meaning we can write sequential blocks.
bool IS31FL_write_multi_registers(uint8_t addr, uint8_t *source_buffer, uint8_t buffer_size, uint8_t transfer_size, uint8_t start_reg_addr) {
// Split the buffer into chunks to transfer
for (int i = 0; i < buffer_size; i += transfer_size) {
// Set the first entry of transfer buffer to the first register we want to write
i2c_transfer_buffer[0] = i + start_reg_addr;
// Copy the section of our source buffer into the transfer buffer after first register address
memcpy(i2c_transfer_buffer + 1, source_buffer + i, transfer_size);
#if ISSI_PERSISTENCE > 0
for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, transfer_size + 1, ISSI_TIMEOUT) != 0) {
return false;
}
}
#else
if (i2c_transmit(addr << 1, i2c_transfer_buffer, transfer_size + 1, ISSI_TIMEOUT) != 0) {
return false;
}
#endif
}
return true;
}
void IS31FL_unlock_register(uint8_t addr, uint8_t page) {
// unlock the command register and select Page to write
IS31FL_write_single_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, ISSI_REGISTER_UNLOCK);
IS31FL_write_single_register(addr, ISSI_COMMANDREGISTER, page);
}
void IS31FL_common_init(uint8_t addr, uint8_t ssr) {
// Setup phase, need to take out of software shutdown and configure
// ISSI_SSR_x is passed to allow Master / Slave setting where applicable
// Unlock the command register & select Function Register
IS31FL_unlock_register(addr, ISSI_PAGE_FUNCTION);
// Set Configuration Register to remove Software shutdown
IS31FL_write_single_register(addr, ISSI_REG_CONFIGURATION, ISSI_CONFIGURATION);
// Set Golbal Current Control Register
IS31FL_write_single_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT);
// Set Pull up & Down for SWx CSy
IS31FL_write_single_register(addr, ISSI_REG_PULLDOWNUP, ISSI_PULLDOWNUP);
// Set Tempature Status
#ifdef ISSI_REG_TEMP
IS31FL_write_single_register(addr, ISSI_REG_TEMP, ISSI_TEMP);
#endif
// Set Spread Spectrum Register, passed through as sets SYNC function
IS31FL_write_single_register(addr, ISSI_REG_SSR, ssr);
// Set PWM Frequency Enable Register if applicable
#ifdef ISSI_REG_PWM_ENABLE
IS31FL_write_single_register(addr, ISSI_REG_PWM_ENABLE, ISSI_PWM_ENABLE);
#endif
// Set PWM Frequency Register if applicable
#ifdef ISSI_REG_PWM_SET
IS31FL_write_single_register(addr, ISSI_REG_PWM_SET, ISSI_PWM_SET);
#endif
// Wait 10ms to ensure the device has woken up.
wait_ms(10);
}
void IS31FL_common_update_pwm_register(uint8_t addr, uint8_t index) {
if (g_pwm_buffer_update_required[index]) {
// Queue up the correct page
IS31FL_unlock_register(addr, ISSI_PAGE_PWM);
// Hand off the update to IS31FL_write_multi_registers
IS31FL_write_multi_registers(addr, g_pwm_buffer[index], ISSI_MAX_LEDS, ISSI_PWM_TRF_SIZE, ISSI_PWM_REG_1ST);
// Update flags that pwm_buffer has been updated
g_pwm_buffer_update_required[index] = false;
}
}
#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++) {
memcpy_P(&scale, (&g_is31_scaling[i]), sizeof(scale));
# ifdef RGB_MATRIX_ENABLE
if (scale.driver >= 0 && scale.driver < RGB_MATRIX_LED_COUNT) {
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) {
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;
}
}
}
#endif
void IS31FL_common_update_scaling_register(uint8_t addr, uint8_t index) {
if (g_scaling_buffer_update_required[index]) {
// Queue up the correct page
IS31FL_unlock_register(addr, ISSI_PAGE_SCALING);
// Hand off the update to IS31FL_write_multi_registers
IS31FL_write_multi_registers(addr, g_scaling_buffer[index], ISSI_SCALING_SIZE, ISSI_SCALING_TRF_SIZE, ISSI_SCL_REG_1ST);
// Update flags that scaling_buffer has been updated
g_scaling_buffer_update_required[index] = false;
}
}
void IS31FL_common_flush(void) {
IS31FL_common_update_pwm_register(DRIVER_ADDR_1, 0);
#if defined(DRIVER_ADDR_2)
IS31FL_common_update_pwm_register(DRIVER_ADDR_2, 1);
# if defined(DRIVER_ADDR_3)
IS31FL_common_update_pwm_register(DRIVER_ADDR_3, 2);
# if defined(DRIVER_ADDR_4)
IS31FL_common_update_pwm_register(DRIVER_ADDR_4, 3);
# endif
# endif
#endif
}
#ifdef RGB_MATRIX_ENABLE
void IS31FL_RGB_init_drivers(void) {
i2c_init();
IS31FL_common_init(DRIVER_ADDR_1, ISSI_SSR_1);
# if defined(DRIVER_ADDR_2)
IS31FL_common_init(DRIVER_ADDR_2, ISSI_SSR_2);
# if defined(DRIVER_ADDR_3)
IS31FL_common_init(DRIVER_ADDR_3, ISSI_SSR_3);
# if defined(DRIVER_ADDR_4)
IS31FL_common_init(DRIVER_ADDR_4, ISSI_SSR_4);
# endif
# endif
# endif
for (int i = 0; i < RGB_MATRIX_LED_COUNT; i++) {
IS31FL_RGB_set_scaling_buffer(i, true, true, true);
}
// This actually updates the LED drivers
# ifdef ISSI_MANUAL_SCALING
IS31FL_set_manual_scaling_buffer();
# endif
IS31FL_common_update_scaling_register(DRIVER_ADDR_1, 0);
# if defined(DRIVER_ADDR_2)
IS31FL_common_update_scaling_register(DRIVER_ADDR_2, 1);
# if defined(DRIVER_ADDR_3)
IS31FL_common_update_scaling_register(DRIVER_ADDR_3, 2);
# if defined(DRIVER_ADDR_4)
IS31FL_common_update_scaling_register(DRIVER_ADDR_4, 3);
# endif
# endif
# endif
}
// 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;
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;
g_pwm_buffer[led.driver][led.b] = blue;
g_pwm_buffer_update_required[led.driver] = true;
}
}
void IS31FL_RGB_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
for (int i = 0; i < RGB_MATRIX_LED_COUNT; i++) {
IS31FL_RGB_set_color(i, red, green, 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;
memcpy_P(&led, (&g_is31_leds[index]), sizeof(led));
if (red) {
g_scaling_buffer[led.driver][led.r] = ISSI_SCAL_RED;
} else {
g_scaling_buffer[led.driver][led.r] = ISSI_SCAL_RED_OFF;
}
if (green) {
g_scaling_buffer[led.driver][led.g] = ISSI_SCAL_GREEN;
} else {
g_scaling_buffer[led.driver][led.g] = ISSI_SCAL_GREEN_OFF;
}
if (blue) {
g_scaling_buffer[led.driver][led.b] = ISSI_SCAL_BLUE;
} else {
g_scaling_buffer[led.driver][led.b] = ISSI_SCAL_BLUE_OFF;
}
g_scaling_buffer_update_required[led.driver] = true;
}
#elif defined(LED_MATRIX_ENABLE)
// LED Matrix Specific scripts
void IS31FL_simple_init_drivers(void) {
i2c_init();
IS31FL_common_init(DRIVER_ADDR_1, ISSI_SSR_1);
# if defined(DRIVER_ADDR_2)
IS31FL_common_init(DRIVER_ADDR_2, ISSI_SSR_2);
# if defined(DRIVER_ADDR_3)
IS31FL_common_init(DRIVER_ADDR_3, ISSI_SSR_3);
# if defined(DRIVER_ADDR_4)
IS31FL_common_init(DRIVER_ADDR_4, ISSI_SSR_4);
# endif
# endif
# endif
for (int i = 0; i < LED_MATRIX_LED_COUNT; i++) {
IS31FL_simple_set_scaling_buffer(i, true);
}
// This actually updates the LED drivers
# ifdef ISSI_MANUAL_SCALING
IS31FL_set_manual_scaling_buffer();
# endif
IS31FL_common_update_scaling_register(DRIVER_ADDR_1, 0);
# if defined(DRIVER_ADDR_2)
IS31FL_common_update_scaling_register(DRIVER_ADDR_2, 1);
# if defined(DRIVER_ADDR_3)
IS31FL_common_update_scaling_register(DRIVER_ADDR_3, 2);
# if defined(DRIVER_ADDR_4)
IS31FL_common_update_scaling_register(DRIVER_ADDR_4, 3);
# endif
# endif
# endif
}
void IS31FL_simple_set_scaling_buffer(uint8_t index, bool value) {
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 {
g_scaling_buffer[led.driver][led.v] = ISSI_SCAL_LED_OFF;
}
g_scaling_buffer_update_required[led.driver] = true;
}
void IS31FL_simple_set_brightness(int index, uint8_t value) {
if (index >= 0 && index < LED_MATRIX_LED_COUNT) {
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;
}
}
void IS31FL_simple_set_brigntness_all(uint8_t value) {
for (int i = 0; i < LED_MATRIX_LED_COUNT; i++) {
IS31FL_simple_set_brightness(i, value);
}
}
#endif

View File

@ -1,95 +0,0 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
* Copyright 2020 MelGeek
* Copyright 2021 MasterSpoon
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
// Which variant header file to use
#if defined(LED_MATRIX_IS31FL3742A) || defined(RGB_MATRIX_IS31FL3742A)
# include "is31fl3742.h"
#elif defined(LED_MATRIX_IS31FL3743A) || defined(RGB_MATRIX_IS31FL3743A)
# include "is31fl3743.h"
#elif defined(LED_MATRIX_IS31FL3745) || defined(RGB_MATRIX_IS31FL3745)
# include "is31fl3745.h"
#elif defined(LED_MATRIX_IS31FL3746A) || defined(RGB_MATRIX_IS31FL3746A)
# include "is31fl3746.h"
#endif
#if defined DRIVER_ADDR_4
# define DRIVER_COUNT 4
#elif defined DRIVER_ADDR_3
# define DRIVER_COUNT 3
#elif defined DRIVER_ADDR_2
# define DRIVER_COUNT 2
#elif defined DRIVER_ADDR_1
# define DRIVER_COUNT 1
#endif
#ifdef RGB_MATRIX_ENABLE
typedef struct is31_led {
uint8_t driver : 2;
uint8_t r;
uint8_t g;
uint8_t b;
} PACKED is31_led;
extern const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT];
#elif defined(LED_MATRIX_ENABLE)
typedef struct is31_led {
uint8_t driver : 2;
uint8_t v;
} PACKED is31_led;
extern const is31_led PROGMEM g_is31_leds[LED_MATRIX_LED_COUNT];
#endif
#ifdef ISSI_MANUAL_SCALING
extern const is31_led PROGMEM g_is31_scaling[];
void IS31FL_set_manual_scaling_buffer(void);
#endif
void IS31FL_write_single_register(uint8_t addr, uint8_t reg, uint8_t data);
bool IS31FL_write_multi_registers(uint8_t addr, uint8_t *source_buffer, uint8_t buffer_size, uint8_t transfer_size, uint8_t start_reg_addr);
void IS31FL_unlock_register(uint8_t addr, uint8_t page);
void IS31FL_common_init(uint8_t addr, uint8_t ssr);
void IS31FL_common_update_pwm_register(uint8_t addr, uint8_t index);
void IS31FL_common_update_scaling_register(uint8_t addr, uint8_t index);
void IS31FL_common_flush(void);
#ifdef RGB_MATRIX_ENABLE
// RGB Matrix Specific scripts
void IS31FL_RGB_init_drivers(void);
void IS31FL_RGB_set_color(int index, uint8_t red, uint8_t green, uint8_t blue);
void IS31FL_RGB_set_color_all(uint8_t red, uint8_t green, uint8_t blue);
void IS31FL_RGB_set_scaling_buffer(uint8_t index, bool red, bool green, bool blue);
#elif defined(LED_MATRIX_ENABLE)
// LED Matrix Specific scripts
void IS31FL_simple_init_drivers(void);
void IS31FL_simple_set_scaling_buffer(uint8_t index, bool value);
void IS31FL_simple_set_brightness(int index, uint8_t value);
void IS31FL_simple_set_brigntness_all(uint8_t value);
#endif

View File

@ -0,0 +1,244 @@
/* Copyright 2021 @ Keychron (https://www.keychron.com)
*
* 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 "snled27351-mono.h"
#include "i2c_master.h"
#define SNLED27351_PWM_REGISTER_COUNT 192
#define SNLED27351_LED_CONTROL_REGISTER_COUNT 24
#ifndef SNLED27351_I2C_TIMEOUT
# define SNLED27351_I2C_TIMEOUT 100
#endif
#ifndef SNLED27351_I2C_PERSISTENCE
# define SNLED27351_I2C_PERSISTENCE 0
#endif
#ifndef SNLED27351_PHASE_CHANNEL
# define SNLED27351_PHASE_CHANNEL SNLED27351_SCAN_PHASE_12_CHANNEL
#endif
#ifndef SNLED27351_CURRENT_TUNE
# define SNLED27351_CURRENT_TUNE \
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
#endif
const uint8_t i2c_addresses[SNLED27351_DRIVER_COUNT] = {
SNLED27351_I2C_ADDRESS_1,
#ifdef SNLED27351_I2C_ADDRESS_2
SNLED27351_I2C_ADDRESS_2,
# ifdef SNLED27351_I2C_ADDRESS_3
SNLED27351_I2C_ADDRESS_3,
# ifdef SNLED27351_I2C_ADDRESS_4
SNLED27351_I2C_ADDRESS_4,
# endif
# endif
#endif
};
// These buffers match the SNLED27351 PWM registers.
// 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 snled27351_write_pwm_buffer() but it's
// probably not worth the extra complexity.
typedef struct snled27351_driver_t {
uint8_t pwm_buffer[SNLED27351_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t led_control_buffer[SNLED27351_LED_CONTROL_REGISTER_COUNT];
bool led_control_buffer_dirty;
} PACKED snled27351_driver_t;
snled27351_driver_t driver_buffers[SNLED27351_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.led_control_buffer = {0},
.led_control_buffer_dirty = false,
}};
void snled27351_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if SNLED27351_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < SNLED27351_I2C_PERSISTENCE; i++) {
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, SNLED27351_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, SNLED27351_I2C_TIMEOUT);
#endif
}
void snled27351_select_page(uint8_t index, uint8_t page) {
snled27351_write_register(index, SNLED27351_REG_COMMAND, page);
}
void snled27351_write_pwm_buffer(uint8_t index) {
// Assumes PG1 is already selected.
// Transmit PWM registers in 12 transfers of 16 bytes.
// Iterate over the pwm_buffer contents at 16 byte intervals.
for (uint8_t i = 0; i < SNLED27351_PWM_REGISTER_COUNT; i += 16) {
#if SNLED27351_I2C_PERSISTENCE > 0
for (uint8_t j = 0; j < SNLED27351_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 16, SNLED27351_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 16, SNLED27351_I2C_TIMEOUT);
#endif
}
}
void snled27351_init_drivers(void) {
i2c_init();
for (uint8_t i = 0; i < SNLED27351_DRIVER_COUNT; i++) {
snled27351_init(i);
}
for (int i = 0; i < SNLED27351_LED_COUNT; i++) {
snled27351_set_led_control_register(i, true);
}
for (uint8_t i = 0; i < SNLED27351_DRIVER_COUNT; i++) {
snled27351_update_led_control_registers(i);
}
}
void snled27351_init(uint8_t index) {
snled27351_select_page(index, SNLED27351_COMMAND_FUNCTION);
// Setting LED driver to shutdown mode
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN, SNLED27351_SOFTWARE_SHUTDOWN_SSD_SHUTDOWN);
// Setting internal channel pulldown/pullup
snled27351_write_register(index, SNLED27351_FUNCTION_REG_PULLDOWNUP, SNLED27351_PULLDOWNUP_ALL_ENABLED);
// Select number of scan phase
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SCAN_PHASE, SNLED27351_PHASE_CHANNEL);
// Setting PWM Delay Phase
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SLEW_RATE_CONTROL_MODE_1, SNLED27351_SLEW_RATE_CONTROL_MODE_1_PDP_ENABLE);
// Setting Driving/Sinking Channel Slew Rate
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SLEW_RATE_CONTROL_MODE_2, SNLED27351_SLEW_RATE_CONTROL_MODE_2_DSL_ENABLE | SNLED27351_SLEW_RATE_CONTROL_MODE_2_SSL_ENABLE);
// Setting Iref
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SOFTWARE_SLEEP, 0);
snled27351_select_page(index, SNLED27351_COMMAND_LED_CONTROL);
for (int i = 0; i < SNLED27351_LED_CONTROL_ON_OFF_LENGTH; i++) {
snled27351_write_register(index, i, 0x00);
}
snled27351_select_page(index, SNLED27351_COMMAND_PWM);
for (int i = 0; i < SNLED27351_LED_CURRENT_TUNE_LENGTH; i++) {
snled27351_write_register(index, i, 0x00);
}
snled27351_select_page(index, SNLED27351_COMMAND_CURRENT_TUNE);
uint8_t current_tune_reg_list[SNLED27351_LED_CURRENT_TUNE_LENGTH] = SNLED27351_CURRENT_TUNE;
for (int i = 0; i < SNLED27351_LED_CURRENT_TUNE_LENGTH; i++) {
snled27351_write_register(index, i, current_tune_reg_list[i]);
}
snled27351_select_page(index, SNLED27351_COMMAND_LED_CONTROL);
for (int i = 0; i < SNLED27351_LED_CONTROL_ON_OFF_LENGTH; i++) {
snled27351_write_register(index, i, 0xFF);
}
snled27351_select_page(index, SNLED27351_COMMAND_FUNCTION);
// Setting LED driver to normal mode
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN, SNLED27351_SOFTWARE_SHUTDOWN_SSD_NORMAL);
}
void snled27351_set_value(int index, uint8_t value) {
snled27351_led_t led;
if (index >= 0 && index < SNLED27351_LED_COUNT) {
memcpy_P(&led, (&g_snled27351_leds[index]), sizeof(led));
if (driver_buffers[led.driver].pwm_buffer[led.v] == value) {
return;
}
driver_buffers[led.driver].pwm_buffer[led.v] = value;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
void snled27351_set_value_all(uint8_t value) {
for (int i = 0; i < SNLED27351_LED_COUNT; i++) {
snled27351_set_value(i, value);
}
}
void snled27351_set_led_control_register(uint8_t index, bool value) {
snled27351_led_t led;
memcpy_P(&led, (&g_snled27351_leds[index]), sizeof(led));
uint8_t control_register = led.v / 8;
uint8_t bit_value = led.v % 8;
if (value) {
driver_buffers[led.driver].led_control_buffer[control_register] |= (1 << bit_value);
} else {
driver_buffers[led.driver].led_control_buffer[control_register] &= ~(1 << bit_value);
}
driver_buffers[led.driver].led_control_buffer_dirty = true;
}
void snled27351_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
snled27351_select_page(index, SNLED27351_COMMAND_PWM);
snled27351_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
}
void snled27351_update_led_control_registers(uint8_t index) {
if (driver_buffers[index].led_control_buffer_dirty) {
snled27351_select_page(index, SNLED27351_COMMAND_LED_CONTROL);
for (uint8_t i = 0; i < SNLED27351_LED_CONTROL_REGISTER_COUNT; i++) {
snled27351_write_register(index, i, driver_buffers[index].led_control_buffer[i]);
}
driver_buffers[index].led_control_buffer_dirty = false;
}
}
void snled27351_flush(void) {
for (uint8_t i = 0; i < SNLED27351_DRIVER_COUNT; i++) {
snled27351_update_pwm_buffers(i);
}
}
void snled27351_sw_return_normal(uint8_t index) {
snled27351_select_page(index, SNLED27351_COMMAND_FUNCTION);
// Setting LED driver to normal mode
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN, SNLED27351_SOFTWARE_SHUTDOWN_SSD_NORMAL);
}
void snled27351_sw_shutdown(uint8_t index) {
snled27351_select_page(index, SNLED27351_COMMAND_FUNCTION);
// Setting LED driver to shutdown mode
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN, SNLED27351_SOFTWARE_SHUTDOWN_SSD_SHUTDOWN);
// Write SW Sleep Register
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SOFTWARE_SLEEP, SNLED27351_SOFTWARE_SLEEP_ENABLE);
}

View File

@ -0,0 +1,586 @@
/* Copyright 2021 @ Keychron (https://www.keychron.com)
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
// ======== DEPRECATED DEFINES - DO NOT USE ========
#ifdef CKLED2001_TIMEOUT
# define SNLED27351_I2C_TIMEOUT CKLED2001_TIMEOUT
#endif
#ifdef CKLED2001_PERSISTENCE
# define SNLED27351_I2C_PERSISTENCE CKLED2001_PERSISTENCE
#endif
#ifdef PHASE_CHANNEL
# define SNLED27351_PHASE_CHANNEL PHASE_CHANNEL
#endif
#ifdef CKLED2001_CURRENT_TUNE
# define SNLED27351_CURRENT_TUNE CKLED2001_CURRENT_TUNE
#endif
#define MSKPHASE_12CHANNEL SNLED27351_SCAN_PHASE_12_CHANNEL
#define MSKPHASE_11CHANNEL SNLED27351_SCAN_PHASE_11_CHANNEL
#define MSKPHASE_10CHANNEL SNLED27351_SCAN_PHASE_10_CHANNEL
#define MSKPHASE_9CHANNEL SNLED27351_SCAN_PHASE_9_CHANNEL
#define MSKPHASE_8CHANNEL SNLED27351_SCAN_PHASE_8_CHANNEL
#define MSKPHASE_7CHANNEL SNLED27351_SCAN_PHASE_7_CHANNEL
#define MSKPHASE_6CHANNEL SNLED27351_SCAN_PHASE_6_CHANNEL
#define MSKPHASE_5CHANNEL SNLED27351_SCAN_PHASE_5_CHANNEL
#define MSKPHASE_4CHANNEL SNLED27351_SCAN_PHASE_4_CHANNEL
#define MSKPHASE_3CHANNEL SNLED27351_SCAN_PHASE_3_CHANNEL
#define MSKPHASE_2CHANNEL SNLED27351_SCAN_PHASE_2_CHANNEL
#define MSKPHASE_1CHANNEL SNLED27351_SCAN_PHASE_1_CHANNEL
#define ckled2001_led snled27351_led_t
#define g_ckled2001_leds g_snled27351_leds
// ========
#define SNLED27351_REG_COMMAND 0xFD
#define SNLED27351_COMMAND_LED_CONTROL 0x00
#define SNLED27351_COMMAND_PWM 0x01
#define SNLED27351_COMMAND_FUNCTION 0x03
#define SNLED27351_COMMAND_CURRENT_TUNE 0x04
#define SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN 0x00
#define SNLED27351_SOFTWARE_SHUTDOWN_SSD_SHUTDOWN (0x0 << 0)
#define SNLED27351_SOFTWARE_SHUTDOWN_SSD_NORMAL (0x1 << 0)
#define SNLED27351_FUNCTION_REG_ID 0x11
#define SNLED27351_DRIVER_ID 0x8A
#define SNLED27351_FUNCTION_REG_PULLDOWNUP 0x13
#define SNLED27351_PULLDOWNUP_ALL_ENABLED 0xAA
#define SNLED27351_FUNCTION_REG_SCAN_PHASE 0x14
#define SNLED27351_SCAN_PHASE_12_CHANNEL 0x00
#define SNLED27351_SCAN_PHASE_11_CHANNEL 0x01
#define SNLED27351_SCAN_PHASE_10_CHANNEL 0x02
#define SNLED27351_SCAN_PHASE_9_CHANNEL 0x03
#define SNLED27351_SCAN_PHASE_8_CHANNEL 0x04
#define SNLED27351_SCAN_PHASE_7_CHANNEL 0x05
#define SNLED27351_SCAN_PHASE_6_CHANNEL 0x06
#define SNLED27351_SCAN_PHASE_5_CHANNEL 0x07
#define SNLED27351_SCAN_PHASE_4_CHANNEL 0x08
#define SNLED27351_SCAN_PHASE_3_CHANNEL 0x09
#define SNLED27351_SCAN_PHASE_2_CHANNEL 0x0A
#define SNLED27351_SCAN_PHASE_1_CHANNEL 0x0B
#define SNLED27351_FUNCTION_REG_SLEW_RATE_CONTROL_MODE_1 0x15
#define SNLED27351_SLEW_RATE_CONTROL_MODE_1_PDP_ENABLE (0b1 << 2)
#define SNLED27351_FUNCTION_REG_SLEW_RATE_CONTROL_MODE_2 0x16
#define SNLED27351_SLEW_RATE_CONTROL_MODE_2_SSL_ENABLE (0b1 << 6)
#define SNLED27351_SLEW_RATE_CONTROL_MODE_2_DSL_ENABLE (0b1 << 7)
#define SNLED27351_FUNCTION_REG_OPEN_SHORT_ENABLE 0x17
#define SNLED27351_OPEN_SHORT_ENABLE_SDS_ENABLE (0b1 << 6)
#define SNLED27351_OPEN_SHORT_ENABLE_ODS_ENABLE (0b1 << 7)
#define SNLED27351_FUNCTION_REG_OPEN_SHORT_DUTY 0x18
#define SNLED27351_FUNCTION_REG_OPEN_SHORT_FLAG 0x19
#define SNLED27351_OPEN_SHORT_FLAG_OSINT_ENABLE (0b1 << 6)
#define SNLED27351_OPEN_SHORT_FLAG_ODINT_ENABLE (0b1 << 7)
#define SNLED27351_FUNCTION_REG_SOFTWARE_SLEEP 0x1A
#define SNLED27351_SOFTWARE_SLEEP_ENABLE (0b1 << 1)
// LED Control Registers
#define SNLED27351_LED_CONTROL_ON_OFF_FIRST_ADDR 0x0
#define SNLED27351_LED_CONTROL_ON_OFF_LAST_ADDR 0x17
#define SNLED27351_LED_CONTROL_ON_OFF_LENGTH ((SNLED27351_LED_CONTROL_ON_OFF_LAST_ADDR - SNLED27351_LED_CONTROL_ON_OFF_FIRST_ADDR) + 1)
#define SNLED27351_LED_CONTROL_OPEN_FIRST_ADDR 0x18
#define SNLED27351_LED_CONTROL_OPEN_LAST_ADDR 0x2F
#define SNLED27351_LED_CONTROL_OPEN_LENGTH ((SNLED27351_LED_CONTROL_OPEN_LAST_ADDR - SNLED27351_LED_CONTROL_OPEN_FIRST_ADDR) + 1)
#define SNLED27351_LED_CONTROL_SHORT_FIRST_ADDR 0x30
#define SNLED27351_LED_CONTROL_SHORT_LAST_ADDR 0x47
#define SNLED27351_LED_CONTROL_SHORT_LENGTH ((SNLED27351_LED_CONTROL_SHORT_LAST_ADDR - SNLED27351_LED_CONTROL_SHORT_FIRST_ADDR) + 1)
#define SNLED27351_LED_CONTROL_PAGE_LENGTH 0x48
// LED Control Registers
#define SNLED27351_LED_PWM_FIRST_ADDR 0x00
#define SNLED27351_LED_PWM_LAST_ADDR 0xBF
#define SNLED27351_LED_PWM_LENGTH 0xC0
// Current Tune Registers
#define SNLED27351_LED_CURRENT_TUNE_FIRST_ADDR 0x00
#define SNLED27351_LED_CURRENT_TUNE_LAST_ADDR 0x0B
#define SNLED27351_LED_CURRENT_TUNE_LENGTH 0x0C
#define SNLED27351_I2C_ADDRESS_GND 0x74
#define SNLED27351_I2C_ADDRESS_SCL 0x75
#define SNLED27351_I2C_ADDRESS_SDA 0x76
#define SNLED27351_I2C_ADDRESS_VDDIO 0x77
#if defined(LED_MATRIX_SNLED27351)
# define SNLED27351_LED_COUNT LED_MATRIX_LED_COUNT
#endif
#if defined(SNLED27351_I2C_ADDRESS_4)
# define SNLED27351_DRIVER_COUNT 4
#elif defined(SNLED27351_I2C_ADDRESS_3)
# define SNLED27351_DRIVER_COUNT 3
#elif defined(SNLED27351_I2C_ADDRESS_2)
# define SNLED27351_DRIVER_COUNT 2
#elif defined(SNLED27351_I2C_ADDRESS_1)
# define SNLED27351_DRIVER_COUNT 1
#endif
typedef struct snled27351_led_t {
uint8_t driver : 2;
uint8_t v;
} PACKED snled27351_led_t;
extern const snled27351_led_t PROGMEM g_snled27351_leds[SNLED27351_LED_COUNT];
void snled27351_init_drivers(void);
void snled27351_init(uint8_t index);
void snled27351_select_page(uint8_t index, uint8_t page);
void snled27351_write_register(uint8_t index, uint8_t reg, uint8_t data);
void snled27351_set_value(int index, uint8_t value);
void snled27351_set_value_all(uint8_t value);
void snled27351_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 snled27351_update_pwm_buffers(uint8_t index);
void snled27351_update_led_control_registers(uint8_t index);
void snled27351_flush(void);
void snled27351_sw_return_normal(uint8_t index);
void snled27351_sw_shutdown(uint8_t index);
#define CB1_CA1 0x00
#define CB1_CA2 0x01
#define CB1_CA3 0x02
#define CB1_CA4 0x03
#define CB1_CA5 0x04
#define CB1_CA6 0x05
#define CB1_CA7 0x06
#define CB1_CA8 0x07
#define CB1_CA9 0x08
#define CB1_CA10 0x09
#define CB1_CA11 0x0A
#define CB1_CA12 0x0B
#define CB1_CA13 0x0C
#define CB1_CA14 0x0D
#define CB1_CA15 0x0E
#define CB1_CA16 0x0F
#define CB2_CA1 0x10
#define CB2_CA2 0x11
#define CB2_CA3 0x12
#define CB2_CA4 0x13
#define CB2_CA5 0x14
#define CB2_CA6 0x15
#define CB2_CA7 0x16
#define CB2_CA8 0x17
#define CB2_CA9 0x18
#define CB2_CA10 0x19
#define CB2_CA11 0x1A
#define CB2_CA12 0x1B
#define CB2_CA13 0x1C
#define CB2_CA14 0x1D
#define CB2_CA15 0x1E
#define CB2_CA16 0x1F
#define CB3_CA1 0x20
#define CB3_CA2 0x21
#define CB3_CA3 0x22
#define CB3_CA4 0x23
#define CB3_CA5 0x24
#define CB3_CA6 0x25
#define CB3_CA7 0x26
#define CB3_CA8 0x27
#define CB3_CA9 0x28
#define CB3_CA10 0x29
#define CB3_CA11 0x2A
#define CB3_CA12 0x2B
#define CB3_CA13 0x2C
#define CB3_CA14 0x2D
#define CB3_CA15 0x2E
#define CB3_CA16 0x2F
#define CB4_CA1 0x30
#define CB4_CA2 0x31
#define CB4_CA3 0x32
#define CB4_CA4 0x33
#define CB4_CA5 0x34
#define CB4_CA6 0x35
#define CB4_CA7 0x36
#define CB4_CA8 0x37
#define CB4_CA9 0x38
#define CB4_CA10 0x39
#define CB4_CA11 0x3A
#define CB4_CA12 0x3B
#define CB4_CA13 0x3C
#define CB4_CA14 0x3D
#define CB4_CA15 0x3E
#define CB4_CA16 0x3F
#define CB5_CA1 0x40
#define CB5_CA2 0x41
#define CB5_CA3 0x42
#define CB5_CA4 0x43
#define CB5_CA5 0x44
#define CB5_CA6 0x45
#define CB5_CA7 0x46
#define CB5_CA8 0x47
#define CB5_CA9 0x48
#define CB5_CA10 0x49
#define CB5_CA11 0x4A
#define CB5_CA12 0x4B
#define CB5_CA13 0x4C
#define CB5_CA14 0x4D
#define CB5_CA15 0x4E
#define CB5_CA16 0x4F
#define CB6_CA1 0x50
#define CB6_CA2 0x51
#define CB6_CA3 0x52
#define CB6_CA4 0x53
#define CB6_CA5 0x54
#define CB6_CA6 0x55
#define CB6_CA7 0x56
#define CB6_CA8 0x57
#define CB6_CA9 0x58
#define CB6_CA10 0x59
#define CB6_CA11 0x5A
#define CB6_CA12 0x5B
#define CB6_CA13 0x5C
#define CB6_CA14 0x5D
#define CB6_CA15 0x5E
#define CB6_CA16 0x5F
#define CB7_CA1 0x60
#define CB7_CA2 0x61
#define CB7_CA3 0x62
#define CB7_CA4 0x63
#define CB7_CA5 0x64
#define CB7_CA6 0x65
#define CB7_CA7 0x66
#define CB7_CA8 0x67
#define CB7_CA9 0x68
#define CB7_CA10 0x69
#define CB7_CA11 0x6A
#define CB7_CA12 0x6B
#define CB7_CA13 0x6C
#define CB7_CA14 0x6D
#define CB7_CA15 0x6E
#define CB7_CA16 0x6F
#define CB8_CA1 0x70
#define CB8_CA2 0x71
#define CB8_CA3 0x72
#define CB8_CA4 0x73
#define CB8_CA5 0x74
#define CB8_CA6 0x75
#define CB8_CA7 0x76
#define CB8_CA8 0x77
#define CB8_CA9 0x78
#define CB8_CA10 0x79
#define CB8_CA11 0x7A
#define CB8_CA12 0x7B
#define CB8_CA13 0x7C
#define CB8_CA14 0x7D
#define CB8_CA15 0x7E
#define CB8_CA16 0x7F
#define CB9_CA1 0x80
#define CB9_CA2 0x81
#define CB9_CA3 0x82
#define CB9_CA4 0x83
#define CB9_CA5 0x84
#define CB9_CA6 0x85
#define CB9_CA7 0x86
#define CB9_CA8 0x87
#define CB9_CA9 0x88
#define CB9_CA10 0x89
#define CB9_CA11 0x8A
#define CB9_CA12 0x8B
#define CB9_CA13 0x8C
#define CB9_CA14 0x8D
#define CB9_CA15 0x8E
#define CB9_CA16 0x8F
#define CB10_CA1 0x90
#define CB10_CA2 0x91
#define CB10_CA3 0x92
#define CB10_CA4 0x93
#define CB10_CA5 0x94
#define CB10_CA6 0x95
#define CB10_CA7 0x96
#define CB10_CA8 0x97
#define CB10_CA9 0x98
#define CB10_CA10 0x99
#define CB10_CA11 0x9A
#define CB10_CA12 0x9B
#define CB10_CA13 0x9C
#define CB10_CA14 0x9D
#define CB10_CA15 0x9E
#define CB10_CA16 0x9F
#define CB11_CA1 0xA0
#define CB11_CA2 0xA1
#define CB11_CA3 0xA2
#define CB11_CA4 0xA3
#define CB11_CA5 0xA4
#define CB11_CA6 0xA5
#define CB11_CA7 0xA6
#define CB11_CA8 0xA7
#define CB11_CA9 0xA8
#define CB11_CA10 0xA9
#define CB11_CA11 0xAA
#define CB11_CA12 0xAB
#define CB11_CA13 0xAC
#define CB11_CA14 0xAD
#define CB11_CA15 0xAE
#define CB11_CA16 0xAF
#define CB12_CA1 0xB0
#define CB12_CA2 0xB1
#define CB12_CA3 0xB2
#define CB12_CA4 0xB3
#define CB12_CA5 0xB4
#define CB12_CA6 0xB5
#define CB12_CA7 0xB6
#define CB12_CA8 0xB7
#define CB12_CA9 0xB8
#define CB12_CA10 0xB9
#define CB12_CA11 0xBA
#define CB12_CA12 0xBB
#define CB12_CA13 0xBC
#define CB12_CA14 0xBD
#define CB12_CA15 0xBE
#define CB12_CA16 0xBF
// DEPRECATED - DO NOT USE
#define A_1 CB1_CA1
#define A_2 CB1_CA2
#define A_3 CB1_CA3
#define A_4 CB1_CA4
#define A_5 CB1_CA5
#define A_6 CB1_CA6
#define A_7 CB1_CA7
#define A_8 CB1_CA8
#define A_9 CB1_CA9
#define A_10 CB1_CA10
#define A_11 CB1_CA11
#define A_12 CB1_CA12
#define A_13 CB1_CA13
#define A_14 CB1_CA14
#define A_15 CB1_CA15
#define A_16 CB1_CA16
#define B_1 CB2_CA1
#define B_2 CB2_CA2
#define B_3 CB2_CA3
#define B_4 CB2_CA4
#define B_5 CB2_CA5
#define B_6 CB2_CA6
#define B_7 CB2_CA7
#define B_8 CB2_CA8
#define B_9 CB2_CA9
#define B_10 CB2_CA10
#define B_11 CB2_CA11
#define B_12 CB2_CA12
#define B_13 CB2_CA13
#define B_14 CB2_CA14
#define B_15 CB2_CA15
#define B_16 CB2_CA16
#define C_1 CB3_CA1
#define C_2 CB3_CA2
#define C_3 CB3_CA3
#define C_4 CB3_CA4
#define C_5 CB3_CA5
#define C_6 CB3_CA6
#define C_7 CB3_CA7
#define C_8 CB3_CA8
#define C_9 CB3_CA9
#define C_10 CB3_CA10
#define C_11 CB3_CA11
#define C_12 CB3_CA12
#define C_13 CB3_CA13
#define C_14 CB3_CA14
#define C_15 CB3_CA15
#define C_16 CB3_CA16
#define D_1 CB4_CA1
#define D_2 CB4_CA2
#define D_3 CB4_CA3
#define D_4 CB4_CA4
#define D_5 CB4_CA5
#define D_6 CB4_CA6
#define D_7 CB4_CA7
#define D_8 CB4_CA8
#define D_9 CB4_CA9
#define D_10 CB4_CA10
#define D_11 CB4_CA11
#define D_12 CB4_CA12
#define D_13 CB4_CA13
#define D_14 CB4_CA14
#define D_15 CB4_CA15
#define D_16 CB4_CA16
#define E_1 CB5_CA1
#define E_2 CB5_CA2
#define E_3 CB5_CA3
#define E_4 CB5_CA4
#define E_5 CB5_CA5
#define E_6 CB5_CA6
#define E_7 CB5_CA7
#define E_8 CB5_CA8
#define E_9 CB5_CA9
#define E_10 CB5_CA10
#define E_11 CB5_CA11
#define E_12 CB5_CA12
#define E_13 CB5_CA13
#define E_14 CB5_CA14
#define E_15 CB5_CA15
#define E_16 CB5_CA16
#define F_1 CB6_CA1
#define F_2 CB6_CA2
#define F_3 CB6_CA3
#define F_4 CB6_CA4
#define F_5 CB6_CA5
#define F_6 CB6_CA6
#define F_7 CB6_CA7
#define F_8 CB6_CA8
#define F_9 CB6_CA9
#define F_10 CB6_CA10
#define F_11 CB6_CA11
#define F_12 CB6_CA12
#define F_13 CB6_CA13
#define F_14 CB6_CA14
#define F_15 CB6_CA15
#define F_16 CB6_CA16
#define G_1 CB7_CA1
#define G_2 CB7_CA2
#define G_3 CB7_CA3
#define G_4 CB7_CA4
#define G_5 CB7_CA5
#define G_6 CB7_CA6
#define G_7 CB7_CA7
#define G_8 CB7_CA8
#define G_9 CB7_CA9
#define G_10 CB7_CA10
#define G_11 CB7_CA11
#define G_12 CB7_CA12
#define G_13 CB7_CA13
#define G_14 CB7_CA14
#define G_15 CB7_CA15
#define G_16 CB7_CA16
#define H_1 CB8_CA1
#define H_2 CB8_CA2
#define H_3 CB8_CA3
#define H_4 CB8_CA4
#define H_5 CB8_CA5
#define H_6 CB8_CA6
#define H_7 CB8_CA7
#define H_8 CB8_CA8
#define H_9 CB8_CA9
#define H_10 CB8_CA10
#define H_11 CB8_CA11
#define H_12 CB8_CA12
#define H_13 CB8_CA13
#define H_14 CB8_CA14
#define H_15 CB8_CA15
#define H_16 CB8_CA16
#define I_1 CB9_CA1
#define I_2 CB9_CA2
#define I_3 CB9_CA3
#define I_4 CB9_CA4
#define I_5 CB9_CA5
#define I_6 CB9_CA6
#define I_7 CB9_CA7
#define I_8 CB9_CA8
#define I_9 CB9_CA9
#define I_10 CB9_CA10
#define I_11 CB9_CA11
#define I_12 CB9_CA12
#define I_13 CB9_CA13
#define I_14 CB9_CA14
#define I_15 CB9_CA15
#define I_16 CB9_CA16
#define J_1 CB10_CA1
#define J_2 CB10_CA2
#define J_3 CB10_CA3
#define J_4 CB10_CA4
#define J_5 CB10_CA5
#define J_6 CB10_CA6
#define J_7 CB10_CA7
#define J_8 CB10_CA8
#define J_9 CB10_CA9
#define J_10 CB10_CA10
#define J_11 CB10_CA11
#define J_12 CB10_CA12
#define J_13 CB10_CA13
#define J_14 CB10_CA14
#define J_15 CB10_CA15
#define J_16 CB10_CA16
#define K_1 CB11_CA1
#define K_2 CB11_CA2
#define K_3 CB11_CA3
#define K_4 CB11_CA4
#define K_5 CB11_CA5
#define K_6 CB11_CA6
#define K_7 CB11_CA7
#define K_8 CB11_CA8
#define K_9 CB11_CA9
#define K_10 CB11_CA10
#define K_11 CB11_CA11
#define K_12 CB11_CA12
#define K_13 CB11_CA13
#define K_14 CB11_CA14
#define K_15 CB11_CA15
#define K_16 CB11_CA16
#define L_1 CB12_CA1
#define L_2 CB12_CA2
#define L_3 CB12_CA3
#define L_4 CB12_CA4
#define L_5 CB12_CA5
#define L_6 CB12_CA6
#define L_7 CB12_CA7
#define L_8 CB12_CA8
#define L_9 CB12_CA9
#define L_10 CB12_CA10
#define L_11 CB12_CA11
#define L_12 CB12_CA12
#define L_13 CB12_CA13
#define L_14 CB12_CA14
#define L_15 CB12_CA15
#define L_16 CB12_CA16

View File

@ -1,272 +0,0 @@
/* Copyright 2021 @ Keychron (https://www.keychron.com)
*
* 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 "snled27351-simple.h"
#include "i2c_master.h"
#define SNLED27351_PWM_REGISTER_COUNT 192
#define SNLED27351_LED_CONTROL_REGISTER_COUNT 24
#ifndef SNLED27351_I2C_TIMEOUT
# define SNLED27351_I2C_TIMEOUT 100
#endif
#ifndef SNLED27351_I2C_PERSISTENCE
# define SNLED27351_I2C_PERSISTENCE 0
#endif
#ifndef SNLED27351_PHASE_CHANNEL
# define SNLED27351_PHASE_CHANNEL SNLED27351_SCAN_PHASE_12_CHANNEL
#endif
#ifndef SNLED27351_CURRENT_TUNE
# define SNLED27351_CURRENT_TUNE \
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
#endif
uint8_t i2c_transfer_buffer[20];
// These buffers match the SNLED27351 PWM registers.
// 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 snled27351_write_pwm_buffer() but it's
// probably not worth the extra complexity.
uint8_t g_pwm_buffer[SNLED27351_DRIVER_COUNT][SNLED27351_PWM_REGISTER_COUNT];
bool g_pwm_buffer_update_required[SNLED27351_DRIVER_COUNT] = {false};
uint8_t g_led_control_registers[SNLED27351_DRIVER_COUNT][SNLED27351_LED_CONTROL_REGISTER_COUNT] = {0};
bool g_led_control_registers_update_required[SNLED27351_DRIVER_COUNT] = {false};
bool snled27351_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
// If the transaction fails function returns false.
i2c_transfer_buffer[0] = reg;
i2c_transfer_buffer[1] = data;
#if SNLED27351_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < SNLED27351_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, SNLED27351_I2C_TIMEOUT) != 0) {
return false;
}
}
#else
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, SNLED27351_I2C_TIMEOUT) != 0) {
return false;
}
#endif
return true;
}
void snled27351_select_page(uint8_t addr, uint8_t page) {
snled27351_write_register(addr, SNLED27351_REG_COMMAND, page);
}
bool snled27351_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.
// i2c_transfer_buffer[] is 20 bytes
// Iterate over the pwm_buffer contents at 16 byte intervals.
for (int i = 0; i < SNLED27351_PWM_REGISTER_COUNT; i += 16) {
i2c_transfer_buffer[0] = i;
// Copy the data from i to i+15.
// Device will auto-increment register for data after the first byte
// Thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer.
for (int j = 0; j < 16; j++) {
i2c_transfer_buffer[1 + j] = pwm_buffer[i + j];
}
#if SNLED27351_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < SNLED27351_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 17, SNLED27351_I2C_TIMEOUT) != 0) {
return false;
}
}
#else
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 17, SNLED27351_I2C_TIMEOUT) != 0) {
return false;
}
#endif
}
return true;
}
void snled27351_init_drivers(void) {
i2c_init();
snled27351_init(SNLED27351_I2C_ADDRESS_1);
#if defined(SNLED27351_I2C_ADDRESS_2)
snled27351_init(SNLED27351_I2C_ADDRESS_2);
# if defined(SNLED27351_I2C_ADDRESS_3)
snled27351_init(SNLED27351_I2C_ADDRESS_3);
# if defined(SNLED27351_I2C_ADDRESS_4)
snled27351_init(SNLED27351_I2C_ADDRESS_4);
# endif
# endif
#endif
for (int i = 0; i < SNLED27351_LED_COUNT; i++) {
snled27351_set_led_control_register(i, true);
}
snled27351_update_led_control_registers(SNLED27351_I2C_ADDRESS_1, 0);
#if defined(SNLED27351_I2C_ADDRESS_2)
snled27351_update_led_control_registers(SNLED27351_I2C_ADDRESS_2, 1);
# if defined(SNLED27351_I2C_ADDRESS_3)
snled27351_update_led_control_registers(SNLED27351_I2C_ADDRESS_3, 2);
# if defined(SNLED27351_I2C_ADDRESS_4)
snled27351_update_led_control_registers(SNLED27351_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
}
void snled27351_init(uint8_t addr) {
snled27351_select_page(addr, SNLED27351_COMMAND_FUNCTION);
// Setting LED driver to shutdown mode
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN, SNLED27351_SOFTWARE_SHUTDOWN_SSD_SHUTDOWN);
// Setting internal channel pulldown/pullup
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_PULLDOWNUP, SNLED27351_PULLDOWNUP_ALL_ENABLED);
// Select number of scan phase
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SCAN_PHASE, SNLED27351_PHASE_CHANNEL);
// Setting PWM Delay Phase
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SLEW_RATE_CONTROL_MODE_1, SNLED27351_SLEW_RATE_CONTROL_MODE_1_PDP_ENABLE);
// Setting Driving/Sinking Channel Slew Rate
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SLEW_RATE_CONTROL_MODE_2, SNLED27351_SLEW_RATE_CONTROL_MODE_2_DSL_ENABLE | SNLED27351_SLEW_RATE_CONTROL_MODE_2_SSL_ENABLE);
// Setting Iref
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SOFTWARE_SLEEP, 0);
snled27351_select_page(addr, SNLED27351_COMMAND_LED_CONTROL);
for (int i = 0; i < SNLED27351_LED_CONTROL_ON_OFF_LENGTH; i++) {
snled27351_write_register(addr, i, 0x00);
}
snled27351_select_page(addr, SNLED27351_COMMAND_PWM);
for (int i = 0; i < SNLED27351_LED_CURRENT_TUNE_LENGTH; i++) {
snled27351_write_register(addr, i, 0x00);
}
snled27351_select_page(addr, SNLED27351_COMMAND_CURRENT_TUNE);
uint8_t current_tune_reg_list[SNLED27351_LED_CURRENT_TUNE_LENGTH] = SNLED27351_CURRENT_TUNE;
for (int i = 0; i < SNLED27351_LED_CURRENT_TUNE_LENGTH; i++) {
snled27351_write_register(addr, i, current_tune_reg_list[i]);
}
snled27351_select_page(addr, SNLED27351_COMMAND_LED_CONTROL);
// Enable LEDs ON/OFF
for (int i = 0; i < SNLED27351_LED_CONTROL_ON_OFF_LENGTH; i++) {
snled27351_write_register(addr, i, 0xFF);
}
snled27351_select_page(addr, SNLED27351_COMMAND_FUNCTION);
// Setting LED driver to normal mode
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN, SNLED27351_SOFTWARE_SHUTDOWN_SSD_NORMAL);
}
void snled27351_set_value(int index, uint8_t value) {
snled27351_led_t led;
if (index >= 0 && index < SNLED27351_LED_COUNT) {
memcpy_P(&led, (&g_snled27351_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 snled27351_set_value_all(uint8_t value) {
for (int i = 0; i < SNLED27351_LED_COUNT; i++) {
snled27351_set_value(i, value);
}
}
void snled27351_set_led_control_register(uint8_t index, bool value) {
snled27351_led_t led;
memcpy_P(&led, (&g_snled27351_leds[index]), sizeof(led));
uint8_t control_register = led.v / 8;
uint8_t bit_value = led.v % 8;
if (value) {
g_led_control_registers[led.driver][control_register] |= (1 << bit_value);
} else {
g_led_control_registers[led.driver][control_register] &= ~(1 << bit_value);
}
g_led_control_registers_update_required[led.driver] = true;
}
void snled27351_update_pwm_buffers(uint8_t addr, uint8_t index) {
if (g_pwm_buffer_update_required[index]) {
snled27351_select_page(addr, SNLED27351_COMMAND_PWM);
// If any of the transactions fail we risk writing dirty PG0,
// refresh page 0 just in case.
if (!snled27351_write_pwm_buffer(addr, g_pwm_buffer[index])) {
g_led_control_registers_update_required[index] = true;
}
}
g_pwm_buffer_update_required[index] = false;
}
void snled27351_update_led_control_registers(uint8_t addr, uint8_t index) {
if (g_led_control_registers_update_required[index]) {
snled27351_select_page(addr, SNLED27351_COMMAND_LED_CONTROL);
for (int i = 0; i < SNLED27351_LED_CONTROL_REGISTER_COUNT; i++) {
snled27351_write_register(addr, i, g_led_control_registers[index][i]);
}
}
g_led_control_registers_update_required[index] = false;
}
void snled27351_flush(void) {
snled27351_update_pwm_buffers(SNLED27351_I2C_ADDRESS_1, 0);
#if defined(SNLED27351_I2C_ADDRESS_2)
snled27351_update_pwm_buffers(SNLED27351_I2C_ADDRESS_2, 1);
# if defined(SNLED27351_I2C_ADDRESS_3)
snled27351_update_pwm_buffers(SNLED27351_I2C_ADDRESS_3, 2);
# if defined(SNLED27351_I2C_ADDRESS_4)
snled27351_update_pwm_buffers(SNLED27351_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
}
void snled27351_sw_return_normal(uint8_t addr) {
snled27351_select_page(addr, SNLED27351_COMMAND_FUNCTION);
// Setting LED driver to normal mode
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN, SNLED27351_SOFTWARE_SHUTDOWN_SSD_NORMAL);
}
void snled27351_sw_shutdown(uint8_t addr) {
snled27351_select_page(addr, SNLED27351_COMMAND_FUNCTION);
// Setting LED driver to shutdown mode
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN, SNLED27351_SOFTWARE_SHUTDOWN_SSD_SHUTDOWN);
// Write SW Sleep Register
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SOFTWARE_SLEEP, SNLED27351_SOFTWARE_SLEEP_ENABLE);
}

View File

@ -1,381 +0,0 @@
/* Copyright 2021 @ Keychron (https://www.keychron.com)
*
* 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>
#include <stdbool.h>
#include "progmem.h"
#include "util.h"
// ======== DEPRECATED DEFINES - DO NOT USE ========
#ifdef CKLED2001_TIMEOUT
# define SNLED27351_I2C_TIMEOUT CKLED2001_TIMEOUT
#endif
#ifdef CKLED2001_PERSISTENCE
# define SNLED27351_I2C_PERSISTENCE CKLED2001_PERSISTENCE
#endif
#ifdef PHASE_CHANNEL
# define SNLED27351_PHASE_CHANNEL PHASE_CHANNEL
#endif
#ifdef CKLED2001_CURRENT_TUNE
# define SNLED27351_CURRENT_TUNE CKLED2001_CURRENT_TUNE
#endif
#define MSKPHASE_12CHANNEL SNLED27351_SCAN_PHASE_12_CHANNEL
#define MSKPHASE_11CHANNEL SNLED27351_SCAN_PHASE_11_CHANNEL
#define MSKPHASE_10CHANNEL SNLED27351_SCAN_PHASE_10_CHANNEL
#define MSKPHASE_9CHANNEL SNLED27351_SCAN_PHASE_9_CHANNEL
#define MSKPHASE_8CHANNEL SNLED27351_SCAN_PHASE_8_CHANNEL
#define MSKPHASE_7CHANNEL SNLED27351_SCAN_PHASE_7_CHANNEL
#define MSKPHASE_6CHANNEL SNLED27351_SCAN_PHASE_6_CHANNEL
#define MSKPHASE_5CHANNEL SNLED27351_SCAN_PHASE_5_CHANNEL
#define MSKPHASE_4CHANNEL SNLED27351_SCAN_PHASE_4_CHANNEL
#define MSKPHASE_3CHANNEL SNLED27351_SCAN_PHASE_3_CHANNEL
#define MSKPHASE_2CHANNEL SNLED27351_SCAN_PHASE_2_CHANNEL
#define MSKPHASE_1CHANNEL SNLED27351_SCAN_PHASE_1_CHANNEL
#define ckled2001_led snled27351_led_t
#define g_ckled2001_leds g_snled27351_leds
// ========
#define SNLED27351_REG_COMMAND 0xFD
#define SNLED27351_COMMAND_LED_CONTROL 0x00
#define SNLED27351_COMMAND_PWM 0x01
#define SNLED27351_COMMAND_FUNCTION 0x03
#define SNLED27351_COMMAND_CURRENT_TUNE 0x04
#define SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN 0x00
#define SNLED27351_SOFTWARE_SHUTDOWN_SSD_SHUTDOWN (0x0 << 0)
#define SNLED27351_SOFTWARE_SHUTDOWN_SSD_NORMAL (0x1 << 0)
#define SNLED27351_FUNCTION_REG_ID 0x11
#define SNLED27351_DRIVER_ID 0x8A
#define SNLED27351_FUNCTION_REG_PULLDOWNUP 0x13
#define SNLED27351_PULLDOWNUP_ALL_ENABLED 0xAA
#define SNLED27351_FUNCTION_REG_SCAN_PHASE 0x14
#define SNLED27351_SCAN_PHASE_12_CHANNEL 0x00
#define SNLED27351_SCAN_PHASE_11_CHANNEL 0x01
#define SNLED27351_SCAN_PHASE_10_CHANNEL 0x02
#define SNLED27351_SCAN_PHASE_9_CHANNEL 0x03
#define SNLED27351_SCAN_PHASE_8_CHANNEL 0x04
#define SNLED27351_SCAN_PHASE_7_CHANNEL 0x05
#define SNLED27351_SCAN_PHASE_6_CHANNEL 0x06
#define SNLED27351_SCAN_PHASE_5_CHANNEL 0x07
#define SNLED27351_SCAN_PHASE_4_CHANNEL 0x08
#define SNLED27351_SCAN_PHASE_3_CHANNEL 0x09
#define SNLED27351_SCAN_PHASE_2_CHANNEL 0x0A
#define SNLED27351_SCAN_PHASE_1_CHANNEL 0x0B
#define SNLED27351_FUNCTION_REG_SLEW_RATE_CONTROL_MODE_1 0x15
#define SNLED27351_SLEW_RATE_CONTROL_MODE_1_PDP_ENABLE (0b1 << 2)
#define SNLED27351_FUNCTION_REG_SLEW_RATE_CONTROL_MODE_2 0x16
#define SNLED27351_SLEW_RATE_CONTROL_MODE_2_SSL_ENABLE (0b1 << 6)
#define SNLED27351_SLEW_RATE_CONTROL_MODE_2_DSL_ENABLE (0b1 << 7)
#define SNLED27351_FUNCTION_REG_OPEN_SHORT_ENABLE 0x17
#define SNLED27351_OPEN_SHORT_ENABLE_SDS_ENABLE (0b1 << 6)
#define SNLED27351_OPEN_SHORT_ENABLE_ODS_ENABLE (0b1 << 7)
#define SNLED27351_FUNCTION_REG_OPEN_SHORT_DUTY 0x18
#define SNLED27351_FUNCTION_REG_OPEN_SHORT_FLAG 0x19
#define SNLED27351_OPEN_SHORT_FLAG_OSINT_ENABLE (0b1 << 6)
#define SNLED27351_OPEN_SHORT_FLAG_ODINT_ENABLE (0b1 << 7)
#define SNLED27351_FUNCTION_REG_SOFTWARE_SLEEP 0x1A
#define SNLED27351_SOFTWARE_SLEEP_ENABLE (0b1 << 1)
// LED Control Registers
#define SNLED27351_LED_CONTROL_ON_OFF_FIRST_ADDR 0x0
#define SNLED27351_LED_CONTROL_ON_OFF_LAST_ADDR 0x17
#define SNLED27351_LED_CONTROL_ON_OFF_LENGTH ((SNLED27351_LED_CONTROL_ON_OFF_LAST_ADDR - SNLED27351_LED_CONTROL_ON_OFF_FIRST_ADDR) + 1)
#define SNLED27351_LED_CONTROL_OPEN_FIRST_ADDR 0x18
#define SNLED27351_LED_CONTROL_OPEN_LAST_ADDR 0x2F
#define SNLED27351_LED_CONTROL_OPEN_LENGTH ((SNLED27351_LED_CONTROL_OPEN_LAST_ADDR - SNLED27351_LED_CONTROL_OPEN_FIRST_ADDR) + 1)
#define SNLED27351_LED_CONTROL_SHORT_FIRST_ADDR 0x30
#define SNLED27351_LED_CONTROL_SHORT_LAST_ADDR 0x47
#define SNLED27351_LED_CONTROL_SHORT_LENGTH ((SNLED27351_LED_CONTROL_SHORT_LAST_ADDR - SNLED27351_LED_CONTROL_SHORT_FIRST_ADDR) + 1)
#define SNLED27351_LED_CONTROL_PAGE_LENGTH 0x48
// LED Control Registers
#define SNLED27351_LED_PWM_FIRST_ADDR 0x00
#define SNLED27351_LED_PWM_LAST_ADDR 0xBF
#define SNLED27351_LED_PWM_LENGTH 0xC0
// Current Tune Registers
#define SNLED27351_LED_CURRENT_TUNE_FIRST_ADDR 0x00
#define SNLED27351_LED_CURRENT_TUNE_LAST_ADDR 0x0B
#define SNLED27351_LED_CURRENT_TUNE_LENGTH 0x0C
#define SNLED27351_I2C_ADDRESS_GND 0x74
#define SNLED27351_I2C_ADDRESS_SCL 0x75
#define SNLED27351_I2C_ADDRESS_SDA 0x76
#define SNLED27351_I2C_ADDRESS_VDDIO 0x77
#if defined(LED_MATRIX_SNLED27351)
# define SNLED27351_LED_COUNT LED_MATRIX_LED_COUNT
#endif
#if defined(SNLED27351_I2C_ADDRESS_4)
# define SNLED27351_DRIVER_COUNT 4
#elif defined(SNLED27351_I2C_ADDRESS_3)
# define SNLED27351_DRIVER_COUNT 3
#elif defined(SNLED27351_I2C_ADDRESS_2)
# define SNLED27351_DRIVER_COUNT 2
#elif defined(SNLED27351_I2C_ADDRESS_1)
# define SNLED27351_DRIVER_COUNT 1
#endif
typedef struct snled27351_led_t {
uint8_t driver : 2;
uint8_t v;
} PACKED snled27351_led_t;
extern const snled27351_led_t PROGMEM g_snled27351_leds[SNLED27351_LED_COUNT];
void snled27351_init_drivers(void);
void snled27351_init(uint8_t addr);
void snled27351_select_page(uint8_t addr, uint8_t page);
bool snled27351_write_register(uint8_t addr, uint8_t reg, uint8_t data);
bool snled27351_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
void snled27351_set_value(int index, uint8_t value);
void snled27351_set_value_all(uint8_t value);
void snled27351_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 snled27351_update_pwm_buffers(uint8_t addr, uint8_t index);
void snled27351_update_led_control_registers(uint8_t addr, uint8_t index);
void snled27351_flush(void);
void snled27351_sw_return_normal(uint8_t addr);
void snled27351_sw_shutdown(uint8_t addr);
#define A_1 0x00
#define A_2 0x01
#define A_3 0x02
#define A_4 0x03
#define A_5 0x04
#define A_6 0x05
#define A_7 0x06
#define A_8 0x07
#define A_9 0x08
#define A_10 0x09
#define A_11 0x0A
#define A_12 0x0B
#define A_13 0x0C
#define A_14 0x0D
#define A_15 0x0E
#define A_16 0x0F
#define B_1 0x10
#define B_2 0x11
#define B_3 0x12
#define B_4 0x13
#define B_5 0x14
#define B_6 0x15
#define B_7 0x16
#define B_8 0x17
#define B_9 0x18
#define B_10 0x19
#define B_11 0x1A
#define B_12 0x1B
#define B_13 0x1C
#define B_14 0x1D
#define B_15 0x1E
#define B_16 0x1F
#define C_1 0x20
#define C_2 0x21
#define C_3 0x22
#define C_4 0x23
#define C_5 0x24
#define C_6 0x25
#define C_7 0x26
#define C_8 0x27
#define C_9 0x28
#define C_10 0x29
#define C_11 0x2A
#define C_12 0x2B
#define C_13 0x2C
#define C_14 0x2D
#define C_15 0x2E
#define C_16 0x2F
#define D_1 0x30
#define D_2 0x31
#define D_3 0x32
#define D_4 0x33
#define D_5 0x34
#define D_6 0x35
#define D_7 0x36
#define D_8 0x37
#define D_9 0x38
#define D_10 0x39
#define D_11 0x3A
#define D_12 0x3B
#define D_13 0x3C
#define D_14 0x3D
#define D_15 0x3E
#define D_16 0x3F
#define E_1 0x40
#define E_2 0x41
#define E_3 0x42
#define E_4 0x43
#define E_5 0x44
#define E_6 0x45
#define E_7 0x46
#define E_8 0x47
#define E_9 0x48
#define E_10 0x49
#define E_11 0x4A
#define E_12 0x4B
#define E_13 0x4C
#define E_14 0x4D
#define E_15 0x4E
#define E_16 0x4F
#define F_1 0x50
#define F_2 0x51
#define F_3 0x52
#define F_4 0x53
#define F_5 0x54
#define F_6 0x55
#define F_7 0x56
#define F_8 0x57
#define F_9 0x58
#define F_10 0x59
#define F_11 0x5A
#define F_12 0x5B
#define F_13 0x5C
#define F_14 0x5D
#define F_15 0x5E
#define F_16 0x5F
#define G_1 0x60
#define G_2 0x61
#define G_3 0x62
#define G_4 0x63
#define G_5 0x64
#define G_6 0x65
#define G_7 0x66
#define G_8 0x67
#define G_9 0x68
#define G_10 0x69
#define G_11 0x6A
#define G_12 0x6B
#define G_13 0x6C
#define G_14 0x6D
#define G_15 0x6E
#define G_16 0x6F
#define H_1 0x70
#define H_2 0x71
#define H_3 0x72
#define H_4 0x73
#define H_5 0x74
#define H_6 0x75
#define H_7 0x76
#define H_8 0x77
#define H_9 0x78
#define H_10 0x79
#define H_11 0x7A
#define H_12 0x7B
#define H_13 0x7C
#define H_14 0x7D
#define H_15 0x7E
#define H_16 0x7F
#define I_1 0x80
#define I_2 0x81
#define I_3 0x82
#define I_4 0x83
#define I_5 0x84
#define I_6 0x85
#define I_7 0x86
#define I_8 0x87
#define I_9 0x88
#define I_10 0x89
#define I_11 0x8A
#define I_12 0x8B
#define I_13 0x8C
#define I_14 0x8D
#define I_15 0x8E
#define I_16 0x8F
#define J_1 0x90
#define J_2 0x91
#define J_3 0x92
#define J_4 0x93
#define J_5 0x94
#define J_6 0x95
#define J_7 0x96
#define J_8 0x97
#define J_9 0x98
#define J_10 0x99
#define J_11 0x9A
#define J_12 0x9B
#define J_13 0x9C
#define J_14 0x9D
#define J_15 0x9E
#define J_16 0x9F
#define K_1 0xA0
#define K_2 0xA1
#define K_3 0xA2
#define K_4 0xA3
#define K_5 0xA4
#define K_6 0xA5
#define K_7 0xA6
#define K_8 0xA7
#define K_9 0xA8
#define K_10 0xA9
#define K_11 0xAA
#define K_12 0xAB
#define K_13 0xAC
#define K_14 0xAD
#define K_15 0xAE
#define K_16 0xAF
#define L_1 0xB0
#define L_2 0xB1
#define L_3 0xB2
#define L_4 0xB3
#define L_5 0xB4
#define L_6 0xB5
#define L_7 0xB6
#define L_8 0xB7
#define L_9 0xB8
#define L_10 0xB9
#define L_11 0xBA
#define L_12 0xBB
#define L_13 0xBC
#define L_14 0xBD
#define L_15 0xBE
#define L_16 0xBF

View File

@ -37,7 +37,18 @@
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
#endif
uint8_t i2c_transfer_buffer[65];
const uint8_t i2c_addresses[SNLED27351_DRIVER_COUNT] = {
SNLED27351_I2C_ADDRESS_1,
#ifdef SNLED27351_I2C_ADDRESS_2
SNLED27351_I2C_ADDRESS_2,
# ifdef SNLED27351_I2C_ADDRESS_3
SNLED27351_I2C_ADDRESS_3,
# ifdef SNLED27351_I2C_ADDRESS_4
SNLED27351_I2C_ADDRESS_4,
# endif
# endif
#endif
};
// These buffers match the SNLED27351 PWM registers.
// The control buffers match the PG0 LED On/Off registers.
@ -45,140 +56,111 @@ uint8_t i2c_transfer_buffer[65];
// We could optimize this and take out the unused registers from these
// buffers and the transfers in snled27351_write_pwm_buffer() but it's
// probably not worth the extra complexity.
uint8_t g_pwm_buffer[SNLED27351_DRIVER_COUNT][SNLED27351_PWM_REGISTER_COUNT];
bool g_pwm_buffer_update_required[SNLED27351_DRIVER_COUNT] = {false};
typedef struct snled27351_driver_t {
uint8_t pwm_buffer[SNLED27351_PWM_REGISTER_COUNT];
bool pwm_buffer_dirty;
uint8_t led_control_buffer[SNLED27351_LED_CONTROL_REGISTER_COUNT];
bool led_control_buffer_dirty;
} PACKED snled27351_driver_t;
uint8_t g_led_control_registers[SNLED27351_DRIVER_COUNT][SNLED27351_LED_CONTROL_REGISTER_COUNT] = {0};
bool g_led_control_registers_update_required[SNLED27351_DRIVER_COUNT] = {false};
bool snled27351_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
// If the transaction fails function returns false.
i2c_transfer_buffer[0] = reg;
i2c_transfer_buffer[1] = data;
snled27351_driver_t driver_buffers[SNLED27351_DRIVER_COUNT] = {{
.pwm_buffer = {0},
.pwm_buffer_dirty = false,
.led_control_buffer = {0},
.led_control_buffer_dirty = false,
}};
void snled27351_write_register(uint8_t index, uint8_t reg, uint8_t data) {
#if SNLED27351_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < SNLED27351_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, SNLED27351_I2C_TIMEOUT) != 0) {
return false;
}
if (i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, SNLED27351_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 2, SNLED27351_I2C_TIMEOUT) != 0) {
return false;
}
i2c_write_register(i2c_addresses[index] << 1, reg, &data, 1, SNLED27351_I2C_TIMEOUT);
#endif
return true;
}
void snled27351_select_page(uint8_t addr, uint8_t page) {
snled27351_write_register(addr, SNLED27351_REG_COMMAND, page);
void snled27351_select_page(uint8_t index, uint8_t page) {
snled27351_write_register(index, SNLED27351_REG_COMMAND, page);
}
bool snled27351_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
void snled27351_write_pwm_buffer(uint8_t index) {
// Assumes PG1 is already selected.
// If any of the transactions fails function returns false.
// Transmit PWM registers in 3 transfers of 64 bytes.
// Iterate over the pwm_buffer contents at 64 byte intervals.
for (uint8_t i = 0; i < SNLED27351_PWM_REGISTER_COUNT; i += 64) {
i2c_transfer_buffer[0] = i;
// Copy the data from i to i+63.
// Device will auto-increment register for data after the first byte
// Thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer.
for (uint8_t j = 0; j < 64; j++) {
i2c_transfer_buffer[1 + j] = pwm_buffer[i + j];
}
// Transmit PWM registers in 12 transfers of 16 bytes.
// Iterate over the pwm_buffer contents at 16 byte intervals.
for (uint8_t i = 0; i < SNLED27351_PWM_REGISTER_COUNT; i += 16) {
#if SNLED27351_I2C_PERSISTENCE > 0
for (uint8_t i = 0; i < SNLED27351_I2C_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 65, SNLED27351_I2C_TIMEOUT) != 0) {
return false;
}
for (uint8_t j = 0; j < SNLED27351_I2C_PERSISTENCE; j++) {
if (i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 16, SNLED27351_I2C_TIMEOUT) == I2C_STATUS_SUCCESS) break;
}
#else
if (i2c_transmit(addr << 1, i2c_transfer_buffer, 65, SNLED27351_I2C_TIMEOUT) != 0) {
return false;
}
i2c_write_register(i2c_addresses[index] << 1, i, driver_buffers[index].pwm_buffer + i, 16, SNLED27351_I2C_TIMEOUT);
#endif
}
return true;
}
void snled27351_init_drivers(void) {
i2c_init();
snled27351_init(SNLED27351_I2C_ADDRESS_1);
#if defined(SNLED27351_I2C_ADDRESS_2)
snled27351_init(SNLED27351_I2C_ADDRESS_2);
# if defined(SNLED27351_I2C_ADDRESS_3)
snled27351_init(SNLED27351_I2C_ADDRESS_3);
# if defined(SNLED27351_I2C_ADDRESS_4)
snled27351_init(SNLED27351_I2C_ADDRESS_4);
# endif
# endif
#endif
for (uint8_t i = 0; i < SNLED27351_DRIVER_COUNT; i++) {
snled27351_init(i);
}
for (int i = 0; i < SNLED27351_LED_COUNT; i++) {
snled27351_set_led_control_register(i, true, true, true);
}
snled27351_update_led_control_registers(SNLED27351_I2C_ADDRESS_1, 0);
#if defined(SNLED27351_I2C_ADDRESS_2)
snled27351_update_led_control_registers(SNLED27351_I2C_ADDRESS_2, 1);
# if defined(SNLED27351_I2C_ADDRESS_3)
snled27351_update_led_control_registers(SNLED27351_I2C_ADDRESS_3, 2);
# if defined(SNLED27351_I2C_ADDRESS_4)
snled27351_update_led_control_registers(SNLED27351_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
for (uint8_t i = 0; i < SNLED27351_DRIVER_COUNT; i++) {
snled27351_update_led_control_registers(i);
}
}
void snled27351_init(uint8_t addr) {
snled27351_select_page(addr, SNLED27351_COMMAND_FUNCTION);
void snled27351_init(uint8_t index) {
snled27351_select_page(index, SNLED27351_COMMAND_FUNCTION);
// Setting LED driver to shutdown mode
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN, SNLED27351_SOFTWARE_SHUTDOWN_SSD_SHUTDOWN);
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN, SNLED27351_SOFTWARE_SHUTDOWN_SSD_SHUTDOWN);
// Setting internal channel pulldown/pullup
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_PULLDOWNUP, SNLED27351_PULLDOWNUP_ALL_ENABLED);
snled27351_write_register(index, SNLED27351_FUNCTION_REG_PULLDOWNUP, SNLED27351_PULLDOWNUP_ALL_ENABLED);
// Select number of scan phase
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SCAN_PHASE, SNLED27351_PHASE_CHANNEL);
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SCAN_PHASE, SNLED27351_PHASE_CHANNEL);
// Setting PWM Delay Phase
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SLEW_RATE_CONTROL_MODE_1, SNLED27351_SLEW_RATE_CONTROL_MODE_1_PDP_ENABLE);
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SLEW_RATE_CONTROL_MODE_1, SNLED27351_SLEW_RATE_CONTROL_MODE_1_PDP_ENABLE);
// Setting Driving/Sinking Channel Slew Rate
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SLEW_RATE_CONTROL_MODE_2, SNLED27351_SLEW_RATE_CONTROL_MODE_2_DSL_ENABLE | SNLED27351_SLEW_RATE_CONTROL_MODE_2_SSL_ENABLE);
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SLEW_RATE_CONTROL_MODE_2, SNLED27351_SLEW_RATE_CONTROL_MODE_2_DSL_ENABLE | SNLED27351_SLEW_RATE_CONTROL_MODE_2_SSL_ENABLE);
// Setting Iref
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SOFTWARE_SLEEP, 0);
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SOFTWARE_SLEEP, 0);
snled27351_select_page(addr, SNLED27351_COMMAND_LED_CONTROL);
snled27351_select_page(index, SNLED27351_COMMAND_LED_CONTROL);
for (int i = 0; i < SNLED27351_LED_CONTROL_ON_OFF_LENGTH; i++) {
snled27351_write_register(addr, i, 0x00);
snled27351_write_register(index, i, 0x00);
}
snled27351_select_page(addr, SNLED27351_COMMAND_PWM);
snled27351_select_page(index, SNLED27351_COMMAND_PWM);
for (int i = 0; i < SNLED27351_LED_CURRENT_TUNE_LENGTH; i++) {
snled27351_write_register(addr, i, 0x00);
snled27351_write_register(index, i, 0x00);
}
snled27351_select_page(addr, SNLED27351_COMMAND_CURRENT_TUNE);
snled27351_select_page(index, SNLED27351_COMMAND_CURRENT_TUNE);
uint8_t current_tune_reg_list[SNLED27351_LED_CURRENT_TUNE_LENGTH] = SNLED27351_CURRENT_TUNE;
for (int i = 0; i < SNLED27351_LED_CURRENT_TUNE_LENGTH; i++) {
snled27351_write_register(addr, i, current_tune_reg_list[i]);
snled27351_write_register(index, i, current_tune_reg_list[i]);
}
snled27351_select_page(addr, SNLED27351_COMMAND_LED_CONTROL);
snled27351_select_page(index, SNLED27351_COMMAND_LED_CONTROL);
for (int i = 0; i < SNLED27351_LED_CONTROL_ON_OFF_LENGTH; i++) {
snled27351_write_register(addr, i, 0xFF);
snled27351_write_register(index, i, 0xFF);
}
snled27351_select_page(addr, SNLED27351_COMMAND_FUNCTION);
snled27351_select_page(index, SNLED27351_COMMAND_FUNCTION);
// Setting LED driver to normal mode
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN, SNLED27351_SOFTWARE_SHUTDOWN_SSD_NORMAL);
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN, SNLED27351_SOFTWARE_SHUTDOWN_SSD_NORMAL);
}
void snled27351_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
@ -186,13 +168,14 @@ void snled27351_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
if (index >= 0 && index < SNLED27351_LED_COUNT) {
memcpy_P(&led, (&g_snled27351_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) {
if (driver_buffers[led.driver].pwm_buffer[led.r] == red && driver_buffers[led.driver].pwm_buffer[led.g] == green && driver_buffers[led.driver].pwm_buffer[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;
driver_buffers[led.driver].pwm_buffer[led.r] = red;
driver_buffers[led.driver].pwm_buffer[led.g] = green;
driver_buffers[led.driver].pwm_buffer[led.b] = blue;
driver_buffers[led.driver].pwm_buffer_dirty = true;
}
}
@ -214,73 +197,64 @@ void snled27351_set_led_control_register(uint8_t index, bool red, bool green, bo
uint8_t bit_b = led.b % 8;
if (red) {
g_led_control_registers[led.driver][control_register_r] |= (1 << bit_r);
driver_buffers[led.driver].led_control_buffer[control_register_r] |= (1 << bit_r);
} else {
g_led_control_registers[led.driver][control_register_r] &= ~(1 << bit_r);
driver_buffers[led.driver].led_control_buffer[control_register_r] &= ~(1 << bit_r);
}
if (green) {
g_led_control_registers[led.driver][control_register_g] |= (1 << bit_g);
driver_buffers[led.driver].led_control_buffer[control_register_g] |= (1 << bit_g);
} else {
g_led_control_registers[led.driver][control_register_g] &= ~(1 << bit_g);
driver_buffers[led.driver].led_control_buffer[control_register_g] &= ~(1 << bit_g);
}
if (blue) {
g_led_control_registers[led.driver][control_register_b] |= (1 << bit_b);
driver_buffers[led.driver].led_control_buffer[control_register_b] |= (1 << bit_b);
} else {
g_led_control_registers[led.driver][control_register_b] &= ~(1 << bit_b);
driver_buffers[led.driver].led_control_buffer[control_register_b] &= ~(1 << bit_b);
}
g_led_control_registers_update_required[led.driver] = true;
driver_buffers[led.driver].led_control_buffer_dirty = true;
}
void snled27351_update_pwm_buffers(uint8_t addr, uint8_t index) {
if (g_pwm_buffer_update_required[index]) {
snled27351_select_page(addr, SNLED27351_COMMAND_PWM);
void snled27351_update_pwm_buffers(uint8_t index) {
if (driver_buffers[index].pwm_buffer_dirty) {
snled27351_select_page(index, SNLED27351_COMMAND_PWM);
// If any of the transactions fail we risk writing dirty PG0,
// refresh page 0 just in case.
if (!snled27351_write_pwm_buffer(addr, g_pwm_buffer[index])) {
g_led_control_registers_update_required[index] = true;
}
snled27351_write_pwm_buffer(index);
driver_buffers[index].pwm_buffer_dirty = false;
}
g_pwm_buffer_update_required[index] = false;
}
void snled27351_update_led_control_registers(uint8_t addr, uint8_t index) {
if (g_led_control_registers_update_required[index]) {
snled27351_select_page(addr, SNLED27351_COMMAND_LED_CONTROL);
void snled27351_update_led_control_registers(uint8_t index) {
if (driver_buffers[index].led_control_buffer_dirty) {
snled27351_select_page(index, SNLED27351_COMMAND_LED_CONTROL);
for (int i = 0; i < SNLED27351_LED_CONTROL_REGISTER_COUNT; i++) {
snled27351_write_register(addr, i, g_led_control_registers[index][i]);
for (uint8_t i = 0; i < SNLED27351_LED_CONTROL_REGISTER_COUNT; i++) {
snled27351_write_register(index, i, driver_buffers[index].led_control_buffer[i]);
}
driver_buffers[index].led_control_buffer_dirty = false;
}
g_led_control_registers_update_required[index] = false;
}
void snled27351_flush(void) {
snled27351_update_pwm_buffers(SNLED27351_I2C_ADDRESS_1, 0);
#if defined(SNLED27351_I2C_ADDRESS_2)
snled27351_update_pwm_buffers(SNLED27351_I2C_ADDRESS_2, 1);
# if defined(SNLED27351_I2C_ADDRESS_3)
snled27351_update_pwm_buffers(SNLED27351_I2C_ADDRESS_3, 2);
# if defined(SNLED27351_I2C_ADDRESS_4)
snled27351_update_pwm_buffers(SNLED27351_I2C_ADDRESS_4, 3);
# endif
# endif
#endif
for (uint8_t i = 0; i < SNLED27351_DRIVER_COUNT; i++) {
snled27351_update_pwm_buffers(i);
}
}
void snled27351_sw_return_normal(uint8_t addr) {
snled27351_select_page(addr, SNLED27351_COMMAND_FUNCTION);
void snled27351_sw_return_normal(uint8_t index) {
snled27351_select_page(index, SNLED27351_COMMAND_FUNCTION);
// Setting LED driver to normal mode
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN, SNLED27351_SOFTWARE_SHUTDOWN_SSD_NORMAL);
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN, SNLED27351_SOFTWARE_SHUTDOWN_SSD_NORMAL);
}
void snled27351_sw_shutdown(uint8_t addr) {
snled27351_select_page(addr, SNLED27351_COMMAND_FUNCTION);
void snled27351_sw_shutdown(uint8_t index) {
snled27351_select_page(index, SNLED27351_COMMAND_FUNCTION);
// Setting LED driver to shutdown mode
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN, SNLED27351_SOFTWARE_SHUTDOWN_SSD_SHUTDOWN);
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SOFTWARE_SHUTDOWN, SNLED27351_SOFTWARE_SHUTDOWN_SSD_SHUTDOWN);
// Write SW Sleep Register
snled27351_write_register(addr, SNLED27351_FUNCTION_REG_SOFTWARE_SLEEP, SNLED27351_SOFTWARE_SLEEP_ENABLE);
snled27351_write_register(index, SNLED27351_FUNCTION_REG_SOFTWARE_SLEEP, SNLED27351_SOFTWARE_SLEEP_ENABLE);
}

View File

@ -168,10 +168,9 @@ typedef struct snled27351_led_t {
extern const snled27351_led_t PROGMEM g_snled27351_leds[SNLED27351_LED_COUNT];
void snled27351_init_drivers(void);
void snled27351_init(uint8_t addr);
void snled27351_select_page(uint8_t addr, uint8_t page);
bool snled27351_write_register(uint8_t addr, uint8_t reg, uint8_t data);
bool snled27351_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
void snled27351_init(uint8_t index);
void snled27351_select_page(uint8_t index, uint8_t page);
void snled27351_write_register(uint8_t index, uint8_t reg, uint8_t data);
void snled27351_set_color(int index, uint8_t red, uint8_t green, uint8_t blue);
void snled27351_set_color_all(uint8_t red, uint8_t green, uint8_t blue);
@ -182,214 +181,420 @@ void snled27351_set_led_control_register(uint8_t index, bool red, bool green, bo
// (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 snled27351_update_pwm_buffers(uint8_t addr, uint8_t index);
void snled27351_update_led_control_registers(uint8_t addr, uint8_t index);
void snled27351_update_pwm_buffers(uint8_t index);
void snled27351_update_led_control_registers(uint8_t index);
void snled27351_flush(void);
void snled27351_sw_return_normal(uint8_t addr);
void snled27351_sw_shutdown(uint8_t addr);
void snled27351_sw_return_normal(uint8_t index);
void snled27351_sw_shutdown(uint8_t index);
#define A_1 0x00
#define A_2 0x01
#define A_3 0x02
#define A_4 0x03
#define A_5 0x04
#define A_6 0x05
#define A_7 0x06
#define A_8 0x07
#define A_9 0x08
#define A_10 0x09
#define A_11 0x0A
#define A_12 0x0B
#define A_13 0x0C
#define A_14 0x0D
#define A_15 0x0E
#define A_16 0x0F
#define CB1_CA1 0x00
#define CB1_CA2 0x01
#define CB1_CA3 0x02
#define CB1_CA4 0x03
#define CB1_CA5 0x04
#define CB1_CA6 0x05
#define CB1_CA7 0x06
#define CB1_CA8 0x07
#define CB1_CA9 0x08
#define CB1_CA10 0x09
#define CB1_CA11 0x0A
#define CB1_CA12 0x0B
#define CB1_CA13 0x0C
#define CB1_CA14 0x0D
#define CB1_CA15 0x0E
#define CB1_CA16 0x0F
#define B_1 0x10
#define B_2 0x11
#define B_3 0x12
#define B_4 0x13
#define B_5 0x14
#define B_6 0x15
#define B_7 0x16
#define B_8 0x17
#define B_9 0x18
#define B_10 0x19
#define B_11 0x1A
#define B_12 0x1B
#define B_13 0x1C
#define B_14 0x1D
#define B_15 0x1E
#define B_16 0x1F
#define CB2_CA1 0x10
#define CB2_CA2 0x11
#define CB2_CA3 0x12
#define CB2_CA4 0x13
#define CB2_CA5 0x14
#define CB2_CA6 0x15
#define CB2_CA7 0x16
#define CB2_CA8 0x17
#define CB2_CA9 0x18
#define CB2_CA10 0x19
#define CB2_CA11 0x1A
#define CB2_CA12 0x1B
#define CB2_CA13 0x1C
#define CB2_CA14 0x1D
#define CB2_CA15 0x1E
#define CB2_CA16 0x1F
#define C_1 0x20
#define C_2 0x21
#define C_3 0x22
#define C_4 0x23
#define C_5 0x24
#define C_6 0x25
#define C_7 0x26
#define C_8 0x27
#define C_9 0x28
#define C_10 0x29
#define C_11 0x2A
#define C_12 0x2B
#define C_13 0x2C
#define C_14 0x2D
#define C_15 0x2E
#define C_16 0x2F
#define CB3_CA1 0x20
#define CB3_CA2 0x21
#define CB3_CA3 0x22
#define CB3_CA4 0x23
#define CB3_CA5 0x24
#define CB3_CA6 0x25
#define CB3_CA7 0x26
#define CB3_CA8 0x27
#define CB3_CA9 0x28
#define CB3_CA10 0x29
#define CB3_CA11 0x2A
#define CB3_CA12 0x2B
#define CB3_CA13 0x2C
#define CB3_CA14 0x2D
#define CB3_CA15 0x2E
#define CB3_CA16 0x2F
#define D_1 0x30
#define D_2 0x31
#define D_3 0x32
#define D_4 0x33
#define D_5 0x34
#define D_6 0x35
#define D_7 0x36
#define D_8 0x37
#define D_9 0x38
#define D_10 0x39
#define D_11 0x3A
#define D_12 0x3B
#define D_13 0x3C
#define D_14 0x3D
#define D_15 0x3E
#define D_16 0x3F
#define CB4_CA1 0x30
#define CB4_CA2 0x31
#define CB4_CA3 0x32
#define CB4_CA4 0x33
#define CB4_CA5 0x34
#define CB4_CA6 0x35
#define CB4_CA7 0x36
#define CB4_CA8 0x37
#define CB4_CA9 0x38
#define CB4_CA10 0x39
#define CB4_CA11 0x3A
#define CB4_CA12 0x3B
#define CB4_CA13 0x3C
#define CB4_CA14 0x3D
#define CB4_CA15 0x3E
#define CB4_CA16 0x3F
#define E_1 0x40
#define E_2 0x41
#define E_3 0x42
#define E_4 0x43
#define E_5 0x44
#define E_6 0x45
#define E_7 0x46
#define E_8 0x47
#define E_9 0x48
#define E_10 0x49
#define E_11 0x4A
#define E_12 0x4B
#define E_13 0x4C
#define E_14 0x4D
#define E_15 0x4E
#define E_16 0x4F
#define CB5_CA1 0x40
#define CB5_CA2 0x41
#define CB5_CA3 0x42
#define CB5_CA4 0x43
#define CB5_CA5 0x44
#define CB5_CA6 0x45
#define CB5_CA7 0x46
#define CB5_CA8 0x47
#define CB5_CA9 0x48
#define CB5_CA10 0x49
#define CB5_CA11 0x4A
#define CB5_CA12 0x4B
#define CB5_CA13 0x4C
#define CB5_CA14 0x4D
#define CB5_CA15 0x4E
#define CB5_CA16 0x4F
#define F_1 0x50
#define F_2 0x51
#define F_3 0x52
#define F_4 0x53
#define F_5 0x54
#define F_6 0x55
#define F_7 0x56
#define F_8 0x57
#define F_9 0x58
#define F_10 0x59
#define F_11 0x5A
#define F_12 0x5B
#define F_13 0x5C
#define F_14 0x5D
#define F_15 0x5E
#define F_16 0x5F
#define CB6_CA1 0x50
#define CB6_CA2 0x51
#define CB6_CA3 0x52
#define CB6_CA4 0x53
#define CB6_CA5 0x54
#define CB6_CA6 0x55
#define CB6_CA7 0x56
#define CB6_CA8 0x57
#define CB6_CA9 0x58
#define CB6_CA10 0x59
#define CB6_CA11 0x5A
#define CB6_CA12 0x5B
#define CB6_CA13 0x5C
#define CB6_CA14 0x5D
#define CB6_CA15 0x5E
#define CB6_CA16 0x5F
#define G_1 0x60
#define G_2 0x61
#define G_3 0x62
#define G_4 0x63
#define G_5 0x64
#define G_6 0x65
#define G_7 0x66
#define G_8 0x67
#define G_9 0x68
#define G_10 0x69
#define G_11 0x6A
#define G_12 0x6B
#define G_13 0x6C
#define G_14 0x6D
#define G_15 0x6E
#define G_16 0x6F
#define CB7_CA1 0x60
#define CB7_CA2 0x61
#define CB7_CA3 0x62
#define CB7_CA4 0x63
#define CB7_CA5 0x64
#define CB7_CA6 0x65
#define CB7_CA7 0x66
#define CB7_CA8 0x67
#define CB7_CA9 0x68
#define CB7_CA10 0x69
#define CB7_CA11 0x6A
#define CB7_CA12 0x6B
#define CB7_CA13 0x6C
#define CB7_CA14 0x6D
#define CB7_CA15 0x6E
#define CB7_CA16 0x6F
#define H_1 0x70
#define H_2 0x71
#define H_3 0x72
#define H_4 0x73
#define H_5 0x74
#define H_6 0x75
#define H_7 0x76
#define H_8 0x77
#define H_9 0x78
#define H_10 0x79
#define H_11 0x7A
#define H_12 0x7B
#define H_13 0x7C
#define H_14 0x7D
#define H_15 0x7E
#define H_16 0x7F
#define CB8_CA1 0x70
#define CB8_CA2 0x71
#define CB8_CA3 0x72
#define CB8_CA4 0x73
#define CB8_CA5 0x74
#define CB8_CA6 0x75
#define CB8_CA7 0x76
#define CB8_CA8 0x77
#define CB8_CA9 0x78
#define CB8_CA10 0x79
#define CB8_CA11 0x7A
#define CB8_CA12 0x7B
#define CB8_CA13 0x7C
#define CB8_CA14 0x7D
#define CB8_CA15 0x7E
#define CB8_CA16 0x7F
#define I_1 0x80
#define I_2 0x81
#define I_3 0x82
#define I_4 0x83
#define I_5 0x84
#define I_6 0x85
#define I_7 0x86
#define I_8 0x87
#define I_9 0x88
#define I_10 0x89
#define I_11 0x8A
#define I_12 0x8B
#define I_13 0x8C
#define I_14 0x8D
#define I_15 0x8E
#define I_16 0x8F
#define CB9_CA1 0x80
#define CB9_CA2 0x81
#define CB9_CA3 0x82
#define CB9_CA4 0x83
#define CB9_CA5 0x84
#define CB9_CA6 0x85
#define CB9_CA7 0x86
#define CB9_CA8 0x87
#define CB9_CA9 0x88
#define CB9_CA10 0x89
#define CB9_CA11 0x8A
#define CB9_CA12 0x8B
#define CB9_CA13 0x8C
#define CB9_CA14 0x8D
#define CB9_CA15 0x8E
#define CB9_CA16 0x8F
#define J_1 0x90
#define J_2 0x91
#define J_3 0x92
#define J_4 0x93
#define J_5 0x94
#define J_6 0x95
#define J_7 0x96
#define J_8 0x97
#define J_9 0x98
#define J_10 0x99
#define J_11 0x9A
#define J_12 0x9B
#define J_13 0x9C
#define J_14 0x9D
#define J_15 0x9E
#define J_16 0x9F
#define CB10_CA1 0x90
#define CB10_CA2 0x91
#define CB10_CA3 0x92
#define CB10_CA4 0x93
#define CB10_CA5 0x94
#define CB10_CA6 0x95
#define CB10_CA7 0x96
#define CB10_CA8 0x97
#define CB10_CA9 0x98
#define CB10_CA10 0x99
#define CB10_CA11 0x9A
#define CB10_CA12 0x9B
#define CB10_CA13 0x9C
#define CB10_CA14 0x9D
#define CB10_CA15 0x9E
#define CB10_CA16 0x9F
#define K_1 0xA0
#define K_2 0xA1
#define K_3 0xA2
#define K_4 0xA3
#define K_5 0xA4
#define K_6 0xA5
#define K_7 0xA6
#define K_8 0xA7
#define K_9 0xA8
#define K_10 0xA9
#define K_11 0xAA
#define K_12 0xAB
#define K_13 0xAC
#define K_14 0xAD
#define K_15 0xAE
#define K_16 0xAF
#define CB11_CA1 0xA0
#define CB11_CA2 0xA1
#define CB11_CA3 0xA2
#define CB11_CA4 0xA3
#define CB11_CA5 0xA4
#define CB11_CA6 0xA5
#define CB11_CA7 0xA6
#define CB11_CA8 0xA7
#define CB11_CA9 0xA8
#define CB11_CA10 0xA9
#define CB11_CA11 0xAA
#define CB11_CA12 0xAB
#define CB11_CA13 0xAC
#define CB11_CA14 0xAD
#define CB11_CA15 0xAE
#define CB11_CA16 0xAF
#define L_1 0xB0
#define L_2 0xB1
#define L_3 0xB2
#define L_4 0xB3
#define L_5 0xB4
#define L_6 0xB5
#define L_7 0xB6
#define L_8 0xB7
#define L_9 0xB8
#define L_10 0xB9
#define L_11 0xBA
#define L_12 0xBB
#define L_13 0xBC
#define L_14 0xBD
#define L_15 0xBE
#define L_16 0xBF
#define CB12_CA1 0xB0
#define CB12_CA2 0xB1
#define CB12_CA3 0xB2
#define CB12_CA4 0xB3
#define CB12_CA5 0xB4
#define CB12_CA6 0xB5
#define CB12_CA7 0xB6
#define CB12_CA8 0xB7
#define CB12_CA9 0xB8
#define CB12_CA10 0xB9
#define CB12_CA11 0xBA
#define CB12_CA12 0xBB
#define CB12_CA13 0xBC
#define CB12_CA14 0xBD
#define CB12_CA15 0xBE
#define CB12_CA16 0xBF
// DEPRECATED - DO NOT USE
#define A_1 CB1_CA1
#define A_2 CB1_CA2
#define A_3 CB1_CA3
#define A_4 CB1_CA4
#define A_5 CB1_CA5
#define A_6 CB1_CA6
#define A_7 CB1_CA7
#define A_8 CB1_CA8
#define A_9 CB1_CA9
#define A_10 CB1_CA10
#define A_11 CB1_CA11
#define A_12 CB1_CA12
#define A_13 CB1_CA13
#define A_14 CB1_CA14
#define A_15 CB1_CA15
#define A_16 CB1_CA16
#define B_1 CB2_CA1
#define B_2 CB2_CA2
#define B_3 CB2_CA3
#define B_4 CB2_CA4
#define B_5 CB2_CA5
#define B_6 CB2_CA6
#define B_7 CB2_CA7
#define B_8 CB2_CA8
#define B_9 CB2_CA9
#define B_10 CB2_CA10
#define B_11 CB2_CA11
#define B_12 CB2_CA12
#define B_13 CB2_CA13
#define B_14 CB2_CA14
#define B_15 CB2_CA15
#define B_16 CB2_CA16
#define C_1 CB3_CA1
#define C_2 CB3_CA2
#define C_3 CB3_CA3
#define C_4 CB3_CA4
#define C_5 CB3_CA5
#define C_6 CB3_CA6
#define C_7 CB3_CA7
#define C_8 CB3_CA8
#define C_9 CB3_CA9
#define C_10 CB3_CA10
#define C_11 CB3_CA11
#define C_12 CB3_CA12
#define C_13 CB3_CA13
#define C_14 CB3_CA14
#define C_15 CB3_CA15
#define C_16 CB3_CA16
#define D_1 CB4_CA1
#define D_2 CB4_CA2
#define D_3 CB4_CA3
#define D_4 CB4_CA4
#define D_5 CB4_CA5
#define D_6 CB4_CA6
#define D_7 CB4_CA7
#define D_8 CB4_CA8
#define D_9 CB4_CA9
#define D_10 CB4_CA10
#define D_11 CB4_CA11
#define D_12 CB4_CA12
#define D_13 CB4_CA13
#define D_14 CB4_CA14
#define D_15 CB4_CA15
#define D_16 CB4_CA16
#define E_1 CB5_CA1
#define E_2 CB5_CA2
#define E_3 CB5_CA3
#define E_4 CB5_CA4
#define E_5 CB5_CA5
#define E_6 CB5_CA6
#define E_7 CB5_CA7
#define E_8 CB5_CA8
#define E_9 CB5_CA9
#define E_10 CB5_CA10
#define E_11 CB5_CA11
#define E_12 CB5_CA12
#define E_13 CB5_CA13
#define E_14 CB5_CA14
#define E_15 CB5_CA15
#define E_16 CB5_CA16
#define F_1 CB6_CA1
#define F_2 CB6_CA2
#define F_3 CB6_CA3
#define F_4 CB6_CA4
#define F_5 CB6_CA5
#define F_6 CB6_CA6
#define F_7 CB6_CA7
#define F_8 CB6_CA8
#define F_9 CB6_CA9
#define F_10 CB6_CA10
#define F_11 CB6_CA11
#define F_12 CB6_CA12
#define F_13 CB6_CA13
#define F_14 CB6_CA14
#define F_15 CB6_CA15
#define F_16 CB6_CA16
#define G_1 CB7_CA1
#define G_2 CB7_CA2
#define G_3 CB7_CA3
#define G_4 CB7_CA4
#define G_5 CB7_CA5
#define G_6 CB7_CA6
#define G_7 CB7_CA7
#define G_8 CB7_CA8
#define G_9 CB7_CA9
#define G_10 CB7_CA10
#define G_11 CB7_CA11
#define G_12 CB7_CA12
#define G_13 CB7_CA13
#define G_14 CB7_CA14
#define G_15 CB7_CA15
#define G_16 CB7_CA16
#define H_1 CB8_CA1
#define H_2 CB8_CA2
#define H_3 CB8_CA3
#define H_4 CB8_CA4
#define H_5 CB8_CA5
#define H_6 CB8_CA6
#define H_7 CB8_CA7
#define H_8 CB8_CA8
#define H_9 CB8_CA9
#define H_10 CB8_CA10
#define H_11 CB8_CA11
#define H_12 CB8_CA12
#define H_13 CB8_CA13
#define H_14 CB8_CA14
#define H_15 CB8_CA15
#define H_16 CB8_CA16
#define I_1 CB9_CA1
#define I_2 CB9_CA2
#define I_3 CB9_CA3
#define I_4 CB9_CA4
#define I_5 CB9_CA5
#define I_6 CB9_CA6
#define I_7 CB9_CA7
#define I_8 CB9_CA8
#define I_9 CB9_CA9
#define I_10 CB9_CA10
#define I_11 CB9_CA11
#define I_12 CB9_CA12
#define I_13 CB9_CA13
#define I_14 CB9_CA14
#define I_15 CB9_CA15
#define I_16 CB9_CA16
#define J_1 CB10_CA1
#define J_2 CB10_CA2
#define J_3 CB10_CA3
#define J_4 CB10_CA4
#define J_5 CB10_CA5
#define J_6 CB10_CA6
#define J_7 CB10_CA7
#define J_8 CB10_CA8
#define J_9 CB10_CA9
#define J_10 CB10_CA10
#define J_11 CB10_CA11
#define J_12 CB10_CA12
#define J_13 CB10_CA13
#define J_14 CB10_CA14
#define J_15 CB10_CA15
#define J_16 CB10_CA16
#define K_1 CB11_CA1
#define K_2 CB11_CA2
#define K_3 CB11_CA3
#define K_4 CB11_CA4
#define K_5 CB11_CA5
#define K_6 CB11_CA6
#define K_7 CB11_CA7
#define K_8 CB11_CA8
#define K_9 CB11_CA9
#define K_10 CB11_CA10
#define K_11 CB11_CA11
#define K_12 CB11_CA12
#define K_13 CB11_CA13
#define K_14 CB11_CA14
#define K_15 CB11_CA15
#define K_16 CB11_CA16
#define L_1 CB12_CA1
#define L_2 CB12_CA2
#define L_3 CB12_CA3
#define L_4 CB12_CA4
#define L_5 CB12_CA5
#define L_6 CB12_CA6
#define L_7 CB12_CA7
#define L_8 CB12_CA8
#define L_9 CB12_CA9
#define L_10 CB12_CA10
#define L_11 CB12_CA11
#define L_12 CB12_CA12
#define L_13 CB12_CA13
#define L_14 CB12_CA14
#define L_15 CB12_CA15
#define L_16 CB12_CA16

View File

@ -223,13 +223,8 @@ __attribute__((weak)) bool oled_send_cmd_P(const uint8_t *data, uint16_t size) {
spi_stop();
return (status >= 0);
# elif defined(OLED_TRANSPORT_I2C)
i2c_status_t status = i2c_start((OLED_DISPLAY_ADDRESS << 1) | I2C_WRITE, OLED_I2C_TIMEOUT);
for (uint16_t i = 0; i < size && status >= 0; i++) {
status = i2c_write(pgm_read_byte((const char *)data++), OLED_I2C_TIMEOUT);
}
i2c_stop();
i2c_status_t status = i2c_transmit_P((OLED_DISPLAY_ADDRESS << 1), data, size, OLED_I2C_TIMEOUT);
return (status == I2C_STATUS_SUCCESS);
# endif
@ -253,7 +248,7 @@ __attribute__((weak)) bool oled_send_data(const uint8_t *data, uint16_t size) {
spi_stop();
return true;
#elif defined(OLED_TRANSPORT_I2C)
i2c_status_t status = i2c_writeReg((OLED_DISPLAY_ADDRESS << 1), I2C_DATA, data, size, OLED_I2C_TIMEOUT);
i2c_status_t status = i2c_write_register((OLED_DISPLAY_ADDRESS << 1), I2C_DATA, data, size, OLED_I2C_TIMEOUT);
return (status == I2C_STATUS_SUCCESS);
#endif
}

View File

@ -28,18 +28,14 @@ bool qp_comms_i2c_init(painter_device_t device) {
}
bool qp_comms_i2c_start(painter_device_t device) {
painter_driver_t * driver = (painter_driver_t *)device;
qp_comms_i2c_config_t *comms_config = (qp_comms_i2c_config_t *)driver->comms_config;
return i2c_start(comms_config->chip_address << 1) == I2C_STATUS_SUCCESS;
return true;
}
uint32_t qp_comms_i2c_send_data(painter_device_t device, const void *data, uint32_t byte_count) {
return qp_comms_i2c_send_raw(device, data, byte_count);
}
void qp_comms_i2c_stop(painter_device_t device) {
i2c_stop();
}
void qp_comms_i2c_stop(painter_device_t device) {}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Command+Data I2C support

View File

@ -128,6 +128,9 @@ report_analog_joystick_t analog_joystick_read(void) {
}
void analog_joystick_init(void) {
setPinInputHigh(ANALOG_JOYSTICK_X_AXIS_PIN);
setPinInputHigh(ANALOG_JOYSTICK_Y_AXIS_PIN);
#ifdef ANALOG_JOYSTICK_CLICK_PIN
setPinInputHigh(ANALOG_JOYSTICK_CLICK_PIN);
#endif

View File

@ -107,18 +107,17 @@ static struct {
i2c_status_t azoteq_iqs5xx_wake(void) {
uint8_t data = 0;
i2c_status_t status = i2c_readReg16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_PREVIOUS_CYCLE_TIME, (uint8_t *)&data, sizeof(data), 1);
i2c_stop();
i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_PREVIOUS_CYCLE_TIME, (uint8_t *)&data, sizeof(data), 1);
wait_us(150);
return status;
}
i2c_status_t azoteq_iqs5xx_end_session(void) {
const uint8_t END_BYTE = 1; // any data
return i2c_writeReg16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_END_COMMS, &END_BYTE, 1, AZOTEQ_IQS5XX_TIMEOUT_MS);
return i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_END_COMMS, &END_BYTE, 1, AZOTEQ_IQS5XX_TIMEOUT_MS);
}
i2c_status_t azoteq_iqs5xx_get_base_data(azoteq_iqs5xx_base_data_t *base_data) {
i2c_status_t status = i2c_readReg16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_PREVIOUS_CYCLE_TIME, (uint8_t *)base_data, 10, AZOTEQ_IQS5XX_TIMEOUT_MS);
i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_PREVIOUS_CYCLE_TIME, (uint8_t *)base_data, 10, AZOTEQ_IQS5XX_TIMEOUT_MS);
if (status == I2C_STATUS_SUCCESS) {
azoteq_iqs5xx_end_session();
}
@ -131,7 +130,7 @@ i2c_status_t azoteq_iqs5xx_get_report_rate(azoteq_iqs5xx_report_rate_t *report_r
return I2C_STATUS_ERROR;
}
uint16_t selected_reg = AZOTEQ_IQS5XX_REG_REPORT_RATE_ACTIVE + (2 * mode);
i2c_status_t status = i2c_readReg16(AZOTEQ_IQS5XX_ADDRESS, selected_reg, (uint8_t *)report_rate, 2, AZOTEQ_IQS5XX_TIMEOUT_MS);
i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, selected_reg, (uint8_t *)report_rate, 2, AZOTEQ_IQS5XX_TIMEOUT_MS);
if (end_session) {
azoteq_iqs5xx_end_session();
}
@ -147,7 +146,7 @@ i2c_status_t azoteq_iqs5xx_set_report_rate(uint16_t report_rate_ms, azoteq_iqs5x
azoteq_iqs5xx_report_rate_t report_rate = {0};
report_rate.h = (uint8_t)((report_rate_ms >> 8) & 0xFF);
report_rate.l = (uint8_t)(report_rate_ms & 0xFF);
i2c_status_t status = i2c_writeReg16(AZOTEQ_IQS5XX_ADDRESS, selected_reg, (uint8_t *)&report_rate, 2, AZOTEQ_IQS5XX_TIMEOUT_MS);
i2c_status_t status = i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, selected_reg, (uint8_t *)&report_rate, 2, AZOTEQ_IQS5XX_TIMEOUT_MS);
if (end_session) {
azoteq_iqs5xx_end_session();
}
@ -156,10 +155,10 @@ i2c_status_t azoteq_iqs5xx_set_report_rate(uint16_t report_rate_ms, azoteq_iqs5x
i2c_status_t azoteq_iqs5xx_set_reati(bool enabled, bool end_session) {
azoteq_iqs5xx_system_config_0_t config = {0};
i2c_status_t status = i2c_readReg16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONFIG_0, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_config_0_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONFIG_0, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_config_0_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
if (status == I2C_STATUS_SUCCESS) {
config.reati = enabled;
status = i2c_writeReg16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONFIG_0, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_config_0_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
status = i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONFIG_0, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_config_0_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
}
if (end_session) {
azoteq_iqs5xx_end_session();
@ -169,7 +168,7 @@ i2c_status_t azoteq_iqs5xx_set_reati(bool enabled, bool end_session) {
i2c_status_t azoteq_iqs5xx_set_event_mode(bool enabled, bool end_session) {
azoteq_iqs5xx_system_config_1_t config = {0};
i2c_status_t status = i2c_readReg16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONFIG_1, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_config_1_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONFIG_1, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_config_1_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
if (status == I2C_STATUS_SUCCESS) {
config.event_mode = enabled;
config.touch_event = true;
@ -179,7 +178,7 @@ i2c_status_t azoteq_iqs5xx_set_event_mode(bool enabled, bool end_session) {
config.reati_event = false;
config.alp_prox_event = false;
config.gesture_event = true;
status = i2c_writeReg16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONFIG_1, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_config_1_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
status = i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONFIG_1, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_config_1_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
}
if (end_session) {
azoteq_iqs5xx_end_session();
@ -189,7 +188,7 @@ i2c_status_t azoteq_iqs5xx_set_event_mode(bool enabled, bool end_session) {
i2c_status_t azoteq_iqs5xx_set_gesture_config(bool end_session) {
azoteq_iqs5xx_gesture_config_t config = {0};
i2c_status_t status = i2c_readReg16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SINGLE_FINGER_GESTURES, (uint8_t *)&config, sizeof(azoteq_iqs5xx_gesture_config_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SINGLE_FINGER_GESTURES, (uint8_t *)&config, sizeof(azoteq_iqs5xx_gesture_config_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
pd_dprintf("azo scroll: %d\n", config.multi_finger_gestures.scroll);
if (status == I2C_STATUS_SUCCESS) {
config.single_finger_gestures.single_tap = AZOTEQ_IQS5XX_TAP_ENABLE;
@ -211,7 +210,7 @@ i2c_status_t azoteq_iqs5xx_set_gesture_config(bool end_session) {
config.scroll_initial_distance = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_SCROLL_INITIAL_DISTANCE);
config.zoom_initial_distance = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_ZOOM_INITIAL_DISTANCE);
config.zoom_consecutive_distance = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_ZOOM_CONSECUTIVE_DISTANCE);
status = i2c_writeReg16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SINGLE_FINGER_GESTURES, (uint8_t *)&config, sizeof(azoteq_iqs5xx_gesture_config_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
status = i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SINGLE_FINGER_GESTURES, (uint8_t *)&config, sizeof(azoteq_iqs5xx_gesture_config_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
}
if (end_session) {
azoteq_iqs5xx_end_session();
@ -221,7 +220,7 @@ i2c_status_t azoteq_iqs5xx_set_gesture_config(bool end_session) {
i2c_status_t azoteq_iqs5xx_set_xy_config(bool flip_x, bool flip_y, bool switch_xy, bool palm_reject, bool end_session) {
azoteq_iqs5xx_xy_config_0_t config = {0};
i2c_status_t status = i2c_readReg16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_XY_CONFIG_0, (uint8_t *)&config, sizeof(azoteq_iqs5xx_xy_config_0_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_XY_CONFIG_0, (uint8_t *)&config, sizeof(azoteq_iqs5xx_xy_config_0_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
if (status == I2C_STATUS_SUCCESS) {
if (flip_x) {
config.flip_x = !config.flip_x;
@ -233,7 +232,7 @@ i2c_status_t azoteq_iqs5xx_set_xy_config(bool flip_x, bool flip_y, bool switch_x
config.switch_xy_axis = !config.switch_xy_axis;
}
config.palm_reject = palm_reject;
status = i2c_writeReg16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_XY_CONFIG_0, (uint8_t *)&config, sizeof(azoteq_iqs5xx_xy_config_0_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
status = i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_XY_CONFIG_0, (uint8_t *)&config, sizeof(azoteq_iqs5xx_xy_config_0_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
}
if (end_session) {
azoteq_iqs5xx_end_session();
@ -243,11 +242,11 @@ i2c_status_t azoteq_iqs5xx_set_xy_config(bool flip_x, bool flip_y, bool switch_x
i2c_status_t azoteq_iqs5xx_reset_suspend(bool reset, bool suspend, bool end_session) {
azoteq_iqs5xx_system_control_1_t config = {0};
i2c_status_t status = i2c_readReg16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONTROL_1, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_control_1_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONTROL_1, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_control_1_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
if (status == I2C_STATUS_SUCCESS) {
config.reset = reset;
config.suspend = suspend;
status = i2c_writeReg16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONTROL_1, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_control_1_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
status = i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONTROL_1, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_control_1_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
}
if (end_session) {
azoteq_iqs5xx_end_session();
@ -260,14 +259,14 @@ void azoteq_iqs5xx_set_cpi(uint16_t cpi) {
azoteq_iqs5xx_resolution_t resolution = {0};
resolution.x_resolution = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(MIN(azoteq_iqs5xx_device_resolution_t.resolution_x, AZOTEQ_IQS5XX_INCH_TO_RESOLUTION_X(cpi)));
resolution.y_resolution = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(MIN(azoteq_iqs5xx_device_resolution_t.resolution_y, AZOTEQ_IQS5XX_INCH_TO_RESOLUTION_Y(cpi)));
i2c_writeReg16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_X_RESOLUTION, (uint8_t *)&resolution, sizeof(azoteq_iqs5xx_resolution_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_X_RESOLUTION, (uint8_t *)&resolution, sizeof(azoteq_iqs5xx_resolution_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
}
}
uint16_t azoteq_iqs5xx_get_cpi(void) {
if (azoteq_iqs5xx_product_number != AZOTEQ_IQS5XX_UNKNOWN) {
azoteq_iqs5xx_resolution_t resolution = {0};
i2c_status_t status = i2c_readReg16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_X_RESOLUTION, (uint8_t *)&resolution, sizeof(azoteq_iqs5xx_resolution_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_X_RESOLUTION, (uint8_t *)&resolution, sizeof(azoteq_iqs5xx_resolution_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
if (status == I2C_STATUS_SUCCESS) {
return AZOTEQ_IQS5XX_RESOLUTION_X_TO_INCH(AZOTEQ_IQS5XX_SWAP_H_L_BYTES(resolution.x_resolution));
}
@ -276,7 +275,7 @@ uint16_t azoteq_iqs5xx_get_cpi(void) {
}
uint16_t azoteq_iqs5xx_get_product(void) {
i2c_status_t status = i2c_readReg16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_PRODUCT_NUMBER, (uint8_t *)&azoteq_iqs5xx_product_number, sizeof(uint16_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_PRODUCT_NUMBER, (uint8_t *)&azoteq_iqs5xx_product_number, sizeof(uint16_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
if (status == I2C_STATUS_SUCCESS) {
azoteq_iqs5xx_product_number = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(azoteq_iqs5xx_product_number);
}

Some files were not shown because too many files have changed in this diff Show More