1 /*
2 * Copyright (c) 2022 - 2024, Nordic Semiconductor ASA
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice, this
11 * list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the copyright holder nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <nrfx_example.h>
35 #include <helpers/nrfx_gppi.h>
36 #include <nrfx_timer.h>
37 #include <nrfx_gpiote.h>
38
39 #define NRFX_LOG_MODULE EXAMPLE
40 #define NRFX_EXAMPLE_CONFIG_LOG_ENABLED 1
41 #define NRFX_EXAMPLE_CONFIG_LOG_LEVEL 3
42 #include <nrfx_log.h>
43
44 /**
45 * @defgroup nrfx_gppi_fork_example Fork GPPI example
46 * @{
47 * @ingroup nrfx_gppi_examples
48 *
49 * @brief Example showing basic fork functionality of a nrfx_gppi helper.
50 *
51 * @details Application initializes nrfx_gpiote, nrfx_timer drivers and nrfx_gppi helper in a way that
52 * TIMER compare event is set up to be forwarded via PPI/DPPI to GPIOTE and toggle a pin.
53 * Fork mechanism in PPI/DPPI is also set up to toggle a second pin in GPIOTE at the same time.
54 */
55
56 /** @brief Symbol specifying timer instance to be used. */
57 #define TIMER_INST_IDX 0
58
59 /** @brief Symbol specifying time in milliseconds to wait for handler execution. */
60 #define TIME_TO_WAIT_MS 1000UL
61
62 /** @brief Symbol specifying GPIOTE instance to be used. */
63 #define GPIOTE_INST_IDX 0
64
65 /** @brief Symbol specifying output pin associated with primary task. */
66 #define OUTPUT_PIN_PRIMARY LED1_PIN
67
68 /** @brief Symbol specifying output pin associated with fork task. */
69 #define OUTPUT_PIN_FORK LED2_PIN
70
71 /**
72 * @brief Function for handling TIMER driver events.
73 *
74 * @param[in] event_type Timer event.
75 * @param[in] p_context General purpose parameter set during initialization of the timer.
76 * This parameter can be used to pass additional information to the handler
77 * function, for example the timer ID.
78 */
timer_handler(nrf_timer_event_t event_type,void * p_context)79 static void timer_handler(nrf_timer_event_t event_type, void * p_context)
80 {
81 if (event_type == NRF_TIMER_EVENT_COMPARE0)
82 {
83 char * p_msg = p_context;
84 NRFX_LOG_INFO("Timer finished. Context passed to the handler: >%s<", p_msg);
85 NRFX_LOG_INFO("GPIOTE output pin (primary): %d is %s", OUTPUT_PIN_PRIMARY,
86 nrfx_gpiote_in_is_set(OUTPUT_PIN_PRIMARY) ? "high" : "low");
87 NRFX_LOG_INFO("GPIOTE output pin (fork): %d is %s", OUTPUT_PIN_FORK,
88 nrfx_gpiote_in_is_set(OUTPUT_PIN_FORK) ? "high" : "low");
89 }
90 }
91
92 /**
93 * @brief Function for application main entry.
94 *
95 * @return Nothing.
96 */
main(void)97 int main(void)
98 {
99 nrfx_err_t status;
100 (void)status;
101
102 uint8_t out_channel_primary, out_channel_fork;
103 uint8_t gppi_channel;
104
105 #if defined(__ZEPHYR__)
106 IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_TIMER_INST_GET(TIMER_INST_IDX)), IRQ_PRIO_LOWEST,
107 NRFX_TIMER_INST_HANDLER_GET(TIMER_INST_IDX), 0, 0);
108 IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_GPIOTE_INST_GET(GPIOTE_INST_IDX)), IRQ_PRIO_LOWEST,
109 NRFX_GPIOTE_INST_HANDLER_GET(GPIOTE_INST_IDX), 0, 0);
110 #endif
111
112 NRFX_EXAMPLE_LOG_INIT();
113
114 NRFX_LOG_INFO("Starting nrfx_gppi basic fork example.");
115 NRFX_EXAMPLE_LOG_PROCESS();
116
117 nrfx_gpiote_t const gpiote_inst = NRFX_GPIOTE_INSTANCE(GPIOTE_INST_IDX);
118 status = nrfx_gpiote_init(&gpiote_inst, NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY);
119 NRFX_ASSERT(status == NRFX_SUCCESS);
120 NRFX_LOG_INFO("GPIOTE status: %s",
121 nrfx_gpiote_init_check(&gpiote_inst) ? "initialized" : "not initialized");
122
123 status = nrfx_gpiote_channel_alloc(&gpiote_inst, &out_channel_primary);
124 NRFX_ASSERT(status == NRFX_SUCCESS);
125
126 status = nrfx_gpiote_channel_alloc(&gpiote_inst, &out_channel_fork);
127 NRFX_ASSERT(status == NRFX_SUCCESS);
128
129 /*
130 * Initialize the output pin associated with the primary task.
131 * The SET task will turn the LED on, CLR will turn it off, and OUT will toggle it.
132 */
133 static const nrfx_gpiote_output_config_t output_config =
134 {
135 .drive = NRF_GPIO_PIN_S0S1,
136 .input_connect = NRF_GPIO_PIN_INPUT_DISCONNECT,
137 .pull = NRF_GPIO_PIN_NOPULL,
138 };
139
140 nrfx_gpiote_task_config_t task_config =
141 {
142 .task_ch = out_channel_primary,
143 .polarity = NRF_GPIOTE_POLARITY_TOGGLE,
144 .init_val = NRF_GPIOTE_INITIAL_VALUE_HIGH,
145 };
146
147 status = nrfx_gpiote_output_configure(&gpiote_inst,
148 OUTPUT_PIN_PRIMARY,
149 &output_config,
150 &task_config);
151 NRFX_ASSERT(status == NRFX_SUCCESS);
152
153 nrfx_gpiote_out_task_enable(&gpiote_inst, OUTPUT_PIN_PRIMARY);
154
155 /*
156 * Initialize the output pin associated with the fork task.
157 * The SET task will turn the LED off, CLR will turn it on, and OUT will toggle it.
158 */
159 task_config.task_ch = out_channel_fork;
160 task_config.init_val = NRF_GPIOTE_INITIAL_VALUE_LOW;
161
162 status = nrfx_gpiote_output_configure(&gpiote_inst,
163 OUTPUT_PIN_FORK,
164 &output_config,
165 &task_config);
166 NRFX_ASSERT(status == NRFX_SUCCESS);
167
168 nrfx_gpiote_out_task_enable(&gpiote_inst, OUTPUT_PIN_FORK);
169
170 nrfx_timer_t timer_inst = NRFX_TIMER_INSTANCE(TIMER_INST_IDX);
171 uint32_t base_frequency = NRF_TIMER_BASE_FREQUENCY_GET(timer_inst.p_reg);
172 nrfx_timer_config_t timer_config = NRFX_TIMER_DEFAULT_CONFIG(base_frequency);
173 timer_config.bit_width = NRF_TIMER_BIT_WIDTH_32;
174 timer_config.p_context = "Some context";
175
176 status = nrfx_timer_init(&timer_inst, &timer_config, timer_handler);
177 NRFX_ASSERT(status == NRFX_SUCCESS);
178
179 nrfx_timer_clear(&timer_inst);
180
181 /* Create variable desired_ticks to store the output of nrfx_timer_ms_to_ticks function. */
182 uint32_t desired_ticks = nrfx_timer_ms_to_ticks(&timer_inst, TIME_TO_WAIT_MS);
183 NRFX_LOG_INFO("Time to wait: %lu ms", TIME_TO_WAIT_MS);
184
185 /*
186 * Set the timer channel NRF_TIMER_CC_CHANNEL0 in the extended compare mode to clear
187 * the timer and to trigger an interrupt if the internal counter register is equal to
188 * desired_ticks.
189 */
190 nrfx_timer_extended_compare(&timer_inst, NRF_TIMER_CC_CHANNEL0, desired_ticks,
191 NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
192
193 status = nrfx_gppi_channel_alloc(&gppi_channel);
194 NRFX_ASSERT(status == NRFX_SUCCESS);
195
196 /*
197 * Configure endpoints of the channel so that the input timer event is connected with the output
198 * pin OUT task. This means that each time the timer interrupt occurs, the LED pin will be toggled.
199 */
200 nrfx_gppi_channel_endpoints_setup(gppi_channel,
201 nrfx_timer_compare_event_address_get(&timer_inst, NRF_TIMER_CC_CHANNEL0),
202 nrfx_gpiote_out_task_address_get(&gpiote_inst, OUTPUT_PIN_PRIMARY));
203
204 /*
205 * Set up the task endpoint for a given PPI fork or for associating the DPPI channel
206 * with an additional task register depending on which driver the GPPI helper is using.
207 */
208 nrfx_gppi_fork_endpoint_setup(gppi_channel,
209 nrfx_gpiote_out_task_address_get(&gpiote_inst, OUTPUT_PIN_FORK));
210
211 nrfx_gppi_channels_enable(BIT(gppi_channel));
212
213 nrfx_timer_enable(&timer_inst);
214 NRFX_LOG_INFO("Timer status: %s", nrfx_timer_is_enabled(&timer_inst) ? "enabled" : "disabled");
215
216 while (1)
217 {
218 NRFX_EXAMPLE_LOG_PROCESS();
219 }
220 }
221
222 /** @} */
223