Closed weiying-chen closed 3 months ago
I also tried something a little more complex like this:
use anyhow::Result;
use esp_idf_hal::delay::FreeRtos;
use esp_idf_hal::gpio::{AnyOutputPin, Output, OutputPin, PinDriver};
use esp_idf_hal::peripherals::Peripherals;
use esp_idf_hal::spi::{config::Config, SpiDeviceDriver, SpiDriver, SpiDriverConfig, SPI2};
use esp_idf_svc::log::EspLogger;
use esp_idf_sys::{self as _};
use log::info;
struct WS2812<'a, CS: OutputPin> {
spi: SpiDeviceDriver<'a, &'a SpiDriver<'a>>,
cs: PinDriver<'a, CS, Output>,
}
impl<'a, CS> WS2812<'a, CS>
where
CS: OutputPin,
{
pub fn new(spi: SpiDeviceDriver<'a, &'a SpiDriver<'a>>, cs: PinDriver<'a, CS, Output>) -> Self {
Self { spi, cs }
}
pub fn write_byte(&mut self, data: u8) -> Result<()> {
let patterns = [0b1000_1000, 0b1000_1110, 0b1110_1000, 0b1110_1110];
let mut buffer = [0u8; 4];
let mut data = data;
for i in 0..4 {
let bits = (data & 0b1100_0000) >> 6;
buffer[i] = patterns[bits as usize];
data <<= 2;
}
self.cs.set_low()?;
self.spi.write(&buffer)?;
self.cs.set_high()?;
Ok(())
}
pub fn flush(&mut self) -> Result<()> {
let buffer = [0u8; 140];
self.cs.set_low()?;
self.spi.write(&buffer)?;
self.cs.set_high()?;
Ok(())
}
}
fn main() -> Result<()> {
esp_idf_svc::sys::link_patches();
EspLogger::initialize_default();
let peripherals = Peripherals::take()?;
let spi = peripherals.spi2;
let sclk = peripherals.pins.gpio6; // SCLK
let serial_in = peripherals.pins.gpio4; // SDI (MISO)
let serial_out = peripherals.pins.gpio7; // SDO (MOSI)
let cs_pin = peripherals.pins.gpio10; // Chip Select for device (LED pin)
println!("Starting SPI WS2812 control");
let driver = SpiDriver::new(
spi,
sclk,
serial_out,
Some(serial_in),
&SpiDriverConfig::new(),
)?;
let config = Config::new().baudrate(3_000_000.into());
let spi_device = SpiDeviceDriver::new(&driver, None::<AnyOutputPin>, &config)?; // No CS pin here
let cs = PinDriver::output(cs_pin)?; // CS pin managed separately
let mut ws2812 = WS2812::new(spi_device, cs);
let red = 255;
let green = 0;
let blue = 0;
loop {
FreeRtos::delay_ms(500);
ws2812.flush()?;
ws2812.write_byte(green)?;
ws2812.write_byte(red)?;
ws2812.write_byte(blue)?;
ws2812.flush()?;
info!("WS2812: Sent LED data for Red color");
}
}
Same: No compile errors. There's output. But the WS2812 LED doesn't turn on.
Are you sure that the ws2812 are fast enough to be able to work with a 3MHz clocked signal?
Ah, maybe not (Sorry, I'm not very experienced with this). I guess it'll be too complicated to use SPI.
Now I'm using this RMT code. It works for external ws2812s. But not with the built-in ws2812 of the ESP32-C3-Zero. It used to be off all the time. And now it's always green no matter what. (The exact same thing happens with the official Arduino code for the ESP32-C3-Zero.)
The https://github.com/smart-leds-rs/ws2812-spi-rs you mentioned is fully compatible with esp-idf-hal. The pull request for embedded-hal 1.0 is merged now. You also need to enable features = ["mosi_idle_high"]
for it to work, and probably need to change RGB order. I did a fork of ws2812-spi-rs before embedded-hal 1.0 support was merged, the fork consists of the pull request with embedded-hal 1.0 support + RGB color order. You can see the working code for esp32-c3 with SPI + DMA here: https://github.com/okhsunrog/esp_pd_rs
@Vollbrecht I think this issue can be closed
Are you sure that the ws2812 are fast enough to be able to work with a 3MHz clocked signal?
It most certainly is, I'm using 3.2 MHz in my code, the SPI signal is used to form correct timings, the timings I get with 3.2 MHz match the ones described in the datasheet for WS2812B
@weiying-chen the code you can find in my links is tested to work with ESP32-C3-Zero built-in WS2812 led
@okhsunrog Thanks a lot! I'll try it out.
@okhsunrog Your code works. Thanks a lot again!
I want to control the WS2812 LED of my ESP32-C3-Zero using
esp_idf_hal
's SPI. I tried this:No compiler errors. And there's output. But the WS2812 LED doesn't turn on.
Note: This is a rust library for WS2812. But I don't think it's compatible with
esp_idf_hal
.