CanHobby Explorations
Published

ESP-C3 NeoPixels with RMT & BLE

Connect 10 neoPixel strips to an ESP32-C3 RISC-V MCU using the RMT peripheral.

IntermediateWork in progress150
ESP-C3 NeoPixels with RMT & BLE

Things used in this project

Hardware components

ESP32-C3
This project was developed using the SuperMini Board. Also available from eBay and AliExpress.
×1

Software apps and online services

Espressif-IDE
Eclipse based IDE doe the ESP32 family- One of the best factory supported IDEs.

Story

Read more

Code

show()

C/C++
void show( void *arg ) // arg is pointer to strip
void show( void *arg ) {
	
uint8_t Stp = 0;
stps[0] = &NEO0;
stps[1] = &NEO1;
stps[2] = &NEO1;

ESP_LOGI( TAG, "Show Task starting" );
// printf("Show: len = %d, gpio = %d, name = %s\n", stps[Stp]->len, stps[Stp]->gpio, stps[Stp]->name );
  
while( 1 ) {
	
	for( Stp = 0; Stp < NUM_STRIPS; Stp++ ) {

	REG_WRITE( GPIO_FUNC0_OUT_SEL_CFG_REG + ( Stp * 4 ), 51 );	
     ESP_ERROR_CHECK( rmt_transmit( led_chan, encoder, stps[Stp]->pixels, NEO0.len * 3, &tx_cfg ));
     ESP_ERROR_CHECK(rmt_tx_wait_all_done( led_chan, portMAX_DELAY));
   	REG_WRITE( GPIO_FUNC0_OUT_SEL_CFG_REG + ( Stp * 4 ), 128 );

        }  //  end STPs
             vTaskDelay(pdMS_TO_TICKS(EXAMPLE_FRAME_DURATION_MS));
    }
}
 

NEO.h

C/C++
header file with various defines
/** NEO.h
 *  Created on: Oct. 17, 2024
 *  Updated on: Dec. 19, 2024
 *  Author: CanHobby.ca
 */

#ifndef USER_NEO_H_
#define USER_NEO_H_

#define NUM_STRIPS 3

#include "stdbool.h"
#include "stdlib.h"
#include "stdint.h"
#include "driver/rmt_tx.h"

#define START 0
#define END   1
#define SIZE  2
#define YY	  3
#define BRT	  4
#define DLY	  5
// #define FWD   1

#define FALSE 0
#define TRUE  1
// #define DMA	  FALSE // TRUE  //  FALSE

#define MAX_LEN    144 // Length of longest strip

//  We aren't using C++ but we will use this object for each strip
typedef struct {
	gpio_num_t gpio;
	uint8_t *pixels;
	uint16_t  len;
	uint8_t   segs[5][9]; // up to 5 segments with 9 static parameters
	char	 *name;
} strip;

#define RED 0x000400	// GRB  format
#define RDD 0x00FF00
#define grn 0x800000
#define grN 0x000001
#define GRN 0x030000
#define BLU 0x000005
#define MAG 0x000403
#define YEL 0x030300
#define CYN 0x030005
#define BLK 0x000000
#define WHT 0x040201

// Colour offsets
#define BLUE 2
#define REDD 1
#define GREN 0

#endif /* USER_NEO_H_ */

rmt_setup()

C/C++
used to setup the RMT peripheral and encoder etc. - Basically copied straight from the Espressif example.
     
void rmt_setup( ) {
	
	 ESP_LOGI(TAG, "rmt SetUp" );
    
    rmt_tx_channel_config_t tx_chan_config = {
        .clk_src = RMT_CLK_SRC_DEFAULT, // select source clock
        .gpio_num = 0,
        .mem_block_symbols = 64, // increase the block size to reduce LED flickering
        .resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ,
        .trans_queue_depth = 16, // set the number of transactions that can be pending in the background
    };

    ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &led_chan ));
    
 	ESP_LOGI(TAG, "Create simple callback-based encoder");
	encoder = NULL;
 	
 	    const rmt_simple_encoder_config_t simple_encoder_cfg = {
        .callback = encoder_callback
        //Note we don't set min_chunk_size here as the default of 64 is good enough.
    };
    ESP_ERROR_CHECK(rmt_new_simple_encoder(&simple_encoder_cfg, &encoder ));
 	
 	ESP_ERROR_CHECK(rmt_enable( led_chan ));

	tx_cfg.loop_count = 0;
 
}

strip_setup()

