neopixel: Add initial support for "neopixel" leds
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
977d0cf711
commit
b7bc96c3b2
|
@ -1648,6 +1648,16 @@
|
||||||
#measurement_delay: 100
|
#measurement_delay: 100
|
||||||
|
|
||||||
|
|
||||||
|
# Neopixel (aka WS2812) LED support (one may define any number of
|
||||||
|
# sections with a "neopixel" prefix). One may set the LED color via a
|
||||||
|
# "SET_NEOPIXEL NEOPIXEL=my_neopixel RED=0.1 GREEN=0.1 BLUE=0.1" type
|
||||||
|
# extended g-code commands.
|
||||||
|
#[neopixel my_neopixel]
|
||||||
|
#pin:
|
||||||
|
# The pin connected to the neopixel. This parameter must be
|
||||||
|
# provided.
|
||||||
|
|
||||||
|
|
||||||
# Firmware filament retraction. This enables G10 (retract) and G11
|
# Firmware filament retraction. This enables G10 (retract) and G11
|
||||||
# (unretract) GCODE commands issued by many slicers. The parameters
|
# (unretract) GCODE commands issued by many slicers. The parameters
|
||||||
# below provide startup defaults, although the values can be adjusted
|
# below provide startup defaults, although the values can be adjusted
|
||||||
|
|
|
@ -191,6 +191,14 @@ The following command is available when an "output_pin" config section
|
||||||
is enabled:
|
is enabled:
|
||||||
- `SET_PIN PIN=config_name VALUE=<value>`
|
- `SET_PIN PIN=config_name VALUE=<value>`
|
||||||
|
|
||||||
|
## Neopixel Commands
|
||||||
|
|
||||||
|
The following command is available when a "neopixel" config section
|
||||||
|
is enabled:
|
||||||
|
- `SET_NEOPIXEL NEOPIXEL=<config_name> RED=<value> GREEN=<value>
|
||||||
|
BLUE=<value>`: This sets the neopixel LED output. Each <value> must
|
||||||
|
be between 0.0 and 1.0.
|
||||||
|
|
||||||
## Servo Commands
|
## Servo Commands
|
||||||
|
|
||||||
The following commands are available when a "servo" config section is
|
The following commands are available when a "servo" config section is
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Support for "neopixel" leds
|
||||||
|
#
|
||||||
|
# Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
|
||||||
|
class PrinterNeoPixel:
|
||||||
|
def __init__(self, config):
|
||||||
|
self.printer = config.get_printer()
|
||||||
|
name = config.get_name().split()[1]
|
||||||
|
# Configure neopixel
|
||||||
|
ppins = self.printer.lookup_object('pins')
|
||||||
|
pin_params = ppins.lookup_pin(config.get('pin'))
|
||||||
|
self.mcu = pin_params['chip']
|
||||||
|
self.oid = self.mcu.create_oid()
|
||||||
|
self.mcu.add_config_cmd("config_neopixel oid=%d pin=%s"
|
||||||
|
% (self.oid, pin_params['pin']))
|
||||||
|
self.mcu.register_config_callback(self.build_config)
|
||||||
|
self.neopixel_send_cmd = None
|
||||||
|
# Register commands
|
||||||
|
self.gcode = self.printer.lookup_object('gcode')
|
||||||
|
self.gcode.register_mux_command("SET_NEOPIXEL", "NEOPIXEL", name,
|
||||||
|
self.cmd_SET_NEOPIXEL,
|
||||||
|
desc=self.cmd_SET_NEOPIXEL_help)
|
||||||
|
def build_config(self):
|
||||||
|
cmd_queue = self.mcu.alloc_command_queue()
|
||||||
|
self.neopixel_send_cmd = self.mcu.lookup_command(
|
||||||
|
"neopixel_send oid=%c data=%*s", cq=cmd_queue)
|
||||||
|
cmd_SET_NEOPIXEL_help = "Set the color of a neopixel led"
|
||||||
|
def cmd_SET_NEOPIXEL(self, params):
|
||||||
|
# Parse parameters
|
||||||
|
red = self.gcode.get_float('RED', params, 0., minval=0., maxval=1.)
|
||||||
|
green = self.gcode.get_float('GREEN', params, 0., minval=0., maxval=1.)
|
||||||
|
blue = self.gcode.get_float('BLUE', params, 0., minval=0., maxval=1.)
|
||||||
|
red = int(red * 255. + .5)
|
||||||
|
blue = int(blue * 255. + .5)
|
||||||
|
green = int(green * 255. + .5)
|
||||||
|
# Send command
|
||||||
|
print_time = self.printer.lookup_object('toolhead').get_last_move_time()
|
||||||
|
minclock = self.mcu.print_time_to_clock(print_time)
|
||||||
|
self.neopixel_send_cmd.send([self.oid, [green, red, blue]],
|
||||||
|
minclock=minclock)
|
||||||
|
|
||||||
|
def load_config_prefix(config):
|
||||||
|
return PrinterNeoPixel(config)
|
|
@ -7,4 +7,4 @@ src-$(CONFIG_HAVE_GPIO_SPI) += spicmds.c thermocouple.c
|
||||||
src-$(CONFIG_HAVE_GPIO_I2C) += i2ccmds.c
|
src-$(CONFIG_HAVE_GPIO_I2C) += i2ccmds.c
|
||||||
src-$(CONFIG_HAVE_GPIO_HARD_PWM) += pwmcmds.c
|
src-$(CONFIG_HAVE_GPIO_HARD_PWM) += pwmcmds.c
|
||||||
src-$(CONFIG_HAVE_GPIO_BITBANGING) += lcd_st7920.c lcd_hd44780.c buttons.c \
|
src-$(CONFIG_HAVE_GPIO_BITBANGING) += lcd_st7920.c lcd_hd44780.c buttons.c \
|
||||||
tmcuart.c spi_software.c
|
tmcuart.c spi_software.c neopixel.c
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
// Support for bit-banging commands to WS2812 type "neopixel" LEDs
|
||||||
|
//
|
||||||
|
// Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
//
|
||||||
|
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
|
||||||
|
#include "autoconf.h" // CONFIG_MACH_AVR
|
||||||
|
#include "board/gpio.h" // gpio_out_write
|
||||||
|
#include "board/irq.h" // irq_poll
|
||||||
|
#include "board/misc.h" // timer_read_time
|
||||||
|
#include "basecmd.h" // oid_alloc
|
||||||
|
#include "command.h" // DECL_COMMAND
|
||||||
|
|
||||||
|
struct neopixel_s {
|
||||||
|
struct gpio_out pin;
|
||||||
|
uint32_t last_req_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
command_config_neopixel(uint32_t *args)
|
||||||
|
{
|
||||||
|
struct gpio_out pin = gpio_out_setup(args[1], 0);
|
||||||
|
struct neopixel_s *n = oid_alloc(args[0], command_config_neopixel
|
||||||
|
, sizeof(*n));
|
||||||
|
n->pin = pin;
|
||||||
|
}
|
||||||
|
#if !CONFIG_MACH_AVR
|
||||||
|
DECL_COMMAND(command_config_neopixel, "config_neopixel oid=%c pin=%u");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
timer_from_ns(uint32_t ns)
|
||||||
|
{
|
||||||
|
return timer_from_us(ns * 1000) / 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
send_data(struct neopixel_s *n, uint8_t *data, uint_fast8_t data_len)
|
||||||
|
{
|
||||||
|
// Make sure at least 50us has passed since last request
|
||||||
|
uint32_t last_req_time = n->last_req_time, cur = timer_read_time();
|
||||||
|
while (cur - last_req_time < timer_from_us(50)) {
|
||||||
|
irq_poll();
|
||||||
|
cur = timer_read_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct gpio_out pin = n->pin;
|
||||||
|
uint32_t expire_time = cur + 0x40000000;
|
||||||
|
while (data_len--) {
|
||||||
|
uint_fast8_t byte = *data++;
|
||||||
|
uint_fast8_t bits = 8;
|
||||||
|
while (bits--) {
|
||||||
|
// Calculate pulse duration
|
||||||
|
uint32_t on, off;
|
||||||
|
if (byte & 0x80) {
|
||||||
|
on = timer_from_ns(700 - 150);
|
||||||
|
off = timer_from_ns(600 - 150);
|
||||||
|
} else {
|
||||||
|
on = timer_from_ns(350 - 150);
|
||||||
|
off = timer_from_ns(800 - 150);
|
||||||
|
}
|
||||||
|
byte <<= 1;
|
||||||
|
|
||||||
|
// Set output high
|
||||||
|
gpio_out_toggle(pin);
|
||||||
|
uint32_t on_start_time = timer_read_time();
|
||||||
|
if (timer_is_before(expire_time, on_start_time))
|
||||||
|
goto fail;
|
||||||
|
cur = on_start_time;
|
||||||
|
while (timer_is_before(cur, on_start_time + on)) {
|
||||||
|
irq_poll();
|
||||||
|
cur = timer_read_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set output low
|
||||||
|
gpio_out_toggle(pin);
|
||||||
|
uint32_t off_start_time = timer_read_time();
|
||||||
|
expire_time = on_start_time + on + timer_from_ns(300);
|
||||||
|
if (timer_is_before(expire_time, off_start_time))
|
||||||
|
goto fail;
|
||||||
|
cur = off_start_time;
|
||||||
|
while (timer_is_before(cur, off_start_time + off)) {
|
||||||
|
irq_poll();
|
||||||
|
cur = timer_read_time();
|
||||||
|
}
|
||||||
|
expire_time = off_start_time + off + timer_from_ns(300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n->last_req_time = cur;
|
||||||
|
return 0;
|
||||||
|
fail:
|
||||||
|
// A hardware irq messed up the transmission - report a failure
|
||||||
|
n->last_req_time = cur;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
command_neopixel_send(uint32_t *args)
|
||||||
|
{
|
||||||
|
uint8_t oid = args[0];
|
||||||
|
struct neopixel_s *n = oid_lookup(oid, command_config_neopixel);
|
||||||
|
uint_fast8_t data_len = args[1];
|
||||||
|
uint8_t *data = (void*)(size_t)args[2];
|
||||||
|
|
||||||
|
uint_fast8_t retry = 8;
|
||||||
|
while (retry--) {
|
||||||
|
int ret = send_data(n, data, data_len);
|
||||||
|
if (!ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if !CONFIG_MACH_AVR
|
||||||
|
DECL_COMMAND(command_neopixel_send, "neopixel_send oid=%c data=%*s");
|
||||||
|
#endif
|
Loading…
Reference in New Issue