Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8channelmod #12

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build/*
sdkconfig.old
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@ on the ESP32. It uses interrupts from the RMT peripheral to keep the
buffer filled until all the bytes have been sent to the LED array.

For more information see http://insentricity.com/a.cl/268


Modified for 8 RMT channels by Martin Burger <https://github.com/mburger82>

The driver is now capable of driving all 8 channels of the RMT Module in parallel.
50 changes: 44 additions & 6 deletions main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,41 @@
#include <soc/rmt_struct.h>
#include <esp_system.h>
#include <nvs_flash.h>
#include <esp_log.h>
#include <driver/gpio.h>
#include <stdio.h>
#include "ws2812.h"

#define WS2812_PIN 18
#define TAG "WS2812-DEMO"

#define LEDSTRIPE1_RMTCHANNEL 0
#define LEDSTRIPE2_RMTCHANNEL 1
#define LEDSTRIPE3_RMTCHANNEL 2
#define LEDSTRIPE4_RMTCHANNEL 3
#define LEDSTRIPE5_RMTCHANNEL 4
#define LEDSTRIPE6_RMTCHANNEL 5
#define LEDSTRIPE7_RMTCHANNEL 6
#define LEDSTRIPE8_RMTCHANNEL 7

#define LEDSTRIPE1_RMT_TX_GPIO 19
#define LEDSTRIPE2_RMT_TX_GPIO 18
#define LEDSTRIPE3_RMT_TX_GPIO 17
#define LEDSTRIPE4_RMT_TX_GPIO 16
#define LEDSTRIPE5_RMT_TX_GPIO 04
#define LEDSTRIPE6_RMT_TX_GPIO 02
#define LEDSTRIPE7_RMT_TX_GPIO 15
#define LEDSTRIPE8_RMT_TX_GPIO 13

#define delay_ms(ms) vTaskDelay((ms) / portTICK_RATE_MS)

void rainbow(void *pvParameters)
{
uint8_t rainbowChannel = (((uint32_t)pvParameters) & 0x00FF);
ESP_LOGI(TAG, "Start rainbow Task nr: %i", rainbowChannel);

const uint8_t anim_step = 10;
const uint8_t anim_max = 250;
const uint8_t pixel_count = 64; // Number of your "pixels"
const uint8_t pixel_count = 200; // Number of your "pixels"
const uint8_t delay = 25; // duration between color changes
rgbVal color = makeRGBVal(anim_max, 0, 0);
uint8_t step = 0;
Expand Down Expand Up @@ -80,18 +102,34 @@ void rainbow(void *pvParameters)
}
}

ws2812_setColors(pixel_count, pixels);
ws2812_setColors(pixel_count, pixels, rainbowChannel);


delay_ms(delay);
delay_ms(delay*(rainbowChannel+1));
}
}

void app_main()
{
nvs_flash_init();

ws2812_init(WS2812_PIN);
xTaskCreate(rainbow, "ws2812 rainbow demo", 4096, NULL, 10, NULL);
ws2812_init(LEDSTRIPE1_RMT_TX_GPIO, LEDSTRIPE1_RMTCHANNEL);
ws2812_init(LEDSTRIPE2_RMT_TX_GPIO, LEDSTRIPE2_RMTCHANNEL);
ws2812_init(LEDSTRIPE3_RMT_TX_GPIO, LEDSTRIPE3_RMTCHANNEL);
ws2812_init(LEDSTRIPE4_RMT_TX_GPIO, LEDSTRIPE4_RMTCHANNEL);
ws2812_init(LEDSTRIPE5_RMT_TX_GPIO, LEDSTRIPE5_RMTCHANNEL);
ws2812_init(LEDSTRIPE6_RMT_TX_GPIO, LEDSTRIPE6_RMTCHANNEL);
ws2812_init(LEDSTRIPE7_RMT_TX_GPIO, LEDSTRIPE7_RMTCHANNEL);
ws2812_init(LEDSTRIPE8_RMT_TX_GPIO, LEDSTRIPE8_RMTCHANNEL);

xTaskCreate(rainbow, "ws2812 rainbow demo 1", 3*2048, (void*)LEDSTRIPE1_RMTCHANNEL, 10, NULL);
xTaskCreate(rainbow, "ws2812 rainbow demo 1", 3*2048, (void*)LEDSTRIPE2_RMTCHANNEL, 11, NULL);
xTaskCreate(rainbow, "ws2812 rainbow demo 1", 3*2048, (void*)LEDSTRIPE3_RMTCHANNEL, 12, NULL);
xTaskCreate(rainbow, "ws2812 rainbow demo 1", 3*2048, (void*)LEDSTRIPE4_RMTCHANNEL, 13, NULL);
xTaskCreate(rainbow, "ws2812 rainbow demo 1", 3*2048, (void*)LEDSTRIPE5_RMTCHANNEL, 14, NULL);
xTaskCreate(rainbow, "ws2812 rainbow demo 1", 3*2048, (void*)LEDSTRIPE6_RMTCHANNEL, 15, NULL);
xTaskCreate(rainbow, "ws2812 rainbow demo 1", 3*2048, (void*)LEDSTRIPE7_RMTCHANNEL, 16, NULL);
xTaskCreate(rainbow, "ws2812 rainbow demo 1", 3*2048, (void*)LEDSTRIPE8_RMTCHANNEL, 17, NULL);

return;
}
189 changes: 140 additions & 49 deletions main/ws2812.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,12 @@
#include <soc/dport_reg.h>
#include <driver/gpio.h>
#include <soc/gpio_sig_map.h>
#include <esp_intr.h>
#include <esp_intr_alloc.h>
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

esp_intr.h is deprecated according to compiler output

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <driver/rmt.h>

#define ETS_RMT_CTRL_INUM 18
#define ESP_RMT_CTRL_DISABLE ESP_RMT_CTRL_DIABLE /* Typo in esp_intr.h */

