Bare Metal Bit Banging: WS2812B Driver

Поділитися
Вставка
  • Опубліковано 12 чер 2024
  • In this video, we examine the WS2812B RGB LED device, and write a bit-banged driver from scratch for an STM32 microcontroller.
    Chapters
    00:00 What is a WS2812 / NeoPixel
    02:33 Hardware overview
    06:00 What is a "device driver"?
    08:35 The signalling protocol
    15:00 Reviewing the datasheet
    22:00 Figuring out the GPIO timing
    49:32 First LED test
    53:36 Implementing the driver interface
    =[ 🔗 Links 🔗 ]=
    🎥 Bare metal playlist: • Blinky To Bootloader: ...
    🗣 Discord: / discord
    ⭐️ Patreon: / lowleveljavascript
    💻 Github Repo: github.com/lowbyteproductions...

КОМЕНТАРІ • 50

  • @davidlarsson7555
    @davidlarsson7555 5 місяців тому +14

    Great video! Thank you!
    One thing I noticed was that you will only have either 255 or 0 on the RGB channels, since you only check bit 7. So, if you would set the channel to 0x70 for instance, then you would get no color in that channel. You'll probably want to do if (r & (1

    • @LowByteProductions
      @LowByteProductions  5 місяців тому +5

      Ahhh you're right, don't know how I forgot to shift 🤦‍♂️

  • @tamas-ruszka
    @tamas-ruszka 5 місяців тому +2

    You are back, wohoo! (while I was waiting, I started watching your oldest videos) A fun story about the WS2812 family: I have the WS2812C and I tried to place on the PCB without checking its datasheet. The problem is, that I assumed that the pin 1 is the marked corner, (just like on every other components) but in reality it's on the oposite side of the led and the marked pin is pin 3, so I had to spent many hours debugging my design. A good tip to everyone: you should always double check your datasheets!

    • @LowByteProductions
      @LowByteProductions  5 місяців тому

      One more reason to be grateful for the reverse polarity protection they built in!

  • @emasheep
    @emasheep 5 місяців тому +4

    Was completely stumped by why it was working without the bit-shift at all... but given your "0/255-only" use-case, the code works just fine :D
    Edit: reminds me of a friend who was using "OTTO" as text to display.. and realizing quite late in the project, that his code was sending the string backwards.

  • @InfiniteCoder01
    @InfiniteCoder01 5 місяців тому +2

    A year ago, I've got my hands on a WS2812B LED strip, I did a 12 by 12 matrix powered by ESP12F. It was much fun. I've programmed it through ArduinoIDE and Adafruit library. I even did some self-playing games like snake and tetris

  • @Cybnew
    @Cybnew 5 місяців тому

    This video is great! Thank you

  • @GeorgeBratley
    @GeorgeBratley 5 місяців тому

    An absolute banger to finish the year with (pun intended)! Would be interesting to see something like a DMX decoder for this, taking an input of RGB values in one protocol like DMX, and translating it and outputing it in another like WS2812B.

    • @LowByteProductions
      @LowByteProductions  5 місяців тому +1

      As it happens someone was discussing a project on the discord server recently where they were translating a DMX signal to an AMX signal on the fly using two cores of an ESP32

  • @josemiguelperricone5993
    @josemiguelperricone5993 5 місяців тому +3

    Great video. 🙂 You forgot to shift the leds values.

    • @LowByteProductions
      @LowByteProductions  5 місяців тому

      Ahhh you're right, don't know how I forgot to shift 🤦‍♂️

  • @bacphan7582
    @bacphan7582 5 місяців тому +3

    For driving ws2812 I like using SPI more. Just define a bunch of constant for bit 1 and 0, send them to MOSI with correct clock and you are done

    • @LowByteProductions
      @LowByteProductions  5 місяців тому

      That's a pretty cool approach! Not without tradeoffs though, right - since you'd need an additional transmit buffer 8x larger than the data you're trying to send, and also need to spend CPU cycles translating the bits to bytes in that buffer.

    • @gionag
      @gionag 5 місяців тому

      done the same, you are trading "space" for "time", sometimes it is worth, other don't...

  • @StreuB1
    @StreuB1 5 місяців тому

    This is one of those videos for a channel that you have never heard of before, and you just sit and watch with your mouth open. This was absolutely unbelievable. The bit at the end where you lamented that getting an arduino or an STM32 is the easy part, but then OK, I can flash a LED. But then what?? How do I develop code? Rather how do I even start or go about developing a project?!?!? Where and how do I start?!?! If you don't know, you honestly don't know. That is where I have been for 2 years, since my initial C++ course. I have bought arduinos, STM's, ESP32, but I have no idea where to start, more so how to start a project.
    One in particular that I want to do and have had no idea how to begin. Is to literally send a simple query request to a device using MODBUS every 100ms (or 250ms really...), then receive the response, take that number and do a calculation with it, then output a pulse train from it. It seems super easy, but no idea where to start. How do I even generate an accurate pulse train with an ON time that comes from my calculation???
    This video sort of gave me a place to start.
    I believe I would use one of the MCU's hardware counters instead of trying to use software as I need the software to do the communication and the calculation based on the received communication. I think I would need to use interrupts as well. Gave me more to think about and I think some type of a pathway forward. Its amazing how watching someone explain and do something, breaks down the fear of trying it yourself. Fear of failure is so insidious. 🙂
    Thank you so much!! Subscribed and looking at your other videos shortly!

    • @LowByteProductions
      @LowByteProductions  5 місяців тому +1

      Thank you for this comment - I'm really happy to hear that this video gave you a direction to follow. I know how opaque this stuff can be, and how hard it is to find quality resources. Take a look at the bare metal programming playlist if you're interested in going further. I used it as a vehicle to discuss a lot of the areas that are often taken for granted in embedded, like understanding datasheets and reference manuals, memory mapped IO, how to use peripherals properly, etc.

  • @merrickryman4853
    @merrickryman4853 5 місяців тому

    I built a WS2812B driver in Rust in for a college lab, was an interesting one 😅 although it was fairly easy with PIO on the RP2040. Great video!

  • @user-qf6yt3id3w
    @user-qf6yt3id3w 3 місяці тому

    One technique I've seen used in a lot in vXWorks board support packages is to calibrate a spinloop based timer against a slower hardware timer. The idea is you spin incrementing a counter starting at one timer tick until the next one. That then tells you "x counter increments equals one timer tick". E.g. on PC AT hardware the PIT timer runs at 18.2Hz, i.e. a 54.945 ms period. So if you know x timer increments equals 54.945ms you can scale that to smaller numbers for smaller delays. You probably need to lock the CPU clock speed and disable interrupts during the spinloop.

  • @sefalibhakat143
    @sefalibhakat143 5 місяців тому +1

    Next video suggestion:- An SD card driver..
    It would be a nice idea to read the binary colour values from the SD card and display the same on pixel leds...

    • @LowByteProductions
      @LowByteProductions  5 місяців тому

      As it happens I've actually built an SD card driver / FAT32 filesystem on the channel before: Bus Pirate Adventures: ua-cam.com/play/PLP29wDx6QmW5zKp0hGR7kvwYlfl8YlxLP.html
      But I agree it would make a great addition to a microcontroller / neopixel project!

  • @gionag
    @gionag 5 місяців тому

    i have made an implementation on stm32 to drive this """smart""" led by leveraging DMA and SPI. the only caveat was to bound the peripheral speed to a certain, specific speed to make the bit timing correct.
    Worked like a charm

    • @LowByteProductions
      @LowByteProductions  5 місяців тому

      I had assumed that you'd need an 8x larger buffer for that, but haven't looked into it I see that you can get 3 bits per byte which isn't bad at all. Nice method indeed

    • @gionag
      @gionag 5 місяців тому

      @@LowByteProductionsyes, you are 100% right. buffer was very big indeed. not always useful in any situation.. but, if the number of led's was small enough, could be a good method to not have mcu "wasting" time between bits...
      Oh... by the way, your contents are killer... thanks

  • @4567guuyth
    @4567guuyth 5 місяців тому

    Hi, nice to meet you.
    I am a student who wants to start studying the Linux kernel.
    However, I don't know what books or lectures on the Linux kernel I should take. In particular, I want to study the network side of Linux and create a server through socket programming. I'm wondering how to start.

  • @scrambledmandible
    @scrambledmandible 5 місяців тому +1

    Hey, your vx6 series has inspired me to try creating a RISC-V processor in the graphical logic simulator Digital (ever unsearchable successor to Logisim)
    I'm following the biriscv verilog repo, but assuming I can finish it and get it working, do you want a copy to play with?
    It has a lot of the pieces you need to boot vx6, like a simple MMU and cache and those bits and bobs, though not RV64GC, it is RV32IM-Zicsr

    • @LowByteProductions
      @LowByteProductions  5 місяців тому

      Definitely!

    • @scrambledmandible
      @scrambledmandible 5 місяців тому

      @@LowByteProductions I'll tell you what though, verilog was not meant for this kind of translation 😓

  • @kilwo
    @kilwo 5 місяців тому

    Just a quick thought. Should you be turning off interrupts while you are bit-banging? And could this cause the issues of the flickering. Would only be visible when the LED is off as a single bit flip due to timing error would not be visible on a lit led. Just a thought.

    • @LowByteProductions
      @LowByteProductions  5 місяців тому

      It's possible, but not probable in my opinion, since the interrupt code here would be running very quickly - 10s of nanoseconds.

  • @thoup
    @thoup 5 місяців тому

    This is so cool. Where do you find ideas like these? And any good resources on learning and getting more involved in low level development? I have programmed a fair bit in C/C++ but mostly from university, and I would really like to make some projects to showcase/expand my knowledge.

    • @LowByteProductions
      @LowByteProductions  5 місяців тому

      Thanks, glad you enjoyed it! I think a good way of getting into lower level code is grab a cheap arduino kit from amazon or aliexpress with an uno and a few sensors, wires, etc and get some lights blinking, read some sensors, and other little projects using the arduino libraries. From there you can learn about programming without using the arduino framework and libraries (search something like arduino register level propgramming), reimplementing the same projects from scratch. Combine that with Elicia White's book "Making Embedded Systems", and that'll put you on a fast track to learning C, low level programming, CPU internals, how to talk to other devices over different protocols, etc.

    • @LowByteProductions
      @LowByteProductions  5 місяців тому

      Oh, and look into the wokwi online simulator. You can program for virtual devices (emulated arduinos, ESP32s, etc), which can be a good way of learning about this kind of thing without paying a single penny.

  • @andyschneider6402
    @andyschneider6402 24 дні тому

    Is it possible that the fact the nop instructions don’t consume time consistently as you add them is because a NOP on ARM is not guaranteed to consume time, the processor is allowed to remove them from the pipeline?

  • @LordHog
    @LordHog 5 місяців тому

    I know this topic is bit banging the control/data signal, but wouldn’t using a PWM be better to keep tighter timing?

    • @LowByteProductions
      @LowByteProductions  5 місяців тому +3

      Sure! I mention a possible PWM approach in the video using Timers and DMA. It's definitely the better way to do it, but bit banging is universal and the method will apply to any micro

    • @LordHog
      @LordHog 5 місяців тому

      @@LowByteProductions sorry, was a long video and sort of skipped around to the middle and watched some while I was out. Bookmarked to watch it fully a bit later. Thanks

    • @LowByteProductions
      @LowByteProductions  5 місяців тому

      @LordHog no worries!

  • @electrolyteorb
    @electrolyteorb 5 місяців тому

    Next time, please show the top view of how everything is connected

  • @patricklehmann24
    @patricklehmann24 5 місяців тому +2

    The duty-cycle is 33% vs. 66%, not 25% vs. 75%. 400ns out of 1200ns is a 1/3. We also see later, the period is not 1200ns, but 1250ns.

    • @LowByteProductions
      @LowByteProductions  5 місяців тому

      True - doing the mental math while speaking to the camera is tricky!

  • @lbirkert
    @lbirkert 5 місяців тому +2

    ua-cam.com/video/KUklOA91nk0/v-deo.htmlfeature=shared&t=2572
    I do not think your reasoning is correct here. The thing does not work because your NOP_420NS macro does in fact not take 420ns but rather 420ns - 120ns = 300ns to run (the whole thing sums up to 420ns, as your port write takes about 120ns). Doing the calculations, this lines up with what you were getting with 2x NOP_420NS: 300ns * 2 + 120ns = 720ns.

    • @LowByteProductions
      @LowByteProductions  5 місяців тому

      You're right! Hard to think and speak out loud at the same time 😅

  • @user-dy4rh5vz4w
    @user-dy4rh5vz4w 5 місяців тому

    I have an 8*8

  • @rty1955
    @rty1955 3 місяці тому

    Horrible implimentation. Using assembly code for critical timming is a bad way of doing it. Because of the many, many different types of uP boards out there with so many timming variants will require too much tweaking of the assembler code. Very sloppy code
    I developed a hardware interface that you can raise a PROCESS line, then send the three data bytes and monitor a BUSY line to drop when u can send another group of 3 bytes. You so this for all the pixels you want to send. At end u drop the PROCESS line and wait for busy line to drop and you are done. Easy peasy. Works on ANY uP too and is rock solid

  • @stati5tik
    @stati5tik 5 місяців тому

    what precisly is the reasoning behind using LED_PIN at 30:46? As far as i see gpio_port_write expects data as an argument, how exactly can a LED_PIN considered a data in the classical sense? I understand that the 8th bit denotes the very pin we want to use to communicate. Does that mean gpio_port_write turns the pin on and off? why 16 bits then?

    • @LowByteProductions
      @LowByteProductions  5 місяців тому +1

      A "port" is made up of uo to 16 GPIOs, which you can change the state of simultaneously.

    • @stati5tik
      @stati5tik 5 місяців тому

      @@LowByteProductions okay makes sense (-: