I have been working with digital LEDs such as WS2812, WS2815 or SK6812 for a long time, which I usually call Magic LED.

I tested many strips, rings and displays (even my own) based on Magic LED (even with RGBW type). I used Arduino, Nucleo (with STM), Raspberry Pi and my own boards with AVR microcontrollers.

Regardless of the platform, writing a program to control magic LEDs is difficult (due to the need for NZR protocol software), unless you are using ready-made libraries that make it easy, but still not fully optimal in terms of code usage, interrupt responses, or memory utilization, and only work on specific platforms (porting them to e.g. from Raspberry to AVR microcontrollers is impossible).

Due to the fact that I often use various platforms, I had the need for the program code to be as compatible as possible with Arduino, Raspberry Pi, ARM / STM (Nucleo) or AVR - especially when it comes to lighting effects.

I have been working on the youtube channel for a long time and I have prepared more than one guide on programming digital diodes in C language for AVR microcontrollers (but so far only in Polish for now). I often have contact with beginners who struggle with programming magic LEDs. Of course, some, depending on the platform, choose ready libraries for their one-time projects. However, many people look for other solutions or try to learn the secrets of programming and I am one of them.

I decided to prepare a module that will do the dirty work for the user using the NZR protocol. The module that will act as SPI to NZR converter and just like SPI, can be used on any platform with ease. The screenshot below shows the conversion of SPI signals to NZR protocol in the Magic Hercules module.

When connecting digital LEDs to different systems, one should remember about the appropriate voltage tolerance for different microcontrollers. Most of the I / O pins of ARM microcontrollers work in the +3.3 V standard, while the AVR microcontrollers work in the TTL standard. Due to this, the input pins of the Magic Hercules module have a tolerance of +3.3 V, so they can be safely connected to eg a Raspberry P or any ARM based microcontroller powered +3.3 V.

As I mentioned before, I often work with different types of digital LEDs. Depending on the manufacturer, individual colors in the LEDs can be in different positions, e.g. RGB, BGR, GRB, RGBW, GRBW, etc. It's not uncommon for the manufacturer's documentation to mention the RGB sequence, but it actually looks different. I have equipped the Hercules module with a color sequence test so that there is no problem with quickly figuring out how to write a program for the correct color order. Several additional functions of the tester allow you to quickly check whether the digital LED strip works at all, whether all the colors in each LED across the strip (up to 1024 LEDs!) Are working correctly (no dead pixels). And all this without connecting a microcontroller and writing any program.

I don't think there was such a thing yet, to control digital LEDs using a simple and common SPI protocol, which can be operated on any platform or family of microcontrollers.

Of course, there are many ways to control digital LEDs, some are more optimal and others are less optimal. The Magic Hercules module is another option and very practical for me.

I think that someone may like this unusual solution. I recently took off on the crowdfunding platform - kickstarter, where I prepared a broader description of the Magic Hercules module in several videos, including how easy it is to work with it on Arduino, Nucleo (STM), Raspberry Pi and on AVR and PIC microcontrollers. If you would like to support the Magic Hercules project, check this out:

My Magic Hercules module project on kickstarter

I prepared a program in C language - a simple stargate effect, which is based on table operations and sequential sending of the buffer in the main loop. Thanks to the Magic Hercules module, I was able to easily transfer the source code to other languages and platforms - check the source code section (Python for Raspberry Pi or Arduino).

Source Codes section:

I. AVR - C source

#include <avr/io.h>
#include <util/delay.h>
#include <string.h>

#include "MK_HERCULES_SPI/mk_hercules_spi.h"

typedef struct {
	uint8_t g;
	uint8_t r;
	uint8_t b;
} TRGB;

TRGB mbuf[24];

int ir=0, ig=8, ib=16;

void draw_stargate( void ) {

	mbuf[ir].r = 5;
	mbuf[ig].g = 5;
	mbuf[ib].r = 5; mbuf[ib].g = 3;

	if( ++ir == 24 ) ir = 0;
	if( --ig < 0 ) ig = 23;
	if( ++ib == 24 ) ib = 0;

	mbuf[3].b = 10;
	mbuf[9].b = 10;
	mbuf[15].b = 10;
	mbuf[21].b = 10;

	hspi_send_buf( mbuf, 24*3 );
	memset( mbuf, 0, 24*3 );
}


int main( void ) {

	hspi_init();

	while(1) {

		draw_stargate();
		_delay_ms(50);

	}
}

 II. Raspberry Pi - Python source

import spidev
from time import *

spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 800000 # 800 kHz

rgb = 3
led_count = 24

mbuf = [[0] * rgb for i in range(led_count)]
spibuf = [0] * 72

# LED start indexes
ir = 0
ig = 8
ib = 16

# Convert 2D mbuf to 1D spibuf
def buf_convert():
    idx = 0
    for list in mbuf:
        for x in list:
            spibuf[idx] = x
            idx += 1

def draw_stargate():
    
    global ir
    global ig
    global ib
 
    for i in range(24):
        for j in range(3):
            mbuf[i][j] = 0
                  
    buf_convert()
    spi.writebytes(spibuf)
    
    mbuf[3] = [0,0,5]
    mbuf[9] = [0,0,5]
    mbuf[15] = [0,0,5]
    mbuf[21] = [0,0,6]
    
    mbuf[ir][1] = 5
    mbuf[ig][0] = 5
    mbuf[ib][0] = 3
    mbuf[ib][1] = 5
    
    ir = ir + 1
    if ir == 24:
        ir = 0
        
    ig -= 1
    if ig < 0:
        ig = 23
        
    ib += 1
    if ib == 24:
        ib = 0
    
    buf_convert()
    spi.writebytes(spibuf)
    

while True:
    
    draw_stargate()
    sleep(0.05)

 III. Arduino C++ source code

#include <SPI.h>

typedef struct {
  uint8_t g;
  uint8_t r;
  uint8_t b;
} TRGB ;

TRGB mbuf[24];

int ir=0, ig=8, ib=16;

void setup() {
  SPI.begin();
  SPI.setClockDivider( SPI_CLOCK_DIV32 );
}

void draw_stargate() {

  memset( mbuf, 0, sizeof(mbuf) );
  
  mbuf[ir].r = 5;
  mbuf[ig].g = 5;
  mbuf[ib].r = 5; mbuf[ib].g = 3;

  if( ++ir == 24 ) ir = 0;
  if( --ig < 0 ) ig = 23;
  if( ++ib == 24 ) ib = 0;

  mbuf[3].b = 10;
  mbuf[9].b = 10;
  mbuf[15].b = 10;
  mbuf[21].b = 10;

  cli();
  SPI.transfer( mbuf, sizeof(mbuf) );
  sei();
}

void loop() {
  draw_stargate();
  delay(50);
}

 IV. ARM/STM - C source code

/* USER CODE BEGIN Header */
/**
  **************************
  * @file           : main.c
  * @brief          : Main program body
  **************************
  * @attention
  *
  * <h2><center>© Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  **************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include <string.h>

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi1;
DMA_HandleTypeDef hdma_spi1_tx;

UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_SPI1_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */


// new TRGB type
typedef struct {
	uint8_t g;
	uint8_t r;
	uint8_t b;
} TRGB;

// Magic LED RING - 24 LEDs
TRGB mbuf[24];	// FX buffer


// LED start indexes
int ir=0, ig=8, ib=16;


void draw_stargate( void ) {

	// clear FX buffer
	memset( mbuf, 0, 24*3 );

	// moving lights
	mbuf[ir].r = 5;
	mbuf[ig].g = 5;
	mbuf[ib].r = 5; mbuf[ib].g = 3;

	// change moving lights position
	if( ++ir == 24 ) ir = 0;
	if( --ig < 0 ) ig = 23;
	if( ++ib == 24 ) ib = 0;

	// 4 blue light
	mbuf[3].b = 10;
	mbuf[9].b = 10;
	mbuf[15].b = 10;
	mbuf[21].b = 10;

	// send FX buffer via SPI to Magic HERCULES
	HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)mbuf, 72 );
}


/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART2_UART_Init();
  MX_SPI1_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  draw_stargate();
	  HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
	  HAL_Delay(50);

  }
  /* USER CODE END 3 */
}

I think MH can be an extremely beginner-friendly module, regardless of the platform and language they use. It is enough to know the well-known SPI protocol, and the possibility to start checking whether the digital LED strip works at all and what color sequence it has is only a plus.