C/C++
void strip_setup( strip *stp, uint16_t ln, gpio_num_t gpio, char* name )
used to specify basic parameters of a strip.
 
void strip_setup( strip *stp, uint16_t ln, gpio_num_t gpio, char* name ) {
	
	 ESP_LOGI(TAG, "stg SetUp: %s = %d", name, ln );
 	     
    strip *strp  = (strip *)stp;
    strp->gpio   = gpio;	// we will use gpio 0
    strp->len    = ln;
    strp->pixels = (uint8_t*)calloc( ln, sizeof(uint8_t) * 3 );
    strp->name   = name;
    
    }
  

anim1()

C/C++
void anim1( void *arg ) // arg is pointer to strip
void anim1( void *arg  ) {

 strip *strp = (strip *)arg;
 uint8_t x, c = GREN, idx = 1;
 uint8_t start =  strp->segs[ idx ][ START ] - 1;
 uint8_t  end  =  strp->segs[ idx ][ END ];

// printf( "anim1 Dly = %d\n", strp->segs[ idx ][ DLY ] ); 
// printf( "anim1 %d : %d, %s [%d] -> %d\n", strp->segs[ idx ][ START ], strp->segs[ idx ][ END ], strp->name, idx, strp->gpio );
 
 ESP_LOGI(TAG, "Start tetis"); 
while(1) {

for( x=start; x<end; x++ ) {

 if( strp->pixels[ x*3 + c%3 ] != 7 ) { strp->pixels[ x*3 + c%3 ] = 7; }
 else { strp->pixels[ x*3 + c%3 ] =  0; }
strp->pixels[ x*3 + c%3 ] =  0;
 c++;
 if( c > 2 ) c = 0;
 	vTaskDelay( strp->segs[ idx ][ DLY ] );
	}
	}
}

anim2()

C/C++
void anim2( void *arg ) // arg is pointer to strip
void anim2( void *arg  ) {

 strip *strp = (strip *)arg;
 uint8_t x, rn, idx = 0;
static uint8_t start, end;

start = strp->segs[ idx ][ START ] - 1;
 end  = strp->segs[ idx ][ END ];
 
  ESP_LOGI(TAG, "Start anim2");
// printf( "anim2 Dly = %d\n", strp->segs[ idx ][ DLY ] );
// printf( "anim2: %d : %d -- %s [%d] -> %d\n", strp->segs[ idx ][ START ], strp->segs[ idx ][ END ], strp->name, idx, strp->gpio );  

while(1) {

for( x=start; x<end; x++ ) {
	
getrandom( &rn, 1, 0 );  //  get RNG value

// if( strp->pixels[ x*3 + BLUE ] != 17 ) { strp->pixels[ x*3 + BLUE ] = 17; }
// else { strp->pixels[ x*3 + BLUE ] =  0; }

strp->pixels[ x*3 + (rn%3) ] = (rn&0x1f); // &0x2f;

	vTaskDelay( strp->segs[ idx ][ DLY ] );
	}
  }
}

app_main.c

C/C++
1st things 1st
void app_main(void)
{
printf("\nSimple rainbow APP\n");

uint8_t buff;
getrandom( &buff, 1, 0 );
printf("RNG = %d\n", buff & 15 );

rmt_setup();

strip_setup( &NEO0, 15, 0, "neo0" );
strip_setup( &NEO1, 15, 2, "neo1" );

/******  Setup Animation parameters  ********/

NEO0.segs[0][START] = 1;
NEO0.segs[0][END]   = 13;
NEO0.segs[0][DLY]   = 5;

NEO1.segs[1][START] = 3;
NEO1.segs[1][END]   = 14;
NEO1.segs[1][DLY]   = 3;

NEO0.segs[1][START] = 1;
NEO0.segs[1][END]   = 5;
NEO0.segs[1][DLY]   = 15;

NEO0.segs[2][START] = 7;
NEO0.segs[2][END]   = 10;

xTaskCreate( show, "Show", 4048, &NEO0, 9, NULL );
 
 xTaskCreate( anim1, "Anim1", 2824, &NEO1, 5, NULL);
 xTaskCreate( anim2, "Anim2", 2824, &NEO0, 5, NULL);
// xTaskCreate( rainbow, "rbow", 1824, &NEO0, 5, NULL);

}

Credits

CanHobby Explorations
2 projects • 0 followers
Self Taught on MCU hard and software since before PCs existed. Sporadically do videos and blogs, mostly exploring small RISC-V MCUs.
Contact
Thanks to PCBway.

Comments

Please log in or sign up to comment.