ESPHome  2024.4.1
my9231.cpp
Go to the documentation of this file.
1 #include "my9231.h"
2 #include "esphome/core/log.h"
3 #include "esphome/core/helpers.h"
4 
5 namespace esphome {
6 namespace my9231 {
7 
8 static const char *const TAG = "my9231.output";
9 
10 // One-shot select (frame cycle repeat mode / frame cycle One-shot mode)
11 static const uint8_t MY9231_CMD_ONE_SHOT_DISABLE = 0x0 << 6;
12 static const uint8_t MY9231_CMD_ONE_SHOT_ENFORCE = 0x1 << 6;
13 // Reaction time of Iout
14 static const uint8_t MY9231_CMD_REACTION_FAST = 0x0 << 5;
15 static const uint8_t MY9231_CMD_REACTION_SLOW = 0x1 << 5;
16 // Grayscale resolution select
17 static const uint8_t MY9231_CMD_BIT_WIDTH_16 = 0x0 << 3;
18 static const uint8_t MY9231_CMD_BIT_WIDTH_14 = 0x1 << 3;
19 static const uint8_t MY9231_CMD_BIT_WIDTH_12 = 0x2 << 3;
20 static const uint8_t MY9231_CMD_BIT_WIDTH_8 = 0x3 << 3;
21 // Internal oscillator freq. select (divider)
22 static const uint8_t MY9231_CMD_FREQUENCY_DIVIDE_1 = 0x0 << 1;
23 static const uint8_t MY9231_CMD_FREQUENCY_DIVIDE_4 = 0x1 << 1;
24 static const uint8_t MY9231_CMD_FREQUENCY_DIVIDE_16 = 0x2 << 1;
25 static const uint8_t MY9231_CMD_FREQUENCY_DIVIDE_64 = 0x3 << 1;
26 // Output waveform
27 static const uint8_t MY9231_CMD_SCATTER_APDM = 0x0 << 0;
28 static const uint8_t MY9231_CMD_SCATTER_PWM = 0x1 << 0;
29 
31  ESP_LOGCONFIG(TAG, "Setting up MY9231OutputComponent...");
32  this->pin_di_->setup();
33  this->pin_di_->digital_write(false);
34  this->pin_dcki_->setup();
35  this->pin_dcki_->digital_write(false);
36  this->pwm_amounts_.resize(this->num_channels_, 0);
37  uint8_t command = 0;
38  if (this->bit_depth_ <= 8) {
39  this->bit_depth_ = 8;
40  command |= MY9231_CMD_BIT_WIDTH_8;
41  } else if (this->bit_depth_ <= 12) {
42  this->bit_depth_ = 12;
43  command |= MY9231_CMD_BIT_WIDTH_12;
44  } else if (this->bit_depth_ <= 14) {
45  this->bit_depth_ = 14;
46  command |= MY9231_CMD_BIT_WIDTH_14;
47  } else {
48  this->bit_depth_ = 16;
49  command |= MY9231_CMD_BIT_WIDTH_16;
50  }
51  command |=
52  MY9231_CMD_SCATTER_APDM | MY9231_CMD_FREQUENCY_DIVIDE_1 | MY9231_CMD_REACTION_FAST | MY9231_CMD_ONE_SHOT_DISABLE;
53  ESP_LOGV(TAG, " Command: 0x%02X", command);
54 
55  {
56  InterruptLock lock;
57  this->send_dcki_pulses_(32 * this->num_chips_);
58  this->init_chips_(command);
59  }
60  ESP_LOGV(TAG, " Chips initialized.");
61 }
63  ESP_LOGCONFIG(TAG, "MY9231:");
64  LOG_PIN(" DI Pin: ", this->pin_di_);
65  LOG_PIN(" DCKI Pin: ", this->pin_dcki_);
66  ESP_LOGCONFIG(TAG, " Total number of channels: %u", this->num_channels_);
67  ESP_LOGCONFIG(TAG, " Number of chips: %u", this->num_chips_);
68  ESP_LOGCONFIG(TAG, " Bit depth: %u", this->bit_depth_);
69 }
71  if (!this->update_)
72  return;
73 
74  {
75  InterruptLock lock;
76  for (auto pwm_amount : this->pwm_amounts_) {
77  this->write_word_(pwm_amount, this->bit_depth_);
78  }
79  // Send 8 DI pulses. After 8 falling edges, the duty data are store.
80  this->send_di_pulses_(8);
81  }
82  this->update_ = false;
83 }
84 void MY9231OutputComponent::set_channel_value_(uint8_t channel, uint16_t value) {
85  ESP_LOGV(TAG, "set channels %u to %u", channel, value);
86  uint8_t index = this->num_channels_ - channel - 1;
87  if (this->pwm_amounts_[index] != value) {
88  this->update_ = true;
89  }
90  this->pwm_amounts_[index] = value;
91 }
92 void MY9231OutputComponent::init_chips_(uint8_t command) {
93  // Send 12 DI pulse. After 6 falling edges, the duty data are stored
94  // and after 12 rising edges the command mode is activated.
95  this->send_di_pulses_(12);
97  for (uint8_t i = 0; i < this->num_chips_; i++) {
98  this->write_word_(command, 8);
99  }
100  // Send 16 DI pulse. After 14 falling edges, the command data are
101  // stored and after 16 falling edges the duty mode is activated.
102  this->send_di_pulses_(16);
103  delayMicroseconds(12);
104 }
105 void MY9231OutputComponent::write_word_(uint16_t value, uint8_t bits) {
106  for (uint8_t i = bits; i > 0; i--) {
107  this->pin_di_->digital_write(value & (1 << (i - 1)));
108  this->pin_dcki_->digital_write(!this->pin_dcki_->digital_read());
109  }
110 }
112  delayMicroseconds(12);
113  for (uint8_t i = 0; i < count; i++) {
114  this->pin_di_->digital_write(true);
115  this->pin_di_->digital_write(false);
116  }
117 }
119  delayMicroseconds(12);
120  for (uint8_t i = 0; i < count; i++) {
121  this->pin_dcki_->digital_write(true);
122  this->pin_dcki_->digital_write(false);
123  }
124 }
125 
126 } // namespace my9231
127 } // namespace esphome
virtual void digital_write(bool value)=0
void set_channel_value_(uint8_t channel, uint16_t value)
Definition: my9231.cpp:84
virtual void setup()=0
void setup() override
Setup the MY9231.
Definition: my9231.cpp:30
void send_di_pulses_(uint8_t count)
Definition: my9231.cpp:111
virtual bool digital_read()=0
std::vector< uint16_t > pwm_amounts_
Definition: my9231.h:59
Helper class to disable interrupts.
Definition: helpers.h:587
void write_word_(uint16_t value, uint8_t bits)
Definition: my9231.cpp:105
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition: core.cpp:28
void loop() override
Send new values if they were updated.
Definition: my9231.cpp:70
void init_chips_(uint8_t command)
Definition: my9231.cpp:92
void send_dcki_pulses_(uint8_t count)
Definition: my9231.cpp:118