Страница 1 из 1

Не удается управлять WS2812 с ESP32

Добавлено: Пт июн 03, 2022 19:07:28
HEhX
Доброго времени суток, господа. Возникла проблема с управлением тремя адресными светодиодами WS2812 с помощью ESP32.
Схема подключение классическая:
- Питание светодиодов пробовал 3.3V, 4.4V(понижение с 5V через диод) и 5V.
- Общая с ESP32 земля.
- Сигнальный на DIN с 12 GPIO напрямую, дорожкой порядка 2 сантиметров.

Использовал библиотеку FastLED. Проверял точно такой же код на меге 328 - всё работает, с ESP32 же результат нулевой.
Собственно, есть соображения в чем может быть проблема?

Re: Не удается управлять WS2812 с ESP32

Добавлено: Вт июн 07, 2022 12:06:40
ELECTROS
Ну ровняйте осцилограмы по клеткам, удобней же смотреть. Не пойму что с уровнем напряжения, должно же быть 5 вольт, ну 3.3, а там 1 вольт на осциллограмме.

Re: Не удается управлять WS2812 с ESP32

Добавлено: Чт июн 23, 2022 11:05:24
AlanDrakes
У себя повесил SK6805 (он же WS2812, только в другом корпусе) на SPI пин ESP32. Заработало почти сразу. На ногодрыге не получилось - сильно мешает многозадачность и ОС.
Напряжение, кстати, тоже проверьте.

Мой код, может поможет:
Спойлер

Код: Выделить всё

spi_device_handle_t LED_SPI_DEV;
int64_t LastSPILedTime = 0; // Запоминаем время, когда в последний раз отправляли светодиоду команду. Если отправить две команды одновременно - примется только первая.

void Init_SPI_Led(void) {
	spi_bus_config_t spi_cfg = {
		.miso_io_num = -1,
		.mosi_io_num = GPIO_NUM_21,
		.sclk_io_num = -1,
		.max_transfer_sz = 0,
		.quadhd_io_num = -1,
		.quadwp_io_num = -1,
		.flags = SPICOMMON_BUSFLAG_MASTER,
		.intr_flags = ESP_INTR_FLAG_IRAM,
	};
	ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &spi_cfg, SPI_DMA_CH_AUTO));
	spi_device_interface_config_t dev_cfg = {
		.address_bits = 0,
		// WS2812 require ~5MHz sck wich is 1.6us / bit slot
		.clock_speed_hz = 5000000,
		.command_bits = 0,
		.cs_ena_posttrans = 0,
		.cs_ena_pretrans = 0,
		.dummy_bits = 0,
		.duty_cycle_pos = 0,
		.flags = 0,
		.input_delay_ns = 0,
		.mode = 0,
		.pre_cb = 0,
		.post_cb = 0,
		.queue_size = 1,
		.spics_io_num = -1,
	};
	ESP_ERROR_CHECK(spi_bus_add_device(SPI2_HOST, &dev_cfg, &LED_SPI_DEV));
}

void SPI_Led_Set(uint8_t R, uint8_t G, uint8_t B) {
	uint8_t spi_tx_buf[24];
	int64_t CurrTime = esp_timer_get_time();
	if ((CurrTime - LastSPILedTime) < 100) {
		vTaskDelay(1);
	};
	int i = 0;
	int pos = 0;
	for (i=0; i<8; i++) {
		if (G & (0x80 >> i)) {
			spi_tx_buf[pos++] = 0x70;
		} else {
			spi_tx_buf[pos++] = 0x40;
		}
	}
	for (i=0; i<8; i++) {
		if (R & (0x80 >> i)) {
			spi_tx_buf[pos++] = 0x70;
		} else {
			spi_tx_buf[pos++] = 0x40;
		}
	}
	for (i=0; i<8; i++) {
		if (B & (0x80 >> i)) {
			spi_tx_buf[pos++] = 0x70;
		} else {
			spi_tx_buf[pos++] = 0x40;
		}
	}
	spi_transaction_t trans = {
		.addr = 0,
		.cmd = 0,
		.flags = 0,
		.length = 24 * 8,
		.tx_buffer = &spi_tx_buf,
		.user = 0,
	};
	ESP_ERROR_CHECK(spi_device_transmit(LED_SPI_DEV, &trans));
	LastSPILedTime = esp_timer_get_time();	// Safety delay
}
Значения 0x40 / 0x70 выбраны специально, чтобы шина в начале/конце тайм-слота возвращалась в нулевое состояние. Если отправлять 0x80 - шина может зависнуть в "1" после команды.
Код управляет только одним диодом! Но функцию можно переписать для массива светодиодов. Рекомендую использовать её как пример или отправную точку после того, как разберётесь с заниженным напряжением на ваших же скриншотах.