You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by st...@apache.org on 2016/07/27 23:13:46 UTC
[17/51] [partial] incubator-mynewt-core git commit: add stm32 and
nordic sdks based on new structure
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f06c2d2b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/pwm/app_pwm.c
----------------------------------------------------------------------
diff --git a/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/pwm/app_pwm.c b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/pwm/app_pwm.c
new file mode 100644
index 0000000..091fb70
--- /dev/null
+++ b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/pwm/app_pwm.c
@@ -0,0 +1,876 @@
+/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+#include "app_pwm.h"
+#include "nrf_drv_timer.h"
+#include "nrf_drv_ppi.h"
+#include "nrf_drv_common.h"
+#include "nrf_drv_gpiote.h"
+#include "nrf_gpiote.h"
+#include "nrf_gpio.h"
+#include "app_util.h"
+#include "app_util_platform.h"
+#include "nrf_assert.h"
+
+#define APP_PWM_CHANNEL_INITIALIZED 1
+#define APP_PWM_CHANNEL_UNINITIALIZED 0
+
+#define APP_PWM_CHANNEL_ENABLED 1
+#define APP_PWM_CHANNEL_DISABLED 0
+
+#define TIMER_PRESCALER_MAX 9
+#define TIMER_MAX_PULSEWIDTH_US_ON_16M 4095
+
+#define APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE 2
+#define APP_PWM_REQUIRED_PPI_CHANNELS_PER_CHANNEL 2
+
+#define UNALLOCATED 0xFFFFFFFFUL
+#define BUSY_STATE_CHANGING 0xFE
+#define BUSY_STATE_IDLE 0xFF
+
+#define PWM_MAIN_CC_CHANNEL 2
+#define PWM_SECONDARY_CC_CHANNEL 3
+
+#ifdef NRF52
+ static bool m_use_ppi_delay_workaround;
+#endif
+
+
+/**
+ * @brief PWM busy status
+ *
+ * Stores the number of a channel being currently updated.
+ *
+ */
+static volatile uint8_t m_pwm_busy[TIMER_COUNT];
+
+
+/**
+ * @brief New duty cycle value
+ *
+ * When the channel duty cycle reaches this value, the update process is complete.
+ */
+static volatile uint32_t m_pwm_target_value[TIMER_COUNT];
+
+
+/**
+ * @brief PWM ready counter
+ *
+ * The value in this counter is decremented in every PWM cycle after initiating the update.
+ * If an event handler function was specified by the user, it is being called
+ * after two cycle events (at least one full PWM cycle).
+ */
+volatile uint8_t m_pwm_ready_counter[TIMER_COUNT][APP_PWM_CHANNELS_PER_INSTANCE];
+
+/**
+ * @brief Pointers to instances
+ *
+ * This array connects any active timer instance number with the pointer to the PWM instance.
+ * It is used by the interrupt runtime.
+ */
+static const app_pwm_t * m_instances[TIMER_COUNT];
+
+// Macros for getting the polarity of given instance/channel.
+#define POLARITY_ACTIVE(INST,CH) (( ((INST)->p_cb)->channels_cb[(CH)].polarity == \
+ APP_PWM_POLARITY_ACTIVE_LOW)?(0):(1))
+#define POLARITY_INACTIVE(INST,CH) (( ((INST)->p_cb)->channels_cb[(CH)].polarity == \
+ APP_PWM_POLARITY_ACTIVE_LOW)?(1):(0))
+
+//lint -save -e534
+
+/**
+ * @brief Workaround for PAN-73.
+ *
+ * @param[in] timer Timer.
+ * @param[in] enable Enable or disable.
+ */
+static void pan73_workaround(NRF_TIMER_Type * p_timer, bool enable)
+{
+#ifdef NRF51
+ if (p_timer == NRF_TIMER0)
+ {
+ *(uint32_t *)0x40008C0C = (enable ? 1 : 0);
+ }
+ else if (p_timer == NRF_TIMER1)
+ {
+ *(uint32_t *)0x40009C0C = (enable ? 1 : 0);
+ }
+ else if (p_timer == NRF_TIMER2)
+ {
+ *(uint32_t *)0x4000AC0C = (enable ? 1 : 0);
+ }
+#endif
+ return;
+}
+
+bool app_pwm_busy_check(app_pwm_t const * const p_instance)
+{
+ uint8_t busy_state = (m_pwm_busy[p_instance->p_timer->instance_id]);
+ bool busy = true;
+ if (busy_state != BUSY_STATE_IDLE)
+ {
+ if (busy_state != BUSY_STATE_CHANGING)
+ {
+ if (nrf_drv_timer_capture_get(p_instance->p_timer, (nrf_timer_cc_channel_t) busy_state)
+ == m_pwm_target_value[p_instance->p_timer->instance_id])
+ {
+ m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE;
+ busy = false;
+ }
+ }
+ }
+ else
+ {
+ busy = false;
+ }
+ return busy;
+}
+
+
+/**
+ * @brief Function for enabling the IRQ for a given PWM instance.
+ *
+ * @param[in] p_instance PWM instance.
+ */
+__STATIC_INLINE void pwm_irq_enable(app_pwm_t const * const p_instance)
+{
+ nrf_drv_timer_compare_int_enable(p_instance->p_timer, PWM_MAIN_CC_CHANNEL);
+}
+
+
+/**
+ * @brief Function for disabling the IRQ for a given PWM instance.
+ *
+ * @param[in] p_instance PWM instance.
+ */
+__STATIC_INLINE void pwm_irq_disable(app_pwm_t const * const p_instance)
+{
+ nrf_drv_timer_compare_int_disable(p_instance->p_timer, PWM_MAIN_CC_CHANNEL);
+}
+
+
+/**
+ * @brief Function for disabling PWM channel PPI.
+ *
+ * @param[in] p_instance PWM instance.
+ */
+__STATIC_INLINE void pwm_channel_ppi_disable(app_pwm_t const * const p_instance, uint8_t channel)
+{
+ app_pwm_cb_t * p_cb = p_instance->p_cb;
+
+ nrf_drv_ppi_channel_disable(p_cb->channels_cb[channel].ppi_channels[0]);
+ nrf_drv_ppi_channel_disable(p_cb->channels_cb[channel].ppi_channels[1]);
+}
+
+
+/**
+ * @brief Function for disabling PWM PPI.
+ *
+ * @param[in] p_instance PWM instance.
+ */
+__STATIC_INLINE void pwm_ppi_disable(app_pwm_t const * const p_instance)
+{
+ app_pwm_cb_t * p_cb = p_instance->p_cb;
+
+ nrf_drv_ppi_channel_disable(p_cb->ppi_channels[0]);
+ nrf_drv_ppi_channel_disable(p_cb->ppi_channels[1]);
+}
+
+
+/**
+ * @brief This function is called on interrupt after duty set.
+ *
+ * @param[in] timer Timer used by PWM.
+ * @param[in] timer_instance_id Timer index.
+ */
+void pwm_ready_tick(nrf_timer_event_t event_type, void * p_context)
+{
+ uint32_t timer_instance_id = (uint32_t)p_context;
+ uint8_t disable = 1;
+
+ for (uint8_t channel = 0; channel < APP_PWM_CHANNELS_PER_INSTANCE; ++channel)
+ {
+ if (m_pwm_ready_counter[timer_instance_id][channel])
+ {
+ --m_pwm_ready_counter[timer_instance_id][channel];
+ if (!m_pwm_ready_counter[timer_instance_id][channel])
+ {
+ app_pwm_cb_t * p_cb = m_instances[timer_instance_id]->p_cb;
+ p_cb->p_ready_callback(timer_instance_id);
+ }
+ else
+ {
+ disable = 0;
+ }
+ }
+ }
+
+ if (disable)
+ {
+ pwm_irq_disable(m_instances[timer_instance_id]);
+ }
+}
+
+
+/**
+ * @brief Function for resource de-allocation.
+ *
+ * @param[in] p_instance PWM instance.
+ */
+//lint -e{650}
+static void pwm_dealloc(app_pwm_t const * const p_instance)
+{
+ app_pwm_cb_t * p_cb = p_instance->p_cb;
+
+ for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE; ++i)
+ {
+ if (p_cb->ppi_channels[i] != (nrf_ppi_channel_t)(uint8_t)(UNALLOCATED))
+ {
+ nrf_drv_ppi_channel_free(p_cb->ppi_channels[i]);
+ }
+ }
+ if (p_cb->ppi_group != (nrf_ppi_channel_group_t)UNALLOCATED)
+ {
+ nrf_drv_ppi_group_free(p_cb->ppi_group);
+ }
+
+ for (uint8_t ch = 0; ch < APP_PWM_CHANNELS_PER_INSTANCE; ++ch)
+ {
+ for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_CHANNEL; ++i)
+ {
+ if (p_cb->channels_cb[ch].ppi_channels[i] != (nrf_ppi_channel_t)UNALLOCATED)
+ {
+ nrf_drv_ppi_channel_free(p_cb->channels_cb[ch].ppi_channels[i]);
+ p_cb->channels_cb[ch].ppi_channels[i] = (nrf_ppi_channel_t)UNALLOCATED;
+ }
+ }
+ if (p_cb->channels_cb[ch].gpio_pin != UNALLOCATED)
+ {
+ nrf_drv_gpiote_out_uninit(p_cb->channels_cb[ch].gpio_pin);
+ p_cb->channels_cb[ch].gpio_pin = UNALLOCATED;
+ }
+ p_cb->channels_cb[ch].initialized = APP_PWM_CHANNEL_UNINITIALIZED;
+ }
+ nrf_drv_timer_uninit(p_instance->p_timer);
+ return;
+}
+
+
+/**
+ * @brief PWM state transition from (0%, 100%) to 0% or 100%.
+ *
+ * @param[in] p_instance PWM instance.
+ * @param[in] channel PWM channel number.
+ * @param[in] ticks Number of clock ticks.
+ */
+static void pwm_transition_n_to_0or100(app_pwm_t const * const p_instance,
+ uint8_t channel, uint16_t ticks)
+{
+ app_pwm_cb_t * p_cb = p_instance->p_cb;
+ app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
+ nrf_ppi_channel_group_t p_ppigrp = p_cb->ppi_group;
+
+ pwm_ppi_disable(p_instance);
+ nrf_drv_ppi_group_clear(p_ppigrp);
+ nrf_drv_ppi_channels_include_in_group(
+ nrf_drv_ppi_channel_to_mask(p_ch_cb->ppi_channels[0]) |
+ nrf_drv_ppi_channel_to_mask(p_ch_cb->ppi_channels[1]),
+ p_ppigrp);
+
+ if (!ticks)
+ {
+ nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0],
+ nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel),
+ nrf_drv_ppi_task_addr_group_disable_get(p_ppigrp));
+ nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, 0, false);
+ m_pwm_target_value[p_instance->p_timer->instance_id] =
+ nrf_drv_timer_capture_get(p_instance->p_timer, (nrf_timer_cc_channel_t) channel);
+ nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1],
+ nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel),
+ nrf_drv_timer_capture_task_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL));
+ }
+ else
+ {
+ ticks = p_cb->period;
+ nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0],
+ nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL),
+ nrf_drv_ppi_task_addr_group_disable_get(p_ppigrp));
+ // Set secondary CC channel to non-zero value:
+ nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, 1, false);
+ m_pwm_target_value[p_instance->p_timer->instance_id] = 0;
+ // The captured value will be equal to 0, because timer clear on main PWM CC channel compare is enabled.
+ nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1],
+ nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL),
+ nrf_drv_timer_capture_task_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL));
+ }
+
+ nrf_drv_ppi_channel_enable(p_cb->ppi_channels[0]);
+ nrf_drv_ppi_channel_enable(p_cb->ppi_channels[1]);
+
+ p_ch_cb->pulsewidth = ticks;
+ m_pwm_busy[p_instance->p_timer->instance_id] = PWM_SECONDARY_CC_CHANNEL;
+}
+
+
+/**
+ * @brief PWM state transition from (0%, 100%) to (0%, 100%).
+ *
+ * @param[in] p_instance PWM instance.
+ * @param[in] channel PWM channel number.
+ * @param[in] ticks Number of clock ticks.
+ */
+static void pwm_transition_n_to_m(app_pwm_t const * const p_instance,
+ uint8_t channel, uint16_t ticks)
+{
+ app_pwm_cb_t * p_cb = p_instance->p_cb;
+ app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
+ nrf_ppi_channel_group_t p_ppigrp = p_cb->ppi_group;
+
+ pwm_ppi_disable(p_instance);
+ nrf_drv_ppi_group_clear(p_ppigrp);
+ nrf_drv_ppi_channels_include_in_group(
+ nrf_drv_ppi_channel_to_mask(p_cb->ppi_channels[0]) |
+ nrf_drv_ppi_channel_to_mask(p_cb->ppi_channels[1]),
+ p_ppigrp);
+
+ nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0],
+ nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL),
+ nrf_drv_timer_capture_task_address_get(p_instance->p_timer, channel));
+
+#ifdef NRF52
+ if (ticks + ((nrf_timer_frequency_get(p_instance->p_timer->p_reg) ==
+ (m_use_ppi_delay_workaround ? NRF_TIMER_FREQ_8MHz : NRF_TIMER_FREQ_16MHz) ) ? 1 : 0)
+ < p_ch_cb->pulsewidth)
+#else
+ if (ticks + ((nrf_timer_frequency_get(p_instance->p_timer->p_reg) == NRF_TIMER_FREQ_16MHz) ? 1 : 0)
+ < p_ch_cb->pulsewidth)
+#endif
+ {
+ // For lower value, we need one more transition. Timer task delay is included.
+ // If prescaler is disabled, one tick must be added because of 1 PCLK16M clock cycle delay.
+ nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1],
+ nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL),
+ nrf_drv_gpiote_out_task_addr_get(p_ch_cb->gpio_pin));
+ }
+ else
+ {
+ nrf_drv_ppi_channel_remove_from_group(p_cb->ppi_channels[1], p_ppigrp);
+ }
+ p_ch_cb->pulsewidth = ticks;
+ nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, ticks, false);
+ nrf_drv_ppi_group_enable(p_ppigrp);
+
+ m_pwm_target_value[p_instance->p_timer->instance_id] = ticks;
+ m_pwm_busy[p_instance->p_timer->instance_id] = channel;
+}
+
+
+/**
+ * @brief PWM state transition from 0% or 100% to (0%, 100%).
+ *
+ * @param[in] p_instance PWM instance.
+ * @param[in] channel PWM channel number.
+ * @param[in] ticks Number of clock ticks.
+ */
+static void pwm_transition_0or100_to_n(app_pwm_t const * const p_instance,
+ uint8_t channel, uint16_t ticks)
+{
+ app_pwm_cb_t * p_cb = p_instance->p_cb;
+ app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
+ nrf_ppi_channel_group_t p_ppigrp = p_cb->ppi_group;
+ nrf_timer_cc_channel_t pwm_ch_cc = (nrf_timer_cc_channel_t)(channel);
+
+ pwm_ppi_disable(p_instance);
+ pwm_channel_ppi_disable(p_instance, channel);
+
+ nrf_drv_timer_compare(p_instance->p_timer, pwm_ch_cc, ticks, false);
+ nrf_drv_ppi_group_clear(p_ppigrp);
+ nrf_drv_ppi_channels_include_in_group(
+ nrf_drv_ppi_channel_to_mask(p_ch_cb->ppi_channels[0])|
+ nrf_drv_ppi_channel_to_mask(p_ch_cb->ppi_channels[1]),
+ p_ppigrp);
+
+ if (!p_ch_cb->pulsewidth)
+ {
+ // Channel is at 0%.
+ nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0],
+ nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel),
+ nrf_drv_ppi_task_addr_group_enable_get(p_ppigrp));
+ nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, 0, false);
+ m_pwm_target_value[p_instance->p_timer->instance_id] =
+ nrf_drv_timer_capture_get(p_instance->p_timer, (nrf_timer_cc_channel_t) channel);
+ nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1],
+ nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel),
+ nrf_drv_timer_capture_task_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL));
+
+ }
+ else
+ {
+ // Channel is at 100%.
+ nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0],
+ nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL),
+ nrf_drv_ppi_task_addr_group_enable_get(p_ppigrp));
+ // Set secondary CC channel to non-zero value:
+ nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, 1, false);
+ m_pwm_target_value[p_instance->p_timer->instance_id] = 0;
+ // The captured value will be equal to 0, because timer clear on main PWM CC channel compare is enabled.
+ nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1],
+ nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL),
+ nrf_drv_timer_capture_task_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL));
+ }
+ nrf_drv_ppi_channel_enable(p_cb->ppi_channels[0]);
+ nrf_drv_ppi_channel_enable(p_cb->ppi_channels[1]);
+
+ p_ch_cb->pulsewidth = ticks;
+ m_pwm_busy[p_instance->p_timer->instance_id] = PWM_SECONDARY_CC_CHANNEL;
+}
+
+
+/**
+ * @brief PWM state transition from 0% or 100% to 0% or 100%.
+ *
+ * @param[in] p_instance PWM instance.
+ * @param[in] channel PWM channel number.
+ * @param[in] ticks Number of clock ticks.
+ */
+static void pwm_transition_0or100_to_0or100(app_pwm_t const * const p_instance,
+ uint8_t channel, uint16_t ticks)
+{
+ app_pwm_cb_t * p_cb = p_instance->p_cb;
+ app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
+ nrf_timer_cc_channel_t pwm_ch_cc = (nrf_timer_cc_channel_t)(channel);
+
+ pwm_ppi_disable(p_instance);
+ pwm_channel_ppi_disable(p_instance, channel);
+ if (!ticks)
+ {
+ // Set to 0%.
+ nrf_drv_gpiote_out_task_force(p_ch_cb->gpio_pin, POLARITY_INACTIVE(p_instance, channel));
+ }
+ else if (ticks >= p_cb->period)
+ {
+ // Set to 100%.
+ ticks = p_cb->period;
+ nrf_drv_gpiote_out_task_force(p_ch_cb->gpio_pin, POLARITY_ACTIVE(p_instance, channel));
+ }
+ nrf_drv_timer_compare(p_instance->p_timer, pwm_ch_cc, ticks, false);
+ p_ch_cb->pulsewidth = ticks;
+
+ m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE;
+ return;
+}
+
+
+ret_code_t app_pwm_channel_duty_ticks_set(app_pwm_t const * const p_instance,
+ uint8_t channel,
+ uint16_t ticks)
+{
+ app_pwm_cb_t * p_cb = p_instance->p_cb;
+ app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
+
+ ASSERT(channel < APP_PWM_CHANNELS_PER_INSTANCE);
+ ASSERT(p_ch_cb->initialized == APP_PWM_CHANNEL_INITIALIZED);
+
+ if (p_cb->state != NRF_DRV_STATE_POWERED_ON)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+ if (ticks == p_ch_cb->pulsewidth)
+ {
+ if (p_cb->p_ready_callback)
+ {
+ p_cb->p_ready_callback(p_instance->p_timer->instance_id);
+ }
+ return NRF_SUCCESS; // No action required.
+ }
+ if (app_pwm_busy_check(p_instance))
+ {
+ return NRF_ERROR_BUSY; // PPI channels for synchronization are still in use.
+ }
+
+ m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_CHANGING;
+
+ // Pulse width change sequence:
+ if (!p_ch_cb->pulsewidth || p_ch_cb->pulsewidth >= p_cb->period)
+ {
+ // Channel is disabled (0%) or at 100%.
+ if (!ticks || ticks >= p_cb->period)
+ {
+ // Set to 0 or 100%.
+ pwm_transition_0or100_to_0or100(p_instance, channel, ticks);
+ }
+ else
+ {
+ // Other value.
+ pwm_transition_0or100_to_n(p_instance, channel, ticks);
+ }
+ }
+ else
+ {
+ // Channel is at other value.
+ if (!ticks || ticks >= p_cb->period)
+ {
+ // Disable channel (set to 0%) or set to 100%.
+ pwm_transition_n_to_0or100(p_instance, channel, ticks);
+ }
+ else
+ {
+ // Set to any other value.
+ pwm_transition_n_to_m(p_instance, channel, ticks);
+ }
+ }
+ if (p_instance->p_cb->p_ready_callback)
+ {
+ //PWM ready interrupt handler will be called after one full period.
+ m_pwm_ready_counter[p_instance->p_timer->instance_id][channel] = 2;
+ pwm_irq_enable(p_instance);
+ }
+ return NRF_SUCCESS;
+}
+
+uint16_t app_pwm_channel_duty_ticks_get(app_pwm_t const * const p_instance, uint8_t channel)
+{
+ app_pwm_cb_t * p_cb = p_instance->p_cb;
+ app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
+
+ return p_ch_cb->pulsewidth;
+}
+
+uint16_t app_pwm_cycle_ticks_get(app_pwm_t const * const p_instance)
+{
+ app_pwm_cb_t * p_cb = p_instance->p_cb;
+
+ return (uint16_t)p_cb->period;
+}
+
+ret_code_t app_pwm_channel_duty_set(app_pwm_t const * const p_instance,
+ uint8_t channel, app_pwm_duty_t duty)
+{
+ uint32_t ticks = ((uint32_t)app_pwm_cycle_ticks_get(p_instance) * (uint32_t)duty) / 100UL;
+ return app_pwm_channel_duty_ticks_set(p_instance, channel, ticks);
+}
+
+
+app_pwm_duty_t app_pwm_channel_duty_get(app_pwm_t const * const p_instance, uint8_t channel)
+{
+ uint32_t value = ((uint32_t)app_pwm_channel_duty_ticks_get(p_instance, channel) * 100UL) \
+ / (uint32_t)app_pwm_cycle_ticks_get(p_instance);
+
+ return (app_pwm_duty_t)value;
+}
+
+
+/**
+ * @brief Function for initializing the PWM channel.
+ *
+ * @param[in] p_instance PWM instance.
+ * @param[in] channel Channel number.
+ * @param[in] pin GPIO pin number.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ * @retval NRF_ERROR_NO_MEM If there were not enough free resources.
+ * @retval NRF_ERROR_INVALID_STATE If the timer is already in use or initialization failed.
+ */
+static ret_code_t app_pwm_channel_init(app_pwm_t const * const p_instance, uint8_t channel,
+ uint32_t pin, app_pwm_polarity_t polarity)
+{
+ ASSERT(channel < APP_PWM_CHANNELS_PER_INSTANCE);
+ app_pwm_cb_t * p_cb = p_instance->p_cb;
+ app_pwm_channel_cb_t * p_channel_cb = &p_cb->channels_cb[channel];
+
+ if (p_cb->state != NRF_DRV_STATE_UNINITIALIZED)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ p_channel_cb->pulsewidth = 0;
+ p_channel_cb->polarity = polarity;
+ ret_code_t err_code;
+
+ /* GPIOTE setup: */
+ nrf_drv_gpiote_out_config_t out_cfg = GPIOTE_CONFIG_OUT_TASK_TOGGLE( POLARITY_INACTIVE(p_instance, channel) );
+ err_code = nrf_drv_gpiote_out_init((nrf_drv_gpiote_pin_t)pin,&out_cfg);
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+ p_cb->channels_cb[channel].gpio_pin = pin;
+
+ // Set output to inactive state.
+ if (polarity)
+ {
+ nrf_gpio_pin_clear(pin);
+ }
+ else
+ {
+ nrf_gpio_pin_set(pin);
+ }
+
+ /* PPI setup: */
+ for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_CHANNEL; ++i)
+ {
+ if (nrf_drv_ppi_channel_alloc(&p_channel_cb->ppi_channels[i]) != NRF_SUCCESS)
+ {
+ return NRF_ERROR_NO_MEM; // Resource de-allocation is done by callee.
+ }
+ }
+
+ nrf_drv_ppi_channel_disable(p_channel_cb->ppi_channels[0]);
+ nrf_drv_ppi_channel_disable(p_channel_cb->ppi_channels[1]);
+ nrf_drv_ppi_channel_assign(p_channel_cb->ppi_channels[0],
+ nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel),
+ nrf_drv_gpiote_out_task_addr_get(p_channel_cb->gpio_pin));
+ nrf_drv_ppi_channel_assign(p_channel_cb->ppi_channels[1],
+ nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL),
+ nrf_drv_gpiote_out_task_addr_get(p_channel_cb->gpio_pin));
+
+ p_channel_cb->initialized = APP_PWM_CHANNEL_INITIALIZED;
+ m_pwm_ready_counter[p_instance->p_timer->instance_id][channel] = 0;
+
+ return NRF_SUCCESS;
+}
+
+
+/**
+ * @brief Function for calculating target timer frequency, which will allow to set given period length.
+ *
+ * @param[in] period_us Desired period in microseconds.
+ *
+ * @retval Timer frequency.
+ */
+__STATIC_INLINE nrf_timer_frequency_t pwm_calculate_timer_frequency(uint32_t period_us)
+{
+ uint32_t f = (uint32_t) NRF_TIMER_FREQ_16MHz;
+ uint32_t min = (uint32_t) NRF_TIMER_FREQ_31250Hz;
+
+ while ((period_us > TIMER_MAX_PULSEWIDTH_US_ON_16M) && (f < min))
+ {
+ period_us >>= 1;
+ ++f;
+ }
+
+#ifdef NRF52
+ if ((m_use_ppi_delay_workaround) && (f == (uint32_t) NRF_TIMER_FREQ_16MHz))
+ {
+ f = (uint32_t) NRF_TIMER_FREQ_8MHz;
+ }
+#endif
+
+ return (nrf_timer_frequency_t) f;
+}
+
+
+ret_code_t app_pwm_init(app_pwm_t const * const p_instance, app_pwm_config_t const * const p_config,
+ app_pwm_callback_t p_ready_callback)
+{
+ ASSERT(p_instance);
+
+ if (!p_config)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ app_pwm_cb_t * p_cb = p_instance->p_cb;
+
+ if (p_cb->state != NRF_DRV_STATE_UNINITIALIZED)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ uint32_t err_code = nrf_drv_ppi_init();
+ if ((err_code != NRF_SUCCESS) && (err_code != MODULE_ALREADY_INITIALIZED))
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+
+
+ if (!nrf_drv_gpiote_is_init())
+ {
+ err_code = nrf_drv_gpiote_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+ }
+
+#ifdef NRF52
+ if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30)
+ {
+ m_use_ppi_delay_workaround = false;
+ }
+ else
+ {
+ m_use_ppi_delay_workaround = true;
+ }
+#endif
+
+ // Innitialize resource status:
+ p_cb->ppi_channels[0] = (nrf_ppi_channel_t)UNALLOCATED;
+ p_cb->ppi_channels[1] = (nrf_ppi_channel_t)UNALLOCATED;
+ p_cb->ppi_group = (nrf_ppi_channel_group_t)UNALLOCATED;
+
+ for (uint8_t i = 0; i < APP_PWM_CHANNELS_PER_INSTANCE; ++i)
+ {
+ p_cb->channels_cb[i].initialized = APP_PWM_CHANNEL_UNINITIALIZED;
+ p_cb->channels_cb[i].ppi_channels[0] = (nrf_ppi_channel_t)UNALLOCATED;
+ p_cb->channels_cb[i].ppi_channels[1] = (nrf_ppi_channel_t)UNALLOCATED;
+ p_cb->channels_cb[i].gpio_pin = UNALLOCATED;
+ }
+
+ // Allocate PPI channels and groups:
+ for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE; ++i)
+ {
+ if (nrf_drv_ppi_channel_alloc(&p_cb->ppi_channels[i]) != NRF_SUCCESS)
+ {
+ pwm_dealloc(p_instance);
+ return NRF_ERROR_NO_MEM;
+ }
+ }
+ if (nrf_drv_ppi_group_alloc(&p_cb->ppi_group) != NRF_SUCCESS)
+ {
+ pwm_dealloc(p_instance);
+ return NRF_ERROR_NO_MEM;
+ }
+
+ // Initialize channels:
+ for (uint8_t i = 0; i < APP_PWM_CHANNELS_PER_INSTANCE; ++i)
+ {
+ if (p_config->pins[i] != APP_PWM_NOPIN)
+ {
+ err_code = app_pwm_channel_init(p_instance, i, p_config->pins[i], p_config->pin_polarity[i]);
+ if (err_code != NRF_SUCCESS)
+ {
+ pwm_dealloc(p_instance);
+ return err_code;
+ }
+ app_pwm_channel_duty_ticks_set(p_instance, i, 0);
+ }
+ }
+
+ // Initialize timer:
+ nrf_timer_frequency_t timer_freq = pwm_calculate_timer_frequency(p_config->period_us);
+ nrf_drv_timer_config_t timer_cfg = {
+ .frequency = timer_freq,
+ .mode = NRF_TIMER_MODE_TIMER,
+ .bit_width = NRF_TIMER_BIT_WIDTH_16,
+ .interrupt_priority = APP_IRQ_PRIORITY_LOW,
+ .p_context = (void *) (uint32_t) p_instance->p_timer->instance_id
+ };
+ err_code = nrf_drv_timer_init(p_instance->p_timer, &timer_cfg,
+ pwm_ready_tick);
+ if (err_code != NRF_SUCCESS)
+ {
+ pwm_dealloc(p_instance);
+ return err_code;
+ }
+
+ uint32_t ticks = nrf_drv_timer_us_to_ticks(p_instance->p_timer, p_config->period_us);
+ p_cb->period = ticks;
+ nrf_drv_timer_clear(p_instance->p_timer);
+ nrf_drv_timer_extended_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_MAIN_CC_CHANNEL,
+ ticks, NRF_TIMER_SHORT_COMPARE2_CLEAR_MASK, true);
+ nrf_drv_timer_compare_int_disable(p_instance->p_timer, PWM_MAIN_CC_CHANNEL);
+
+ p_cb->p_ready_callback = p_ready_callback;
+ m_instances[p_instance->p_timer->instance_id] = p_instance;
+ m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE;
+ p_cb->state = NRF_DRV_STATE_INITIALIZED;
+
+ return NRF_SUCCESS;
+}
+
+
+void app_pwm_enable(app_pwm_t const * const p_instance)
+{
+ app_pwm_cb_t * p_cb = p_instance->p_cb;
+
+ ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED);
+
+ for (uint32_t channel = 0; channel < APP_PWM_CHANNELS_PER_INSTANCE; ++channel)
+ {
+ app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
+ m_pwm_ready_counter[p_instance->p_timer->instance_id][channel] = 0;
+ if (p_ch_cb->initialized)
+ {
+ nrf_drv_gpiote_out_task_force(p_ch_cb->gpio_pin, POLARITY_INACTIVE(p_instance, channel));
+ nrf_drv_gpiote_out_task_enable(p_ch_cb->gpio_pin);
+ p_ch_cb->pulsewidth = 0;
+ }
+ }
+ m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE;
+ pan73_workaround(p_instance->p_timer->p_reg, true);
+ nrf_drv_timer_clear(p_instance->p_timer);
+ nrf_drv_timer_enable(p_instance->p_timer);
+
+ p_cb->state = NRF_DRV_STATE_POWERED_ON;
+ return;
+}
+
+
+void app_pwm_disable(app_pwm_t const * const p_instance)
+{
+ app_pwm_cb_t * p_cb = p_instance->p_cb;
+
+ ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED);
+
+ nrf_drv_timer_disable(p_instance->p_timer);
+ pwm_irq_disable(p_instance);
+ for (uint8_t ppi_channel = 0; ppi_channel < APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE; ++ppi_channel)
+ {
+ nrf_drv_ppi_channel_disable(p_cb->ppi_channels[ppi_channel]);
+ }
+ for (uint8_t channel = 0; channel < APP_PWM_CHANNELS_PER_INSTANCE; ++channel)
+ {
+ app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
+ if (p_ch_cb->initialized)
+ {
+ uint8_t polarity = POLARITY_INACTIVE(p_instance, channel);
+ if (polarity)
+ {
+ nrf_gpio_pin_set(p_ch_cb->gpio_pin);
+ }
+ else
+ {
+ nrf_gpio_pin_clear(p_ch_cb->gpio_pin);
+ }
+ nrf_drv_gpiote_out_task_disable(p_ch_cb->gpio_pin);
+ nrf_drv_ppi_channel_disable(p_ch_cb->ppi_channels[0]);
+ nrf_drv_ppi_channel_disable(p_ch_cb->ppi_channels[1]);
+ }
+ }
+ pan73_workaround(p_instance->p_timer->p_reg, false);
+
+ p_cb->state = NRF_DRV_STATE_INITIALIZED;
+ return;
+}
+
+
+ret_code_t app_pwm_uninit(app_pwm_t const * const p_instance)
+{
+ app_pwm_cb_t * p_cb = p_instance->p_cb;
+
+ if (p_cb->state == NRF_DRV_STATE_POWERED_ON)
+ {
+ app_pwm_disable(p_instance);
+ }
+ else if (p_cb->state == NRF_DRV_STATE_UNINITIALIZED)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+ pwm_dealloc(p_instance);
+
+ p_cb->state = NRF_DRV_STATE_UNINITIALIZED;
+ return NRF_SUCCESS;
+}
+
+
+//lint -restore
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f06c2d2b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/pwm/app_pwm.h
----------------------------------------------------------------------
diff --git a/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/pwm/app_pwm.h b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/pwm/app_pwm.h
new file mode 100644
index 0000000..ebeaa64
--- /dev/null
+++ b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/pwm/app_pwm.h
@@ -0,0 +1,295 @@
+/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup app_pwm Pulse-width modulation (PWM)
+ * @{
+ * @ingroup app_common
+ *
+ * @brief Module for generating a pulse-width modulated output signal.
+ *
+ * @details This module provides a PWM implementation using timers, GPIOTE, and PPI.
+ *
+ * Resource usage:
+ * - 2 PPI channels per instance + 2 PPI channels per PWM channel.
+ * - 1 PPI group per instance.
+ * - 1 GPIOTE channel per PWM channel.
+ *
+ * For example, a PWM instance with two channels will consume 2+4 PPI channels, 1 PPI group, and 2 GPIOTE channels.
+ *
+ * The maximum number of PWM channels per instance is 2.
+ */
+
+#ifndef APP_PWM_H__
+#define APP_PWM_H__
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "nrf_drv_timer.h"
+#include "nrf_drv_common.h"
+#include "nrf_drv_ppi.h"
+
+
+#define APP_PWM_NOPIN 0xFFFFFFFF
+
+/** @brief Number of channels for one timer instance (fixed to 2 due to timer properties).*/
+#define APP_PWM_CHANNELS_PER_INSTANCE 2
+
+/**@brief Macro for creating a PWM instance. */
+#define APP_PWM_INSTANCE(name, num) \
+ const nrf_drv_timer_t m_pwm_##name##_timer = NRF_DRV_TIMER_INSTANCE(num); \
+ app_pwm_cb_t m_pwm_##name##_cb; \
+ /*lint -e{545}*/ \
+ const app_pwm_t name = { \
+ .p_cb = &m_pwm_##name##_cb, \
+ .p_timer = &m_pwm_##name##_timer, \
+ }
+
+
+/**@brief PWM instance default configuration (1 channel). */
+#define APP_PWM_DEFAULT_CONFIG_1CH(period_in_us, pin) \
+ { \
+ .pins = {pin, APP_PWM_NOPIN}, \
+ .pin_polarity = {APP_PWM_POLARITY_ACTIVE_LOW, APP_PWM_POLARITY_ACTIVE_LOW}, \
+ .num_of_channels = 1, \
+ .period_us = period_in_us \
+ }
+
+/**@brief PWM instance default configuration (2 channels). */
+#define APP_PWM_DEFAULT_CONFIG_2CH(period_in_us, pin0, pin1) \
+ { \
+ .pins = {pin0, pin1}, \
+ .pin_polarity = {APP_PWM_POLARITY_ACTIVE_LOW, APP_PWM_POLARITY_ACTIVE_LOW}, \
+ .num_of_channels = 2, \
+ .period_us = period_in_us \
+ }
+
+typedef uint16_t app_pwm_duty_t;
+
+/**
+ * @brief PWM callback that is executed when a PWM duty change has been completed.
+ *
+ * @param[in] pwm_id PWM instance ID.
+ */
+typedef void (* app_pwm_callback_t)(uint32_t);
+
+/**
+ * @brief Channel polarity.
+ */
+typedef enum
+{
+ APP_PWM_POLARITY_ACTIVE_LOW = 0,
+ APP_PWM_POLARITY_ACTIVE_HIGH = 1
+} app_pwm_polarity_t;
+
+/**@brief PWM configuration structure used for initialization. */
+typedef struct
+{
+ uint32_t pins[APP_PWM_CHANNELS_PER_INSTANCE]; //!< Pins configured as PWM output.
+ app_pwm_polarity_t pin_polarity[APP_PWM_CHANNELS_PER_INSTANCE]; //!< Polarity of active state on pin.
+ uint32_t num_of_channels; //!< Number of channels that can be used.
+ uint32_t period_us; //!< PWM signal output period to configure (in microseconds).
+} app_pwm_config_t;
+
+
+/**
+ * @cond (NODOX)
+ * @defgroup app_pwm_internal Auxiliary internal types declarations
+ * @{
+ * @internal
+ *
+ * @brief Module for internal usage inside the library only
+ *
+ * There are some definitions that must be included in the header file because
+ * of the way the library is set up. In this way, the are accessible to the user.
+ * However, any functions and variables defined here may change at any time
+ * without a warning, so you should not access them directly.
+ */
+
+ /**
+ * @brief PWM channel instance
+ *
+ * This structure holds all data needed by a single PWM channel.
+ */
+ typedef struct
+ {
+ uint32_t gpio_pin; //!< Pin that is used by this PWM channel.
+ uint32_t pulsewidth; //!< The copy of duty currently set (in ticks).
+ nrf_ppi_channel_t ppi_channels[2]; //!< PPI channels used by the PWM channel to clear and set the output.
+ app_pwm_polarity_t polarity; //!< The active state of the pin.
+ uint8_t initialized; //!< The internal information if the selected channel was initialized.
+ } app_pwm_channel_cb_t;
+
+ /**
+ * @brief Variable part of PWM instance
+ *
+ * This structure holds instance data that may change.
+ */
+ typedef struct
+ {
+ app_pwm_channel_cb_t channels_cb[APP_PWM_CHANNELS_PER_INSTANCE]; //!< Channels data
+ uint32_t period; //!< Selected period in ticks
+ app_pwm_callback_t p_ready_callback; //!< Callback function called on PWM readiness
+ nrf_ppi_channel_t ppi_channels[2]; //!< PPI channels used temporary while changing duty
+ nrf_ppi_channel_group_t ppi_group; //!< PPI group used to synchronize changes on channels
+ nrf_drv_state_t state; //!< Current driver status
+ } app_pwm_cb_t;
+/** @}
+ * @endcond
+ */
+
+
+/**@brief PWM instance structure. */
+typedef struct
+{
+ app_pwm_cb_t *p_cb; //!< Pointer to control block internals.
+ nrf_drv_timer_t const * const p_timer; //!< Timer used by this PWM instance.
+} app_pwm_t;
+
+/**
+ * @brief Function for checking if the PWM instance is busy updating the duty cycle.
+ *
+ * @param[in] p_instance PWM instance.
+ *
+ * @retval True If the PWM instance is ready for duty cycle changes.
+ * @retval False If a change operation is in progress.
+ */
+bool app_pwm_busy_check(app_pwm_t const * const p_instance);
+
+/**
+ * @brief Function for initializing a PWM instance.
+ *
+ * @param[in] p_instance PWM instance.
+ * @param[in] p_config Initial configuration.
+ * @param[in] p_ready_callback Pointer to ready callback function (or NULL to disable).
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ * @retval NRF_ERROR_NO_MEM If there were not enough free resources.
+ * @retval NRF_ERROR_INVALID_PARAM If an invalid configuration structure was passed.
+ * @retval NRF_ERROR_INVALID_STATE If the timer/PWM is already in use or if initialization failed.
+ */
+ret_code_t app_pwm_init(app_pwm_t const * const p_instance, app_pwm_config_t const * const p_config,
+ app_pwm_callback_t p_ready_callback);
+
+
+/**
+ * @brief Function for uninitializing a PWM instance and releasing the allocated resources.
+ *
+ * @param[in] p_instance PWM instance.
+ *
+ * @retval NRF_SUCCESS If uninitialization was successful.
+ * @retval NRF_ERROR_INVALID_STATE If the given instance was not initialized.
+ */
+ret_code_t app_pwm_uninit(app_pwm_t const * const p_instance);
+
+/**
+ * @brief Function for enabling a PWM instance after initialization.
+ *
+ * @param[in] p_instance PWM instance.
+ */
+void app_pwm_enable(app_pwm_t const * const p_instance);
+
+/**
+ * @brief Function for disabling a PWM instance after initialization.
+ *
+ * @param[in] p_instance PWM instance.
+ */
+void app_pwm_disable(app_pwm_t const * const p_instance);
+
+/**
+ * @brief Function for setting the PWM channel duty cycle in percents.
+ *
+ * A duty cycle change requires one full PWM clock period to finish.
+ * If another change is attempted for any channel of given instance before
+ * the current change is complete, the new attempt will result in the error
+ * NRF_ERROR_BUSY.
+ *
+ * @param[in] p_instance PWM instance.
+ * @param[in] channel Channel number.
+ * @param[in] duty Duty cycle (0 - 100).
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_BUSY If the PWM is not ready yet.
+ * @retval NRF_ERROR_INVALID_STATE If the given instance was not initialized.
+ *
+ */
+ret_code_t app_pwm_channel_duty_set(app_pwm_t const * const p_instance,
+ uint8_t channel, app_pwm_duty_t duty);
+
+/**
+ * @brief Function for retrieving the PWM channel duty cycle in percents.
+ *
+ * @param[in] p_instance PWM instance.
+ * @param[in] channel Channel number.
+ *
+ * @return Duty cycle value.
+ */
+app_pwm_duty_t app_pwm_channel_duty_get(app_pwm_t const * const p_instance, uint8_t channel);
+
+
+/**
+ * @name Functions accessing values in ticks
+ *
+ * Auxiliary functions that allow to get values in actual timer ticks.
+ * @{
+ */
+
+ /**
+ * @brief Function for setting PWM channel duty cycle in clock ticks.
+ *
+ * @note Duty cycle changes require one full PWM clock period to finish.
+ * Until that, the next change attempt (for any channel of given instance)
+ * will result in an NRF_ERROR_BUSY error.
+ *
+ * @param[in] p_instance PWM instance.
+ * @param[in] channel Channel number.
+ * @param[in] ticks Number of PWM clock ticks.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_BUSY If PWM is not ready yet.
+ * @retval NRF_ERROR_INVALID_STATE If the given instance was not initialized.
+ */
+ ret_code_t app_pwm_channel_duty_ticks_set(app_pwm_t const * const p_instance,
+ uint8_t channel,
+ uint16_t ticks);
+
+
+ /**
+ * @brief Function for retrieving the PWM channel duty cycle in ticks.
+ *
+ * This function retrieves the real, currently set duty cycle in ticks.
+ * For one full PWM cycle the value might be different than the value set by the last
+ * @ref app_pwm_channel_duty_ticks_set function call.
+ *
+ * @param[in] p_instance PWM instance.
+ * @param[in] channel Channel number.
+ *
+ * @return Number of ticks set for selected channel.
+ *
+ */
+ uint16_t app_pwm_channel_duty_ticks_get(app_pwm_t const * const p_instance, uint8_t channel);
+
+ /**
+ * @brief Function for returning the number of ticks in a whole cycle.
+ *
+ * @param[in] p_instance PWM instance.
+ *
+ * @return Number of ticks that corresponds to 100% of the duty cycle.
+ */
+ uint16_t app_pwm_cycle_ticks_get(app_pwm_t const * const p_instance);
+/** @} */
+
+
+#endif
+
+/** @} */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f06c2d2b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/scheduler/app_scheduler.c
----------------------------------------------------------------------
diff --git a/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/scheduler/app_scheduler.c b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/scheduler/app_scheduler.c
new file mode 100644
index 0000000..829d7f9
--- /dev/null
+++ b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/scheduler/app_scheduler.c
@@ -0,0 +1,227 @@
+/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+#include "app_scheduler.h"
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include "nrf_soc.h"
+#include "nrf_assert.h"
+#include "app_util.h"
+#include "app_util_platform.h"
+
+/**@brief Structure for holding a scheduled event header. */
+typedef struct
+{
+ app_sched_event_handler_t handler; /**< Pointer to event handler to receive the event. */
+ uint16_t event_data_size; /**< Size of event data. */
+} event_header_t;
+
+STATIC_ASSERT(sizeof(event_header_t) <= APP_SCHED_EVENT_HEADER_SIZE);
+
+static event_header_t * m_queue_event_headers; /**< Array for holding the queue event headers. */
+static uint8_t * m_queue_event_data; /**< Array for holding the queue event data. */
+static volatile uint8_t m_queue_start_index; /**< Index of queue entry at the start of the queue. */
+static volatile uint8_t m_queue_end_index; /**< Index of queue entry at the end of the queue. */
+static uint16_t m_queue_event_size; /**< Maximum event size in queue. */
+static uint16_t m_queue_size; /**< Number of queue entries. */
+
+#ifdef APP_SCHEDULER_WITH_PROFILER
+static uint16_t m_max_queue_utilization; /**< Maximum observed queue utilization. */
+#endif
+
+/**@brief Function for incrementing a queue index, and handle wrap-around.
+ *
+ * @param[in] index Old index.
+ *
+ * @return New (incremented) index.
+ */
+static __INLINE uint8_t next_index(uint8_t index)
+{
+ return (index < m_queue_size) ? (index + 1) : 0;
+}
+
+
+static __INLINE uint8_t app_sched_queue_full()
+{
+ uint8_t tmp = m_queue_start_index;
+ return next_index(m_queue_end_index) == tmp;
+}
+
+/**@brief Macro for checking if a queue is full. */
+#define APP_SCHED_QUEUE_FULL() app_sched_queue_full()
+
+
+static __INLINE uint8_t app_sched_queue_empty()
+{
+ uint8_t tmp = m_queue_start_index;
+ return m_queue_end_index == tmp;
+}
+
+/**@brief Macro for checking if a queue is empty. */
+#define APP_SCHED_QUEUE_EMPTY() app_sched_queue_empty()
+
+
+uint32_t app_sched_init(uint16_t event_size, uint16_t queue_size, void * p_event_buffer)
+{
+ uint16_t data_start_index = (queue_size + 1) * sizeof(event_header_t);
+
+ // Check that buffer is correctly aligned
+ if (!is_word_aligned(p_event_buffer))
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ // Initialize event scheduler
+ m_queue_event_headers = p_event_buffer;
+ m_queue_event_data = &((uint8_t *)p_event_buffer)[data_start_index];
+ m_queue_end_index = 0;
+ m_queue_start_index = 0;
+ m_queue_event_size = event_size;
+ m_queue_size = queue_size;
+
+#ifdef APP_SCHEDULER_WITH_PROFILER
+ m_max_queue_utilization = 0;
+#endif
+
+ return NRF_SUCCESS;
+}
+
+
+#ifdef APP_SCHEDULER_WITH_PROFILER
+static void queue_utilization_check(void)
+{
+ uint16_t start = m_queue_start_index;
+ uint16_t end = m_queue_end_index;
+ uint16_t queue_utilization = (end >= start) ? (end - start) :
+ (m_queue_size + 1 - start + end);
+
+ if (queue_utilization > m_max_queue_utilization)
+ {
+ m_max_queue_utilization = queue_utilization;
+ }
+}
+
+uint16_t app_sched_queue_utilization_get(void)
+{
+ return m_max_queue_utilization;
+}
+#endif
+
+
+uint32_t app_sched_event_put(void * p_event_data,
+ uint16_t event_data_size,
+ app_sched_event_handler_t handler)
+{
+ uint32_t err_code;
+
+ if (event_data_size <= m_queue_event_size)
+ {
+ uint16_t event_index = 0xFFFF;
+
+ CRITICAL_REGION_ENTER();
+
+ if (!APP_SCHED_QUEUE_FULL())
+ {
+ event_index = m_queue_end_index;
+ m_queue_end_index = next_index(m_queue_end_index);
+
+ #ifdef APP_SCHEDULER_WITH_PROFILER
+ // This function call must be protected with critical region because
+ // it modifies 'm_max_queue_utilization'.
+ queue_utilization_check();
+ #endif
+ }
+
+ CRITICAL_REGION_EXIT();
+
+ if (event_index != 0xFFFF)
+ {
+ // NOTE: This can be done outside the critical region since the event consumer will
+ // always be called from the main loop, and will thus never interrupt this code.
+ m_queue_event_headers[event_index].handler = handler;
+ if ((p_event_data != NULL) && (event_data_size > 0))
+ {
+ memcpy(&m_queue_event_data[event_index * m_queue_event_size],
+ p_event_data,
+ event_data_size);
+ m_queue_event_headers[event_index].event_data_size = event_data_size;
+ }
+ else
+ {
+ m_queue_event_headers[event_index].event_data_size = 0;
+ }
+
+ err_code = NRF_SUCCESS;
+ }
+ else
+ {
+ err_code = NRF_ERROR_NO_MEM;
+ }
+ }
+ else
+ {
+ err_code = NRF_ERROR_INVALID_LENGTH;
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for reading the next event from specified event queue.
+ *
+ * @param[out] pp_event_data Pointer to pointer to event data.
+ * @param[out] p_event_data_size Pointer to size of event data.
+ * @param[out] p_event_handler Pointer to event handler function pointer.
+ *
+ * @return NRF_SUCCESS if new event, NRF_ERROR_NOT_FOUND if event queue is empty.
+ */
+static uint32_t app_sched_event_get(void ** pp_event_data,
+ uint16_t * p_event_data_size,
+ app_sched_event_handler_t * p_event_handler)
+{
+ uint32_t err_code = NRF_ERROR_NOT_FOUND;
+
+ if (!APP_SCHED_QUEUE_EMPTY())
+ {
+ uint16_t event_index;
+
+ // NOTE: There is no need for a critical region here, as this function will only be called
+ // from app_sched_execute() from inside the main loop, so it will never interrupt
+ // app_sched_event_put(). Also, updating of (i.e. writing to) the start index will be
+ // an atomic operation.
+ event_index = m_queue_start_index;
+ m_queue_start_index = next_index(m_queue_start_index);
+
+ *pp_event_data = &m_queue_event_data[event_index * m_queue_event_size];
+ *p_event_data_size = m_queue_event_headers[event_index].event_data_size;
+ *p_event_handler = m_queue_event_headers[event_index].handler;
+
+ err_code = NRF_SUCCESS;
+ }
+
+ return err_code;
+}
+
+
+void app_sched_execute(void)
+{
+ void * p_event_data;
+ uint16_t event_data_size;
+ app_sched_event_handler_t event_handler;
+
+ // Get next event (if any), and execute handler
+ while ((app_sched_event_get(&p_event_data, &event_data_size, &event_handler) == NRF_SUCCESS))
+ {
+ event_handler(p_event_data, event_data_size);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f06c2d2b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/scheduler/app_scheduler.h
----------------------------------------------------------------------
diff --git a/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/scheduler/app_scheduler.h b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/scheduler/app_scheduler.h
new file mode 100644
index 0000000..f52e616
--- /dev/null
+++ b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/scheduler/app_scheduler.h
@@ -0,0 +1,163 @@
+/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup app_scheduler Scheduler
+ * @{
+ * @ingroup app_common
+ *
+ * @brief The scheduler is used for transferring execution from the interrupt context to the main
+ * context.
+ *
+ * @details See @ref seq_diagrams_sched for sequence diagrams illustrating the flow of events
+ * when using the Scheduler.
+ *
+ * @section app_scheduler_req Requirements:
+ *
+ * @subsection main_context_logic Logic in main context:
+ *
+ * - Define an event handler for each type of event expected.
+ * - Initialize the scheduler by calling the APP_SCHED_INIT() macro before entering the
+ * application main loop.
+ * - Call app_sched_execute() from the main loop each time the application wakes up because of an
+ * event (typically when sd_app_evt_wait() returns).
+ *
+ * @subsection int_context_logic Logic in interrupt context:
+ *
+ * - In the interrupt handler, call app_sched_event_put()
+ * with the appropriate data and event handler. This will insert an event into the
+ * scheduler's queue. The app_sched_execute() function will pull this event and call its
+ * handler in the main context.
+ *
+ * @if (PERIPHERAL)
+ * For an example usage of the scheduler, see the implementations of
+ * @ref ble_sdk_app_hids_mouse and @ref ble_sdk_app_hids_keyboard.
+ * @endif
+ *
+ * @image html scheduler_working.jpg The high level design of the scheduler
+ */
+
+#ifndef APP_SCHEDULER_H__
+#define APP_SCHEDULER_H__
+
+#include <stdint.h>
+#include "app_error.h"
+#include "app_util.h"
+
+#define APP_SCHED_EVENT_HEADER_SIZE 8 /**< Size of app_scheduler.event_header_t (only for use inside APP_SCHED_BUF_SIZE()). */
+
+/**@brief Compute number of bytes required to hold the scheduler buffer.
+ *
+ * @param[in] EVENT_SIZE Maximum size of events to be passed through the scheduler.
+ * @param[in] QUEUE_SIZE Number of entries in scheduler queue (i.e. the maximum number of events
+ * that can be scheduled for execution).
+ *
+ * @return Required scheduler buffer size (in bytes).
+ */
+#define APP_SCHED_BUF_SIZE(EVENT_SIZE, QUEUE_SIZE) \
+ (((EVENT_SIZE) + APP_SCHED_EVENT_HEADER_SIZE) * ((QUEUE_SIZE) + 1))
+
+/**@brief Scheduler event handler type. */
+typedef void (*app_sched_event_handler_t)(void * p_event_data, uint16_t event_size);
+
+/**@brief Macro for initializing the event scheduler.
+ *
+ * @details It will also handle dimensioning and allocation of the memory buffer required by the
+ * scheduler, making sure the buffer is correctly aligned.
+ *
+ * @param[in] EVENT_SIZE Maximum size of events to be passed through the scheduler.
+ * @param[in] QUEUE_SIZE Number of entries in scheduler queue (i.e. the maximum number of events
+ * that can be scheduled for execution).
+ *
+ * @note Since this macro allocates a buffer, it must only be called once (it is OK to call it
+ * several times as long as it is from the same location, e.g. to do a reinitialization).
+ */
+#define APP_SCHED_INIT(EVENT_SIZE, QUEUE_SIZE) \
+ do \
+ { \
+ static uint32_t APP_SCHED_BUF[CEIL_DIV(APP_SCHED_BUF_SIZE((EVENT_SIZE), (QUEUE_SIZE)), \
+ sizeof(uint32_t))]; \
+ uint32_t ERR_CODE = app_sched_init((EVENT_SIZE), (QUEUE_SIZE), APP_SCHED_BUF); \
+ APP_ERROR_CHECK(ERR_CODE); \
+ } while (0)
+
+/**@brief Function for initializing the Scheduler.
+ *
+ * @details It must be called before entering the main loop.
+ *
+ * @param[in] max_event_size Maximum size of events to be passed through the scheduler.
+ * @param[in] queue_size Number of entries in scheduler queue (i.e. the maximum number of
+ * events that can be scheduled for execution).
+ * @param[in] p_evt_buffer Pointer to memory buffer for holding the scheduler queue. It must
+ * be dimensioned using the APP_SCHED_BUFFER_SIZE() macro. The buffer
+ * must be aligned to a 4 byte boundary.
+ *
+ * @note Normally initialization should be done using the APP_SCHED_INIT() macro, as that will both
+ * allocate the scheduler buffer, and also align the buffer correctly.
+ *
+ * @retval NRF_SUCCESS Successful initialization.
+ * @retval NRF_ERROR_INVALID_PARAM Invalid parameter (buffer not aligned to a 4 byte
+ * boundary).
+ */
+uint32_t app_sched_init(uint16_t max_event_size, uint16_t queue_size, void * p_evt_buffer);
+
+/**@brief Function for executing all scheduled events.
+ *
+ * @details This function must be called from within the main loop. It will execute all events
+ * scheduled since the last time it was called.
+ */
+void app_sched_execute(void);
+
+/**@brief Function for scheduling an event.
+ *
+ * @details Puts an event into the event queue.
+ *
+ * @param[in] p_event_data Pointer to event data to be scheduled.
+ * @param[in] event_size Size of event data to be scheduled.
+ * @param[in] handler Event handler to receive the event.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t app_sched_event_put(void * p_event_data,
+ uint16_t event_size,
+ app_sched_event_handler_t handler);
+
+#ifdef APP_SCHEDULER_WITH_PROFILER
+/**@brief Function for getting the maximum observed queue utilization.
+ *
+ * Function for tuning the module and determining QUEUE_SIZE value and thus module RAM usage.
+ *
+ * @return Maximum number of events in queue observed so far.
+ */
+uint16_t app_sched_queue_utilization_get(void);
+#endif
+
+#ifdef APP_SCHEDULER_WITH_PAUSE
+/**@brief A function to pause the scheduler.
+ *
+ * @details When the scheduler is paused events are not pulled from the scheduler queue for
+ * processing. The function can be called multiple times. To unblock the scheduler the
+ * function @ref app_sched_resume has to be called the same number of times.
+ */
+void app_sched_pause(void);
+
+/**@brief A function to resume a scheduler.
+ *
+ * @details To unblock the scheduler this function has to be called the same number of times as
+ * @ref app_sched_pause function.
+ */
+void app_sched_resume(void);
+#endif
+#endif // APP_SCHEDULER_H__
+
+/** @} */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f06c2d2b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/scheduler/app_scheduler_serconn.c
----------------------------------------------------------------------
diff --git a/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/scheduler/app_scheduler_serconn.c b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/scheduler/app_scheduler_serconn.c
new file mode 100644
index 0000000..f411eff
--- /dev/null
+++ b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/scheduler/app_scheduler_serconn.c
@@ -0,0 +1,262 @@
+/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+#include "app_scheduler.h"
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include "nrf_soc.h"
+#include "nrf_assert.h"
+#include "app_util.h"
+#include "app_util_platform.h"
+
+/**@brief Structure for holding a scheduled event header. */
+typedef struct
+{
+ app_sched_event_handler_t handler; /**< Pointer to event handler to receive the event. */
+ uint16_t event_data_size; /**< Size of event data. */
+} event_header_t;
+
+STATIC_ASSERT(sizeof (event_header_t) <= APP_SCHED_EVENT_HEADER_SIZE);
+
+static event_header_t * m_queue_event_headers; /**< Array for holding the queue event headers. */
+static uint8_t * m_queue_event_data; /**< Array for holding the queue event data. */
+static volatile uint8_t m_queue_start_index; /**< Index of queue entry at the start of the queue. */
+static volatile uint8_t m_queue_end_index; /**< Index of queue entry at the end of the queue. */
+static uint16_t m_queue_event_size; /**< Maximum event size in queue. */
+static uint16_t m_queue_size; /**< Number of queue entries. */
+
+#ifdef APP_SCHEDULER_WITH_PROFILER
+static uint16_t m_max_queue_utilization; /**< Maximum observed queue utilization. */
+#endif
+
+static uint32_t m_scheduler_paused_counter = 0; /**< Counter storing the difference between pausing
+ and resuming the scheduler. */
+
+/**@brief Function for incrementing a queue index, and handle wrap-around.
+ *
+ * @param[in] index Old index.
+ *
+ * @return New (incremented) index.
+ */
+static __INLINE uint8_t next_index(uint8_t index)
+{
+ return (index < m_queue_size) ? (index + 1) : 0;
+}
+
+static __INLINE uint8_t app_sched_queue_full(void)
+{
+ uint8_t tmp = m_queue_start_index;
+ return next_index(m_queue_end_index) == tmp;
+}
+
+/**@brief Macro for checking if a queue is full. */
+#define APP_SCHED_QUEUE_FULL() app_sched_queue_full()
+
+static __INLINE uint8_t app_sched_queue_empty(void)
+{
+ uint8_t tmp = m_queue_start_index;
+ return m_queue_end_index == tmp;
+}
+
+/**@brief Macro for checking if a queue is empty. */
+#define APP_SCHED_QUEUE_EMPTY() app_sched_queue_empty()
+
+
+uint32_t app_sched_init(uint16_t event_size, uint16_t queue_size, void * p_event_buffer)
+{
+ uint16_t data_start_index = (queue_size + 1) * sizeof (event_header_t);
+
+ //Check that buffer is correctly aligned
+ if (!is_word_aligned(p_event_buffer))
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ //Initialize event scheduler
+ m_queue_event_headers = p_event_buffer;
+ m_queue_event_data = &((uint8_t *)p_event_buffer)[data_start_index];
+ m_queue_end_index = 0;
+ m_queue_start_index = 0;
+ m_queue_event_size = event_size;
+ m_queue_size = queue_size;
+
+#ifdef APP_SCHEDULER_WITH_PROFILER
+ m_max_queue_utilization = 0;
+#endif
+
+ return NRF_SUCCESS;
+}
+
+
+#ifdef APP_SCHEDULER_WITH_PROFILER
+static void check_queue_utilization(void)
+{
+ uint16_t start = m_queue_start_index;
+ uint16_t end = m_queue_end_index;
+ uint16_t queue_utilization = (end >= start) ? (end - start) :
+ (m_queue_size + 1 - start + end);
+
+ if (queue_utilization > m_max_queue_utilization)
+ {
+ m_max_queue_utilization = queue_utilization;
+ }
+}
+
+uint16_t app_sched_queue_utilization_get(void)
+{
+ return m_max_queue_utilization;
+}
+#endif
+
+
+uint32_t app_sched_event_put(void * p_event_data,
+ uint16_t event_data_size,
+ app_sched_event_handler_t handler)
+{
+ uint32_t err_code;
+
+ if (event_data_size <= m_queue_event_size)
+ {
+ uint16_t event_index = 0xFFFF;
+
+ CRITICAL_REGION_ENTER();
+
+ if (!APP_SCHED_QUEUE_FULL())
+ {
+ event_index = m_queue_end_index;
+ m_queue_end_index = next_index(m_queue_end_index);
+ }
+
+ CRITICAL_REGION_EXIT();
+
+ if (event_index != 0xFFFF)
+ {
+ //NOTE: This can be done outside the critical region since the event consumer will
+ //always be called from the main loop, and will thus never interrupt this code.
+ m_queue_event_headers[event_index].handler = handler;
+
+ if ((p_event_data != NULL) && (event_data_size > 0))
+ {
+ memcpy(&m_queue_event_data[event_index * m_queue_event_size],
+ p_event_data,
+ event_data_size);
+ m_queue_event_headers[event_index].event_data_size = event_data_size;
+ }
+ else
+ {
+ m_queue_event_headers[event_index].event_data_size = 0;
+ }
+
+ #ifdef APP_SCHEDULER_WITH_PROFILER
+ check_queue_utilization();
+ #endif
+
+ err_code = NRF_SUCCESS;
+ }
+ else
+ {
+ err_code = NRF_ERROR_NO_MEM;
+ }
+ }
+ else
+ {
+ err_code = NRF_ERROR_INVALID_LENGTH;
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for reading the next event from specified event queue.
+ *
+ * @param[out] pp_event_data Pointer to pointer to event data.
+ * @param[out] p_event_data_size Pointer to size of event data.
+ * @param[out] p_event_handler Pointer to event handler function pointer.
+ *
+ * @return NRF_SUCCESS if new event, NRF_ERROR_NOT_FOUND if event queue is empty.
+ */
+static uint32_t app_sched_event_get(void * * pp_event_data,
+ uint16_t * p_event_data_size,
+ app_sched_event_handler_t * p_event_handler)
+{
+ uint32_t err_code = NRF_ERROR_NOT_FOUND;
+
+ if (!APP_SCHED_QUEUE_EMPTY())
+ {
+ uint16_t event_index;
+
+ //NOTE: There is no need for a critical region here, as this function will only be called
+ //from app_sched_execute() from inside the main loop, so it will never interrupt
+ //app_sched_event_put(). Also, updating of (i.e. writing to) the start index will be
+ //an atomic operation.
+ event_index = m_queue_start_index;
+ m_queue_start_index = next_index(m_queue_start_index);
+
+ *pp_event_data = &m_queue_event_data[event_index * m_queue_event_size];
+ *p_event_data_size = m_queue_event_headers[event_index].event_data_size;
+ *p_event_handler = m_queue_event_headers[event_index].handler;
+
+ err_code = NRF_SUCCESS;
+ }
+
+ return err_code;
+}
+
+
+void app_sched_pause(void)
+{
+ CRITICAL_REGION_ENTER();
+
+ if (m_scheduler_paused_counter < UINT32_MAX)
+ {
+ m_scheduler_paused_counter++;
+ }
+ CRITICAL_REGION_EXIT();
+}
+
+
+void app_sched_resume(void)
+{
+ CRITICAL_REGION_ENTER();
+
+ if (m_scheduler_paused_counter > 0)
+ {
+ m_scheduler_paused_counter--;
+ }
+ CRITICAL_REGION_EXIT();
+}
+
+/**@brief Function for checking if scheduler is paused which means that should break processing
+ * events.
+ *
+ * @return Boolean value - true if scheduler is paused, false otherwise.
+ */
+static __INLINE bool is_app_sched_paused(void)
+{
+ return (m_scheduler_paused_counter > 0);
+}
+
+
+void app_sched_execute(void)
+{
+ void * p_event_data;
+ uint16_t event_data_size;
+ app_sched_event_handler_t event_handler;
+
+ //Get next event (if any), and execute handler
+ while ((!is_app_sched_paused()) &&
+ (app_sched_event_get(&p_event_data, &event_data_size, &event_handler) == NRF_SUCCESS))
+ {
+ event_handler(p_event_data, event_data_size);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f06c2d2b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/sensorsim/sensorsim.c
----------------------------------------------------------------------
diff --git a/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/sensorsim/sensorsim.c b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/sensorsim/sensorsim.c
new file mode 100644
index 0000000..e584666
--- /dev/null
+++ b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/sensorsim/sensorsim.c
@@ -0,0 +1,73 @@
+/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+#include "sensorsim.h"
+
+
+void sensorsim_init(sensorsim_state_t * p_state,
+ const sensorsim_cfg_t * p_cfg)
+{
+ if (p_cfg->start_at_max)
+ {
+ p_state->current_val = p_cfg->max;
+ p_state->is_increasing = false;
+ }
+ else
+ {
+ p_state->current_val = p_cfg->min;
+ p_state->is_increasing = true;
+ }
+}
+
+
+uint32_t sensorsim_measure(sensorsim_state_t * p_state,
+ const sensorsim_cfg_t * p_cfg)
+{
+ if (p_state->is_increasing)
+ {
+ sensorsim_increment(p_state, p_cfg);
+ }
+ else
+ {
+ sensorsim_decrement(p_state, p_cfg);
+ }
+ return p_state->current_val;
+}
+
+void sensorsim_increment(sensorsim_state_t * p_state,
+ const sensorsim_cfg_t * p_cfg)
+{
+ if (p_cfg->max - p_state->current_val > p_cfg->incr)
+ {
+ p_state->current_val += p_cfg->incr;
+ }
+ else
+ {
+ p_state->current_val = p_cfg->max;
+ p_state->is_increasing = false;
+ }
+}
+
+
+void sensorsim_decrement(sensorsim_state_t * p_state,
+ const sensorsim_cfg_t * p_cfg)
+{
+ if (p_state->current_val - p_cfg->min > p_cfg->incr)
+ {
+ p_state->current_val -= p_cfg->incr;
+ }
+ else
+ {
+ p_state->current_val = p_cfg->min;
+ p_state->is_increasing = true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f06c2d2b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/sensorsim/sensorsim.h
----------------------------------------------------------------------
diff --git a/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/sensorsim/sensorsim.h b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/sensorsim/sensorsim.h
new file mode 100644
index 0000000..3aa278d
--- /dev/null
+++ b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/sensorsim/sensorsim.h
@@ -0,0 +1,85 @@
+/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup ble_sdk_lib_sensorsim Sensor Data Simulator
+ * @{
+ * @ingroup ble_sdk_lib
+ * @brief Functions for simulating sensor data.
+ *
+ * @details Currently only a triangular waveform simulator is implemented.
+ */
+
+#ifndef SENSORSIM_H__
+#define SENSORSIM_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/**@brief Triangular waveform sensor simulator configuration. */
+typedef struct
+{
+ uint32_t min; /**< Minimum simulated value. */
+ uint32_t max; /**< Maximum simulated value. */
+ uint32_t incr; /**< Increment between each measurement. */
+ bool start_at_max; /**< TRUE is measurement is to start at the maximum value, FALSE if it is to start at the minimum. */
+} sensorsim_cfg_t;
+
+/**@brief Triangular waveform sensor simulator state. */
+typedef struct
+{
+ uint32_t current_val; /**< Current sensor value. */
+ bool is_increasing; /**< TRUE if the simulator is in increasing state, FALSE otherwise. */
+} sensorsim_state_t;
+
+/**@brief Function for initializing a triangular waveform sensor simulator.
+ *
+ * @param[out] p_state Current state of simulator.
+ * @param[in] p_cfg Simulator configuration.
+ */
+void sensorsim_init(sensorsim_state_t * p_state,
+ const sensorsim_cfg_t * p_cfg);
+
+/**@brief Function for generating a simulated sensor measurement using a triangular waveform generator.
+ *
+ * @param[in,out] p_state Current state of simulator.
+ * @param[in] p_cfg Simulator configuration.
+ *
+ * @return Simulator output.
+ */
+uint32_t sensorsim_measure(sensorsim_state_t * p_state,
+ const sensorsim_cfg_t * p_cfg);
+
+/**@brief Function for incrementing a simulated sensor measurement value.
+ *
+ * @param[in,out] p_state Current state of simulator.
+ * @param[in] p_cfg Simulator configuration.
+ *
+ * @return Simulator output.
+ */
+void sensorsim_increment(sensorsim_state_t * p_state,
+ const sensorsim_cfg_t * p_cfg);
+
+/**@brief Function for decrementing a simulated sensor measurement value.
+ *
+ * @param[in,out] p_state Current state of simulator.
+ * @param[in] p_cfg Simulator configuration.
+ *
+ * @return Simulator output.
+ */
+void sensorsim_decrement(sensorsim_state_t * p_state,
+ const sensorsim_cfg_t * p_cfg);
+
+#endif // SENSORSIM_H__
+
+/** @} */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f06c2d2b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/sha256/sha256.c
----------------------------------------------------------------------
diff --git a/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/sha256/sha256.c b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/sha256/sha256.c
new file mode 100644
index 0000000..79b4484
--- /dev/null
+++ b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/sha256/sha256.c
@@ -0,0 +1,183 @@
+
+/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+
+#include <stdlib.h>
+#include "sha256.h"
+#include "sdk_errors.h"
+#include "sdk_common.h"
+
+
+#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
+#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
+
+#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
+#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
+#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
+#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
+#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
+
+
+static const uint32_t k[64] = {
+ 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
+ 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
+ 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
+ 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
+ 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
+ 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
+ 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
+ 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
+};
+
+
+/**@brief Function for calculating the hash of a 64-byte section of data.
+ *
+ * @param[in,out] ctx Hash instance.
+ * @param[in] data Aray with data to be hashed. Assumed to be 64 bytes long.
+ */
+void sha256_transform(sha256_context_t *ctx, const uint8_t * data)
+{
+ uint32_t a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
+
+ for (i = 0, j = 0; i < 16; ++i, j += 4)
+ m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
+ for ( ; i < 64; ++i)
+ m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
+
+ a = ctx->state[0];
+ b = ctx->state[1];
+ c = ctx->state[2];
+ d = ctx->state[3];
+ e = ctx->state[4];
+ f = ctx->state[5];
+ g = ctx->state[6];
+ h = ctx->state[7];
+
+ for (i = 0; i < 64; ++i) {
+ t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
+ t2 = EP0(a) + MAJ(a,b,c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + t1;
+ d = c;
+ c = b;
+ b = a;
+ a = t1 + t2;
+ }
+
+ ctx->state[0] += a;
+ ctx->state[1] += b;
+ ctx->state[2] += c;
+ ctx->state[3] += d;
+ ctx->state[4] += e;
+ ctx->state[5] += f;
+ ctx->state[6] += g;
+ ctx->state[7] += h;
+}
+
+
+ret_code_t sha256_init(sha256_context_t *ctx)
+{
+ VERIFY_PARAM_NOT_NULL(ctx);
+
+ ctx->datalen = 0;
+ ctx->bitlen = 0;
+ ctx->state[0] = 0x6a09e667;
+ ctx->state[1] = 0xbb67ae85;
+ ctx->state[2] = 0x3c6ef372;
+ ctx->state[3] = 0xa54ff53a;
+ ctx->state[4] = 0x510e527f;
+ ctx->state[5] = 0x9b05688c;
+ ctx->state[6] = 0x1f83d9ab;
+ ctx->state[7] = 0x5be0cd19;
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t sha256_update(sha256_context_t *ctx, const uint8_t * data, size_t len)
+{
+ VERIFY_PARAM_NOT_NULL(ctx);
+ if (((len > 0) && (data == NULL)))
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ uint32_t i;
+
+ for (i = 0; i < len; ++i) {
+ ctx->data[ctx->datalen] = data[i];
+ ctx->datalen++;
+ if (ctx->datalen == 64) {
+ sha256_transform(ctx, ctx->data);
+ ctx->bitlen += 512;
+ ctx->datalen = 0;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t sha256_final(sha256_context_t *ctx, uint8_t * hash)
+{
+ VERIFY_PARAM_NOT_NULL(ctx);
+ VERIFY_PARAM_NOT_NULL(hash);
+
+ uint32_t i;
+
+ i = ctx->datalen;
+
+ // Pad whatever data is left in the buffer.
+ if (ctx->datalen < 56) {
+ ctx->data[i++] = 0x80;
+ while (i < 56)
+ ctx->data[i++] = 0x00;
+ }
+ else {
+ ctx->data[i++] = 0x80;
+ while (i < 64)
+ ctx->data[i++] = 0x00;
+ sha256_transform(ctx, ctx->data);
+ memset(ctx->data, 0, 56);
+ }
+
+ // Append to the padding the total message's length in bits and transform.
+ ctx->bitlen += (uint64_t)ctx->datalen * 8;
+ ctx->data[63] = ctx->bitlen;
+ ctx->data[62] = ctx->bitlen >> 8;
+ ctx->data[61] = ctx->bitlen >> 16;
+ ctx->data[60] = ctx->bitlen >> 24;
+ ctx->data[59] = ctx->bitlen >> 32;
+ ctx->data[58] = ctx->bitlen >> 40;
+ ctx->data[57] = ctx->bitlen >> 48;
+ ctx->data[56] = ctx->bitlen >> 56;
+ sha256_transform(ctx, ctx->data);
+
+ // Since this implementation uses little endian uint8_t ordering and SHA uses big endian,
+ // reverse all the uint8_ts when copying the final state to the output hash.
+ for (i = 0; i < 4; ++i) {
+ hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
+ }
+
+ return NRF_SUCCESS;
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f06c2d2b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/sha256/sha256.h
----------------------------------------------------------------------
diff --git a/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/sha256/sha256.h b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/sha256/sha256.h
new file mode 100644
index 0000000..acea32b
--- /dev/null
+++ b/hw/mcu/nordic/src/ext/nRF5_SDK_11.0.0_89a8197/components/libraries/sha256/sha256.h
@@ -0,0 +1,91 @@
+
+/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup sha256 SHA-256 hash library
+ * @{
+ * @ingroup app_common
+ *
+ * @brief This module calculates SHA-256 (SHA-2, FIPS-180) hashes.
+ *
+ * @details To use this module, first call @ref sha256_init on a @ref sha256_context_t instance. Then call @ref
+ * sha256_update with the data to be hashed. This step can optionally be done with multiple
+ * calls to @ref sha256_update, each with a section of the data (in the correct order).
+ * After all data has been passed to @ref sha256_update, call @ref sha256_final to finalize
+ * and extract the hash value.
+ *
+ * This code is adapted from code by Brad Conte, retrieved from
+ * https://github.com/B-Con/crypto-algorithms.
+ *
+ */
+
+#ifndef SHA256_H
+#define SHA256_H
+
+
+#include <stdint.h>
+#include "sdk_errors.h"
+
+
+/**@brief Current state of a hash operation.
+ */
+typedef struct {
+ uint8_t data[64];
+ uint32_t datalen;
+ uint64_t bitlen;
+ uint32_t state[8];
+} sha256_context_t;
+
+
+/**@brief Function for initializing a @ref sha256_context_t instance.
+ *
+ * @param[out] ctx Context instance to be initialized.
+ *
+ * @retval NRF_SUCCESS If the instance was successfully initialized.
+ * @retval NRF_ERROR_NULL If the parameter was NULL.
+ */
+ret_code_t sha256_init(sha256_context_t *ctx);
+
+/**@brief Function for calculating the hash of an array of uint8_t data.
+ *
+ * @details This function can be called multiple times in sequence. This is equivalent to calling
+ * the function once on a concatenation of the data from the different calls.
+ *
+ * @param[in,out] ctx Hash instance.
+ * @param[in] data Data to be hashed.
+ * @param[in] len Length of the data to be hashed.
+ *
+ * @retval NRF_SUCCESS If the data was successfully hashed.
+ * @retval NRF_ERROR_NULL If the ctx parameter was NULL or the data parameter was NULL, while the len parameter was not zero.
+ */
+ret_code_t sha256_update(sha256_context_t *ctx, const uint8_t * data, const size_t len);
+
+/**@brief Function for extracting the hash value from a hash instance.
+ *
+ * @details This function should be called after all data to be hashed has been passed to the hash
+ * instance (by one or more calls to @ref sha256_update).
+ *
+ * Do not call @ref sha256_update again after @ref sha256_final has been called.
+ *
+ * @param[in,out] ctx Hash instance.
+ * @param[out] hash Array to hold the extracted hash value (assumed to be 32 bytes long).
+ *
+ * @retval NRF_SUCCESS If the has value was successfully extracted.
+ * @retval NRF_ERROR_NULL If a parameter was NULL.
+ */
+ret_code_t sha256_final(sha256_context_t *ctx, uint8_t * hash);
+
+#endif // SHA256_H
+
+/** @} */