mlaz closed pull request #836: PWM add cycle interrupt handling to pwm_nrf52 
driver
URL: https://github.com/apache/mynewt-core/pull/836
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/apps/pwm_test/pkg.yml b/apps/pwm_test/pkg.yml
index 83b4013b0..44d6f32ef 100644
--- a/apps/pwm_test/pkg.yml
+++ b/apps/pwm_test/pkg.yml
@@ -28,3 +28,4 @@ pkg.deps:
     - kernel/os
     - sys/console/full
     - hw/drivers/pwm
+    - util/easing
diff --git a/apps/pwm_test/src/main.c b/apps/pwm_test/src/main.c
index 34d5cf727..b57a437af 100755
--- a/apps/pwm_test/src/main.c
+++ b/apps/pwm_test/src/main.c
@@ -21,96 +21,128 @@
 #include <os/os.h>
 #include <pwm/pwm.h>
 #include <bsp/bsp.h>
+#include <easing/easing.h>
+#include <console/console.h>
 
 struct pwm_dev *pwm;
-uint16_t max_val;
-static struct os_callout my_callout;
+static uint32_t pwm_freq = 1000;
+static uint32_t max_steps = 500; /* two seconds motion up/down */
+static uint16_t top_val;
+static volatile uint32_t step = 0;
+static volatile bool up = false;
+static volatile int func_num = 1;
+static easing_int_func_t easing_funct = sine_int_io;
+
+static void
+pwm_cycle_handler(void* unused)
+{
+    int16_t eased;
+    eased = easing_funct(step, max_steps, top_val);
+    pwm_enable_duty_cycle(pwm, 0, eased);
+    if (step >= max_steps || step <= 0) {
+        up = !up;
+    }
+
+    step += (up) ? 1 : -1;
+}
+
+static void
+pwm_end_seq_handler(void* chan_conf)
+{
+    int rc;
+    step = 0;
+    up = false;
+
+    switch (func_num)
+    {
+    case 0:
+        easing_funct = sine_int_io;
+        console_printf ("Easing: sine io\n");
+        break;
+    case 1:
+        easing_funct = bounce_int_io;
+        console_printf ("Easing: bounce io\n");
+        break;
+    case 2:
+        easing_funct = circular_int_io;
+        console_printf ("Easing: circular io\n");
+        break;
+    case 3:
+        easing_funct = quadratic_int_io;
+        console_printf ("Easing: quadratic io\n");
+        break;
+    case 4:
+        easing_funct = cubic_int_io;
+        console_printf ("Easing: cubic io\n");
+        break;
+    case 5:
+        easing_funct = quartic_int_io;
+        console_printf ("Easing: quartic io\n");
+        break;
+    default:
+        easing_funct = quintic_int_io;
+        console_printf ("Easing: quintic io\n");
+    }
+
+    if (func_num > 5) {
+        func_num = 0;
+    } else {
+        func_num++;
+    }
+    rc = pwm_enable_duty_cycle(pwm, 0, top_val);
+    assert(rc == 0);
+}
 
 int
 pwm_init(void)
 {
-    struct pwm_chan_cfg chan_conf = {
-        .pin = LED_BLINK_PIN,
-        .inverted = true,
-        .data = NULL
+    struct pwm_dev_interrupt_cfg chan_conf = {
+        .cfg = {
+            .pin = LED_BLINK_PIN,
+            .inverted = true,
+            .n_cycles = pwm_freq * 5, /* 5 seconds */
+            .interrupts_cfg = true,
+            .data = NULL,
+        },
+        .int_prio = 3,
+        .cycle_handler = pwm_cycle_handler, /* this won't work on soft_pwm */
+        .cycle_data = NULL,
+        .seq_end_handler = pwm_end_seq_handler, /* this won't work on soft_pwm 
*/
+        .seq_end_data = NULL
     };
-    uint32_t base_freq;
     int rc;
 
+    chan_conf.seq_end_data = &chan_conf;
+
 #if MYNEWT_VAL(SOFT_PWM)
     pwm = (struct pwm_dev *) os_dev_open("spwm", 0, NULL);
+    chan_conf.cfg.interrupts_cfg = false;
 #else
     pwm = (struct pwm_dev *) os_dev_open("pwm0", 0, NULL);
 #endif
 
     /* set the PWM frequency */
-    pwm_set_frequency(pwm, 10000);
-    base_freq = pwm_get_clock_freq(pwm);
-    max_val = (uint16_t) (base_freq / 10000);
-
-    /* setup led 1 - 100% duty cycle*/
-    rc = pwm_chan_config(pwm, 0, &chan_conf);
-    assert(rc == 0);
+    pwm_set_frequency(pwm, 1000);
+    top_val = (uint16_t) pwm_get_top_value(pwm);
 
-    rc = pwm_enable_duty_cycle(pwm, 0, max_val);
+    /* setup led 1 */
+    rc = pwm_chan_config(pwm, 0, (struct pwm_chan_cfg*) &chan_conf);
     assert(rc == 0);
 
-#ifdef LED_2
-    /* setup led 2 - 50% duty cycle */
-    chan_conf.pin = LED_2;
-    rc = pwm_chan_config(pwm, 1, &chan_conf);
-    assert(rc == 0);
-
-    rc = pwm_enable_duty_cycle(pwm, 1, max_val/2);
-    assert(rc == 0);
-#endif
-#ifdef LED_3
-    /* setup led 3 - 25% duty cycle */
-    chan_conf.pin = LED_3;
-    rc = pwm_chan_config(pwm, 2, &chan_conf);
-    assert(rc == 0);
-
-    rc = pwm_enable_duty_cycle(pwm, 2, max_val/4);
-    assert(rc == 0);
-#endif
-#ifdef LED_4
-    /* setup led 4 - 10% duty cycle */
-    chan_conf.pin = LED_4;
-    rc = pwm_chan_config(pwm, 3, &chan_conf);
-    assert(rc == 0);
+    console_printf ("Easing: sine io\n");
 
-    rc = pwm_enable_duty_cycle(pwm, 3, max_val/10);
+    rc = pwm_enable_duty_cycle(pwm, 0, top_val);
     assert(rc == 0);
-#endif
 
     return rc;
 }
 
-static void
-pwm_toggle(struct os_event *ev)
-{
-    int rc;
-
-    if(pwm!=0){
-        rc = os_dev_close((struct os_dev *)pwm);
-        assert(rc == 0);
-        pwm = NULL;
-    }else{
-        rc = pwm_init();
-        assert(rc == 0);
-    }
-    os_callout_reset(&my_callout, OS_TICKS_PER_SEC * 5);
-}
-
 int
 main(int argc, char **argv)
 {
     sysinit();
 
-    os_callout_init(&my_callout, os_eventq_dflt_get(),
-                    pwm_toggle, NULL);
-
-    os_callout_reset(&my_callout, OS_TICKS_PER_SEC * 5);
+    pwm_init();
 
     while (1) {
         os_eventq_run(os_eventq_dflt_get());
diff --git a/hw/drivers/pwm/include/pwm/pwm.h b/hw/drivers/pwm/include/pwm/pwm.h
index 84e6e5cff..745702bef 100644
--- a/hw/drivers/pwm/include/pwm/pwm.h
+++ b/hw/drivers/pwm/include/pwm/pwm.h
@@ -42,7 +42,7 @@ typedef int (*pwm_configure_channel_func_t)(struct pwm_dev *,
                                             uint8_t,
                                             struct pwm_chan_cfg *);
 
- /**
+/**
  * Enable the PWM with specified duty cycle.
  *
  * This duty cycle is a fractional duty cycle where 0 == off, 65535=on,
@@ -80,6 +80,16 @@ typedef int (*pwm_set_frequency_func_t) (struct pwm_dev *, 
uint32_t);
  */
 typedef int (*pwm_get_clock_freq_func_t) (struct pwm_dev *);
 
+/**
+ * Get the top value for the cycle counter, i.e. the value which sets
+ * the duty cycle to 100%.
+ *
+ * @param dev
+ *
+ * @return value in cycles on success, negative on error.
+ */
+typedef int (*pwm_get_top_value_funct_t) (struct pwm_dev *dev);
+
 /**
  * Get the resolution of the PWM in bits.
  *
@@ -99,11 +109,14 @@ typedef int (*pwm_get_resolution_bits_func_t) (struct 
pwm_dev *);
  */
 typedef int (*pwm_disable_func_t) (struct pwm_dev *, uint8_t);
 
+typedef void (*user_handler_t) (void*);
+
 struct pwm_driver_funcs {
     pwm_configure_channel_func_t pwm_configure_channel;
     pwm_enable_duty_cycle_func_t pwm_enable_duty_cycle;
     pwm_set_frequency_func_t pwm_set_frequency;
     pwm_get_clock_freq_func_t pwm_get_clock_freq;
+    pwm_get_top_value_funct_t pwm_get_top_value;
     pwm_get_resolution_bits_func_t pwm_get_resolution_bits;
     pwm_disable_func_t pwm_disable;
 };
@@ -121,18 +134,43 @@ struct pwm_dev {
  *
  * pin - The pin to be assigned to this pwm channel.
  * inverted - Whether this channel's output polarity is inverted or not.
- * data - A pointer do a driver specific parameter.
+ * n_cycles - The number of cycles for the channel to play. 0 for loop mode.
+ * interrupts - Whether interruptions are to be configured or not.
+ * data - Driver specific data.
  */
 struct pwm_chan_cfg {
     uint8_t pin;
     bool inverted;
+    uint32_t n_cycles;
+    bool interrupts_cfg;
     void* data;
 };
 
+/**
+ * PWM device interrupt configuration data.
+ *
+ * int_prio - Driver Interrupts priority.
+ * cycle_handler - A pointer to a user_handler_t function for a cycle 
interrupt.
+ * seq_end_handler - A pointer to a user_handler_t function for
+ * a end-of-sequence interrupt.
+ * cycle_data - User data to be passed to cycle_handler as a parameter.
+ * seq_end_data - User data to be passed to seq_end_handler as a parameter.
+ *
+ */
+struct pwm_dev_interrupt_cfg {
+    struct pwm_chan_cfg cfg;
+    uint32_t int_prio;
+    user_handler_t cycle_handler;
+    user_handler_t seq_end_handler;
+    void* cycle_data;
+    void* seq_end_data;
+};
+
 int pwm_chan_config(struct pwm_dev *dev, uint8_t cnum, struct pwm_chan_cfg 
*cfg);
 int pwm_enable_duty_cycle(struct pwm_dev *pwm_d, uint8_t cnum, uint16_t 
fraction);
 int pwm_set_frequency(struct pwm_dev *dev, uint32_t freq_hz);
 int pwm_get_clock_freq(struct pwm_dev *dev);
+int pwm_get_top_value(struct pwm_dev *dev);
 int pwm_get_resolution_bits(struct pwm_dev *dev);
 int pwm_disable(struct pwm_dev *dev, uint8_t cnum);
 
diff --git a/hw/drivers/pwm/pwm_nrf52/src/pwm_nrf52.c 
b/hw/drivers/pwm/pwm_nrf52/src/pwm_nrf52.c
index 09fe5ef0e..8390e856c 100644
--- a/hw/drivers/pwm/pwm_nrf52/src/pwm_nrf52.c
+++ b/hw/drivers/pwm/pwm_nrf52/src/pwm_nrf52.c
@@ -24,6 +24,7 @@
 #include <errno.h>
 #include <pwm/pwm.h>
 #include <string.h>
+#include <bsp/cmsis_nvic.h>
 
 /* Nordic headers */
 #include <nrfx.h>
@@ -39,6 +40,13 @@ struct nrf52_pwm_dev_global {
     nrfx_pwm_t drv_instance;
     nrfx_pwm_config_t config;
     nrf_pwm_values_individual_t duty_cycles;
+    uint32_t n_cycles;
+    nrfx_pwm_flag_t flags;
+    nrfx_pwm_handler_t internal_handler;
+    user_handler_t cycle_handler;
+    user_handler_t seq_end_handler;
+    void* cycle_data;
+    void* seq_end_data;
 };
 
 static struct nrf52_pwm_dev_global instances[] =
@@ -48,7 +56,14 @@ static struct nrf52_pwm_dev_global instances[] =
     [0].playing = false,
     [0].drv_instance = NRFX_PWM_INSTANCE(0),
     [0].config = NRFX_PWM_DEFAULT_CONFIG,
-    [0].duty_cycles = {0}
+    [0].flags = NRFX_PWM_FLAG_LOOP,
+    [0].duty_cycles = {0},
+    [0].n_cycles = 1,
+    [0].internal_handler = NULL,
+    [0].cycle_handler = NULL,
+    [0].cycle_data = NULL,
+    [0].seq_end_handler = NULL,
+    [0].seq_end_data = NULL
 #endif
 #if MYNEWT_VAL(PWM_1)
     ,
@@ -56,7 +71,14 @@ static struct nrf52_pwm_dev_global instances[] =
     [1].playing = false,
     [1].drv_instance = NRFX_PWM_INSTANCE(1),
     [1].config = NRFX_PWM_DEFAULT_CONFIG,
-    [1].duty_cycles = {0}
+    [1].flags = NRFX_PWM_FLAG_LOOP,
+    [1].duty_cycles = {0},
+    [1].n_cycles = 1,
+    [1].internal_handler = NULL,
+    [1].cycle_handler = NULL,
+    [1].cycle_data = NULL,
+    [1].seq_end_handler = NULL,
+    [1].seq_end_data = NULL
 #endif
 #if MYNEWT_VAL(PWM_2)
     ,
@@ -64,7 +86,14 @@ static struct nrf52_pwm_dev_global instances[] =
     [2].playing = false,
     [2].drv_instance = NRFX_PWM_INSTANCE(2),
     [2].config = NRFX_PWM_DEFAULT_CONFIG,
-    [2].duty_cycles = {0}
+    [2].flags = NRFX_PWM_FLAG_LOOP,
+    [2].duty_cycles = {0},
+    [2].n_cycles = 1,
+    [2].internal_handler = NULL,
+    [2].cycle_handler = NULL,
+    [2].cycle_data = NULL,
+    [2].seq_end_handler = NULL,
+    [2].seq_end_data = NULL
 #endif
 #if MYNEWT_VAL(PWM_3)
     ,
@@ -72,18 +101,123 @@ static struct nrf52_pwm_dev_global instances[] =
     [3].playing = false,
     [3].drv_instance = NRFX_PWM_INSTANCE(3),
     [3].config = NRFX_PWM_DEFAULT_CONFIG,
-    [3].duty_cycles = {0}
+    [3].flags = NRFX_PWM_FLAG_LOOP,
+    [3].duty_cycles = {0},
+    [3].n_cycles = 1,
+    [3].internal_handler = NULL,
+    [3].cycle_handler = NULL,
+    [3].cycle_data = NULL,
+    [3].seq_end_handler = NULL,
+    [3].seq_end_data = NULL
 #endif
 };
 
-/* /\** */
-/*  * Validate the contents of a given nrf_drv_pwm_config_t structure. */
-/*  *\/ */
-/* static int */
-/* validate_config(nrf_drv_pwm_config_t* config) */
-/* { */
-/*     return 0; */
-/* } */
+#if MYNEWT_VAL(PWM_0)
+static void handler_0(nrfx_pwm_evt_type_t event_type)
+{
+    switch (event_type)
+    {
+    case NRFX_PWM_EVT_END_SEQ0 :
+    case NRFX_PWM_EVT_END_SEQ1 :
+        instances[0].cycle_handler(instances[0].cycle_data);
+        break;
+
+    case NRFX_PWM_EVT_FINISHED :
+        instances[0].playing = false;
+        nrfx_pwm_uninit(&instances[0].drv_instance);
+        instances[0].seq_end_handler(instances[0].seq_end_data);
+        break;
+
+    default:
+        assert(0);
+    }
+}
+#endif
+
+#if MYNEWT_VAL(PWM_1)
+static void handler_1(nrfx_pwm_evt_type_t event_type)
+{
+    switch (event_type)
+    {
+    case NRF_DRV_PWM_EVT_SIGNAL_END_SEQ0 :
+    case NRF_DRV_PWM_EVT_SIGNAL_END_SEQ1 :
+        instances[1].cycle_handler(instances[1].cycle_data);
+        break;
+
+    case NRFX_PWM_EVT_FINISHED :
+        instances[1].playing = false;
+        nrfx_pwm_uninit(&instances[1].drv_instance);
+        instances[1].seq_end_handler(instances[1].seq_end_data);
+        break;
+
+    default:
+        assert(0);
+    }
+}
+#endif
+
+#if MYNEWT_VAL(PWM_2)
+static void handler_2(nrfx_pwm_evt_type_t event_type)
+{
+    switch (event_type)
+    {
+    case NRF_DRV_PWM_EVT_SIGNAL_END_SEQ0 :
+    case NRF_DRV_PWM_EVT_SIGNAL_END_SEQ1 :
+        instances[2].cycle_handler(instances[2].cycle_data);
+        break;
+
+    case NRFX_PWM_EVT_FINISHED :
+        instances[2].playing = false;
+        nrfx_pwm_uninit(&instances[2].drv_instance);
+        instances[2].seq_end_handler(instances[2].seq_end_data);
+        break;
+
+    default:
+        assert(0);
+    }
+
+}
+#endif
+
+#if MYNEWT_VAL(PWM_3)
+static void handler_3(nrfx_pwm_evt_type_t event_type)
+{
+    switch (event_type)
+    {
+    case NRF_DRV_PWM_EVT_SIGNAL_END_SEQ0 :
+    case NRF_DRV_PWM_EVT_SIGNAL_END_SEQ1 :
+        instances[3].cycle_handler(instances[3].cycle_data);
+        break;
+
+    case NRFX_PWM_EVT_FINISHED :
+        instances[3].playing = false;
+        nrfx_pwm_uninit(&instances[3].drv_instance);
+        instances[3].seq_end_handler(instances[3].seq_end_data);
+        break;
+
+    default:
+        assert(0);
+    }
+}
+#endif
+
+static nrfx_pwm_handler_t internal_handlers[] = {
+#if MYNEWT_VAL(PWM_0)
+handler_0
+#endif
+#if MYNEWT_VAL(PWM_1)
+,
+handler_1
+#endif
+#if MYNEWT_VAL(PWM_2)
+,
+handler_2
+#endif
+#if MYNEWT_VAL(PWM_3)
+,
+handler_3
+#endif
+};
 
 /**
  * Initialize a driver instance.
@@ -91,12 +225,7 @@ static struct nrf52_pwm_dev_global instances[] =
 static int
 init_instance(int inst_id, nrfx_pwm_config_t* init_conf)
 {
-    if(!instances[inst_id].in_use) {
-        return (EINVAL);
-    }
     nrfx_pwm_config_t *config;
-    memset(&instances[inst_id].duty_cycles, 0,
-               sizeof(instances[inst_id].duty_cycles));
 
     config = &instances[inst_id].config;
     if (!init_conf) {
@@ -113,10 +242,27 @@ init_instance(int inst_id, nrfx_pwm_config_t* init_conf)
     } else {
         memcpy(config, init_conf, sizeof(nrfx_pwm_config_t));
     }
-
     return (0);
 }
 
+/**
+ * Cleanup a driver instance.
+ */
+static void
+cleanup_instance(int inst_id)
+{
+    instances[inst_id].in_use = false;
+    instances[inst_id].playing = false;
+    instances[inst_id].internal_handler = NULL;
+    instances[inst_id].cycle_handler = NULL;
+    instances[inst_id].seq_end_handler = NULL;
+    instances[inst_id].cycle_data = NULL;
+    instances[inst_id].seq_end_data = NULL;
+    memset((uint16_t *) &instances[inst_id].duty_cycles,
+           0x00,
+           4 * sizeof(uint16_t));
+}
+
 /**
  * Open the NRF52 PWM device
  *
@@ -141,6 +287,11 @@ nrf52_pwm_open(struct os_dev *odev, uint32_t wait, void 
*arg)
     dev = (struct pwm_dev *) odev;
     inst_id = dev->pwm_instance_id;
 
+    if (instances[inst_id].in_use) {
+        return (EINVAL);
+    }
+    instances[inst_id].in_use = true;
+
     if (os_started()) {
         stat = os_mutex_pend(&dev->pwm_lock, wait);
         if (stat != OS_OK) {
@@ -168,6 +319,8 @@ nrf52_pwm_open(struct os_dev *odev, uint32_t wait, void 
*arg)
  * This function unlocks the device.
  *
  * @param odev The device to close.
+ *
+ * @return 0 on success, non-zero on failure.
  */
 static int
 nrf52_pwm_close(struct os_dev *odev)
@@ -178,8 +331,12 @@ nrf52_pwm_close(struct os_dev *odev)
     dev = (struct pwm_dev *) odev;
     inst_id = dev->pwm_instance_id;
 
+    if (!instances[inst_id].in_use) {
+        return (EINVAL);
+    }
+
     nrfx_pwm_uninit(&instances[inst_id].drv_instance);
-    instances[inst_id].playing = false;
+    cleanup_instance(inst_id);
 
     if (os_started()) {
         os_mutex_release(&dev->pwm_lock);
@@ -204,8 +361,8 @@ play_current_config(struct nrf52_pwm_dev_global *instance)
 
     nrfx_pwm_simple_playback(&instance->drv_instance,
                              &seq,
-                             1,
-                             NRFX_PWM_FLAG_LOOP);
+                             instance->n_cycles,
+                             instance->flags);
 }
 
 /**
@@ -213,7 +370,7 @@ play_current_config(struct nrf52_pwm_dev_global *instance)
  *
  * @param dev The device to configure.
  * @param cnum The channel number to configure.
- * @param cfg  A pwm_chan_cfg data structure.
+ * @param cfg  A pwm_chan_cfg data structure, where .
  *
  * @return 0 on success, non-zero error code on failure.
  */
@@ -223,30 +380,62 @@ nrf52_pwm_configure_channel(struct pwm_dev *dev,
                             struct pwm_chan_cfg *cfg)
 {
     int inst_id = dev->pwm_instance_id;
-    nrfx_pwm_config_t *config = &instances[inst_id].config;
+    struct nrf52_pwm_dev_global *instance = &instances[inst_id];
+    nrfx_pwm_config_t *config = &instance->config;
+    struct pwm_dev_interrupt_cfg *int_cfg;
+
+    if (!instance->in_use) {
+        return (EINVAL);
+    }
+
 
     config->output_pins[cnum] = cfg->pin;
     config->output_pins[cnum] |= (cfg->inverted) ?
         NRFX_PWM_PIN_INVERTED : config->output_pins[cnum];
-
-    if (instances[inst_id].playing) {
-        nrfx_pwm_uninit(&instances[inst_id].drv_instance);
-        nrfx_pwm_init(&instances[inst_id].drv_instance,
-                         &instances[inst_id].config,
-                         NULL);
-
-        play_current_config(&instances[inst_id]);
+    instance->n_cycles = (cfg->n_cycles) ? cfg->n_cycles : 1;
+
+    /* Configure Interrupts  */
+    if (cfg->interrupts_cfg) {
+        int_cfg = (struct pwm_dev_interrupt_cfg*) cfg;
+        if (int_cfg->cycle_handler || int_cfg->seq_end_handler) {
+            config->irq_priority = int_cfg->int_prio;
+            instance->internal_handler = internal_handlers[inst_id];
+            instance->cycle_handler = (user_handler_t) int_cfg->cycle_handler;
+            instance->seq_end_handler = (user_handler_t) 
int_cfg->seq_end_handler;
+            instance->cycle_data = int_cfg->cycle_data;
+            instance->seq_end_data = int_cfg->seq_end_data;
+        } else {
+            instance->internal_handler = NULL;
+        }
     }
 
+    instance->flags = (instance->n_cycles > 1) ?
+        0 :
+        NRFX_PWM_FLAG_LOOP;
+    instance->flags |= (instance->cycle_handler) ?
+        (NRFX_PWM_FLAG_SIGNAL_END_SEQ0 | NRFX_PWM_FLAG_SIGNAL_END_SEQ0) :
+        0;
+    instance->flags |= (instance->seq_end_handler) ?
+        0 :
+        NRFX_PWM_FLAG_NO_EVT_FINISHED;
+
+    if (instance->playing) {
+        nrfx_pwm_uninit(&instance->drv_instance);
+        nrfx_pwm_init(&instance->drv_instance,
+                         &instance->config,
+                         instance->internal_handler);
+
+        play_current_config(instance);
+    }
     return (0);
 }
 
 /**
  * Enable the PWM with specified duty cycle.
  *
- * This duty cycle is a fractional duty cycle where 0 == off, 65535=on,
- * and any value in between is on for fraction clocks and off
- * for 65535-fraction clocks.
+ * This duty cycle is a fractional duty cycle where 0 == off,
+ * base_freq / pwm_freq == on and any value in between is on for fraction 
clocks
+ * and off for (base_freq / pwm_freq)-fraction clocks.
  *
  * @param dev The device to configure.
  * @param cnum The channel number. The channel should be in use.
@@ -262,8 +451,15 @@ nrf52_pwm_enable_duty_cycle(struct pwm_dev *dev, uint8_t 
cnum, uint16_t fraction
     nrfx_pwm_config_t *config;
     bool inverted;
 
+    if (!instances[inst_id].in_use) {
+        return (-EINVAL);
+    }
+
     config = &instances[inst_id].config;
-    assert(config->output_pins[cnum] != NRFX_PWM_PIN_NOT_USED);
+    if (config->output_pins[cnum] == NRFX_PWM_PIN_NOT_USED) {
+        return (-EINVAL);
+    }
+
     inverted = ((config->output_pins[cnum] & NRFX_PWM_PIN_INVERTED) != 0);
 
     ((uint16_t *) &instances[inst_id].duty_cycles)[cnum] =
@@ -272,7 +468,7 @@ nrf52_pwm_enable_duty_cycle(struct pwm_dev *dev, uint8_t 
cnum, uint16_t fraction
     if (!instances[inst_id].playing) {
         stat = nrfx_pwm_init(&instances[inst_id].drv_instance,
                                 &instances[inst_id].config,
-                                NULL);
+                                instances[inst_id].internal_handler);
         if (stat != NRFX_SUCCESS) {
             return (stat);
         }
@@ -294,12 +490,17 @@ static int
 nrf52_pwm_disable(struct pwm_dev *dev, uint8_t cnum)
 {
     int inst_id = dev->pwm_instance_id;
+    if (!instances[inst_id].in_use) {
+        return (-EINVAL);
+    }
+
     instances[inst_id].config.output_pins[cnum] = NRFX_PWM_PIN_NOT_USED;
 
     nrfx_pwm_uninit(&instances[inst_id].drv_instance);
     nrfx_pwm_init(&instances[inst_id].drv_instance,
-                     &instances[inst_id].config,
-                     NULL);
+                  &instances[inst_id].config,
+                  instances[inst_id].internal_handler);
+
     /* check if there is any channel in use */
     if (instances[inst_id].playing) {
         play_current_config(&instances[inst_id]);
@@ -321,6 +522,10 @@ static int
 nrf52_pwm_set_frequency(struct pwm_dev *dev, uint32_t freq_hz)
 {
     int inst_id = dev->pwm_instance_id;
+    if (!instances[inst_id].in_use) {
+        return (-EINVAL);
+    }
+
     nrf_pwm_clk_t *frq = &instances[inst_id].config.base_clock;
     uint16_t *top_value = &instances[inst_id].config.top_value;
     uint32_t base_freq_val;
@@ -359,8 +564,8 @@ nrf52_pwm_set_frequency(struct pwm_dev *dev, uint32_t 
freq_hz)
     if (instances[inst_id].playing) {
         nrfx_pwm_uninit(&instances[inst_id].drv_instance);
         nrfx_pwm_init(&instances[inst_id].drv_instance,
-                         &instances[inst_id].config,
-                         NULL);
+                      &instances[inst_id].config,
+                      instances[inst_id].internal_handler);
 
         play_current_config(&instances[inst_id]);
     }
@@ -379,7 +584,9 @@ static int
 nrf52_pwm_get_clock_freq(struct pwm_dev *dev)
 {
     int inst_id = dev->pwm_instance_id;
-    assert(instances[inst_id].in_use);
+    if (!instances[inst_id].in_use) {
+        return (-EINVAL);
+    }
 
     switch (instances[inst_id].config.base_clock) {
     case NRF_PWM_CLK_16MHz:
@@ -402,6 +609,25 @@ nrf52_pwm_get_clock_freq(struct pwm_dev *dev)
     return (-EINVAL);
 }
 
+/**
+ * Get the top value for the cycle counter, i.e. the value which sets
+ * the duty cycle to 100%.
+ *
+ * @param dev
+ *
+ * @return value in cycles on success, negative on error.
+ */
+int
+nrf52_pwm_get_top_value(struct pwm_dev *dev)
+{
+    int inst_id = dev->pwm_instance_id;
+    if (!instances[inst_id].in_use) {
+        return (-EINVAL);
+    }
+
+    return (instances[inst_id].config.top_value);
+}
+
 /**
  * Get the resolution of the PWM in bits.
  *
@@ -413,7 +639,9 @@ static int
 nrf52_pwm_get_resolution_bits(struct pwm_dev *dev)
 {
     int inst_id = dev->pwm_instance_id;
-    assert(instances[inst_id].in_use);
+    if (!instances[inst_id].in_use) {
+        return (-EINVAL);
+    }
 
     uint16_t top_val = instances[inst_id].config.top_value;
     if (top_val >= 32768)
@@ -463,11 +691,11 @@ nrf52_pwm_dev_init(struct os_dev *odev, void *arg)
     struct pwm_dev *dev;
     struct pwm_driver_funcs *pwm_funcs;
 
+    assert(odev);
     dev = (struct pwm_dev *) odev;
 
-    assert(arg != NULL);
+    assert(arg);
     dev->pwm_instance_id = *((int*) arg);
-    instances[dev->pwm_instance_id].in_use = true;
 
     dev->pwm_chan_count = NRF_PWM_CHANNEL_COUNT;
     os_mutex_init(&dev->pwm_lock);
@@ -479,8 +707,35 @@ nrf52_pwm_dev_init(struct os_dev *odev, void *arg)
     pwm_funcs->pwm_enable_duty_cycle = nrf52_pwm_enable_duty_cycle;
     pwm_funcs->pwm_set_frequency = nrf52_pwm_set_frequency;
     pwm_funcs->pwm_get_clock_freq = nrf52_pwm_get_clock_freq;
+    pwm_funcs->pwm_get_top_value = nrf52_pwm_get_top_value;
     pwm_funcs->pwm_get_resolution_bits = nrf52_pwm_get_resolution_bits;
     pwm_funcs->pwm_disable = nrf52_pwm_disable;
 
+    switch (dev->pwm_instance_id) {
+#if MYNEWT_VAL(PWM_0)
+    case 0:
+        NVIC_SetVector(PWM0_IRQn, (uint32_t) nrfx_pwm_0_irq_handler);
+        break;
+#endif
+
+#if MYNEWT_VAL(PWM_1)
+    case 1:
+        NVIC_SetVector(PWM1_IRQn, (uint32_t) nrfx_pwm_1_irq_handler);
+        break;
+#endif
+
+#if MYNEWT_VAL(PWM_2)
+    case 2:
+        NVIC_SetVector(PWM2_IRQn, (uint32_t) nrfx_pwm_2_irq_handler);
+        break;
+#endif
+
+#if MYNEWT_VAL(PWM_3)
+    case 3:
+        NVIC_SetVector(PWM3_IRQn, (uint32_t) nrfx_pwm_3_irq_handler);
+        break;
+#endif
+    }
+
     return (0);
 }
diff --git a/hw/drivers/pwm/src/pwm.c b/hw/drivers/pwm/src/pwm.c
index fd1656fd4..8f01d6cc7 100644
--- a/hw/drivers/pwm/src/pwm.c
+++ b/hw/drivers/pwm/src/pwm.c
@@ -100,6 +100,22 @@ pwm_get_clock_freq(struct pwm_dev *dev)
     return (dev->pwm_funcs.pwm_get_clock_freq(dev));
 }
 
+/**
+ * Get the top value for the cycle counter, i.e. the value which sets
+ * the duty cycle to 100%.
+ *
+ * @param dev
+ *
+ * @return value in cycles on success, negative on error.
+ */
+int
+pwm_get_top_value(struct pwm_dev *dev)
+{
+    assert(dev->pwm_funcs.pwm_get_top_value != NULL);
+
+    return (dev->pwm_funcs.pwm_get_top_value(dev));
+}
+
 /**
  * Get the resolution of the PWM in bits.
  *


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to