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.
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