12 #include "general_dma_pub.h" 19 static const uint32_t SPI_TX_DMA_CHANNEL = GDMA_CHANNEL_3;
22 static const uint32_t SPI_PERI_CLK_26M = 26000000;
23 static const uint32_t SPI_PERI_CLK_DCO = 120000000;
25 static const uint32_t SPI_BASE = 0x00802700;
26 static const uint32_t SPI_DAT = SPI_BASE + 3 * 4;
27 static const uint32_t SPI_CONFIG = SPI_BASE + 1 * 4;
29 static const uint32_t SPI_TX_EN = 1 << 0;
30 static const uint32_t CTRL_NSSMD_3 = 1 << 17;
31 static const uint32_t SPI_TX_FINISH_EN = 1 << 2;
32 static const uint32_t SPI_RX_FINISH_EN = 1 << 3;
35 namespace beken_spi_led_strip {
37 static const char *
const TAG =
"beken_spi_led_strip";
40 SemaphoreHandle_t dma_tx_semaphore;
41 volatile bool tx_in_progress;
45 static spi_data_t *spi_data =
nullptr;
47 static void set_spi_ctrl_register(
unsigned long bit,
bool val) {
48 uint32_t value = REG_READ(SPI_CTRL);
51 }
else if (val == 1) {
54 REG_WRITE(SPI_CTRL, value);
57 static void set_spi_config_register(
unsigned long bit,
bool val) {
58 uint32_t value = REG_READ(SPI_CONFIG);
61 }
else if (val == 1) {
64 REG_WRITE(SPI_CONFIG, value);
69 set_spi_config_register(SPI_TX_EN, enable ? 1 : 0);
70 en_cfg.channel = SPI_TX_DMA_CHANNEL;
71 en_cfg.param = enable ? 1 : 0;
72 sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_DMA_ENABLE, &en_cfg);
75 static void spi_set_clock(uint32_t max_hz) {
80 if (max_hz > 4333000) {
81 if (max_hz > 30000000) {
86 sddev_control(ICU_DEV_NAME, CMD_CLK_PWR_DOWN, ¶m);
87 source_clk = SPI_PERI_CLK_DCO;
88 param = PCLK_POSI_SPI;
89 sddev_control(ICU_DEV_NAME, CMD_CONF_PCLK_DCO, ¶m);
90 param = PWD_SPI_CLK_BIT;
91 sddev_control(ICU_DEV_NAME, CMD_CLK_PWR_UP, ¶m);
94 #if CFG_XTAL_FREQUENCE 95 source_clk = CFG_XTAL_FREQUENCE;
97 source_clk = SPI_PERI_CLK_26M;
99 param = PCLK_POSI_SPI;
100 sddev_control(ICU_DEV_NAME, CMD_CONF_PCLK_26M, ¶m);
102 div = ((source_clk >> 1) / spi_clk);
105 }
else if (div >= 255) {
108 param = REG_READ(SPI_CTRL);
109 param &= ~(SPI_CKR_MASK << SPI_CKR_POSI);
110 param |= (div << SPI_CKR_POSI);
111 REG_WRITE(SPI_CTRL, param);
112 ESP_LOGD(TAG,
"target frequency: %d, actual frequency: %d", max_hz, source_clk / 2 / div);
116 spi_data->tx_in_progress =
false;
117 xSemaphoreGive(spi_data->dma_tx_semaphore);
122 ESP_LOGCONFIG(TAG,
"Setting up Beken SPI LED Strip...");
124 size_t buffer_size = this->get_buffer_size_();
125 size_t dma_buffer_size = (buffer_size * 8) + (2 * 64);
128 this->buf_ = allocator.
allocate(buffer_size);
129 if (this->buf_ ==
nullptr) {
130 ESP_LOGE(TAG,
"Cannot allocate LED buffer!");
135 this->effect_data_ = allocator.
allocate(this->num_leds_);
136 if (this->effect_data_ ==
nullptr) {
137 ESP_LOGE(TAG,
"Cannot allocate effect data!");
142 this->dma_buf_ = allocator.
allocate(dma_buffer_size);
143 if (this->dma_buf_ ==
nullptr) {
144 ESP_LOGE(TAG,
"Cannot allocate DMA buffer!");
149 memset(this->buf_, 0, buffer_size);
150 memset(this->effect_data_, 0, this->num_leds_);
151 memset(this->dma_buf_, 0, dma_buffer_size);
153 uint32_t value = PCLK_POSI_SPI;
154 sddev_control(ICU_DEV_NAME, CMD_CONF_PCLK_26M, &value);
156 value = PWD_SPI_CLK_BIT;
157 sddev_control(ICU_DEV_NAME, CMD_CLK_PWR_UP, &value);
159 if (spi_data !=
nullptr) {
160 ESP_LOGE(TAG,
"SPI device already initialized!");
165 spi_data = (spi_data_t *) calloc(1,
sizeof(spi_data_t));
166 if (spi_data ==
nullptr) {
167 ESP_LOGE(TAG,
"Cannot allocate spi_data!");
172 spi_data->dma_tx_semaphore = xSemaphoreCreateBinary();
173 if (spi_data->dma_tx_semaphore ==
nullptr) {
174 ESP_LOGE(TAG,
"TX Semaphore init faild!");
179 spi_data->first_run =
true;
181 set_spi_ctrl_register(MSTEN, 0);
182 set_spi_ctrl_register(BIT_WDTH, 0);
183 spi_set_clock(this->spi_frequency_);
184 set_spi_ctrl_register(CKPOL, 0);
185 set_spi_ctrl_register(CKPHA, 0);
186 set_spi_ctrl_register(MSTEN, 1);
187 set_spi_ctrl_register(SPIEN, 1);
189 set_spi_ctrl_register(TXINT_EN, 0);
190 set_spi_ctrl_register(RXINT_EN, 0);
191 set_spi_config_register(SPI_TX_FINISH_EN, 1);
192 set_spi_config_register(SPI_RX_FINISH_EN, 1);
193 set_spi_ctrl_register(RXOVR_EN, 0);
194 set_spi_ctrl_register(TXOVR_EN, 0);
196 value = REG_READ(SPI_CTRL);
197 value &= ~CTRL_NSSMD_3;
199 REG_WRITE(SPI_CTRL, value);
201 value = GFUNC_MODE_SPI_DMA;
202 sddev_control(GPIO_DEV_NAME, CMD_GPIO_ENABLE_SECOND, &value);
203 set_spi_ctrl_register(SPI_S_CS_UP_INT_EN, 0);
206 GDMACFG_TPYES_ST init_cfg;
207 memset(&init_cfg, 0,
sizeof(GDMACFG_TPYES_ST));
209 init_cfg.dstdat_width = 8;
210 init_cfg.srcdat_width = 32;
211 init_cfg.dstptr_incr = 0;
212 init_cfg.srcptr_incr = 1;
213 init_cfg.src_start_addr = this->dma_buf_;
214 init_cfg.dst_start_addr = (
void *) SPI_DAT;
215 init_cfg.channel = SPI_TX_DMA_CHANNEL;
217 init_cfg.u.type4.src_loop_start_addr = this->dma_buf_;
218 init_cfg.u.type4.src_loop_end_addr = this->dma_buf_ + dma_buffer_size;
219 init_cfg.half_fin_handler =
nullptr;
221 init_cfg.src_module = GDMA_X_SRC_DTCM_RD_REQ;
222 init_cfg.dst_module = GDMA_X_DST_GSPI_TX_REQ;
223 sddev_control(GDMA_DEV_NAME, CMD_GDMA_CFG_TYPE4, (
void *) &init_cfg);
224 en_cfg.channel = SPI_TX_DMA_CHANNEL;
225 en_cfg.param = dma_buffer_size;
226 sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_TRANS_LENGTH, (
void *) &en_cfg);
227 en_cfg.channel = SPI_TX_DMA_CHANNEL;
229 sddev_control(GDMA_DEV_NAME, CMD_GDMA_CFG_WORK_MODE, (
void *) &en_cfg);
230 en_cfg.channel = SPI_TX_DMA_CHANNEL;
232 sddev_control(GDMA_DEV_NAME, CMD_GDMA_CFG_SRCADDR_LOOP, &en_cfg);
236 value = REG_READ(SPI_CONFIG);
237 value &= ~(0xFFF << 8);
238 value |= ((dma_buffer_size & 0xFFF) << 8);
239 REG_WRITE(SPI_CONFIG, value);
245 this->spi_frequency_ = spi_frequency;
251 if (*this->max_refresh_rate_ != 0 && (now - this->last_refresh_) < *this->max_refresh_rate_) {
253 this->schedule_show();
256 this->last_refresh_ = now;
259 ESP_LOGVV(TAG,
"Writing RGB values to bus...");
261 if (spi_data ==
nullptr) {
262 ESP_LOGE(TAG,
"SPI not initialized");
263 this->status_set_warning();
267 if (!spi_data->first_run && !xSemaphoreTake(spi_data->dma_tx_semaphore, 10 / portTICK_PERIOD_MS)) {
268 ESP_LOGE(TAG,
"Timed out waiting for semaphore");
272 if (spi_data->tx_in_progress) {
273 ESP_LOGE(TAG,
"tx_in_progress is set");
274 this->status_set_warning();
278 spi_data->tx_in_progress =
true;
280 size_t buffer_size = this->get_buffer_size_();
282 uint8_t *psrc = this->buf_;
283 uint8_t *pdest = this->dma_buf_ + 64;
287 while (size < buffer_size) {
289 for (
int i = 0; i < 8; i++) {
290 *pdest++ = b & (1 << (7 - i)) ? this->bit1_ : this->bit0_;
296 spi_data->first_run =
false;
299 this->status_clear_warning();
303 int32_t r = 0, g = 0, b = 0;
304 switch (this->rgb_order_) {
336 uint8_t multiplier = this->is_rgbw_ || this->is_wrgb_ ? 4 : 3;
337 uint8_t white = this->is_wrgb_ ? 0 : 3;
339 return {this->buf_ + (index * multiplier) + r + this->is_wrgb_,
340 this->buf_ + (index * multiplier) + g + this->is_wrgb_,
341 this->buf_ + (index * multiplier) + b + this->is_wrgb_,
342 this->is_rgbw_ || this->is_wrgb_ ? this->buf_ + (index * multiplier) + white :
nullptr,
343 &this->effect_data_[index],
348 ESP_LOGCONFIG(TAG,
"Beken SPI LED Strip:");
349 ESP_LOGCONFIG(TAG,
" Pin: %u", this->pin_);
350 const char *rgb_order;
351 switch (this->rgb_order_) {
371 rgb_order =
"UNKNOWN";
374 ESP_LOGCONFIG(TAG,
" RGB Order: %s", rgb_order);
375 ESP_LOGCONFIG(TAG,
" Max refresh rate: %" PRIu32, *this->max_refresh_rate_);
376 ESP_LOGCONFIG(TAG,
" Number of LEDs: %u", this->num_leds_);
This class represents the communication layer between the front-end MQTT layer and the hardware outpu...
float get_setup_priority() const override
void spi_dma_tx_finish_callback(unsigned int param)
uint32_t IRAM_ATTR HOT micros()
void dump_config() override
void spi_dma_tx_enable(bool enable)
const float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
Implementation of SPI Controller mode.
An STL allocator that uses SPI or internal RAM.
void set_led_params(uint8_t bit0, uint8_t bit1, uint32_t spi_frequency)
light::ESPColorView get_view_internal(int32_t index) const override
void write_state(light::LightState *state) override