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