#define DIVIDER 4 /* Above 4, timings start to deviate*/
#define DURATION 12.5 /* minimum time of a single RMT duration
in nanoseconds based on clock */
Expand All @@ -35,8 +32,6 @@

#define MAX_PULSES 32

#define RMTCHANNEL 0

typedef union {
struct {
uint32_t duration0:15;
Expand All @@ -47,9 +42,9 @@ typedef union {
uint32_t val;
} rmtPulsePair;

static uint8_t *ws2812_buffer = NULL;
static unsigned int ws2812_pos, ws2812_len, ws2812_half;
static xSemaphoreHandle ws2812_sem = NULL;
static uint8_t *ws2812_buffer[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
static unsigned int ws2812_pos[8], ws2812_len[8], ws2812_half[8];
static xSemaphoreHandle ws2812_sem[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
static intr_handle_t rmt_intr_handle = NULL;
static rmtPulsePair ws2812_bits[2];

Expand All @@ -73,38 +68,38 @@ void ws2812_initRMTChannel(int rmtChannel)
return;
}

void ws2812_copy()
void ws2812_copy(int RMTChannel)
{
unsigned int i, j, offset, len, bit;


offset = ws2812_half * MAX_PULSES;
ws2812_half = !ws2812_half;
offset = ws2812_half[RMTChannel] * MAX_PULSES;
ws2812_half[RMTChannel] = !ws2812_half[RMTChannel];

len = ws2812_len - ws2812_pos;
len = ws2812_len[RMTChannel] - ws2812_pos[RMTChannel];
if (len > (MAX_PULSES / 8))
len = (MAX_PULSES / 8);

if (!len) {
for (i = 0; i < MAX_PULSES; i++)
RMTMEM.chan[RMTCHANNEL].data32[i + offset].val = 0;
RMTMEM.chan[RMTChannel].data32[i + offset].val = 0;
return;
}

for (i = 0; i < len; i++) {
bit = ws2812_buffer[i + ws2812_pos];
bit = ws2812_buffer[RMTChannel][i + ws2812_pos[RMTChannel]];
for (j = 0; j < 8; j++, bit <<= 1) {
RMTMEM.chan[RMTCHANNEL].data32[j + i * 8 + offset].val =
RMTMEM.chan[RMTChannel].data32[j + i * 8 + offset].val =
ws2812_bits[(bit >> 7) & 0x01].val;
}
if (i + ws2812_pos == ws2812_len - 1)
RMTMEM.chan[RMTCHANNEL].data32[7 + i * 8 + offset].duration1 = PULSE_TRS;
if (i + ws2812_pos[RMTChannel] == ws2812_len[RMTChannel] - 1)
RMTMEM.chan[RMTChannel].data32[7 + i * 8 + offset].duration1 = PULSE_TRS;
}

for (i *= 8; i < MAX_PULSES; i++)
RMTMEM.chan[RMTCHANNEL].data32[i + offset].val = 0;
RMTMEM.chan[RMTChannel].data32[i + offset].val = 0;

ws2812_pos += len;
ws2812_pos[RMTChannel] += len;
return;
}

Expand All @@ -114,29 +109,126 @@ void ws2812_handleInterrupt(void *arg)


if (RMT.int_st.ch0_tx_thr_event) {
ws2812_copy();
ws2812_copy(0);
RMT.int_clr.ch0_tx_thr_event = 1;
}
else if (RMT.int_st.ch0_tx_end && ws2812_sem) {
xSemaphoreGiveFromISR(ws2812_sem, &taskAwoken);
else if (RMT.int_st.ch0_tx_end && ws2812_sem[0]) {
xSemaphoreGiveFromISR(ws2812_sem[0], &taskAwoken);
RMT.int_clr.ch0_tx_end = 1;
}
if (RMT.int_st.ch1_tx_thr_event) {
ws2812_copy(1);
RMT.int_clr.ch1_tx_thr_event = 1;
}
else if (RMT.int_st.ch1_tx_end && ws2812_sem[1]) {
xSemaphoreGiveFromISR(ws2812_sem[1], &taskAwoken);
RMT.int_clr.ch1_tx_end = 1;
}
if (RMT.int_st.ch2_tx_thr_event) {
ws2812_copy(2);
RMT.int_clr.ch2_tx_thr_event = 1;
}
else if (RMT.int_st.ch2_tx_end && ws2812_sem[2]) {
xSemaphoreGiveFromISR(ws2812_sem[2], &taskAwoken);
RMT.int_clr.ch2_tx_end = 1;
}
if (RMT.int_st.ch3_tx_thr_event) {
ws2812_copy(3);
RMT.int_clr.ch3_tx_thr_event = 1;
}
else if (RMT.int_st.ch3_tx_end && ws2812_sem[3]) {
xSemaphoreGiveFromISR(ws2812_sem[3], &taskAwoken);
RMT.int_clr.ch3_tx_end = 1;
}
if (RMT.int_st.ch4_tx_thr_event) {
ws2812_copy(4);
RMT.int_clr.ch4_tx_thr_event = 1;
}
else if (RMT.int_st.ch4_tx_end && ws2812_sem[4]) {
xSemaphoreGiveFromISR(ws2812_sem[4], &taskAwoken);
RMT.int_clr.ch4_tx_end = 1;
}
if (RMT.int_st.ch5_tx_thr_event) {
ws2812_copy(5);
RMT.int_clr.ch5_tx_thr_event = 1;
}
else if (RMT.int_st.ch5_tx_end && ws2812_sem[5]) {
xSemaphoreGiveFromISR(ws2812_sem[5], &taskAwoken);
RMT.int_clr.ch5_tx_end = 1;
}
if (RMT.int_st.ch6_tx_thr_event) {
ws2812_copy(6);
RMT.int_clr.ch6_tx_thr_event = 1;
}
else if (RMT.int_st.ch6_tx_end && ws2812_sem[6]) {
xSemaphoreGiveFromISR(ws2812_sem[6], &taskAwoken);
RMT.int_clr.ch6_tx_end = 1;
}
if (RMT.int_st.ch7_tx_thr_event) {
ws2812_copy(7);
RMT.int_clr.ch7_tx_thr_event = 1;
}
else if (RMT.int_st.ch7_tx_end && ws2812_sem[7]) {
xSemaphoreGiveFromISR(ws2812_sem[7], &taskAwoken);
RMT.int_clr.ch7_tx_end = 1;
}

return;
}

void ws2812_init(int gpioNum)
void ws2812_init(int gpioNum, int RMTChannel)
{
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_RMT_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST);

rmt_set_pin((rmt_channel_t)RMTCHANNEL, RMT_MODE_TX, (gpio_num_t)gpioNum);
rmt_set_pin((rmt_channel_t)RMTChannel, RMT_MODE_TX, (gpio_num_t)gpioNum);

ws2812_initRMTChannel(RMTCHANNEL);
ws2812_initRMTChannel(RMTChannel);

RMT.tx_lim_ch[RMTCHANNEL].limit = MAX_PULSES;
RMT.int_ena.ch0_tx_thr_event = 1;
RMT.int_ena.ch0_tx_end = 1;
RMT.tx_lim_ch[RMTChannel].limit = MAX_PULSES;
switch(RMTChannel) {
case 0: {
RMT.int_ena.ch0_tx_thr_event = 1;
RMT.int_ena.ch0_tx_end = 1;
break;
}
case 1: {
RMT.int_ena.ch1_tx_thr_event = 1;
RMT.int_ena.ch1_tx_end = 1;
break;
}
case 2: {
RMT.int_ena.ch2_tx_thr_event = 1;
RMT.int_ena.ch2_tx_end = 1;
break;
}
case 3: {
RMT.int_ena.ch3_tx_thr_event = 1;
RMT.int_ena.ch3_tx_end = 1;
break;
}
case 4: {
RMT.int_ena.ch4_tx_thr_event = 1;
RMT.int_ena.ch4_tx_end = 1;
break;
}
case 5: {
RMT.int_ena.ch5_tx_thr_event = 1;
RMT.int_ena.ch5_tx_end = 1;
break;
}
case 6: {
RMT.int_ena.ch6_tx_thr_event = 1;
RMT.int_ena.ch6_tx_end = 1;
break;
}
case 7: {
RMT.int_ena.ch7_tx_thr_event = 1;
RMT.int_ena.ch7_tx_end = 1;
break;
}
}


ws2812_bits[0].level0 = 1;
ws2812_bits[0].level1 = 0;
Expand All @@ -152,38 +244,37 @@ void ws2812_init(int gpioNum)
return;
}

void ws2812_setColors(unsigned int length, rgbVal *array)
void ws2812_setColors(unsigned int length, rgbVal *array, int RMTChannel)
{
unsigned int i;


ws2812_len = (length * 3) * sizeof(uint8_t);
ws2812_buffer = malloc(ws2812_len);
ws2812_len[RMTChannel] = (length * 3) * sizeof(uint8_t);
ws2812_buffer[RMTChannel] = malloc(ws2812_len[RMTChannel]);

for (i = 0; i < length; i++) {
ws2812_buffer[0 + i * 3] = array[i].g;
ws2812_buffer[1 + i * 3] = array[i].r;
ws2812_buffer[2 + i * 3] = array[i].b;
ws2812_buffer[RMTChannel][0 + i * 3] = array[i].g;
ws2812_buffer[RMTChannel][1 + i * 3] = array[i].r;
ws2812_buffer[RMTChannel][2 + i * 3] = array[i].b;
}

ws2812_pos = 0;
ws2812_half = 0;
ws2812_pos[RMTChannel] = 0;
ws2812_half[RMTChannel] = 0;

ws2812_copy();
ws2812_copy(RMTChannel);

if (ws2812_pos < ws2812_len)
ws2812_copy();
if (ws2812_pos[RMTChannel] < ws2812_len[RMTChannel])
ws2812_copy(RMTChannel);

ws2812_sem = xSemaphoreCreateBinary();
ws2812_sem[RMTChannel] = xSemaphoreCreateBinary();

RMT.conf_ch[RMTCHANNEL].conf1.mem_rd_rst = 1;
RMT.conf_ch[RMTCHANNEL].conf1.tx_start = 1;
RMT.conf_ch[RMTChannel].conf1.mem_rd_rst = 1;
RMT.conf_ch[RMTChannel].conf1.tx_start = 1;

xSemaphoreTake(ws2812_sem, portMAX_DELAY);
vSemaphoreDelete(ws2812_sem);
ws2812_sem = NULL;
xSemaphoreTake(ws2812_sem[RMTChannel], portMAX_DELAY);
vSemaphoreDelete(ws2812_sem[RMTChannel]);
ws2812_sem[RMTChannel] = NULL;

free(ws2812_buffer);
free(ws2812_buffer[RMTChannel]);

return;
}
}
4 changes: 2 additions & 2 deletions main/ws2812.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ typedef union {
uint32_t num;
} rgbVal;

extern void ws2812_init(int gpioNum);
extern void ws2812_setColors(unsigned int length, rgbVal *array);
extern void ws2812_init(int gpioNum, int RMTChannel);
extern void ws2812_setColors(unsigned int length, rgbVal *array, int RMTChannel);

inline rgbVal makeRGBVal(uint8_t r, uint8_t g, uint8_t b)
{
Expand Down
Loading