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