diff --git a/src/Kconfig b/src/Kconfig index 0445685e..db265c96 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -21,6 +21,9 @@ config HAVE_GPIO_ADC config HAVE_GPIO_SPI bool default n +config HAVE_GPIO_HARD_PWM + bool + default n config INLINE_STEPPER_HACK # Enables gcc to inline stepper_event() into the main timer irq handler diff --git a/src/Makefile b/src/Makefile index 5c7dc085..b4a4c33e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -3,3 +3,4 @@ src-y += sched.c command.c stepper.c basecmd.c gpiocmds.c endstop.c src-$(CONFIG_HAVE_GPIO_ADC) += adccmds.c src-$(CONFIG_HAVE_GPIO_SPI) += spicmds.c +src-$(CONFIG_HAVE_GPIO_HARD_PWM) += pwmcmds.c diff --git a/src/avr/Kconfig b/src/avr/Kconfig index efc8484a..8d5d4522 100644 --- a/src/avr/Kconfig +++ b/src/avr/Kconfig @@ -7,6 +7,7 @@ config AVR_SELECT default y select HAVE_GPIO_ADC select HAVE_GPIO_SPI + select HAVE_GPIO_HARD_PWM config BOARD_DIRECTORY string diff --git a/src/gpiocmds.c b/src/gpiocmds.c index 283d3d2e..70608a6f 100644 --- a/src/gpiocmds.c +++ b/src/gpiocmds.c @@ -4,12 +4,11 @@ // // This file may be distributed under the terms of the GNU GPLv3 license. -#include // offsetof #include "basecmd.h" // alloc_oid -#include "board/gpio.h" // struct gpio +#include "board/gpio.h" // struct gpio_out #include "board/irq.h" // irq_save #include "command.h" // DECL_COMMAND -#include "sched.h" // DECL_TASK +#include "sched.h" // sched_timer /**************************************************************** @@ -86,73 +85,6 @@ command_set_digital_out(uint32_t *args) DECL_COMMAND(command_set_digital_out, "set_digital_out pin=%u value=%c"); -/**************************************************************** - * Hardware PWM pins - ****************************************************************/ - -struct pwm_out_s { - struct timer timer; - struct gpio_pwm pin; - uint32_t max_duration; - uint8_t value, default_value; -}; - -static uint8_t -pwm_event(struct timer *timer) -{ - struct pwm_out_s *p = container_of(timer, struct pwm_out_s, timer); - gpio_pwm_write(p->pin, p->value); - if (p->value == p->default_value || !p->max_duration) - return SF_DONE; - p->timer.waketime += p->max_duration; - p->timer.func = digital_end_event; - return SF_RESCHEDULE; -} - -void -command_config_pwm_out(uint32_t *args) -{ - struct pwm_out_s *p = alloc_oid(args[0], command_config_pwm_out, sizeof(*p)); - p->default_value = args[3]; - p->pin = gpio_pwm_setup(args[1], args[2], p->default_value); - p->max_duration = args[4]; -} -DECL_COMMAND(command_config_pwm_out, - "config_pwm_out oid=%c pin=%u cycle_ticks=%u default_value=%c" - " max_duration=%u"); - -void -command_schedule_pwm_out(uint32_t *args) -{ - struct pwm_out_s *p = lookup_oid(args[0], command_config_pwm_out); - sched_del_timer(&p->timer); - p->timer.func = pwm_event; - p->timer.waketime = args[1]; - p->value = args[2]; - sched_timer(&p->timer); -} -DECL_COMMAND(command_schedule_pwm_out, - "schedule_pwm_out oid=%c clock=%u value=%c"); - -static void -pwm_shutdown(void) -{ - uint8_t i; - struct pwm_out_s *p; - foreach_oid(i, p, command_config_pwm_out) { - gpio_pwm_write(p->pin, p->default_value); - } -} -DECL_SHUTDOWN(pwm_shutdown); - -void -command_set_pwm_out(uint32_t *args) -{ - gpio_pwm_setup(args[0], args[1], args[2]); -} -DECL_COMMAND(command_set_pwm_out, "set_pwm_out pin=%u cycle_ticks=%u value=%c"); - - /**************************************************************** * Soft PWM output pins ****************************************************************/ diff --git a/src/pwmcmds.c b/src/pwmcmds.c new file mode 100644 index 00000000..bc9fec03 --- /dev/null +++ b/src/pwmcmds.c @@ -0,0 +1,78 @@ +// Commands for controlling hardware based pulse-width-modulator pins +// +// Copyright (C) 2016 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "basecmd.h" // alloc_oid +#include "board/gpio.h" // struct gpio_pwm +#include "command.h" // DECL_COMMAND +#include "sched.h" // sched_timer + +struct pwm_out_s { + struct timer timer; + struct gpio_pwm pin; + uint32_t max_duration; + uint8_t value, default_value; +}; + +static uint8_t +pwm_end_event(struct timer *timer) +{ + shutdown("Missed scheduling of next hard pwm event"); +} + +static uint8_t +pwm_event(struct timer *timer) +{ + struct pwm_out_s *p = container_of(timer, struct pwm_out_s, timer); + gpio_pwm_write(p->pin, p->value); + if (p->value == p->default_value || !p->max_duration) + return SF_DONE; + p->timer.waketime += p->max_duration; + p->timer.func = pwm_end_event; + return SF_RESCHEDULE; +} + +void +command_config_pwm_out(uint32_t *args) +{ + struct pwm_out_s *p = alloc_oid(args[0], command_config_pwm_out, sizeof(*p)); + p->default_value = args[3]; + p->pin = gpio_pwm_setup(args[1], args[2], p->default_value); + p->max_duration = args[4]; +} +DECL_COMMAND(command_config_pwm_out, + "config_pwm_out oid=%c pin=%u cycle_ticks=%u default_value=%c" + " max_duration=%u"); + +void +command_schedule_pwm_out(uint32_t *args) +{ + struct pwm_out_s *p = lookup_oid(args[0], command_config_pwm_out); + sched_del_timer(&p->timer); + p->timer.func = pwm_event; + p->timer.waketime = args[1]; + p->value = args[2]; + sched_timer(&p->timer); +} +DECL_COMMAND(command_schedule_pwm_out, + "schedule_pwm_out oid=%c clock=%u value=%c"); + +static void +pwm_shutdown(void) +{ + uint8_t i; + struct pwm_out_s *p; + foreach_oid(i, p, command_config_pwm_out) { + gpio_pwm_write(p->pin, p->default_value); + } +} +DECL_SHUTDOWN(pwm_shutdown); + +void +command_set_pwm_out(uint32_t *args) +{ + gpio_pwm_setup(args[0], args[1], args[2]); +} +DECL_COMMAND(command_set_pwm_out, "set_pwm_out pin=%u cycle_ticks=%u value=%c");