diff --git a/examples/pwm_test/Makefile b/examples/pwm_test/Makefile new file mode 100644 index 0000000..36ee7d0 --- /dev/null +++ b/examples/pwm_test/Makefile @@ -0,0 +1,4 @@ +# Simple makefile for simple example +PROGRAM=pwm_test +COMPONENTS = FreeRTOS lwip core extras/pwm +include ../../common.mk diff --git a/examples/pwm_test/pwm_test.c b/examples/pwm_test/pwm_test.c new file mode 100644 index 0000000..d0372ac --- /dev/null +++ b/examples/pwm_test/pwm_test.c @@ -0,0 +1,50 @@ +/* Very basic example to test the pwm library + * Hook up an LED to pin14 and you should see the intensity change + * + * Part of esp-open-rtos + * Copyright (C) 2015 Javier Cardona (https://github.com/jcard0na) + * BSD Licensed as described in the file LICENSE + */ +#include "espressif/esp_common.h" +#include "esp/uart.h" +#include "FreeRTOS.h" +#include "task.h" +#include "pwm.h" + +void task1(void *pvParameters) +{ + printf("Hello from task1!\r\n"); + uint32_t const init_count = 0; + uint32_t count = init_count; + while(1) { + vTaskDelay(100); + printf("duty cycle set to %d/UINT16_MAX%%\r\n", count); + pwm_set_duty(count); + count += UINT16_MAX/17; + if (count > UINT16_MAX) + count = init_count; + } +} + +void user_init(void) +{ + uint8_t pins[1]; + uart_set_baud(0, 115200); + + printf("SDK version:%s\n", sdk_system_get_sdk_version()); + + printf("pwm_init(1, [14])\n"); + pins[0] = 14; + pwm_init(1, pins); + + printf("pwm_set_freq(1000) # 1 kHz\n"); + pwm_set_freq(1000); + + printf("pwm_set_duty(UINT16_MAX/2) # 50%%\n"); + pwm_set_duty(UINT16_MAX/2); + + printf("pwm_start()\n"); + pwm_start(); + + xTaskCreate(task1, (signed char *)"tsk1", 256, NULL, 2, NULL); +} diff --git a/extras/pwm/component.mk b/extras/pwm/component.mk new file mode 100644 index 0000000..6c96fbd --- /dev/null +++ b/extras/pwm/component.mk @@ -0,0 +1,9 @@ +# Component makefile for extras/pwm + +INC_DIRS += $(ROOT)extras/pwm + +# args for passing into compile rule generation +extras/pwm_INC_DIR = $(ROOT)extras/pwm +extras/pwm_SRC_DIR = $(ROOT)extras/pwm + +$(eval $(call component_compile_rules,extras/pwm)) diff --git a/extras/pwm/pwm.c b/extras/pwm/pwm.c new file mode 100644 index 0000000..338dff0 --- /dev/null +++ b/extras/pwm/pwm.c @@ -0,0 +1,181 @@ +/* Implementation of PWM support for the Espressif SDK. + * + * Part of esp-open-rtos + * Copyright (C) 2015 Guillem Pascual Ginovart (https://github.com/gpascualg) + * Copyright (C) 2015 Javier Cardona (https://github.com/jcard0na) + * BSD Licensed as described in the file LICENSE + */ +#include "pwm.h" + +#include +#include +#include +#include + +typedef struct PWMPinDefinition +{ + uint8_t pin; + uint8_t divider; +} PWMPin; + +typedef enum { + PERIOD_ON = 0, + PERIOD_OFF = 1 +} pwm_step_t; + + +typedef struct pwmInfoDefinition +{ + uint8_t running; + + uint16_t freq; + uint16_t dutyCicle; + + /* private */ + uint32_t _maxLoad; + uint32_t _onLoad; + uint32_t _offLoad; + pwm_step_t _step; + + uint16_t usedPins; + PWMPin pins[8]; +} PWMInfo; + +static PWMInfo pwmInfo; + +static void frc1_interrupt_handler(void) +{ + uint8_t i = 0; + bool out = true; + uint32_t load = pwmInfo._onLoad; + pwm_step_t step = PERIOD_ON; + + if (pwmInfo._step == PERIOD_ON) + { + out = false; + load = pwmInfo._offLoad; + step = PERIOD_OFF; + } + + for (; i < pwmInfo.usedPins; ++i) + { + gpio_write(pwmInfo.pins[i].pin, out); + } + + timer_set_load(FRC1, load); + pwmInfo._step = step; +} + +void pwm_init(uint8_t npins, uint8_t* pins) +{ + /* Assert number of pins is correct */ + if (npins > MAX_PWM_PINS) + { + printf("Incorrect number of PWM pins (%d)\n", npins); + return; + } + + /* Initialize */ + pwmInfo._maxLoad = 0; + pwmInfo._onLoad = 0; + pwmInfo._offLoad = 0; + pwmInfo._step = PERIOD_ON; + + /* Save pins information */ + pwmInfo.usedPins = npins; + + uint8_t i = 0; + for (; i < npins; ++i) + { + pwmInfo.pins[i].pin = pins[i]; + + /* configure GPIOs */ + gpio_enable(pins[i], GPIO_OUTPUT); + } + + /* Stop timers and mask interrupts */ + pwm_stop(); + + /* set up ISRs */ + _xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler); + + /* Flag not running */ + pwmInfo.running = 0; +} + +void pwm_set_freq(uint16_t freq) +{ + pwmInfo.freq = freq; + + /* Stop now to avoid load being used */ + if (pwmInfo.running) + { + pwm_stop(); + pwmInfo.running = 1; + } + + timer_set_frequency(FRC1, freq); + pwmInfo._maxLoad = timer_get_load(FRC1); + + if (pwmInfo.running) + { + pwm_start(); + } +} + +void pwm_set_duty(uint16_t duty) +{ + bool output; + + pwmInfo.dutyCicle = duty; + if (duty > 0 && duty < UINT16_MAX) { + pwm_restart(); + return; + } + + // 0% and 100% duty cycle are special cases: constant output. + pwm_stop(); + pwmInfo.running = 1; + output = (duty == UINT16_MAX); + for (uint8_t i = 0; i < pwmInfo.usedPins; ++i) + { + gpio_write(pwmInfo.pins[i].pin, output); + } +} + +void pwm_restart() +{ + if (pwmInfo.running) + { + pwm_stop(); + pwm_start(); + } +} + +void pwm_start() +{ + pwmInfo._onLoad = pwmInfo.dutyCicle * pwmInfo._maxLoad / UINT16_MAX; + pwmInfo._offLoad = pwmInfo._maxLoad - pwmInfo._onLoad; + pwmInfo._step = PERIOD_ON; + + // Trigger ON + uint8_t i = 0; + for (; i < pwmInfo.usedPins; ++i) + { + gpio_write(pwmInfo.pins[i].pin, true); + } + + timer_set_load(FRC1, pwmInfo._onLoad); + timer_set_reload(FRC1, false); + timer_set_interrupts(FRC1, true); + timer_set_run(FRC1, true); + + pwmInfo.running = 1; +} + +void pwm_stop() +{ + timer_set_interrupts(FRC1, false); + timer_set_run(FRC1, false); + pwmInfo.running = 0; +} diff --git a/extras/pwm/pwm.h b/extras/pwm/pwm.h new file mode 100644 index 0000000..ddf7f2b --- /dev/null +++ b/extras/pwm/pwm.h @@ -0,0 +1,18 @@ +/* Implementation of PWM support for the Espressif SDK. + * + * Part of esp-open-rtos + * Copyright (C) 2015 Guillem Pascual Ginovart (https://github.com/gpascualg) + * Copyright (C) 2015 Javier Cardona (https://github.com/jcard0na) + * BSD Licensed as described in the file LICENSE + */ +#include + +#define MAX_PWM_PINS 8 + +void pwm_init(uint8_t npins, uint8_t* pins); +void pwm_set_freq(uint16_t freq); +void pwm_set_duty(uint16_t duty); + +void pwm_restart(); +void pwm_start(); +void pwm_stop();