forked from nkolban/esp32-snippets
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
kolban
committed
Nov 28, 2016
1 parent
ecc89d9
commit ac57831
Showing
3 changed files
with
172 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
/* | ||
* WS2812.cpp | ||
* | ||
* Created on: Nov 27, 2016 | ||
* Author: kolban | ||
*/ | ||
|
||
#include "WS2812.h" | ||
#include <esp_log.h> | ||
#include <driver/gpio.h> | ||
#include <stdint.h> | ||
#include <driver/rmt.h> | ||
#include "sdkconfig.h" | ||
|
||
static char tag[] = "WS2812"; | ||
|
||
/** | ||
* A NeoPixel is defined by 3 bytes ... red, green and blue. | ||
* Each byte is composed of 8 bits ... therefore a NeoPixel is 24 bits of data. | ||
* At the underlying level, 1 bit of NeoPixel data is one item (two levels) | ||
* This means that the number of items we need is: | ||
* | ||
* #pixels * 24 | ||
* | ||
*/ | ||
|
||
static void setItem1(rmt_item32_t *pItem) { | ||
pItem->level0 = 1; | ||
pItem->duration0 = 7; | ||
pItem->level1 = 0; | ||
pItem->duration1 = 6; | ||
} // setItem1 | ||
|
||
|
||
static void setItem0(rmt_item32_t *pItem) { | ||
pItem->level0 = 1; | ||
pItem->duration0 = 4; | ||
pItem->level1 = 0; | ||
pItem->duration1 = 8; | ||
} // setItem0 | ||
|
||
|
||
WS2812::WS2812(rmt_channel_t channel, gpio_num_t gpioNum, uint16_t pixelCount) { | ||
this->pixelCount = pixelCount; | ||
this->channel = channel; | ||
this->items = (rmt_item32_t *)malloc(sizeof(rmt_item32_t) * (pixelCount * 24)); | ||
this->pixels = (pixel_t *)malloc(sizeof(pixel_t) * pixelCount); | ||
|
||
rmt_config_t config; | ||
config.rmt_mode = RMT_MODE_TX; | ||
config.channel = channel; | ||
config.gpio_num = gpioNum; | ||
config.mem_block_num = 1; | ||
config.tx_config.loop_en = 0; | ||
config.tx_config.carrier_en = 0; | ||
config.tx_config.idle_output_en = 1; | ||
config.tx_config.idle_level = (rmt_idle_level_t)0; | ||
config.tx_config.carrier_duty_percent = 50; | ||
config.tx_config.carrier_freq_hz = 10000; | ||
config.tx_config.carrier_level = (rmt_carrier_level_t)1; | ||
config.clk_div = 8; | ||
|
||
ESP_ERROR_CHECK(rmt_config(&config)); | ||
ESP_ERROR_CHECK(rmt_driver_install(this->channel, 0, 19)); | ||
} // WS2812 | ||
|
||
|
||
void WS2812::show() { | ||
uint32_t i,j; | ||
rmt_item32_t *pCurrentItem = this->items; | ||
for (i=0; i<this->pixelCount; i++) { | ||
uint32_t currentPixel = this->pixels[i].red | (this->pixels[i].green << 8) | (this->pixels[i].blue << 16); | ||
for (j=0; j<24; j++) { | ||
if (currentPixel & 1<<j) { | ||
setItem1(pCurrentItem); | ||
} else { | ||
setItem0(pCurrentItem); | ||
} | ||
pCurrentItem++; | ||
} | ||
} | ||
// Show the pixels. | ||
rmt_write_items(this->channel, this->items, this->pixelCount*24, | ||
1 /* wait till done */); | ||
} // show | ||
|
||
|
||
void WS2812::setPixel(uint16_t index, uint8_t red, uint8_t green, | ||
uint8_t blue) { | ||
if (index >= this->pixelCount) { | ||
ESP_LOGE(tag, "setPixel: index out of range: %d", index); | ||
return; | ||
} | ||
this->pixels[index].red = red; | ||
this->pixels[index].green = green; | ||
this->pixels[index].blue = blue; | ||
} // setPixel | ||
|
||
|
||
void WS2812::setPixel(uint16_t index, pixel_t pixel) { | ||
if (index >= this->pixelCount) { | ||
ESP_LOGE(tag, "setPixel: index out of range: %d", index); | ||
return; | ||
} | ||
this->pixels[index] = pixel; | ||
} // setPixel | ||
|
||
void WS2812::setPixel(uint16_t index, uint32_t pixel) { | ||
if (index >= this->pixelCount) { | ||
ESP_LOGE(tag, "setPixel: index out of range: %d", index); | ||
return; | ||
} | ||
this->pixels[index].red = pixel & 0xff; | ||
this->pixels[index].green = (pixel & 0xff00) >> 8; | ||
this->pixels[index].blue = (pixel & 0xff0000) >> 16; | ||
} // setPixel | ||
|
||
void WS2812::clear() { | ||
uint16_t i; | ||
for (i=0; i<this->pixelCount; i++) { | ||
this->pixels[i].red = 0; | ||
this->pixels[i].green = 0; | ||
this->pixels[i].blue = 0; | ||
} | ||
} // clear | ||
|
||
WS2812::~WS2812() { | ||
free(this->items); | ||
free(this->pixels); | ||
} // ~WS2812() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
* WS2812.h | ||
* | ||
* Created on: Nov 27, 2016 | ||
* Author: kolban | ||
*/ | ||
|
||
#ifndef MAIN_WS2812_H_ | ||
#define MAIN_WS2812_H_ | ||
#include <stdint.h> | ||
#include <driver/rmt.h> | ||
typedef struct { | ||
uint8_t red; | ||
uint8_t green; | ||
uint8_t blue; | ||
} pixel_t; | ||
|
||
class WS2812 { | ||
public: | ||
WS2812(rmt_channel_t channel, gpio_num_t gpioNum, uint16_t pixelCount); | ||
void show(); | ||
void setPixel(uint16_t index, uint8_t red, uint8_t green, uint8_t blue); | ||
void setPixel(uint16_t index, pixel_t pixel); | ||
void setPixel(uint16_t index, uint32_t pixel); | ||
void clear(); | ||
virtual ~WS2812(); | ||
private: | ||
uint16_t pixelCount; | ||
rmt_channel_t channel; | ||
rmt_item32_t *items; | ||
pixel_t *pixels; | ||
}; | ||
|
||
#endif /* MAIN_WS2812_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# | ||
# Main component makefile. | ||
# | ||
# This Makefile can be left empty. By default, it will take the sources in the | ||
# src/ directory, compile them and link them into lib(subdirectory_name).a | ||
# in the build directory. This behaviour is entirely configurable, | ||
# please read the ESP-IDF documents if you need to do this. | ||
# |