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