1 /*
2 * Copyright (c) 2015 - 2020, Nordic Semiconductor ASA
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <nrfx.h>
33
34 #if NRFX_CHECK(NRFX_PWM_ENABLED)
35
36 #if !(NRFX_CHECK(NRFX_PWM0_ENABLED) || NRFX_CHECK(NRFX_PWM1_ENABLED) || \
37 NRFX_CHECK(NRFX_PWM2_ENABLED) || NRFX_CHECK(NRFX_PWM3_ENABLED))
38 #error "No enabled PWM instances. Check <nrfx_config.h>."
39 #endif
40
41 #include <nrfx_pwm.h>
42 #include <hal/nrf_gpio.h>
43
44 #define NRFX_LOG_MODULE PWM
45 #include <nrfx_log.h>
46
47 #if NRFX_CHECK(NRFX_PWM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
48 // The workaround uses interrupts to wake up the CPU and ensure it is active
49 // when PWM is about to start a DMA transfer. For initial transfer, done when
50 // a playback is started via PPI, a specific EGU instance is used to generate
51 // an interrupt. During the playback, the PWM interrupt triggered on SEQEND
52 // event of a preceding sequence is used to protect the transfer done for
53 // the next sequence to be played.
54 #include <hal/nrf_egu.h>
55 #define USE_DMA_ISSUE_WORKAROUND
56 #endif
57 #if defined(USE_DMA_ISSUE_WORKAROUND)
58 #define EGU_IRQn(i) EGU_IRQn_(i)
59 #define EGU_IRQn_(i) SWI##i##_EGU##i##_IRQn
60 #define EGU_IRQHandler(i) EGU_IRQHandler_(i)
61 #define EGU_IRQHandler_(i) nrfx_egu_##i##_irq_handler
62 #define DMA_ISSUE_EGU_IDX NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE
63 #define DMA_ISSUE_EGU NRFX_CONCAT_2(NRF_EGU, DMA_ISSUE_EGU_IDX)
64 #define DMA_ISSUE_EGU_IRQn EGU_IRQn(DMA_ISSUE_EGU_IDX)
65 #define DMA_ISSUE_EGU_IRQHandler EGU_IRQHandler(DMA_ISSUE_EGU_IDX)
66 #endif
67
68 // Control block - driver instance local data.
69 typedef struct
70 {
71 #if defined(USE_DMA_ISSUE_WORKAROUND)
72 uint32_t starting_task_address;
73 #endif
74 nrfx_pwm_handler_t handler;
75 void * p_context;
76 nrfx_drv_state_t volatile state;
77 uint8_t flags;
78 } pwm_control_block_t;
79 static pwm_control_block_t m_cb[NRFX_PWM_ENABLED_COUNT];
80
configure_pins(nrfx_pwm_t const * p_instance,nrfx_pwm_config_t const * p_config)81 static void configure_pins(nrfx_pwm_t const * p_instance,
82 nrfx_pwm_config_t const * p_config)
83 {
84 uint32_t out_pins[NRF_PWM_CHANNEL_COUNT];
85 uint8_t i;
86
87 for (i = 0; i < NRF_PWM_CHANNEL_COUNT; ++i)
88 {
89 uint8_t output_pin = p_config->output_pins[i];
90 if (output_pin != NRFX_PWM_PIN_NOT_USED)
91 {
92 bool inverted = output_pin & NRFX_PWM_PIN_INVERTED;
93 out_pins[i] = output_pin & ~NRFX_PWM_PIN_INVERTED;
94
95 if (!p_config->skip_gpio_cfg)
96 {
97 if (inverted)
98 {
99 nrf_gpio_pin_set(out_pins[i]);
100 }
101 else
102 {
103 nrf_gpio_pin_clear(out_pins[i]);
104 }
105
106 nrf_gpio_cfg_output(out_pins[i]);
107 }
108 }
109 else
110 {
111 out_pins[i] = NRF_PWM_PIN_NOT_CONNECTED;
112 }
113 }
114
115 nrf_pwm_pins_set(p_instance->p_registers, out_pins);
116 }
117
deconfigure_pins(nrfx_pwm_t const * p_instance)118 static void deconfigure_pins(nrfx_pwm_t const * p_instance)
119 {
120 for (uint8_t ch_idx = 0; ch_idx < NRF_PWM_CHANNEL_COUNT; ch_idx++)
121 {
122 uint32_t pin = nrf_pwm_pin_get(p_instance->p_registers, ch_idx);
123 if (pin != NRF_PWM_PIN_NOT_CONNECTED)
124 {
125 nrf_gpio_cfg_default(pin);
126 }
127 }
128 }
129
nrfx_pwm_init(nrfx_pwm_t const * p_instance,nrfx_pwm_config_t const * p_config,nrfx_pwm_handler_t handler,void * p_context)130 nrfx_err_t nrfx_pwm_init(nrfx_pwm_t const * p_instance,
131 nrfx_pwm_config_t const * p_config,
132 nrfx_pwm_handler_t handler,
133 void * p_context)
134 {
135 NRFX_ASSERT(p_config);
136
137 nrfx_err_t err_code;
138
139 pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
140
141 if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
142 {
143 err_code = NRFX_ERROR_INVALID_STATE;
144 NRFX_LOG_WARNING("Function: %s, error code: %s.",
145 __func__,
146 NRFX_LOG_ERROR_STRING_GET(err_code));
147 return err_code;
148 }
149
150 p_cb->handler = handler;
151 p_cb->p_context = p_context;
152
153 configure_pins(p_instance, p_config);
154
155 nrf_pwm_enable(p_instance->p_registers);
156 nrf_pwm_configure(p_instance->p_registers,
157 p_config->base_clock, p_config->count_mode, p_config->top_value);
158 nrf_pwm_decoder_set(p_instance->p_registers,
159 p_config->load_mode, p_config->step_mode);
160
161 nrf_pwm_shorts_set(p_instance->p_registers, 0);
162 nrf_pwm_int_set(p_instance->p_registers, 0);
163 nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_LOOPSDONE);
164 nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_SEQEND0);
165 nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_SEQEND1);
166 nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_STOPPED);
167
168 // The workaround for nRF52 Anomaly 109 "protects" DMA transfers by handling
169 // interrupts generated on SEQEND0 and SEQEND1 events (this ensures that
170 // the 64 MHz clock is ready when data for the next sequence to be played
171 // is read). Therefore, the PWM interrupt must be enabled even if the event
172 // handler is not used.
173 #if defined(USE_DMA_ISSUE_WORKAROUND)
174 NRFX_IRQ_PRIORITY_SET(DMA_ISSUE_EGU_IRQn, p_config->irq_priority);
175 NRFX_IRQ_ENABLE(DMA_ISSUE_EGU_IRQn);
176 #else
177 if (p_cb->handler)
178 #endif
179 {
180 NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_registers),
181 p_config->irq_priority);
182 NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_registers));
183 }
184
185 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
186
187 err_code = NRFX_SUCCESS;
188 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
189 return err_code;
190 }
191
192
nrfx_pwm_uninit(nrfx_pwm_t const * p_instance)193 void nrfx_pwm_uninit(nrfx_pwm_t const * p_instance)
194 {
195 pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
196 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
197
198 NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_registers));
199 #if defined(USE_DMA_ISSUE_WORKAROUND)
200 NRFX_IRQ_DISABLE(DMA_ISSUE_EGU_IRQn);
201 #endif
202
203 nrf_pwm_disable(p_instance->p_registers);
204
205 deconfigure_pins(p_instance);
206
207 p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
208 }
209
210
start_playback(nrfx_pwm_t const * p_instance,pwm_control_block_t * p_cb,uint8_t flags,nrf_pwm_task_t starting_task)211 static uint32_t start_playback(nrfx_pwm_t const * p_instance,
212 pwm_control_block_t * p_cb,
213 uint8_t flags,
214 nrf_pwm_task_t starting_task)
215 {
216 p_cb->state = NRFX_DRV_STATE_POWERED_ON;
217 p_cb->flags = flags;
218
219 if (p_cb->handler)
220 {
221 // The notification about finished playback is by default enabled,
222 // but this can be suppressed.
223 // The notification that the peripheral has stopped is always enabled.
224 uint32_t int_mask = NRF_PWM_INT_LOOPSDONE_MASK |
225 NRF_PWM_INT_STOPPED_MASK;
226
227 // The workaround for nRF52 Anomaly 109 "protects" DMA transfers by
228 // handling interrupts generated on SEQEND0 and SEQEND1 events (see
229 // 'nrfx_pwm_init'), hence these events must be always enabled
230 // to generate interrupts.
231 // However, the user handler is called for them only when requested
232 // (see 'irq_handler').
233 #if defined(USE_DMA_ISSUE_WORKAROUND)
234 int_mask |= NRF_PWM_INT_SEQEND0_MASK | NRF_PWM_INT_SEQEND1_MASK;
235 #else
236 if (flags & NRFX_PWM_FLAG_SIGNAL_END_SEQ0)
237 {
238 int_mask |= NRF_PWM_INT_SEQEND0_MASK;
239 }
240 if (flags & NRFX_PWM_FLAG_SIGNAL_END_SEQ1)
241 {
242 int_mask |= NRF_PWM_INT_SEQEND1_MASK;
243 }
244 #endif
245 if (flags & NRFX_PWM_FLAG_NO_EVT_FINISHED)
246 {
247 int_mask &= ~NRF_PWM_INT_LOOPSDONE_MASK;
248 }
249
250 nrf_pwm_int_set(p_instance->p_registers, int_mask);
251 }
252 #if defined(USE_DMA_ISSUE_WORKAROUND)
253 else
254 {
255 nrf_pwm_int_set(p_instance->p_registers,
256 NRF_PWM_INT_SEQEND0_MASK | NRF_PWM_INT_SEQEND1_MASK);
257 }
258 #endif
259
260 nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_STOPPED);
261
262 if (flags & NRFX_PWM_FLAG_START_VIA_TASK)
263 {
264 uint32_t starting_task_address =
265 nrf_pwm_task_address_get(p_instance->p_registers, starting_task);
266
267 #if defined(USE_DMA_ISSUE_WORKAROUND)
268 // To "protect" the initial DMA transfer it is required to start
269 // the PWM by triggering the proper task from EGU interrupt handler,
270 // it is not safe to do it directly via PPI.
271 p_cb->starting_task_address = starting_task_address;
272 nrf_egu_int_enable(DMA_ISSUE_EGU, nrf_egu_channel_int_get(p_instance->drv_inst_idx));
273 return nrf_egu_task_address_get(DMA_ISSUE_EGU,
274 nrf_egu_trigger_task_get(p_instance->drv_inst_idx));
275 #else
276 return starting_task_address;
277 #endif
278 }
279
280 nrf_pwm_task_trigger(p_instance->p_registers, starting_task);
281 return 0;
282 }
283
284
nrfx_pwm_simple_playback(nrfx_pwm_t const * p_instance,nrf_pwm_sequence_t const * p_sequence,uint16_t playback_count,uint32_t flags)285 uint32_t nrfx_pwm_simple_playback(nrfx_pwm_t const * p_instance,
286 nrf_pwm_sequence_t const * p_sequence,
287 uint16_t playback_count,
288 uint32_t flags)
289 {
290 pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
291 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
292 NRFX_ASSERT(playback_count > 0);
293 NRFX_ASSERT(nrfx_is_in_ram(p_sequence->values.p_raw));
294
295 // To take advantage of the looping mechanism, we need to use both sequences
296 // (single sequence can be played back only once).
297 nrf_pwm_sequence_set(p_instance->p_registers, 0, p_sequence);
298 nrf_pwm_sequence_set(p_instance->p_registers, 1, p_sequence);
299 bool odd = (playback_count & 1);
300 nrf_pwm_loop_set(p_instance->p_registers,
301 (playback_count / 2) + (odd ? 1 : 0));
302
303 uint32_t shorts_mask;
304 if (flags & NRFX_PWM_FLAG_STOP)
305 {
306 shorts_mask = NRF_PWM_SHORT_LOOPSDONE_STOP_MASK;
307 }
308 else if (flags & NRFX_PWM_FLAG_LOOP)
309 {
310 shorts_mask = odd ? NRF_PWM_SHORT_LOOPSDONE_SEQSTART1_MASK
311 : NRF_PWM_SHORT_LOOPSDONE_SEQSTART0_MASK;
312 }
313 else
314 {
315 shorts_mask = 0;
316 }
317 nrf_pwm_shorts_set(p_instance->p_registers, shorts_mask);
318
319 NRFX_LOG_INFO("Function: %s, sequence length: %d.",
320 __func__,
321 p_sequence->length);
322 NRFX_LOG_DEBUG("Sequence data:");
323 NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)p_sequence->values.p_raw,
324 p_sequence->length * sizeof(uint16_t));
325 return start_playback(p_instance, p_cb, flags,
326 odd ? NRF_PWM_TASK_SEQSTART1 : NRF_PWM_TASK_SEQSTART0);
327 }
328
329
nrfx_pwm_complex_playback(nrfx_pwm_t const * p_instance,nrf_pwm_sequence_t const * p_sequence_0,nrf_pwm_sequence_t const * p_sequence_1,uint16_t playback_count,uint32_t flags)330 uint32_t nrfx_pwm_complex_playback(nrfx_pwm_t const * p_instance,
331 nrf_pwm_sequence_t const * p_sequence_0,
332 nrf_pwm_sequence_t const * p_sequence_1,
333 uint16_t playback_count,
334 uint32_t flags)
335 {
336 pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
337 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
338 NRFX_ASSERT(playback_count > 0);
339 NRFX_ASSERT(nrfx_is_in_ram(p_sequence_0->values.p_raw));
340 NRFX_ASSERT(nrfx_is_in_ram(p_sequence_1->values.p_raw));
341
342 nrf_pwm_sequence_set(p_instance->p_registers, 0, p_sequence_0);
343 nrf_pwm_sequence_set(p_instance->p_registers, 1, p_sequence_1);
344 nrf_pwm_loop_set(p_instance->p_registers, playback_count);
345
346 uint32_t shorts_mask;
347 if (flags & NRFX_PWM_FLAG_STOP)
348 {
349 shorts_mask = NRF_PWM_SHORT_LOOPSDONE_STOP_MASK;
350 }
351 else if (flags & NRFX_PWM_FLAG_LOOP)
352 {
353 shorts_mask = NRF_PWM_SHORT_LOOPSDONE_SEQSTART0_MASK;
354 }
355 else
356 {
357 shorts_mask = 0;
358 }
359 nrf_pwm_shorts_set(p_instance->p_registers, shorts_mask);
360
361 NRFX_LOG_INFO("Function: %s, sequence 0 length: %d.",
362 __func__,
363 p_sequence_0->length);
364 NRFX_LOG_INFO("Function: %s, sequence 1 length: %d.",
365 __func__,
366 p_sequence_1->length);
367 NRFX_LOG_DEBUG("Sequence 0 data:");
368 NRFX_LOG_HEXDUMP_DEBUG(p_sequence_0->values.p_raw,
369 p_sequence_0->length * sizeof(uint16_t));
370 NRFX_LOG_DEBUG("Sequence 1 data:");
371 NRFX_LOG_HEXDUMP_DEBUG(p_sequence_1->values.p_raw,
372 p_sequence_1->length * sizeof(uint16_t));
373 return start_playback(p_instance, p_cb, flags, NRF_PWM_TASK_SEQSTART0);
374 }
375
376
nrfx_pwm_stop(nrfx_pwm_t const * p_instance,bool wait_until_stopped)377 bool nrfx_pwm_stop(nrfx_pwm_t const * p_instance,
378 bool wait_until_stopped)
379 {
380 NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state != NRFX_DRV_STATE_UNINITIALIZED);
381
382 bool ret_val = false;
383
384 // Deactivate shortcuts before triggering the STOP task, otherwise the PWM
385 // could be immediately started again if the LOOPSDONE event occurred in
386 // the same peripheral clock cycle as the STOP task was triggered.
387 nrf_pwm_shorts_set(p_instance->p_registers, 0);
388
389 // Trigger the STOP task even if the PWM appears to be already stopped.
390 // It won't harm, but it could help if for some strange reason the stopped
391 // status was not reported correctly.
392 nrf_pwm_task_trigger(p_instance->p_registers, NRF_PWM_TASK_STOP);
393
394 if (nrfx_pwm_is_stopped(p_instance))
395 {
396 ret_val = true;
397 }
398 else
399 {
400 do {
401 if (nrfx_pwm_is_stopped(p_instance))
402 {
403 ret_val = true;
404 break;
405 }
406 } while (wait_until_stopped);
407 }
408
409 NRFX_LOG_INFO("%s returned %d.", __func__, ret_val);
410 return ret_val;
411 }
412
413
nrfx_pwm_is_stopped(nrfx_pwm_t const * p_instance)414 bool nrfx_pwm_is_stopped(nrfx_pwm_t const * p_instance)
415 {
416 pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
417 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
418
419 bool ret_val = false;
420
421 // If the event handler is used (interrupts are enabled), the state will
422 // be changed in interrupt handler when the STOPPED event occurs.
423 if (p_cb->state != NRFX_DRV_STATE_POWERED_ON)
424 {
425 ret_val = true;
426 }
427 // If interrupts are disabled, we must check the STOPPED event here.
428 if (nrf_pwm_event_check(p_instance->p_registers, NRF_PWM_EVENT_STOPPED))
429 {
430 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
431 NRFX_LOG_INFO("Disabled.");
432 ret_val = true;
433 }
434
435 NRFX_LOG_INFO("%s returned %d.", __func__, ret_val);
436 return ret_val;
437 }
438
439
irq_handler(NRF_PWM_Type * p_pwm,pwm_control_block_t * p_cb)440 static void irq_handler(NRF_PWM_Type * p_pwm, pwm_control_block_t * p_cb)
441 {
442 // The user handler is called for SEQEND0 and SEQEND1 events only when the
443 // user asks for it (by setting proper flags when starting the playback).
444 if (nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_SEQEND0))
445 {
446 nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_SEQEND0);
447 if ((p_cb->flags & NRFX_PWM_FLAG_SIGNAL_END_SEQ0) && p_cb->handler)
448 {
449 p_cb->handler(NRFX_PWM_EVT_END_SEQ0, p_cb->p_context);
450 }
451 }
452 if (nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_SEQEND1))
453 {
454 nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_SEQEND1);
455 if ((p_cb->flags & NRFX_PWM_FLAG_SIGNAL_END_SEQ1) && p_cb->handler)
456 {
457 p_cb->handler(NRFX_PWM_EVT_END_SEQ1, p_cb->p_context);
458 }
459 }
460 // For LOOPSDONE the handler is called by default, but the user can disable
461 // this (via flags).
462 if (nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_LOOPSDONE))
463 {
464 nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_LOOPSDONE);
465 if (!(p_cb->flags & NRFX_PWM_FLAG_NO_EVT_FINISHED) && p_cb->handler)
466 {
467 p_cb->handler(NRFX_PWM_EVT_FINISHED, p_cb->p_context);
468 }
469 }
470
471 // The STOPPED event is always propagated to the user handler.
472 if (nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_STOPPED))
473 {
474 nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_STOPPED);
475
476 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
477 if (p_cb->handler)
478 {
479 p_cb->handler(NRFX_PWM_EVT_STOPPED, p_cb->p_context);
480 }
481 }
482 }
483
484
485 #if defined(USE_DMA_ISSUE_WORKAROUND)
486 // See 'start_playback' why this is needed.
DMA_ISSUE_EGU_IRQHandler(void)487 void DMA_ISSUE_EGU_IRQHandler(void)
488 {
489 for (uint8_t i = 0; i < NRFX_PWM_ENABLED_COUNT; i++)
490 {
491 nrf_egu_event_t event = nrf_egu_triggered_event_get(i);
492 if (nrf_egu_event_check(DMA_ISSUE_EGU, event))
493 {
494 nrf_egu_event_clear(DMA_ISSUE_EGU, event);
495 *(volatile uint32_t *)(m_cb[i].starting_task_address) = 1;
496 }
497 }
498 }
499 #endif
500
501
502 #if NRFX_CHECK(NRFX_PWM0_ENABLED)
nrfx_pwm_0_irq_handler(void)503 void nrfx_pwm_0_irq_handler(void)
504 {
505 irq_handler(NRF_PWM0, &m_cb[NRFX_PWM0_INST_IDX]);
506 }
507 #endif
508
509 #if NRFX_CHECK(NRFX_PWM1_ENABLED)
nrfx_pwm_1_irq_handler(void)510 void nrfx_pwm_1_irq_handler(void)
511 {
512 irq_handler(NRF_PWM1, &m_cb[NRFX_PWM1_INST_IDX]);
513 }
514 #endif
515
516 #if NRFX_CHECK(NRFX_PWM2_ENABLED)
nrfx_pwm_2_irq_handler(void)517 void nrfx_pwm_2_irq_handler(void)
518 {
519 irq_handler(NRF_PWM2, &m_cb[NRFX_PWM2_INST_IDX]);
520 }
521 #endif
522
523 #if NRFX_CHECK(NRFX_PWM3_ENABLED)
nrfx_pwm_3_irq_handler(void)524 void nrfx_pwm_3_irq_handler(void)
525 {
526 irq_handler(NRF_PWM3, &m_cb[NRFX_PWM3_INST_IDX]);
527 }
528 #endif
529
530 #endif // NRFX_CHECK(NRFX_PWM_ENABLED)
531