add My9291 light bulb driver (#2599)
Co-authored-by: Christian Schwinne <dev.aircoookie@gmail.com>
This commit is contained in:
parent
73a9e1c316
commit
46eae410c3
@ -481,6 +481,15 @@ board_build.ldscript = ${common.ldscript_2m512k}
|
|||||||
build_flags = ${common.build_flags_esp8266} -D WLED_USE_IC_CCT -D BTNPIN=-1 -D IRPIN=-1 -D WLED_DISABLE_INFRARED
|
build_flags = ${common.build_flags_esp8266} -D WLED_USE_IC_CCT -D BTNPIN=-1 -D IRPIN=-1 -D WLED_DISABLE_INFRARED
|
||||||
lib_deps = ${esp8266.lib_deps}
|
lib_deps = ${esp8266.lib_deps}
|
||||||
|
|
||||||
|
[env:MY9291]
|
||||||
|
board = esp01_1m
|
||||||
|
platform = ${common.platform_wled_default}
|
||||||
|
platform_packages = ${common.platform_packages}
|
||||||
|
board_build.ldscript = ${common.ldscript_1m128k}
|
||||||
|
build_unflags = ${common.build_unflags}
|
||||||
|
build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP01 -D WLED_DISABLE_OTA -D USERMOD_MY9291
|
||||||
|
lib_deps = ${esp8266.lib_deps}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# travis test board configurations
|
# travis test board configurations
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
321
usermods/MY9291/MY92xx.h
Normal file
321
usermods/MY9291/MY92xx.h
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
MY92XX LED Driver for Arduino
|
||||||
|
Based on the C driver by MaiKe Labs
|
||||||
|
|
||||||
|
Copyright (c) 2016 - 2026 MaiKe Labs
|
||||||
|
Copyright (C) 2017 - 2018 Xose Pérez for the Arduino compatible library
|
||||||
|
|
||||||
|
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 3 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/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _my92xx_h
|
||||||
|
#define _my92xx_h
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#ifdef DEBUG_MY92XX
|
||||||
|
#if ARDUINO_ARCH_ESP8266
|
||||||
|
#define DEBUG_MSG_MY92XX(...) DEBUG_MY92XX.printf( __VA_ARGS__ )
|
||||||
|
#elif ARDUINO_ARCH_AVR
|
||||||
|
#define DEBUG_MSG_MY92XX(...) { char buffer[80]; snprintf(buffer, sizeof(buffer), __VA_ARGS__ ); DEBUG_MY92XX.print(buffer); }
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define DEBUG_MSG_MY92XX(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum my92xx_model_t {
|
||||||
|
MY92XX_MODEL_MY9291 = 0X00,
|
||||||
|
MY92XX_MODEL_MY9231 = 0X01,
|
||||||
|
} my92xx_model_t;
|
||||||
|
|
||||||
|
typedef enum my92xx_cmd_one_shot_t {
|
||||||
|
MY92XX_CMD_ONE_SHOT_DISABLE = 0X00,
|
||||||
|
MY92XX_CMD_ONE_SHOT_ENFORCE = 0X01,
|
||||||
|
} my92xx_cmd_one_shot_t;
|
||||||
|
|
||||||
|
typedef enum my92xx_cmd_reaction_t {
|
||||||
|
MY92XX_CMD_REACTION_FAST = 0X00,
|
||||||
|
MY92XX_CMD_REACTION_SLOW = 0X01,
|
||||||
|
} my92xx_cmd_reaction_t;
|
||||||
|
|
||||||
|
typedef enum my92xx_cmd_bit_width_t {
|
||||||
|
MY92XX_CMD_BIT_WIDTH_16 = 0X00,
|
||||||
|
MY92XX_CMD_BIT_WIDTH_14 = 0X01,
|
||||||
|
MY92XX_CMD_BIT_WIDTH_12 = 0X02,
|
||||||
|
MY92XX_CMD_BIT_WIDTH_8 = 0X03,
|
||||||
|
} my92xx_cmd_bit_width_t;
|
||||||
|
|
||||||
|
typedef enum my92xx_cmd_frequency_t {
|
||||||
|
MY92XX_CMD_FREQUENCY_DIVIDE_1 = 0X00,
|
||||||
|
MY92XX_CMD_FREQUENCY_DIVIDE_4 = 0X01,
|
||||||
|
MY92XX_CMD_FREQUENCY_DIVIDE_16 = 0X02,
|
||||||
|
MY92XX_CMD_FREQUENCY_DIVIDE_64 = 0X03,
|
||||||
|
} my92xx_cmd_frequency_t;
|
||||||
|
|
||||||
|
typedef enum my92xx_cmd_scatter_t {
|
||||||
|
MY92XX_CMD_SCATTER_APDM = 0X00,
|
||||||
|
MY92XX_CMD_SCATTER_PWM = 0X01,
|
||||||
|
} my92xx_cmd_scatter_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
my92xx_cmd_scatter_t scatter : 1;
|
||||||
|
my92xx_cmd_frequency_t frequency : 2;
|
||||||
|
my92xx_cmd_bit_width_t bit_width : 2;
|
||||||
|
my92xx_cmd_reaction_t reaction : 1;
|
||||||
|
my92xx_cmd_one_shot_t one_shot : 1;
|
||||||
|
unsigned char resv : 1;
|
||||||
|
} __attribute__((aligned(1), packed)) my92xx_cmd_t;
|
||||||
|
|
||||||
|
#define MY92XX_COMMAND_DEFAULT { \
|
||||||
|
.scatter = MY92XX_CMD_SCATTER_APDM, \
|
||||||
|
.frequency = MY92XX_CMD_FREQUENCY_DIVIDE_1, \
|
||||||
|
.bit_width = MY92XX_CMD_BIT_WIDTH_8, \
|
||||||
|
.reaction = MY92XX_CMD_REACTION_FAST, \
|
||||||
|
.one_shot = MY92XX_CMD_ONE_SHOT_DISABLE, \
|
||||||
|
.resv = 0 \
|
||||||
|
}
|
||||||
|
|
||||||
|
class my92xx {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
my92xx(my92xx_model_t model, unsigned char chips, unsigned char di, unsigned char dcki, my92xx_cmd_t command);
|
||||||
|
unsigned char getChannels();
|
||||||
|
void setChannel(unsigned char channel, unsigned int value);
|
||||||
|
unsigned int getChannel(unsigned char channel);
|
||||||
|
void setState(bool state);
|
||||||
|
bool getState();
|
||||||
|
void update();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void _di_pulse(unsigned int times);
|
||||||
|
void _dcki_pulse(unsigned int times);
|
||||||
|
void _set_cmd(my92xx_cmd_t command);
|
||||||
|
void _send();
|
||||||
|
void _write(unsigned int data, unsigned char bit_length);
|
||||||
|
|
||||||
|
my92xx_cmd_t _command;
|
||||||
|
my92xx_model_t _model = MY92XX_MODEL_MY9291;
|
||||||
|
unsigned char _chips = 1;
|
||||||
|
unsigned char _channels;
|
||||||
|
uint16_t* _value;
|
||||||
|
bool _state = false;
|
||||||
|
unsigned char _pin_di;
|
||||||
|
unsigned char _pin_dcki;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if ARDUINO_ARCH_ESP8266
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void os_delay_us(unsigned int);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif ARDUINO_ARCH_AVR
|
||||||
|
|
||||||
|
#define os_delay_us delayMicroseconds
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void my92xx::_di_pulse(unsigned int times) {
|
||||||
|
for (unsigned int i = 0; i < times; i++) {
|
||||||
|
digitalWrite(_pin_di, HIGH);
|
||||||
|
digitalWrite(_pin_di, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void my92xx::_dcki_pulse(unsigned int times) {
|
||||||
|
for (unsigned int i = 0; i < times; i++) {
|
||||||
|
digitalWrite(_pin_dcki, HIGH);
|
||||||
|
digitalWrite(_pin_dcki, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void my92xx::_write(unsigned int data, unsigned char bit_length) {
|
||||||
|
|
||||||
|
unsigned int mask = (0x01 << (bit_length - 1));
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < bit_length / 2; i++) {
|
||||||
|
digitalWrite(_pin_dcki, LOW);
|
||||||
|
digitalWrite(_pin_di, (data & mask) ? HIGH : LOW);
|
||||||
|
digitalWrite(_pin_dcki, HIGH);
|
||||||
|
data = data << 1;
|
||||||
|
digitalWrite(_pin_di, (data & mask) ? HIGH : LOW);
|
||||||
|
digitalWrite(_pin_dcki, LOW);
|
||||||
|
digitalWrite(_pin_di, LOW);
|
||||||
|
data = data << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void my92xx::_set_cmd(my92xx_cmd_t command) {
|
||||||
|
|
||||||
|
// ets_intr_lock();
|
||||||
|
|
||||||
|
// TStop > 12us.
|
||||||
|
os_delay_us(12);
|
||||||
|
|
||||||
|
// Send 12 DI pulse, after 6 pulse's falling edge store duty data, and 12
|
||||||
|
// pulse's rising edge convert to command mode.
|
||||||
|
_di_pulse(12);
|
||||||
|
|
||||||
|
// Delay >12us, begin send CMD data
|
||||||
|
os_delay_us(12);
|
||||||
|
|
||||||
|
// Send CMD data
|
||||||
|
unsigned char command_data = *(unsigned char*)(&command);
|
||||||
|
for (unsigned char i = 0; i < _chips; i++) {
|
||||||
|
_write(command_data, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TStart > 12us. Delay 12 us.
|
||||||
|
os_delay_us(12);
|
||||||
|
|
||||||
|
// Send 16 DI pulse,at 14 pulse's falling edge store CMD data, and
|
||||||
|
// at 16 pulse's falling edge convert to duty mode.
|
||||||
|
_di_pulse(16);
|
||||||
|
|
||||||
|
// TStop > 12us.
|
||||||
|
os_delay_us(12);
|
||||||
|
|
||||||
|
// ets_intr_unlock();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void my92xx::_send() {
|
||||||
|
|
||||||
|
#ifdef DEBUG_MY92XX
|
||||||
|
DEBUG_MSG_MY92XX("[MY92XX] Refresh: %s (", _state ? "ON" : "OFF");
|
||||||
|
for (unsigned char channel = 0; channel < _channels; channel++) {
|
||||||
|
DEBUG_MSG_MY92XX(" %d", _value[channel]);
|
||||||
|
}
|
||||||
|
DEBUG_MSG_MY92XX(" )\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unsigned char bit_length = 8;
|
||||||
|
switch (_command.bit_width) {
|
||||||
|
case MY92XX_CMD_BIT_WIDTH_16:
|
||||||
|
bit_length = 16;
|
||||||
|
break;
|
||||||
|
case MY92XX_CMD_BIT_WIDTH_14:
|
||||||
|
bit_length = 14;
|
||||||
|
break;
|
||||||
|
case MY92XX_CMD_BIT_WIDTH_12:
|
||||||
|
bit_length = 12;
|
||||||
|
break;
|
||||||
|
case MY92XX_CMD_BIT_WIDTH_8:
|
||||||
|
bit_length = 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bit_length = 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ets_intr_lock();
|
||||||
|
|
||||||
|
// TStop > 12us.
|
||||||
|
os_delay_us(12);
|
||||||
|
|
||||||
|
// Send color data
|
||||||
|
for (unsigned char channel = 0; channel < _channels; channel++) {
|
||||||
|
_write(_state ? _value[channel] : 0, bit_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TStart > 12us. Ready for send DI pulse.
|
||||||
|
os_delay_us(12);
|
||||||
|
|
||||||
|
// Send 8 DI pulse. After 8 pulse falling edge, store old data.
|
||||||
|
_di_pulse(8);
|
||||||
|
|
||||||
|
// TStop > 12us.
|
||||||
|
os_delay_us(12);
|
||||||
|
|
||||||
|
// ets_intr_unlock();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
unsigned char my92xx::getChannels() {
|
||||||
|
return _channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
void my92xx::setChannel(unsigned char channel, unsigned int value) {
|
||||||
|
if (channel < _channels) {
|
||||||
|
_value[channel] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int my92xx::getChannel(unsigned char channel) {
|
||||||
|
if (channel < _channels) {
|
||||||
|
return _value[channel];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool my92xx::getState() {
|
||||||
|
return _state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void my92xx::setState(bool state) {
|
||||||
|
_state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void my92xx::update() {
|
||||||
|
_send();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
my92xx::my92xx(my92xx_model_t model, unsigned char chips, unsigned char di, unsigned char dcki, my92xx_cmd_t command) : _command(command) {
|
||||||
|
|
||||||
|
_model = model;
|
||||||
|
_chips = chips;
|
||||||
|
_pin_di = di;
|
||||||
|
_pin_dcki = dcki;
|
||||||
|
|
||||||
|
// Init channels
|
||||||
|
if (_model == MY92XX_MODEL_MY9291) {
|
||||||
|
_channels = 4 * _chips;
|
||||||
|
}
|
||||||
|
else if (_model == MY92XX_MODEL_MY9231) {
|
||||||
|
_channels = 3 * _chips;
|
||||||
|
}
|
||||||
|
_value = new uint16_t[_channels];
|
||||||
|
for (unsigned char i = 0; i < _channels; i++) {
|
||||||
|
_value[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init GPIO
|
||||||
|
pinMode(_pin_di, OUTPUT);
|
||||||
|
pinMode(_pin_dcki, OUTPUT);
|
||||||
|
digitalWrite(_pin_di, LOW);
|
||||||
|
digitalWrite(_pin_dcki, LOW);
|
||||||
|
|
||||||
|
// Clear all duty register
|
||||||
|
_dcki_pulse(32 * _chips);
|
||||||
|
|
||||||
|
// Send init command
|
||||||
|
_set_cmd(command);
|
||||||
|
|
||||||
|
DEBUG_MSG_MY92XX("[MY92XX] Initialized\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
45
usermods/MY9291/usermode_MY9291.h
Normal file
45
usermods/MY9291/usermode_MY9291.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "wled.h"
|
||||||
|
#include "MY92xx.h"
|
||||||
|
|
||||||
|
#define MY92XX_MODEL MY92XX_MODEL_MY9291
|
||||||
|
#define MY92XX_CHIPS 1
|
||||||
|
#define MY92XX_DI_PIN 13
|
||||||
|
#define MY92XX_DCKI_PIN 15
|
||||||
|
|
||||||
|
#define MY92XX_RED 0
|
||||||
|
#define MY92XX_GREEN 1
|
||||||
|
#define MY92XX_BLUE 2
|
||||||
|
#define MY92XX_WHITE 3
|
||||||
|
|
||||||
|
class MY9291Usermod : public Usermod {
|
||||||
|
private:
|
||||||
|
my92xx _my92xx = my92xx(MY92XX_MODEL, MY92XX_CHIPS, MY92XX_DI_PIN, MY92XX_DCKI_PIN, MY92XX_COMMAND_DEFAULT);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
_my92xx.setState(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void connected() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
uint32_t c = strip.getPixelColor(0);
|
||||||
|
int w = ((c >> 24) & 0xff) * bri / 255.0;
|
||||||
|
int r = ((c >> 16) & 0xff) * bri / 255.0;
|
||||||
|
int g = ((c >> 8) & 0xff) * bri / 255.0;
|
||||||
|
int b = (c & 0xff) * bri / 255.0;
|
||||||
|
_my92xx.setChannel(MY92XX_RED, r);
|
||||||
|
_my92xx.setChannel(MY92XX_GREEN, g);
|
||||||
|
_my92xx.setChannel(MY92XX_BLUE, b);
|
||||||
|
_my92xx.setChannel(MY92XX_WHITE, w);
|
||||||
|
_my92xx.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t getId() {
|
||||||
|
return USERMOD_ID_MY9291;
|
||||||
|
}
|
||||||
|
};
|
@ -74,6 +74,7 @@
|
|||||||
#define USERMOD_ID_CRONIXIE 25 //Usermod "usermod_cronixie.h"
|
#define USERMOD_ID_CRONIXIE 25 //Usermod "usermod_cronixie.h"
|
||||||
#define USERMOD_ID_WIZLIGHTS 26 //Usermod "wizlights.h"
|
#define USERMOD_ID_WIZLIGHTS 26 //Usermod "wizlights.h"
|
||||||
#define USERMOD_ID_WORDCLOCK 27 //Usermod "usermod_v2_word_clock.h"
|
#define USERMOD_ID_WORDCLOCK 27 //Usermod "usermod_v2_word_clock.h"
|
||||||
|
#define USERMOD_ID_MY9291 28 //Usermod "usermod_MY9291.h"
|
||||||
|
|
||||||
//Access point behavior
|
//Access point behavior
|
||||||
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
||||||
|
@ -120,6 +120,10 @@
|
|||||||
#include "../usermods/usermod_v2_word_clock/usermod_v2_word_clock.h"
|
#include "../usermods/usermod_v2_word_clock/usermod_v2_word_clock.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USERMOD_MY9291
|
||||||
|
#include "../usermods/MY9291/usermode_MY9291.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
void registerUsermods()
|
void registerUsermods()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -223,8 +227,12 @@ void registerUsermods()
|
|||||||
#ifdef USERMOD_WIZLIGHTS
|
#ifdef USERMOD_WIZLIGHTS
|
||||||
usermods.add(new WizLightsUsermod());
|
usermods.add(new WizLightsUsermod());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USERMOD_WORDCLOCK
|
#ifdef USERMOD_WORDCLOCK
|
||||||
usermods.add(new WordClockUsermod());
|
usermods.add(new WordClockUsermod());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USERMOD_MY9291
|
||||||
|
usermods.add(new MY9291Usermod());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user