#include "extdrv/ws2812.h"
-static struct pio ws2812_gpio = LPC_GPIO_0_0;
-
/* Configure Selected GPIO as output. */
-void ws2812_config(const struct pio* gpio)
+void ws2812_config(struct ws2812_conf* ws2812, const struct pio* gpio)
{
struct pin_matrix_entry mat = LPC_GPIO;
config_pio(gpio, &mat, LPC_IO_MODE_PULL_UP);
- pio_copy(&ws2812_gpio, gpio);
- gpio_dir_out(ws2812_gpio);
-}
+ pio_copy(&(ws2812->gpio), gpio);
+ gpio_dir_out(ws2812->gpio);
-static uint8_t led_data[NB_LEDS * 3];
-static uint16_t max_led = 0;
-static uint32_t nb_bytes = 0;
+ ws2812->nb_bytes = 0;
+ ws2812->max_led = 0;
+ if (ws2812->inverted == 0) {
+ gpio_clear(ws2812->gpio);
+ } else {
+ gpio_set(ws2812->gpio);
+ }
+}
-static void ws2812_bit_sender(void)
+
+static void ws2812_bit_sender(struct ws2812_conf* ws2812)
{
- struct lpc_gpio* gpio_port = LPC_GPIO_REGS(ws2812_gpio.port);
- uint32_t gpio_bit = (1 << ws2812_gpio.pin);
+ struct lpc_gpio* gpio_port = LPC_GPIO_REGS(ws2812->gpio.port);
+ uint32_t gpio_bit = (1 << ws2812->gpio.pin);
uint32_t byte_idx = 0;
uint8_t bit_idx = 7;
uint8_t bit = 0;
+ uint8_t data = (ws2812->led_data[0] * ws2812->brightness) >> 8;
lpc_disable_irq();
/* Send data */
- while (byte_idx < nb_bytes) {
- bit = (led_data[byte_idx] & (0x01 << bit_idx));
+ while (byte_idx < ws2812->nb_bytes) {
+ bit = (data & (0x01 << bit_idx));
if (bit == 0) {
/* "high" time : 350ns */
- gpio_port->set = gpio_bit;
+ gpio_port->toggle = gpio_bit;
nop();
nop();
nop();
nop();
nop();
/* "low" time : 800ns */
- gpio_port->clear = gpio_bit;
+ gpio_port->toggle = gpio_bit;
nop();
nop();
nop();
nop();
} else {
/* "high" time : 700ns */
- gpio_port->set = gpio_bit;
+ gpio_port->toggle = gpio_bit;
nop();
nop();
nop();
nop();
nop();
/* "high" time : 600ns */
- gpio_port->clear = gpio_bit;
+ gpio_port->toggle = gpio_bit;
+ nop();
+ nop();
+ }
+
+ /* Move to the next bit */
+ if (bit_idx == 0) {
+ bit_idx = 7;
+ byte_idx++;
+ data = (ws2812->led_data[byte_idx] * ws2812->brightness) >> 8;
+ } else {
+ bit_idx--;
+ }
+ }
+
+ lpc_enable_irq();
+}
+
+static void ws2811_bit_sender(struct ws2812_conf* ws2812)
+{
+ struct lpc_gpio* gpio_port = LPC_GPIO_REGS(ws2812->gpio.port);
+ uint32_t gpio_bit = (1 << ws2812->gpio.pin);
+ uint32_t byte_idx = 0;
+ uint8_t bit_idx = 7;
+ uint8_t bit = 0;
+ uint8_t data = (ws2812->led_data[0] * ws2812->brightness) >> 8;
+
+ lpc_disable_irq();
+
+ /* Send data */
+ while (byte_idx < ws2812->nb_bytes) {
+ bit = (data & (0x01 << bit_idx));
+
+ if (bit == 0) {
+ /* "high" time : 500ns */
+ gpio_port->toggle = gpio_bit;
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ /* "low" time : 2000ns */
+ gpio_port->toggle = gpio_bit;
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ } else {
+ /* "high" time : 1200ns */
+ gpio_port->toggle = gpio_bit;
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ /* "high" time : 1300ns */
+ gpio_port->toggle = gpio_bit;
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
+ nop();
nop();
nop();
}
if (bit_idx == 0) {
bit_idx = 7;
byte_idx++;
+ data = (ws2812->led_data[byte_idx] * ws2812->brightness) >> 8;
} else {
bit_idx--;
}
* Call to this function will disable interrupts due to timming restrictions during
* the call to ws2812_bit_sender().
*/
-int ws2812_send_frame(uint16_t nb_leds)
+int ws2812_send_frame(struct ws2812_conf* ws2812, uint16_t nb_leds)
{
- if (nb_leds > NB_LEDS) {
- return -1;
+ if (nb_leds > ws2812->nb_leds) {
+ nb_leds = ws2812->nb_leds;
}
if (nb_leds == 0) {
- nb_leds = max_led;
+ nb_leds = ws2812->max_led + 1;
+ }
+ ws2812->nb_bytes = nb_leds * 3;
+ switch (ws2812->type) {
+ case WS_LED_WS2811:
+ ws2811_bit_sender(ws2812);
+ break;
+ case WS_LED_WS2812:
+ default:
+ ws2812_bit_sender(ws2812);
+ break;
}
- nb_bytes = (nb_leds + 1) * 3;
- ws2812_bit_sender();
- /* Reset delay */
- usleep(60);
return 0;
}
/* Set a pixel (led) color in the data buffer */
-int ws2812_set_pixel(uint16_t pixel_num, uint8_t red, uint8_t green, uint8_t blue)
+int ws2812_set_pixel(struct ws2812_conf* ws2812, uint16_t pixel_num, uint8_t red, uint8_t green, uint8_t blue)
{
- if (pixel_num >= NB_LEDS) {
+ if (pixel_num >= ws2812->nb_leds) {
return -1;
}
- led_data[ ((pixel_num * 3) + 0) ] = green;
- led_data[ ((pixel_num * 3) + 1) ] = red;
- led_data[ ((pixel_num * 3) + 2) ] = blue;
- if (max_led < pixel_num) {
- max_led = pixel_num;
+ switch (ws2812->type) {
+ case WS_LED_WS2811:
+ ws2812->led_data[ ((pixel_num * 3) + 0) ] = red;
+ ws2812->led_data[ ((pixel_num * 3) + 1) ] = green;
+ ws2812->led_data[ ((pixel_num * 3) + 2) ] = blue;
+ break;
+ case WS_LED_WS2812:
+ default:
+ ws2812->led_data[ ((pixel_num * 3) + 0) ] = green;
+ ws2812->led_data[ ((pixel_num * 3) + 1) ] = red;
+ ws2812->led_data[ ((pixel_num * 3) + 2) ] = blue;
+ break;
+ }
+ if (ws2812->max_led < pixel_num) {
+ ws2812->max_led = pixel_num;
}
return 0;
}
/* Clear the internal data buffer. */
-void ws2812_clear_buffer(void)
+void ws2812_clear_buffer(struct ws2812_conf* ws2812)
{
- memset(led_data, 0, (NB_LEDS * 3));
- max_led = 0;
+ memset(ws2812->led_data, 0, (ws2812->nb_leds * 3));
+ ws2812->max_led = 0;
}
/* Clear the internal data buffer and send it to the Leds, turning them all off */
-void ws2812_clear(void)
+void ws2812_clear(struct ws2812_conf* ws2812)
{
/* Start at first led and send all leds off */
- ws2812_clear_buffer();
- ws2812_send_frame(NB_LEDS);
- max_led = 0;
+ ws2812_clear_buffer(ws2812);
+ ws2812_send_frame(ws2812, ws2812->nb_leds);
+ ws2812->max_led = 0;
}
-void ws2812_stop(void) __attribute__ ((alias ("ws2812_clear")));
+void ws2812_stop(struct ws2812_conf* ws2812) __attribute__ ((alias ("ws2812_clear")));
#include "core/pio.h"
-/* Size of the internal buffer.
- * Change the value to the number of leds of your led strip.
- */
-#define NB_LEDS 60
+enum ws_led_type {
+ WS_LED_WS2812,
+ WS_LED_WS2811,
+};
+
+
+struct ws2812_conf {
+ struct pio gpio;
+ uint8_t* led_data;
+ uint32_t nb_bytes;
+ uint16_t nb_leds;
+ uint16_t max_led;
+ uint8_t inverted;
+ uint8_t brightness;
+ uint8_t type;
+};
/* Configure the pin for the led data signal. */
-void ws2812_config(const struct pio* gpio);
+void ws2812_config(struct ws2812_conf* ws2812, const struct pio* gpio);
/* Send led data from internal buffer using the configured GPIO pin. (Set leds to the
* selected color).
* Call to this function will disable interrupts due to timming restrictions.
* Return -1 on error (nb_leds above NB_LEDS), or 0 on success.
*/
-int ws2812_send_frame(uint16_t nb_leds);
+int ws2812_send_frame(struct ws2812_conf* ws2812, uint16_t nb_leds);
/* Set a pixel (led) color in the data buffer (frame)
* The pixel number 'pixel_num' is the led offset in the led strip.
* while a value of 0xFF (255) is full brightness.
* Return -1 on error (pixel_num above NB_LEDS), or 0 on success.
*/
-int ws2812_set_pixel(uint16_t pixel_num, uint8_t red, uint8_t green, uint8_t blue);
+int ws2812_set_pixel(struct ws2812_conf* ws2812, uint16_t pixel_num, uint8_t red, uint8_t green, uint8_t blue);
/* Clear the internal data buffer. */
-void ws2812_clear_buffer(void);
+void ws2812_clear_buffer(struct ws2812_conf* ws2812);
/* Clear the internal data buffer and send it to the Leds, turning them all off */
-void ws2812_clear(void);
+void ws2812_clear(struct ws2812_conf* ws2812);
/* Alias for ws2812_clear */
-void ws2812_stop(void);
+void ws2812_stop(struct ws2812_conf* ws2812);