|
- static const char *TAG = "spi_leds";
- #include <esp_log.h>
-
- #include <string.h>
-
- #include <driver/gpio.h>
- #include <soc/io_mux_reg.h>
-
- #include "spi_leds.hpp"
-
-
- #define RET_ON_ERR(func, err) { if (err) { ESP_LOGE(TAG, #func ": %d", err); return; } }
-
-
- // LCD is using bus 2 in quad SPI mode
- SPI_LEDs::SPI_LEDs(int _gpio, int length) :
- LEDStrip(length),
- host(SPI3_HOST), gpio(_gpio), device(NULL),
- out_buf(NULL)
- {
- int ret;
-
- spi_bus_config_t buscfg = {
- .mosi_io_num = gpio,
- .miso_io_num = -1,
- .sclk_io_num = -1,
- .data2_io_num = -1,
- .data3_io_num = -1,
- .data4_io_num = -1,
- .data5_io_num = -1,
- .data6_io_num = -1,
- .data7_io_num = -1,
- .max_transfer_sz = 0, // 4092 (?)
- .flags = SPICOMMON_BUSFLAG_MASTER,
- .intr_flags = 0,
- };
-
- // Initialize the SPI bus
- ret = spi_bus_initialize(host, &buscfg, SPI_DMA_CH_AUTO);
- RET_ON_ERR(spi_bus_initialize, ret);
-
- // Invert the signal!
- // TODO: Clean way thru API?
- uint32_t *GPIO39_REG = (uint32_t*)(void*)(0x3f404000 + 0x0554 + (4 * 39));
- *GPIO39_REG |= 0x200;
-
- spi_device_interface_config_t devcfg = {
- .command_bits = 0,
- .address_bits = 0,
- .dummy_bits = 0,
- .mode = 0, // moot
- .duty_cycle_pos = 0, // moot
- .cs_ena_pretrans = 0, // moot
- .cs_ena_posttrans = 0, // moot
- // Datasheet implies 3.2 MHz => 1.25 us / 4
- // We can get away with 4.4_ MHz => 900 ns / 4
- .clock_speed_hz = 3200000,
- .input_delay_ns = 0, // moot
- .spics_io_num = -1,
- .flags = 0, // Keep it MSB first
- .queue_size = 1,
- .pre_cb = NULL,
- .post_cb = NULL,
- };
-
- ret = spi_bus_add_device(host, &devcfg, &device);
- RET_ON_ERR(spi_bus_add_device, ret);
-
- configure(length);
- }
-
- void SPI_LEDs::configure(int len) {
- if (out_buf) {
- free(out_buf);
- out_buf = NULL;
- }
-
- if (len <= 0) return;
-
- out_buf = (uint8_t*)heap_caps_malloc(tx_len(len), MALLOC_CAP_DMA);
-
- memset(out_buf + tx_len(len) - reset_bytes, 0, reset_bytes);
-
- transaction = {
- .flags = 0,
- .cmd = 0,
- .addr = 0,
- .length = tx_len(len) * 8,
- .rxlength = 0,
- .user = NULL,
- .tx_buffer = out_buf,
- .rx_buffer = NULL,
- };
- }
-
- // Inverted
- constexpr uint8_t nibble_0 = 0b0111;
- constexpr uint8_t nibble_1 = 0b0011;
-
- static uint8_t* encode_byte(uint8_t *out, uint8_t in) {
- for (int i = 8; i > 0; i -= 2) {
- *out++ = (((in & 0x80) ? nibble_1 : nibble_0) << 4) |
- (((in & 0x40) ? nibble_1 : nibble_0) << 0);
- in <<= 2;
- }
- return out;
- }
-
- void SPI_LEDs::show() {
- static int index = 0;
- int ret;
- const Color *pixel = pixels;
- uint8_t *out = out_buf;
-
- for (int i = length; i > 0; --i) {
- out = encode_byte(out, pixel->r);
- out = encode_byte(out, pixel->g);
- out = encode_byte(out, pixel->b);
- ++pixel;
- }
-
- ++index;
-
- ret = spi_device_queue_trans(device, &transaction, portMAX_DELAY);
- RET_ON_ERR(spi_device_queue_trans, ret);
-
- /*
- while ((ret = spi_device_queue_trans(device, &transaction, 0)) != ESP_OK) {
- if (ret == ESP_ERR_TIMEOUT) {
- // Wait for the previous transaction to finish
- ESP_LOGI(TAG, "SPI transaction collision (# %d)", index);
- spi_transaction_t *ret_trans;
- ret = spi_device_get_trans_result(device, &ret_trans, portMAX_DELAY);
- RET_ON_ERR(spi_device_get_trans_result, ret);
- ESP_LOGI(TAG, "Transaction complete (# %d)", index);
-
- } else {
- RET_ON_ERR(spi_device_queue_trans, ret);
- }
- }
- */
- }
|