John Karatka / mbed

Fork of mbed-dev by mbed official

Committer:
<>
Date:
Tue Nov 08 17:45:16 2016 +0000
Revision:
150:02e0a0aed4ec
Parent:
149:156823d33999
This updates the lib to the mbed lib v129

Who changed what in which revision?

UserRevisionLine numberNew contents of line
<> 149:156823d33999 1 /*
<> 149:156823d33999 2 * Copyright (c) 2015 Nordic Semiconductor ASA
<> 149:156823d33999 3 * All rights reserved.
<> 149:156823d33999 4 *
<> 149:156823d33999 5 * Redistribution and use in source and binary forms, with or without modification,
<> 149:156823d33999 6 * are permitted provided that the following conditions are met:
<> 149:156823d33999 7 *
<> 149:156823d33999 8 * 1. Redistributions of source code must retain the above copyright notice, this list
<> 149:156823d33999 9 * of conditions and the following disclaimer.
<> 149:156823d33999 10 *
<> 149:156823d33999 11 * 2. Redistributions in binary form, except as embedded into a Nordic Semiconductor ASA
<> 149:156823d33999 12 * integrated circuit in a product or a software update for such product, must reproduce
<> 149:156823d33999 13 * the above copyright notice, this list of conditions and the following disclaimer in
<> 149:156823d33999 14 * the documentation and/or other materials provided with the distribution.
<> 149:156823d33999 15 *
<> 149:156823d33999 16 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its contributors may be
<> 149:156823d33999 17 * used to endorse or promote products derived from this software without specific prior
<> 149:156823d33999 18 * written permission.
<> 149:156823d33999 19 *
<> 149:156823d33999 20 * 4. This software, with or without modification, must only be used with a
<> 149:156823d33999 21 * Nordic Semiconductor ASA integrated circuit.
<> 149:156823d33999 22 *
<> 149:156823d33999 23 * 5. Any software provided in binary or object form under this license must not be reverse
<> 149:156823d33999 24 * engineered, decompiled, modified and/or disassembled.
<> 149:156823d33999 25 *
<> 149:156823d33999 26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
<> 149:156823d33999 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
<> 149:156823d33999 28 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
<> 149:156823d33999 29 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
<> 149:156823d33999 30 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
<> 149:156823d33999 31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
<> 149:156823d33999 32 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
<> 149:156823d33999 33 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
<> 149:156823d33999 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
<> 149:156823d33999 35 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<> 149:156823d33999 36 *
<> 149:156823d33999 37 */
<> 149:156823d33999 38
<> 149:156823d33999 39
<> 149:156823d33999 40 #include "app_pwm.h"
<> 149:156823d33999 41 #include "nrf_drv_timer.h"
<> 149:156823d33999 42 #include "nrf_drv_ppi.h"
<> 149:156823d33999 43 #include "nrf_drv_common.h"
<> 149:156823d33999 44 #include "nrf_drv_gpiote.h"
<> 149:156823d33999 45 #include "nrf_gpiote.h"
<> 149:156823d33999 46 #include "nrf_gpio.h"
<> 149:156823d33999 47 #include "app_util.h"
<> 149:156823d33999 48 #include "app_util_platform.h"
<> 149:156823d33999 49 #include "nrf_assert.h"
<> 149:156823d33999 50
<> 149:156823d33999 51 #define APP_PWM_CHANNEL_INITIALIZED 1
<> 149:156823d33999 52 #define APP_PWM_CHANNEL_UNINITIALIZED 0
<> 149:156823d33999 53
<> 149:156823d33999 54 #define APP_PWM_CHANNEL_ENABLED 1
<> 149:156823d33999 55 #define APP_PWM_CHANNEL_DISABLED 0
<> 149:156823d33999 56
<> 149:156823d33999 57 #define TIMER_PRESCALER_MAX 9
<> 149:156823d33999 58 #define TIMER_MAX_PULSEWIDTH_US_ON_16M 4095
<> 149:156823d33999 59
<> 149:156823d33999 60 #define APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE 2
<> 149:156823d33999 61 #define APP_PWM_REQUIRED_PPI_CHANNELS_PER_CHANNEL 2
<> 149:156823d33999 62
<> 149:156823d33999 63 #define UNALLOCATED 0xFFFFFFFFUL
<> 149:156823d33999 64 #define BUSY_STATE_CHANGING 0xFE
<> 149:156823d33999 65 #define BUSY_STATE_IDLE 0xFF
<> 149:156823d33999 66
<> 149:156823d33999 67 #define PWM_MAIN_CC_CHANNEL 2
<> 149:156823d33999 68 #define PWM_SECONDARY_CC_CHANNEL 3
<> 149:156823d33999 69
<> 149:156823d33999 70 #ifdef NRF52
<> 149:156823d33999 71 static bool m_use_ppi_delay_workaround;
<> 149:156823d33999 72 #endif
<> 149:156823d33999 73
<> 149:156823d33999 74
<> 149:156823d33999 75 /**
<> 149:156823d33999 76 * @brief PWM busy status
<> 149:156823d33999 77 *
<> 149:156823d33999 78 * Stores the number of a channel being currently updated.
<> 149:156823d33999 79 *
<> 149:156823d33999 80 */
<> 149:156823d33999 81 static volatile uint8_t m_pwm_busy[TIMER_COUNT];
<> 149:156823d33999 82
<> 149:156823d33999 83
<> 149:156823d33999 84 /**
<> 149:156823d33999 85 * @brief New duty cycle value
<> 149:156823d33999 86 *
<> 149:156823d33999 87 * When the channel duty cycle reaches this value, the update process is complete.
<> 149:156823d33999 88 */
<> 149:156823d33999 89 static volatile uint32_t m_pwm_target_value[TIMER_COUNT];
<> 149:156823d33999 90
<> 149:156823d33999 91
<> 149:156823d33999 92 /**
<> 149:156823d33999 93 * @brief PWM ready counter
<> 149:156823d33999 94 *
<> 149:156823d33999 95 * The value in this counter is decremented in every PWM cycle after initiating the update.
<> 149:156823d33999 96 * If an event handler function was specified by the user, it is being called
<> 149:156823d33999 97 * after two cycle events (at least one full PWM cycle).
<> 149:156823d33999 98 */
<> 149:156823d33999 99 volatile uint8_t m_pwm_ready_counter[TIMER_COUNT][APP_PWM_CHANNELS_PER_INSTANCE];
<> 149:156823d33999 100
<> 149:156823d33999 101 /**
<> 149:156823d33999 102 * @brief Pointers to instances
<> 149:156823d33999 103 *
<> 149:156823d33999 104 * This array connects any active timer instance number with the pointer to the PWM instance.
<> 149:156823d33999 105 * It is used by the interrupt runtime.
<> 149:156823d33999 106 */
<> 149:156823d33999 107 static const app_pwm_t * m_instances[TIMER_COUNT];
<> 149:156823d33999 108
<> 149:156823d33999 109 // Macros for getting the polarity of given instance/channel.
<> 149:156823d33999 110 #define POLARITY_ACTIVE(INST,CH) (( ((INST)->p_cb)->channels_cb[(CH)].polarity == \
<> 149:156823d33999 111 APP_PWM_POLARITY_ACTIVE_LOW)?(0):(1))
<> 149:156823d33999 112 #define POLARITY_INACTIVE(INST,CH) (( ((INST)->p_cb)->channels_cb[(CH)].polarity == \
<> 149:156823d33999 113 APP_PWM_POLARITY_ACTIVE_LOW)?(1):(0))
<> 149:156823d33999 114
<> 149:156823d33999 115 //lint -save -e534
<> 149:156823d33999 116
<> 149:156823d33999 117 /**
<> 149:156823d33999 118 * @brief Workaround for PAN-73.
<> 149:156823d33999 119 *
<> 149:156823d33999 120 * @param[in] timer Timer.
<> 149:156823d33999 121 * @param[in] enable Enable or disable.
<> 149:156823d33999 122 */
<> 149:156823d33999 123 static void pan73_workaround(NRF_TIMER_Type * p_timer, bool enable)
<> 149:156823d33999 124 {
<> 149:156823d33999 125 #ifdef NRF51
<> 149:156823d33999 126 if (p_timer == NRF_TIMER0)
<> 149:156823d33999 127 {
<> 149:156823d33999 128 *(uint32_t *)0x40008C0C = (enable ? 1 : 0);
<> 149:156823d33999 129 }
<> 149:156823d33999 130 else if (p_timer == NRF_TIMER1)
<> 149:156823d33999 131 {
<> 149:156823d33999 132 *(uint32_t *)0x40009C0C = (enable ? 1 : 0);
<> 149:156823d33999 133 }
<> 149:156823d33999 134 else if (p_timer == NRF_TIMER2)
<> 149:156823d33999 135 {
<> 149:156823d33999 136 *(uint32_t *)0x4000AC0C = (enable ? 1 : 0);
<> 149:156823d33999 137 }
<> 149:156823d33999 138 #endif
<> 149:156823d33999 139 return;
<> 149:156823d33999 140 }
<> 149:156823d33999 141
<> 149:156823d33999 142 bool app_pwm_busy_check(app_pwm_t const * const p_instance)
<> 149:156823d33999 143 {
<> 149:156823d33999 144 uint8_t busy_state = (m_pwm_busy[p_instance->p_timer->instance_id]);
<> 149:156823d33999 145 bool busy = true;
<> 149:156823d33999 146 if (busy_state != BUSY_STATE_IDLE)
<> 149:156823d33999 147 {
<> 149:156823d33999 148 if (busy_state != BUSY_STATE_CHANGING)
<> 149:156823d33999 149 {
<> 149:156823d33999 150 if (nrf_drv_timer_capture_get(p_instance->p_timer, (nrf_timer_cc_channel_t) busy_state)
<> 149:156823d33999 151 == m_pwm_target_value[p_instance->p_timer->instance_id])
<> 149:156823d33999 152 {
<> 149:156823d33999 153 m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE;
<> 149:156823d33999 154 busy = false;
<> 149:156823d33999 155 }
<> 149:156823d33999 156 }
<> 149:156823d33999 157 }
<> 149:156823d33999 158 else
<> 149:156823d33999 159 {
<> 149:156823d33999 160 busy = false;
<> 149:156823d33999 161 }
<> 149:156823d33999 162 return busy;
<> 149:156823d33999 163 }
<> 149:156823d33999 164
<> 149:156823d33999 165
<> 149:156823d33999 166 /**
<> 149:156823d33999 167 * @brief Function for enabling the IRQ for a given PWM instance.
<> 149:156823d33999 168 *
<> 149:156823d33999 169 * @param[in] p_instance PWM instance.
<> 149:156823d33999 170 */
<> 149:156823d33999 171 __STATIC_INLINE void pwm_irq_enable(app_pwm_t const * const p_instance)
<> 149:156823d33999 172 {
<> 149:156823d33999 173 nrf_drv_timer_compare_int_enable(p_instance->p_timer, PWM_MAIN_CC_CHANNEL);
<> 149:156823d33999 174 }
<> 149:156823d33999 175
<> 149:156823d33999 176
<> 149:156823d33999 177 /**
<> 149:156823d33999 178 * @brief Function for disabling the IRQ for a given PWM instance.
<> 149:156823d33999 179 *
<> 149:156823d33999 180 * @param[in] p_instance PWM instance.
<> 149:156823d33999 181 */
<> 149:156823d33999 182 __STATIC_INLINE void pwm_irq_disable(app_pwm_t const * const p_instance)
<> 149:156823d33999 183 {
<> 149:156823d33999 184 nrf_drv_timer_compare_int_disable(p_instance->p_timer, PWM_MAIN_CC_CHANNEL);
<> 149:156823d33999 185 }
<> 149:156823d33999 186
<> 149:156823d33999 187
<> 149:156823d33999 188 /**
<> 149:156823d33999 189 * @brief Function for disabling PWM channel PPI.
<> 149:156823d33999 190 *
<> 149:156823d33999 191 * @param[in] p_instance PWM instance.
<> 149:156823d33999 192 */
<> 149:156823d33999 193 __STATIC_INLINE void pwm_channel_ppi_disable(app_pwm_t const * const p_instance, uint8_t channel)
<> 149:156823d33999 194 {
<> 149:156823d33999 195 app_pwm_cb_t * p_cb = p_instance->p_cb;
<> 149:156823d33999 196
<> 149:156823d33999 197 nrf_drv_ppi_channel_disable(p_cb->channels_cb[channel].ppi_channels[0]);
<> 149:156823d33999 198 nrf_drv_ppi_channel_disable(p_cb->channels_cb[channel].ppi_channels[1]);
<> 149:156823d33999 199 }
<> 149:156823d33999 200
<> 149:156823d33999 201
<> 149:156823d33999 202 /**
<> 149:156823d33999 203 * @brief Function for disabling PWM PPI.
<> 149:156823d33999 204 *
<> 149:156823d33999 205 * @param[in] p_instance PWM instance.
<> 149:156823d33999 206 */
<> 149:156823d33999 207 __STATIC_INLINE void pwm_ppi_disable(app_pwm_t const * const p_instance)
<> 149:156823d33999 208 {
<> 149:156823d33999 209 app_pwm_cb_t * p_cb = p_instance->p_cb;
<> 149:156823d33999 210
<> 149:156823d33999 211 nrf_drv_ppi_channel_disable(p_cb->ppi_channels[0]);
<> 149:156823d33999 212 nrf_drv_ppi_channel_disable(p_cb->ppi_channels[1]);
<> 149:156823d33999 213 }
<> 149:156823d33999 214
<> 149:156823d33999 215
<> 149:156823d33999 216 /**
<> 149:156823d33999 217 * @brief This function is called on interrupt after duty set.
<> 149:156823d33999 218 *
<> 149:156823d33999 219 * @param[in] timer Timer used by PWM.
<> 149:156823d33999 220 * @param[in] timer_instance_id Timer index.
<> 149:156823d33999 221 */
<> 149:156823d33999 222 void pwm_ready_tick(nrf_timer_event_t event_type, void * p_context)
<> 149:156823d33999 223 {
<> 149:156823d33999 224 uint32_t timer_instance_id = (uint32_t)p_context;
<> 149:156823d33999 225 uint8_t disable = 1;
<> 149:156823d33999 226
<> 149:156823d33999 227 for (uint8_t channel = 0; channel < APP_PWM_CHANNELS_PER_INSTANCE; ++channel)
<> 149:156823d33999 228 {
<> 149:156823d33999 229 if (m_pwm_ready_counter[timer_instance_id][channel])
<> 149:156823d33999 230 {
<> 149:156823d33999 231 --m_pwm_ready_counter[timer_instance_id][channel];
<> 149:156823d33999 232 if (!m_pwm_ready_counter[timer_instance_id][channel])
<> 149:156823d33999 233 {
<> 149:156823d33999 234 app_pwm_cb_t * p_cb = m_instances[timer_instance_id]->p_cb;
<> 149:156823d33999 235 p_cb->p_ready_callback(timer_instance_id);
<> 149:156823d33999 236 }
<> 149:156823d33999 237 else
<> 149:156823d33999 238 {
<> 149:156823d33999 239 disable = 0;
<> 149:156823d33999 240 }
<> 149:156823d33999 241 }
<> 149:156823d33999 242 }
<> 149:156823d33999 243
<> 149:156823d33999 244 if (disable)
<> 149:156823d33999 245 {
<> 149:156823d33999 246 pwm_irq_disable(m_instances[timer_instance_id]);
<> 149:156823d33999 247 }
<> 149:156823d33999 248 }
<> 149:156823d33999 249
<> 149:156823d33999 250
<> 149:156823d33999 251 /**
<> 149:156823d33999 252 * @brief Function for resource de-allocation.
<> 149:156823d33999 253 *
<> 149:156823d33999 254 * @param[in] p_instance PWM instance.
<> 149:156823d33999 255 */
<> 149:156823d33999 256 //lint -e{650}
<> 149:156823d33999 257 static void pwm_dealloc(app_pwm_t const * const p_instance)
<> 149:156823d33999 258 {
<> 149:156823d33999 259 app_pwm_cb_t * p_cb = p_instance->p_cb;
<> 149:156823d33999 260
<> 149:156823d33999 261 for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE; ++i)
<> 149:156823d33999 262 {
<> 149:156823d33999 263 if (p_cb->ppi_channels[i] != (nrf_ppi_channel_t)(uint8_t)(UNALLOCATED))
<> 149:156823d33999 264 {
<> 149:156823d33999 265 nrf_drv_ppi_channel_free(p_cb->ppi_channels[i]);
<> 149:156823d33999 266 }
<> 149:156823d33999 267 }
<> 149:156823d33999 268 if (p_cb->ppi_group != (nrf_ppi_channel_group_t)UNALLOCATED)
<> 149:156823d33999 269 {
<> 149:156823d33999 270 nrf_drv_ppi_group_free(p_cb->ppi_group);
<> 149:156823d33999 271 }
<> 149:156823d33999 272
<> 149:156823d33999 273 for (uint8_t ch = 0; ch < APP_PWM_CHANNELS_PER_INSTANCE; ++ch)
<> 149:156823d33999 274 {
<> 149:156823d33999 275 for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_CHANNEL; ++i)
<> 149:156823d33999 276 {
<> 149:156823d33999 277 if (p_cb->channels_cb[ch].ppi_channels[i] != (nrf_ppi_channel_t)UNALLOCATED)
<> 149:156823d33999 278 {
<> 149:156823d33999 279 nrf_drv_ppi_channel_free(p_cb->channels_cb[ch].ppi_channels[i]);
<> 149:156823d33999 280 p_cb->channels_cb[ch].ppi_channels[i] = (nrf_ppi_channel_t)UNALLOCATED;
<> 149:156823d33999 281 }
<> 149:156823d33999 282 }
<> 149:156823d33999 283 if (p_cb->channels_cb[ch].gpio_pin != UNALLOCATED)
<> 149:156823d33999 284 {
<> 149:156823d33999 285 nrf_drv_gpiote_out_uninit(p_cb->channels_cb[ch].gpio_pin);
<> 149:156823d33999 286 p_cb->channels_cb[ch].gpio_pin = UNALLOCATED;
<> 149:156823d33999 287 }
<> 149:156823d33999 288 p_cb->channels_cb[ch].initialized = APP_PWM_CHANNEL_UNINITIALIZED;
<> 149:156823d33999 289 }
<> 149:156823d33999 290 nrf_drv_timer_uninit(p_instance->p_timer);
<> 149:156823d33999 291 return;
<> 149:156823d33999 292 }
<> 149:156823d33999 293
<> 149:156823d33999 294
<> 149:156823d33999 295 /**
<> 149:156823d33999 296 * @brief PWM state transition from (0%, 100%) to 0% or 100%.
<> 149:156823d33999 297 *
<> 149:156823d33999 298 * @param[in] p_instance PWM instance.
<> 149:156823d33999 299 * @param[in] channel PWM channel number.
<> 149:156823d33999 300 * @param[in] ticks Number of clock ticks.
<> 149:156823d33999 301 */
<> 149:156823d33999 302 static void pwm_transition_n_to_0or100(app_pwm_t const * const p_instance,
<> 149:156823d33999 303 uint8_t channel, uint16_t ticks)
<> 149:156823d33999 304 {
<> 149:156823d33999 305 app_pwm_cb_t * p_cb = p_instance->p_cb;
<> 149:156823d33999 306 app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
<> 149:156823d33999 307 nrf_ppi_channel_group_t p_ppigrp = p_cb->ppi_group;
<> 149:156823d33999 308
<> 149:156823d33999 309 pwm_ppi_disable(p_instance);
<> 149:156823d33999 310 nrf_drv_ppi_group_clear(p_ppigrp);
<> 149:156823d33999 311 nrf_drv_ppi_channels_include_in_group(
<> 149:156823d33999 312 nrf_drv_ppi_channel_to_mask(p_ch_cb->ppi_channels[0]) |
<> 149:156823d33999 313 nrf_drv_ppi_channel_to_mask(p_ch_cb->ppi_channels[1]),
<> 149:156823d33999 314 p_ppigrp);
<> 149:156823d33999 315
<> 149:156823d33999 316 if (!ticks)
<> 149:156823d33999 317 {
<> 149:156823d33999 318 nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0],
<> 149:156823d33999 319 nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel),
<> 149:156823d33999 320 nrf_drv_ppi_task_addr_group_disable_get(p_ppigrp));
<> 149:156823d33999 321 nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, 0, false);
<> 149:156823d33999 322 m_pwm_target_value[p_instance->p_timer->instance_id] =
<> 149:156823d33999 323 nrf_drv_timer_capture_get(p_instance->p_timer, (nrf_timer_cc_channel_t) channel);
<> 149:156823d33999 324 nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1],
<> 149:156823d33999 325 nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel),
<> 149:156823d33999 326 nrf_drv_timer_capture_task_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL));
<> 149:156823d33999 327 }
<> 149:156823d33999 328 else
<> 149:156823d33999 329 {
<> 149:156823d33999 330 ticks = p_cb->period;
<> 149:156823d33999 331 nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0],
<> 149:156823d33999 332 nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL),
<> 149:156823d33999 333 nrf_drv_ppi_task_addr_group_disable_get(p_ppigrp));
<> 149:156823d33999 334 // Set secondary CC channel to non-zero value:
<> 149:156823d33999 335 nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, 1, false);
<> 149:156823d33999 336 m_pwm_target_value[p_instance->p_timer->instance_id] = 0;
<> 149:156823d33999 337 // The captured value will be equal to 0, because timer clear on main PWM CC channel compare is enabled.
<> 149:156823d33999 338 nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1],
<> 149:156823d33999 339 nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL),
<> 149:156823d33999 340 nrf_drv_timer_capture_task_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL));
<> 149:156823d33999 341 }
<> 149:156823d33999 342
<> 149:156823d33999 343 nrf_drv_ppi_channel_enable(p_cb->ppi_channels[0]);
<> 149:156823d33999 344 nrf_drv_ppi_channel_enable(p_cb->ppi_channels[1]);
<> 149:156823d33999 345
<> 149:156823d33999 346 p_ch_cb->pulsewidth = ticks;
<> 149:156823d33999 347 m_pwm_busy[p_instance->p_timer->instance_id] = PWM_SECONDARY_CC_CHANNEL;
<> 149:156823d33999 348 }
<> 149:156823d33999 349
<> 149:156823d33999 350
<> 149:156823d33999 351 /**
<> 149:156823d33999 352 * @brief PWM state transition from (0%, 100%) to (0%, 100%).
<> 149:156823d33999 353 *
<> 149:156823d33999 354 * @param[in] p_instance PWM instance.
<> 149:156823d33999 355 * @param[in] channel PWM channel number.
<> 149:156823d33999 356 * @param[in] ticks Number of clock ticks.
<> 149:156823d33999 357 */
<> 149:156823d33999 358 static void pwm_transition_n_to_m(app_pwm_t const * const p_instance,
<> 149:156823d33999 359 uint8_t channel, uint16_t ticks)
<> 149:156823d33999 360 {
<> 149:156823d33999 361 app_pwm_cb_t * p_cb = p_instance->p_cb;
<> 149:156823d33999 362 app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
<> 149:156823d33999 363 nrf_ppi_channel_group_t p_ppigrp = p_cb->ppi_group;
<> 149:156823d33999 364
<> 149:156823d33999 365 pwm_ppi_disable(p_instance);
<> 149:156823d33999 366 nrf_drv_ppi_group_clear(p_ppigrp);
<> 149:156823d33999 367 nrf_drv_ppi_channels_include_in_group(
<> 149:156823d33999 368 nrf_drv_ppi_channel_to_mask(p_cb->ppi_channels[0]) |
<> 149:156823d33999 369 nrf_drv_ppi_channel_to_mask(p_cb->ppi_channels[1]),
<> 149:156823d33999 370 p_ppigrp);
<> 149:156823d33999 371
<> 149:156823d33999 372 nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0],
<> 149:156823d33999 373 nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL),
<> 149:156823d33999 374 nrf_drv_timer_capture_task_address_get(p_instance->p_timer, channel));
<> 149:156823d33999 375
<> 149:156823d33999 376 #ifdef NRF52
<> 149:156823d33999 377 if (ticks + ((nrf_timer_frequency_get(p_instance->p_timer->p_reg) ==
<> 149:156823d33999 378 (m_use_ppi_delay_workaround ? NRF_TIMER_FREQ_8MHz : NRF_TIMER_FREQ_16MHz) ) ? 1U : 0U)
<> 149:156823d33999 379 < p_ch_cb->pulsewidth)
<> 149:156823d33999 380 #else
<> 149:156823d33999 381 if (ticks + ((nrf_timer_frequency_get(p_instance->p_timer->p_reg) == NRF_TIMER_FREQ_16MHz) ? 1U : 0U)
<> 149:156823d33999 382 < p_ch_cb->pulsewidth)
<> 149:156823d33999 383 #endif
<> 149:156823d33999 384 {
<> 149:156823d33999 385 // For lower value, we need one more transition. Timer task delay is included.
<> 149:156823d33999 386 // If prescaler is disabled, one tick must be added because of 1 PCLK16M clock cycle delay.
<> 149:156823d33999 387 nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1],
<> 149:156823d33999 388 nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL),
<> 149:156823d33999 389 nrf_drv_gpiote_out_task_addr_get(p_ch_cb->gpio_pin));
<> 149:156823d33999 390 }
<> 149:156823d33999 391 else
<> 149:156823d33999 392 {
<> 149:156823d33999 393 nrf_drv_ppi_channel_remove_from_group(p_cb->ppi_channels[1], p_ppigrp);
<> 149:156823d33999 394 }
<> 149:156823d33999 395 p_ch_cb->pulsewidth = ticks;
<> 149:156823d33999 396 nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, ticks, false);
<> 149:156823d33999 397 nrf_drv_ppi_group_enable(p_ppigrp);
<> 149:156823d33999 398
<> 149:156823d33999 399 m_pwm_target_value[p_instance->p_timer->instance_id] = ticks;
<> 149:156823d33999 400 m_pwm_busy[p_instance->p_timer->instance_id] = channel;
<> 149:156823d33999 401 }
<> 149:156823d33999 402
<> 149:156823d33999 403
<> 149:156823d33999 404 /**
<> 149:156823d33999 405 * @brief PWM state transition from 0% or 100% to (0%, 100%).
<> 149:156823d33999 406 *
<> 149:156823d33999 407 * @param[in] p_instance PWM instance.
<> 149:156823d33999 408 * @param[in] channel PWM channel number.
<> 149:156823d33999 409 * @param[in] ticks Number of clock ticks.
<> 149:156823d33999 410 */
<> 149:156823d33999 411 static void pwm_transition_0or100_to_n(app_pwm_t const * const p_instance,
<> 149:156823d33999 412 uint8_t channel, uint16_t ticks)
<> 149:156823d33999 413 {
<> 149:156823d33999 414 app_pwm_cb_t * p_cb = p_instance->p_cb;
<> 149:156823d33999 415 app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
<> 149:156823d33999 416 nrf_ppi_channel_group_t p_ppigrp = p_cb->ppi_group;
<> 149:156823d33999 417 nrf_timer_cc_channel_t pwm_ch_cc = (nrf_timer_cc_channel_t)(channel);
<> 149:156823d33999 418
<> 149:156823d33999 419 pwm_ppi_disable(p_instance);
<> 149:156823d33999 420 pwm_channel_ppi_disable(p_instance, channel);
<> 149:156823d33999 421
<> 149:156823d33999 422 nrf_drv_timer_compare(p_instance->p_timer, pwm_ch_cc, ticks, false);
<> 149:156823d33999 423 nrf_drv_ppi_group_clear(p_ppigrp);
<> 149:156823d33999 424 nrf_drv_ppi_channels_include_in_group(
<> 149:156823d33999 425 nrf_drv_ppi_channel_to_mask(p_ch_cb->ppi_channels[0])|
<> 149:156823d33999 426 nrf_drv_ppi_channel_to_mask(p_ch_cb->ppi_channels[1]),
<> 149:156823d33999 427 p_ppigrp);
<> 149:156823d33999 428
<> 149:156823d33999 429 if (!p_ch_cb->pulsewidth)
<> 149:156823d33999 430 {
<> 149:156823d33999 431 // Channel is at 0%.
<> 149:156823d33999 432 nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0],
<> 149:156823d33999 433 nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel),
<> 149:156823d33999 434 nrf_drv_ppi_task_addr_group_enable_get(p_ppigrp));
<> 149:156823d33999 435 nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, 0, false);
<> 149:156823d33999 436 m_pwm_target_value[p_instance->p_timer->instance_id] =
<> 149:156823d33999 437 nrf_drv_timer_capture_get(p_instance->p_timer, (nrf_timer_cc_channel_t) channel);
<> 149:156823d33999 438 nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1],
<> 149:156823d33999 439 nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel),
<> 149:156823d33999 440 nrf_drv_timer_capture_task_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL));
<> 149:156823d33999 441
<> 149:156823d33999 442 }
<> 149:156823d33999 443 else
<> 149:156823d33999 444 {
<> 149:156823d33999 445 // Channel is at 100%.
<> 149:156823d33999 446 nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0],
<> 149:156823d33999 447 nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL),
<> 149:156823d33999 448 nrf_drv_ppi_task_addr_group_enable_get(p_ppigrp));
<> 149:156823d33999 449 // Set secondary CC channel to non-zero value:
<> 149:156823d33999 450 nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, 1, false);
<> 149:156823d33999 451 m_pwm_target_value[p_instance->p_timer->instance_id] = 0;
<> 149:156823d33999 452 // The captured value will be equal to 0, because timer clear on main PWM CC channel compare is enabled.
<> 149:156823d33999 453 nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1],
<> 149:156823d33999 454 nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL),
<> 149:156823d33999 455 nrf_drv_timer_capture_task_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL));
<> 149:156823d33999 456 }
<> 149:156823d33999 457 nrf_drv_ppi_channel_enable(p_cb->ppi_channels[0]);
<> 149:156823d33999 458 nrf_drv_ppi_channel_enable(p_cb->ppi_channels[1]);
<> 149:156823d33999 459
<> 149:156823d33999 460 p_ch_cb->pulsewidth = ticks;
<> 149:156823d33999 461 m_pwm_busy[p_instance->p_timer->instance_id] = PWM_SECONDARY_CC_CHANNEL;
<> 149:156823d33999 462 }
<> 149:156823d33999 463
<> 149:156823d33999 464
<> 149:156823d33999 465 /**
<> 149:156823d33999 466 * @brief PWM state transition from 0% or 100% to 0% or 100%.
<> 149:156823d33999 467 *
<> 149:156823d33999 468 * @param[in] p_instance PWM instance.
<> 149:156823d33999 469 * @param[in] channel PWM channel number.
<> 149:156823d33999 470 * @param[in] ticks Number of clock ticks.
<> 149:156823d33999 471 */
<> 149:156823d33999 472 static void pwm_transition_0or100_to_0or100(app_pwm_t const * const p_instance,
<> 149:156823d33999 473 uint8_t channel, uint16_t ticks)
<> 149:156823d33999 474 {
<> 149:156823d33999 475 app_pwm_cb_t * p_cb = p_instance->p_cb;
<> 149:156823d33999 476 app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
<> 149:156823d33999 477 nrf_timer_cc_channel_t pwm_ch_cc = (nrf_timer_cc_channel_t)(channel);
<> 149:156823d33999 478
<> 149:156823d33999 479 pwm_ppi_disable(p_instance);
<> 149:156823d33999 480 pwm_channel_ppi_disable(p_instance, channel);
<> 149:156823d33999 481 if (!ticks)
<> 149:156823d33999 482 {
<> 149:156823d33999 483 // Set to 0%.
<> 149:156823d33999 484 nrf_drv_gpiote_out_task_force(p_ch_cb->gpio_pin, POLARITY_INACTIVE(p_instance, channel));
<> 149:156823d33999 485 }
<> 149:156823d33999 486 else if (ticks >= p_cb->period)
<> 149:156823d33999 487 {
<> 149:156823d33999 488 // Set to 100%.
<> 149:156823d33999 489 ticks = p_cb->period;
<> 149:156823d33999 490 nrf_drv_gpiote_out_task_force(p_ch_cb->gpio_pin, POLARITY_ACTIVE(p_instance, channel));
<> 149:156823d33999 491 }
<> 149:156823d33999 492 nrf_drv_timer_compare(p_instance->p_timer, pwm_ch_cc, ticks, false);
<> 149:156823d33999 493 p_ch_cb->pulsewidth = ticks;
<> 149:156823d33999 494
<> 149:156823d33999 495 m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE;
<> 149:156823d33999 496 return;
<> 149:156823d33999 497 }
<> 149:156823d33999 498
<> 149:156823d33999 499
<> 149:156823d33999 500 ret_code_t app_pwm_channel_duty_ticks_set(app_pwm_t const * const p_instance,
<> 149:156823d33999 501 uint8_t channel,
<> 149:156823d33999 502 uint16_t ticks)
<> 149:156823d33999 503 {
<> 149:156823d33999 504 app_pwm_cb_t * p_cb = p_instance->p_cb;
<> 149:156823d33999 505 app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
<> 149:156823d33999 506
<> 149:156823d33999 507 ASSERT(channel < APP_PWM_CHANNELS_PER_INSTANCE);
<> 149:156823d33999 508 ASSERT(p_ch_cb->initialized == APP_PWM_CHANNEL_INITIALIZED);
<> 149:156823d33999 509
<> 149:156823d33999 510 if (p_cb->state != NRF_DRV_STATE_POWERED_ON)
<> 149:156823d33999 511 {
<> 149:156823d33999 512 return NRF_ERROR_INVALID_STATE;
<> 149:156823d33999 513 }
<> 149:156823d33999 514 if (ticks == p_ch_cb->pulsewidth)
<> 149:156823d33999 515 {
<> 149:156823d33999 516 if (p_cb->p_ready_callback)
<> 149:156823d33999 517 {
<> 149:156823d33999 518 p_cb->p_ready_callback(p_instance->p_timer->instance_id);
<> 149:156823d33999 519 }
<> 149:156823d33999 520 return NRF_SUCCESS; // No action required.
<> 149:156823d33999 521 }
<> 149:156823d33999 522 if (app_pwm_busy_check(p_instance))
<> 149:156823d33999 523 {
<> 149:156823d33999 524 return NRF_ERROR_BUSY; // PPI channels for synchronization are still in use.
<> 149:156823d33999 525 }
<> 149:156823d33999 526
<> 149:156823d33999 527 m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_CHANGING;
<> 149:156823d33999 528
<> 149:156823d33999 529 // Pulse width change sequence:
<> 149:156823d33999 530 if (!p_ch_cb->pulsewidth || p_ch_cb->pulsewidth >= p_cb->period)
<> 149:156823d33999 531 {
<> 149:156823d33999 532 // Channel is disabled (0%) or at 100%.
<> 149:156823d33999 533 if (!ticks || ticks >= p_cb->period)
<> 149:156823d33999 534 {
<> 149:156823d33999 535 // Set to 0 or 100%.
<> 149:156823d33999 536 pwm_transition_0or100_to_0or100(p_instance, channel, ticks);
<> 149:156823d33999 537 }
<> 149:156823d33999 538 else
<> 149:156823d33999 539 {
<> 149:156823d33999 540 // Other value.
<> 149:156823d33999 541 pwm_transition_0or100_to_n(p_instance, channel, ticks);
<> 149:156823d33999 542 }
<> 149:156823d33999 543 }
<> 149:156823d33999 544 else
<> 149:156823d33999 545 {
<> 149:156823d33999 546 // Channel is at other value.
<> 149:156823d33999 547 if (!ticks || ticks >= p_cb->period)
<> 149:156823d33999 548 {
<> 149:156823d33999 549 // Disable channel (set to 0%) or set to 100%.
<> 149:156823d33999 550 pwm_transition_n_to_0or100(p_instance, channel, ticks);
<> 149:156823d33999 551 }
<> 149:156823d33999 552 else
<> 149:156823d33999 553 {
<> 149:156823d33999 554 // Set to any other value.
<> 149:156823d33999 555 pwm_transition_n_to_m(p_instance, channel, ticks);
<> 149:156823d33999 556 }
<> 149:156823d33999 557 }
<> 149:156823d33999 558 if (p_instance->p_cb->p_ready_callback)
<> 149:156823d33999 559 {
<> 149:156823d33999 560 //PWM ready interrupt handler will be called after one full period.
<> 149:156823d33999 561 m_pwm_ready_counter[p_instance->p_timer->instance_id][channel] = 2;
<> 149:156823d33999 562 pwm_irq_enable(p_instance);
<> 149:156823d33999 563 }
<> 149:156823d33999 564 return NRF_SUCCESS;
<> 149:156823d33999 565 }
<> 149:156823d33999 566
<> 149:156823d33999 567 uint16_t app_pwm_channel_duty_ticks_get(app_pwm_t const * const p_instance, uint8_t channel)
<> 149:156823d33999 568 {
<> 149:156823d33999 569 app_pwm_cb_t * p_cb = p_instance->p_cb;
<> 149:156823d33999 570 app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
<> 149:156823d33999 571
<> 149:156823d33999 572 return p_ch_cb->pulsewidth;
<> 149:156823d33999 573 }
<> 149:156823d33999 574
<> 149:156823d33999 575 uint16_t app_pwm_cycle_ticks_get(app_pwm_t const * const p_instance)
<> 149:156823d33999 576 {
<> 149:156823d33999 577 app_pwm_cb_t * p_cb = p_instance->p_cb;
<> 149:156823d33999 578
<> 149:156823d33999 579 return (uint16_t)p_cb->period;
<> 149:156823d33999 580 }
<> 149:156823d33999 581
<> 149:156823d33999 582 ret_code_t app_pwm_channel_duty_set(app_pwm_t const * const p_instance,
<> 149:156823d33999 583 uint8_t channel, app_pwm_duty_t duty)
<> 149:156823d33999 584 {
<> 149:156823d33999 585 uint32_t ticks = ((uint32_t)app_pwm_cycle_ticks_get(p_instance) * (uint32_t)duty) / 100UL;
<> 149:156823d33999 586 return app_pwm_channel_duty_ticks_set(p_instance, channel, ticks);
<> 149:156823d33999 587 }
<> 149:156823d33999 588
<> 149:156823d33999 589
<> 149:156823d33999 590 app_pwm_duty_t app_pwm_channel_duty_get(app_pwm_t const * const p_instance, uint8_t channel)
<> 149:156823d33999 591 {
<> 149:156823d33999 592 uint32_t value = ((uint32_t)app_pwm_channel_duty_ticks_get(p_instance, channel) * 100UL) \
<> 149:156823d33999 593 / (uint32_t)app_pwm_cycle_ticks_get(p_instance);
<> 149:156823d33999 594
<> 149:156823d33999 595 return (app_pwm_duty_t)value;
<> 149:156823d33999 596 }
<> 149:156823d33999 597
<> 149:156823d33999 598
<> 149:156823d33999 599 /**
<> 149:156823d33999 600 * @brief Function for initializing the PWM channel.
<> 149:156823d33999 601 *
<> 149:156823d33999 602 * @param[in] p_instance PWM instance.
<> 149:156823d33999 603 * @param[in] channel Channel number.
<> 149:156823d33999 604 * @param[in] pin GPIO pin number.
<> 149:156823d33999 605 *
<> 149:156823d33999 606 * @retval NRF_SUCCESS If initialization was successful.
<> 149:156823d33999 607 * @retval NRF_ERROR_NO_MEM If there were not enough free resources.
<> 149:156823d33999 608 * @retval NRF_ERROR_INVALID_STATE If the timer is already in use or initialization failed.
<> 149:156823d33999 609 */
<> 149:156823d33999 610 static ret_code_t app_pwm_channel_init(app_pwm_t const * const p_instance, uint8_t channel,
<> 149:156823d33999 611 uint32_t pin, app_pwm_polarity_t polarity)
<> 149:156823d33999 612 {
<> 149:156823d33999 613 ASSERT(channel < APP_PWM_CHANNELS_PER_INSTANCE);
<> 149:156823d33999 614 app_pwm_cb_t * p_cb = p_instance->p_cb;
<> 149:156823d33999 615 app_pwm_channel_cb_t * p_channel_cb = &p_cb->channels_cb[channel];
<> 149:156823d33999 616
<> 149:156823d33999 617 if (p_cb->state != NRF_DRV_STATE_UNINITIALIZED)
<> 149:156823d33999 618 {
<> 149:156823d33999 619 return NRF_ERROR_INVALID_STATE;
<> 149:156823d33999 620 }
<> 149:156823d33999 621
<> 149:156823d33999 622 p_channel_cb->pulsewidth = 0;
<> 149:156823d33999 623 p_channel_cb->polarity = polarity;
<> 149:156823d33999 624 ret_code_t err_code;
<> 149:156823d33999 625
<> 149:156823d33999 626 /* GPIOTE setup: */
<> 149:156823d33999 627 nrf_drv_gpiote_out_config_t out_cfg = GPIOTE_CONFIG_OUT_TASK_TOGGLE( POLARITY_INACTIVE(p_instance, channel) );
<> 149:156823d33999 628 err_code = nrf_drv_gpiote_out_init((nrf_drv_gpiote_pin_t)pin,&out_cfg);
<> 149:156823d33999 629 if (err_code != NRF_SUCCESS)
<> 149:156823d33999 630 {
<> 149:156823d33999 631 return NRF_ERROR_NO_MEM;
<> 149:156823d33999 632 }
<> 149:156823d33999 633 p_cb->channels_cb[channel].gpio_pin = pin;
<> 149:156823d33999 634
<> 149:156823d33999 635 // Set output to inactive state.
<> 149:156823d33999 636 if (polarity)
<> 149:156823d33999 637 {
<> 149:156823d33999 638 nrf_gpio_pin_clear(pin);
<> 149:156823d33999 639 }
<> 149:156823d33999 640 else
<> 149:156823d33999 641 {
<> 149:156823d33999 642 nrf_gpio_pin_set(pin);
<> 149:156823d33999 643 }
<> 149:156823d33999 644
<> 149:156823d33999 645 /* PPI setup: */
<> 149:156823d33999 646 for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_CHANNEL; ++i)
<> 149:156823d33999 647 {
<> 149:156823d33999 648 if (nrf_drv_ppi_channel_alloc(&p_channel_cb->ppi_channels[i]) != NRF_SUCCESS)
<> 149:156823d33999 649 {
<> 149:156823d33999 650 return NRF_ERROR_NO_MEM; // Resource de-allocation is done by callee.
<> 149:156823d33999 651 }
<> 149:156823d33999 652 }
<> 149:156823d33999 653
<> 149:156823d33999 654 nrf_drv_ppi_channel_disable(p_channel_cb->ppi_channels[0]);
<> 149:156823d33999 655 nrf_drv_ppi_channel_disable(p_channel_cb->ppi_channels[1]);
<> 149:156823d33999 656 nrf_drv_ppi_channel_assign(p_channel_cb->ppi_channels[0],
<> 149:156823d33999 657 nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel),
<> 149:156823d33999 658 nrf_drv_gpiote_out_task_addr_get(p_channel_cb->gpio_pin));
<> 149:156823d33999 659 nrf_drv_ppi_channel_assign(p_channel_cb->ppi_channels[1],
<> 149:156823d33999 660 nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL),
<> 149:156823d33999 661 nrf_drv_gpiote_out_task_addr_get(p_channel_cb->gpio_pin));
<> 149:156823d33999 662
<> 149:156823d33999 663 p_channel_cb->initialized = APP_PWM_CHANNEL_INITIALIZED;
<> 149:156823d33999 664 m_pwm_ready_counter[p_instance->p_timer->instance_id][channel] = 0;
<> 149:156823d33999 665
<> 149:156823d33999 666 return NRF_SUCCESS;
<> 149:156823d33999 667 }
<> 149:156823d33999 668
<> 149:156823d33999 669
<> 149:156823d33999 670 /**
<> 149:156823d33999 671 * @brief Function for calculating target timer frequency, which will allow to set given period length.
<> 149:156823d33999 672 *
<> 149:156823d33999 673 * @param[in] period_us Desired period in microseconds.
<> 149:156823d33999 674 *
<> 149:156823d33999 675 * @retval Timer frequency.
<> 149:156823d33999 676 */
<> 149:156823d33999 677 __STATIC_INLINE nrf_timer_frequency_t pwm_calculate_timer_frequency(uint32_t period_us)
<> 149:156823d33999 678 {
<> 149:156823d33999 679 uint32_t f = (uint32_t) NRF_TIMER_FREQ_16MHz;
<> 149:156823d33999 680 uint32_t min = (uint32_t) NRF_TIMER_FREQ_31250Hz;
<> 149:156823d33999 681
<> 149:156823d33999 682 while ((period_us > TIMER_MAX_PULSEWIDTH_US_ON_16M) && (f < min))
<> 149:156823d33999 683 {
<> 149:156823d33999 684 period_us >>= 1;
<> 149:156823d33999 685 ++f;
<> 149:156823d33999 686 }
<> 149:156823d33999 687
<> 149:156823d33999 688 #ifdef NRF52
<> 149:156823d33999 689 if ((m_use_ppi_delay_workaround) && (f == (uint32_t) NRF_TIMER_FREQ_16MHz))
<> 149:156823d33999 690 {
<> 149:156823d33999 691 f = (uint32_t) NRF_TIMER_FREQ_8MHz;
<> 149:156823d33999 692 }
<> 149:156823d33999 693 #endif
<> 149:156823d33999 694
<> 149:156823d33999 695 return (nrf_timer_frequency_t) f;
<> 149:156823d33999 696 }
<> 149:156823d33999 697
<> 149:156823d33999 698
<> 149:156823d33999 699 ret_code_t app_pwm_init(app_pwm_t const * const p_instance, app_pwm_config_t const * const p_config,
<> 149:156823d33999 700 app_pwm_callback_t p_ready_callback)
<> 149:156823d33999 701 {
<> 149:156823d33999 702 ASSERT(p_instance);
<> 149:156823d33999 703
<> 149:156823d33999 704 if (!p_config)
<> 149:156823d33999 705 {
<> 149:156823d33999 706 return NRF_ERROR_INVALID_DATA;
<> 149:156823d33999 707 }
<> 149:156823d33999 708
<> 149:156823d33999 709 app_pwm_cb_t * p_cb = p_instance->p_cb;
<> 149:156823d33999 710
<> 149:156823d33999 711 if (p_cb->state != NRF_DRV_STATE_UNINITIALIZED)
<> 149:156823d33999 712 {
<> 149:156823d33999 713 return NRF_ERROR_INVALID_STATE;
<> 149:156823d33999 714 }
<> 149:156823d33999 715
<> 149:156823d33999 716 uint32_t err_code = nrf_drv_ppi_init();
<> 149:156823d33999 717 if ((err_code != NRF_SUCCESS) && (err_code != MODULE_ALREADY_INITIALIZED))
<> 149:156823d33999 718 {
<> 149:156823d33999 719 return NRF_ERROR_NO_MEM;
<> 149:156823d33999 720 }
<> 149:156823d33999 721
<> 149:156823d33999 722
<> 149:156823d33999 723 if (!nrf_drv_gpiote_is_init())
<> 149:156823d33999 724 {
<> 149:156823d33999 725 err_code = nrf_drv_gpiote_init();
<> 149:156823d33999 726 if (err_code != NRF_SUCCESS)
<> 149:156823d33999 727 {
<> 149:156823d33999 728 return NRF_ERROR_INTERNAL;
<> 149:156823d33999 729 }
<> 149:156823d33999 730 }
<> 149:156823d33999 731
<> 149:156823d33999 732 #ifdef NRF52
<> 149:156823d33999 733 if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30)
<> 149:156823d33999 734 {
<> 149:156823d33999 735 m_use_ppi_delay_workaround = false;
<> 149:156823d33999 736 }
<> 149:156823d33999 737 else
<> 149:156823d33999 738 {
<> 149:156823d33999 739 m_use_ppi_delay_workaround = true;
<> 149:156823d33999 740 }
<> 149:156823d33999 741 #endif
<> 149:156823d33999 742
<> 149:156823d33999 743 // Innitialize resource status:
<> 149:156823d33999 744 p_cb->ppi_channels[0] = (nrf_ppi_channel_t)UNALLOCATED;
<> 149:156823d33999 745 p_cb->ppi_channels[1] = (nrf_ppi_channel_t)UNALLOCATED;
<> 149:156823d33999 746 p_cb->ppi_group = (nrf_ppi_channel_group_t)UNALLOCATED;
<> 149:156823d33999 747
<> 149:156823d33999 748 for (uint8_t i = 0; i < APP_PWM_CHANNELS_PER_INSTANCE; ++i)
<> 149:156823d33999 749 {
<> 149:156823d33999 750 p_cb->channels_cb[i].initialized = APP_PWM_CHANNEL_UNINITIALIZED;
<> 149:156823d33999 751 p_cb->channels_cb[i].ppi_channels[0] = (nrf_ppi_channel_t)UNALLOCATED;
<> 149:156823d33999 752 p_cb->channels_cb[i].ppi_channels[1] = (nrf_ppi_channel_t)UNALLOCATED;
<> 149:156823d33999 753 p_cb->channels_cb[i].gpio_pin = UNALLOCATED;
<> 149:156823d33999 754 }
<> 149:156823d33999 755
<> 149:156823d33999 756 // Allocate PPI channels and groups:
<> 149:156823d33999 757 for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE; ++i)
<> 149:156823d33999 758 {
<> 149:156823d33999 759 if (nrf_drv_ppi_channel_alloc(&p_cb->ppi_channels[i]) != NRF_SUCCESS)
<> 149:156823d33999 760 {
<> 149:156823d33999 761 pwm_dealloc(p_instance);
<> 149:156823d33999 762 return NRF_ERROR_NO_MEM;
<> 149:156823d33999 763 }
<> 149:156823d33999 764 }
<> 149:156823d33999 765 if (nrf_drv_ppi_group_alloc(&p_cb->ppi_group) != NRF_SUCCESS)
<> 149:156823d33999 766 {
<> 149:156823d33999 767 pwm_dealloc(p_instance);
<> 149:156823d33999 768 return NRF_ERROR_NO_MEM;
<> 149:156823d33999 769 }
<> 149:156823d33999 770
<> 149:156823d33999 771 // Initialize channels:
<> 149:156823d33999 772 for (uint8_t i = 0; i < APP_PWM_CHANNELS_PER_INSTANCE; ++i)
<> 149:156823d33999 773 {
<> 149:156823d33999 774 if (p_config->pins[i] != APP_PWM_NOPIN)
<> 149:156823d33999 775 {
<> 149:156823d33999 776 err_code = app_pwm_channel_init(p_instance, i, p_config->pins[i], p_config->pin_polarity[i]);
<> 149:156823d33999 777 if (err_code != NRF_SUCCESS)
<> 149:156823d33999 778 {
<> 149:156823d33999 779 pwm_dealloc(p_instance);
<> 149:156823d33999 780 return err_code;
<> 149:156823d33999 781 }
<> 149:156823d33999 782 app_pwm_channel_duty_ticks_set(p_instance, i, 0);
<> 149:156823d33999 783 }
<> 149:156823d33999 784 }
<> 149:156823d33999 785
<> 149:156823d33999 786 // Initialize timer:
<> 149:156823d33999 787 nrf_timer_frequency_t timer_freq = pwm_calculate_timer_frequency(p_config->period_us);
<> 149:156823d33999 788 nrf_drv_timer_config_t timer_cfg = {
<> 149:156823d33999 789 .frequency = timer_freq,
<> 149:156823d33999 790 .mode = NRF_TIMER_MODE_TIMER,
<> 149:156823d33999 791 .bit_width = NRF_TIMER_BIT_WIDTH_16,
<> 150:02e0a0aed4ec 792 #ifdef NRF51
<> 149:156823d33999 793 .interrupt_priority = APP_IRQ_PRIORITY_LOW,
<> 150:02e0a0aed4ec 794 #elif defined(NRF52)
<> 150:02e0a0aed4ec 795 .interrupt_priority = APP_IRQ_PRIORITY_LOWEST,
<> 150:02e0a0aed4ec 796 #endif
<> 149:156823d33999 797 .p_context = (void *) (uint32_t) p_instance->p_timer->instance_id
<> 149:156823d33999 798 };
<> 149:156823d33999 799 err_code = nrf_drv_timer_init(p_instance->p_timer, &timer_cfg,
<> 149:156823d33999 800 pwm_ready_tick);
<> 149:156823d33999 801 if (err_code != NRF_SUCCESS)
<> 149:156823d33999 802 {
<> 149:156823d33999 803 pwm_dealloc(p_instance);
<> 149:156823d33999 804 return err_code;
<> 149:156823d33999 805 }
<> 149:156823d33999 806
<> 149:156823d33999 807 uint32_t ticks = nrf_drv_timer_us_to_ticks(p_instance->p_timer, p_config->period_us);
<> 149:156823d33999 808 p_cb->period = ticks;
<> 149:156823d33999 809 nrf_drv_timer_clear(p_instance->p_timer);
<> 149:156823d33999 810 nrf_drv_timer_extended_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_MAIN_CC_CHANNEL,
<> 149:156823d33999 811 ticks, NRF_TIMER_SHORT_COMPARE2_CLEAR_MASK, true);
<> 149:156823d33999 812 nrf_drv_timer_compare_int_disable(p_instance->p_timer, PWM_MAIN_CC_CHANNEL);
<> 149:156823d33999 813
<> 149:156823d33999 814 p_cb->p_ready_callback = p_ready_callback;
<> 149:156823d33999 815 m_instances[p_instance->p_timer->instance_id] = p_instance;
<> 149:156823d33999 816 m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE;
<> 149:156823d33999 817 p_cb->state = NRF_DRV_STATE_INITIALIZED;
<> 149:156823d33999 818
<> 149:156823d33999 819 return NRF_SUCCESS;
<> 149:156823d33999 820 }
<> 149:156823d33999 821
<> 149:156823d33999 822
<> 149:156823d33999 823 void app_pwm_enable(app_pwm_t const * const p_instance)
<> 149:156823d33999 824 {
<> 149:156823d33999 825 app_pwm_cb_t * p_cb = p_instance->p_cb;
<> 149:156823d33999 826
<> 149:156823d33999 827 ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED);
<> 149:156823d33999 828
<> 149:156823d33999 829 for (uint32_t channel = 0; channel < APP_PWM_CHANNELS_PER_INSTANCE; ++channel)
<> 149:156823d33999 830 {
<> 149:156823d33999 831 app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
<> 149:156823d33999 832 m_pwm_ready_counter[p_instance->p_timer->instance_id][channel] = 0;
<> 149:156823d33999 833 if (p_ch_cb->initialized)
<> 149:156823d33999 834 {
<> 149:156823d33999 835 nrf_drv_gpiote_out_task_force(p_ch_cb->gpio_pin, POLARITY_INACTIVE(p_instance, channel));
<> 149:156823d33999 836 nrf_drv_gpiote_out_task_enable(p_ch_cb->gpio_pin);
<> 149:156823d33999 837 p_ch_cb->pulsewidth = 0;
<> 149:156823d33999 838 }
<> 149:156823d33999 839 }
<> 149:156823d33999 840 m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE;
<> 149:156823d33999 841 pan73_workaround(p_instance->p_timer->p_reg, true);
<> 149:156823d33999 842 nrf_drv_timer_clear(p_instance->p_timer);
<> 149:156823d33999 843 nrf_drv_timer_enable(p_instance->p_timer);
<> 149:156823d33999 844
<> 149:156823d33999 845 p_cb->state = NRF_DRV_STATE_POWERED_ON;
<> 149:156823d33999 846 return;
<> 149:156823d33999 847 }
<> 149:156823d33999 848
<> 149:156823d33999 849
<> 149:156823d33999 850 void app_pwm_disable(app_pwm_t const * const p_instance)
<> 149:156823d33999 851 {
<> 149:156823d33999 852 app_pwm_cb_t * p_cb = p_instance->p_cb;
<> 149:156823d33999 853
<> 149:156823d33999 854 ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED);
<> 149:156823d33999 855
<> 149:156823d33999 856 nrf_drv_timer_disable(p_instance->p_timer);
<> 149:156823d33999 857 pwm_irq_disable(p_instance);
<> 149:156823d33999 858 for (uint8_t ppi_channel = 0; ppi_channel < APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE; ++ppi_channel)
<> 149:156823d33999 859 {
<> 149:156823d33999 860 nrf_drv_ppi_channel_disable(p_cb->ppi_channels[ppi_channel]);
<> 149:156823d33999 861 }
<> 149:156823d33999 862 for (uint8_t channel = 0; channel < APP_PWM_CHANNELS_PER_INSTANCE; ++channel)
<> 149:156823d33999 863 {
<> 149:156823d33999 864 app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel];
<> 149:156823d33999 865 if (p_ch_cb->initialized)
<> 149:156823d33999 866 {
<> 149:156823d33999 867 uint8_t polarity = POLARITY_INACTIVE(p_instance, channel);
<> 149:156823d33999 868 if (polarity)
<> 149:156823d33999 869 {
<> 149:156823d33999 870 nrf_gpio_pin_set(p_ch_cb->gpio_pin);
<> 149:156823d33999 871 }
<> 149:156823d33999 872 else
<> 149:156823d33999 873 {
<> 149:156823d33999 874 nrf_gpio_pin_clear(p_ch_cb->gpio_pin);
<> 149:156823d33999 875 }
<> 149:156823d33999 876 nrf_drv_gpiote_out_task_disable(p_ch_cb->gpio_pin);
<> 149:156823d33999 877 nrf_drv_ppi_channel_disable(p_ch_cb->ppi_channels[0]);
<> 149:156823d33999 878 nrf_drv_ppi_channel_disable(p_ch_cb->ppi_channels[1]);
<> 149:156823d33999 879 }
<> 149:156823d33999 880 }
<> 149:156823d33999 881 pan73_workaround(p_instance->p_timer->p_reg, false);
<> 149:156823d33999 882
<> 149:156823d33999 883 p_cb->state = NRF_DRV_STATE_INITIALIZED;
<> 149:156823d33999 884 return;
<> 149:156823d33999 885 }
<> 149:156823d33999 886
<> 149:156823d33999 887
<> 149:156823d33999 888 ret_code_t app_pwm_uninit(app_pwm_t const * const p_instance)
<> 149:156823d33999 889 {
<> 149:156823d33999 890 app_pwm_cb_t * p_cb = p_instance->p_cb;
<> 149:156823d33999 891
<> 149:156823d33999 892 if (p_cb->state == NRF_DRV_STATE_POWERED_ON)
<> 149:156823d33999 893 {
<> 149:156823d33999 894 app_pwm_disable(p_instance);
<> 149:156823d33999 895 }
<> 149:156823d33999 896 else if (p_cb->state == NRF_DRV_STATE_UNINITIALIZED)
<> 149:156823d33999 897 {
<> 149:156823d33999 898 return NRF_ERROR_INVALID_STATE;
<> 149:156823d33999 899 }
<> 149:156823d33999 900 pwm_dealloc(p_instance);
<> 149:156823d33999 901
<> 149:156823d33999 902 p_cb->state = NRF_DRV_STATE_UNINITIALIZED;
<> 149:156823d33999 903 return NRF_SUCCESS;
<> 149:156823d33999 904 }
<> 149:156823d33999 905
<> 149:156823d33999 906
<> 149:156823d33999 907 //lint -restore