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 <saadc_examples_common.h>
36 #include <nrfx_saadc.h>
37 
38 #define NRFX_LOG_MODULE                 EXAMPLE
39 #define NRFX_EXAMPLE_CONFIG_LOG_ENABLED 1
40 #define NRFX_EXAMPLE_CONFIG_LOG_LEVEL   3
41 #include <nrfx_log.h>
42 
43 /**
44  * @defgroup nrfx_saadc_simple_non_blocking_example Simple non-blocking SAADC example
45  * @{
46  * @ingroup nrfx_saadc_examples
47  *
48  * @brief Example showing simple functionality of nrfx_saadc driver operating in the non-blocking mode.
49  *
50  * @details Application initializes nrfx_saadc driver and starts operating in the non-blocking mode.
51  *          Program works as a simple state machine and starts in state @ref m_current_state == STATE_SINGLE_CONFIG.
52  *          In state ( @ref m_current_state ):
53  *          - STATE_SINGLE_CONFIG - SAADC driver is configured to work with only one channel ( @ref m_single_channel )
54  *            in the non-blocking mode. @ref m_current_state is changed to STATE_SINGLE_SAMPLING afterward.
55  *          - STATE_SINGLE_SAMPLING - sampling on a single channel ( @ref m_single_channel ) is performed specified
56  *            number of times ( @ref SAMPLING_ITERATIONS ), after that @ref m_current_state is changed to STATE_MULTIPLE_CONFIG.
57  *          - STATE_MULTIPLE_CONFIG - SAADC driver is configured to work with multiple channels ( @ref m_multiple_channels )
58  *            in the non-blocking mode. @ref m_current_state is changed to STATE_MULTIPLE_SAMPLING afterward.
59  *          - STATE_MULTIPLE_SAMPLING - sampling on multiple channels ( @ref m_multiple_channels ) is performed specified
60  *            number of times ( @ref SAMPLING_ITERATIONS ).
61  *          Before every sampling, calibration in a non-blocking manner is performed. It triggers @ref saadc_handler()
62  *          where sampling is invoked by @p nrfx_saadc_mode_trigger() function.
63  *
64  *          In the example there are GPIOTE tasks configured to toggle specified ( @ref m_out_pins ) loopback pins. Those tasks
65  *          are being triggered between successive samplings to verify the functionality of the SAADC on the non-constant analog signal.
66  */
67 
68 /** @brief Symbol specifying analog input to be observed by SAADC channel 0. */
69 #define CH0_AIN ANALOG_INPUT_TO_SAADC_AIN(ANALOG_INPUT_A0)
70 
71 /** @brief Symbol specifying analog input to be observed by SAADC channel 1. */
72 #define CH1_AIN ANALOG_INPUT_TO_SAADC_AIN(ANALOG_INPUT_A1)
73 
74 /** @brief Symbol specifying analog input to be observed by SAADC channel 2. */
75 #define CH2_AIN ANALOG_INPUT_TO_SAADC_AIN(ANALOG_INPUT_A2)
76 
77 /** @brief Declaration of enum containing a set of states for the simple state machine. */
78 typedef enum
79 {
80     STATE_SINGLE_CONFIG,     ///< Configure a single SAADC channel and set the SAADC driver in the simple mode.
81     STATE_SINGLE_SAMPLING,   ///< Trigger SAADC sampling on the single channel.
82     STATE_MULTIPLE_CONFIG,   ///< Configure multiple SAADC channels and set the SAADC driver in the simple mode.
83     STATE_MULTIPLE_SAMPLING, ///< Trigger SAADC sampling on multiple channels.
84 } state_t;
85 
86 /** @brief SAADC channel configuration structure for single channel use. */
87 static const nrfx_saadc_channel_t m_single_channel = NRFX_SAADC_DEFAULT_CHANNEL_SE(CH0_AIN, 0);
88 
89 /** @brief SAADC channel configuration structure for multiple channel use. */
90 static const nrfx_saadc_channel_t m_multiple_channels[] =
91 {
92     NRFX_SAADC_DEFAULT_CHANNEL_SE(CH0_AIN, 0),
93     NRFX_SAADC_DEFAULT_CHANNEL_SE(CH1_AIN, 1),
94     NRFX_SAADC_DEFAULT_CHANNEL_SE(CH2_AIN, 2)
95 };
96 
97 /** @brief Symbol specifying numbers of multiple channels ( @ref m_multiple_channels) used by SAADC. */
98 #define CHANNEL_COUNT NRFX_ARRAY_SIZE(m_multiple_channels)
99 
100 /** @brief Symbol specifying the number of SAADC samplings to trigger. */
101 #define SAMPLING_ITERATIONS 8
102 
103 /** @brief Symbol specifying the resolution of the SAADC. */
104 #define RESOLUTION NRF_SAADC_RESOLUTION_8BIT
105 
106 /** @brief Symbol specifying GPIOTE instance to be used. */
107 #define GPIOTE_INST_IDX 0
108 
109 /** @brief Array specifying GPIO pins used to test the functionality of SAADC. */
110 static uint8_t m_out_pins[CHANNEL_COUNT] = {LOOPBACK_PIN_1B, LOOPBACK_PIN_2B, LOOPBACK_PIN_3B};
111 
112 /** @brief Samples buffer defined with the size of @ref CHANNEL_COUNT symbol to store values from each channel ( @ref m_multiple_channels). */
113 #if (NRF_SAADC_8BIT_SAMPLE_WIDTH == 8) && (RESOLUTION == NRF_SAADC_RESOLUTION_8BIT)
114 static uint8_t m_samples_buffer[CHANNEL_COUNT];
115 #else
116 static uint16_t m_samples_buffer[CHANNEL_COUNT];
117 #endif
118 
119 /** @brief Enum with the current state of the simple state machine. */
120 static state_t m_current_state = STATE_SINGLE_CONFIG;
121 
122 /** @brief Flag indicating that sampling on every specified channel is finished and buffer ( @ref m_samples_buffer ) is filled with samples. */
123 static bool m_saadc_ready;
124 
125 /**
126  * @brief Function for handling SAADC driver events.
127  *
128  * @param[in] p_event Pointer to an SAADC driver event.
129  */
saadc_handler(nrfx_saadc_evt_t const * p_event)130 static void saadc_handler(nrfx_saadc_evt_t const * p_event)
131 {
132     nrfx_err_t status;
133     (void)status;
134 
135     uint16_t samples_number;
136 
137     switch (p_event->type)
138     {
139         case NRFX_SAADC_EVT_DONE:
140             NRFX_LOG_INFO("SAADC event: DONE");
141 
142             samples_number = p_event->data.done.size;
143             for (uint16_t i = 0; i < samples_number; i++)
144             {
145                 NRFX_LOG_INFO("[Sample %d] value == %d",
146                               i, NRFX_SAADC_SAMPLE_GET(RESOLUTION, p_event->data.done.p_buffer, i));
147             }
148 
149             m_saadc_ready = true;
150             break;
151 
152         case NRFX_SAADC_EVT_CALIBRATEDONE:
153             NRFX_LOG_INFO("SAADC event: CALIBRATEDONE");
154             status = nrfx_saadc_mode_trigger();
155             NRFX_ASSERT(status == NRFX_SUCCESS);
156             break;
157 
158         default:
159             break;
160     }
161 }
162 
163 /**
164  * @brief Function for application main entry.
165  *
166  * @return Nothing.
167  */
main(void)168 int main(void)
169 {
170     nrfx_err_t status;
171     (void)status;
172 
173 #if defined(__ZEPHYR__)
174     IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_SAADC), IRQ_PRIO_LOWEST, nrfx_saadc_irq_handler, 0, 0);
175     IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_GPIOTE_INST_GET(GPIOTE_INST_IDX)), IRQ_PRIO_LOWEST,
176                 NRFX_GPIOTE_INST_HANDLER_GET(GPIOTE_INST_IDX), 0, 0);
177 #endif
178 
179     NRFX_EXAMPLE_LOG_INIT();
180     NRFX_LOG_INFO("Starting nrfx_saadc simple non-blocking example.");
181     NRFX_EXAMPLE_LOG_PROCESS();
182 
183     status = nrfx_saadc_init(NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY);
184     NRFX_ASSERT(status == NRFX_SUCCESS);
185 
186     nrfx_gpiote_t const gpiote_inst = NRFX_GPIOTE_INSTANCE(GPIOTE_INST_IDX);
187     status = nrfx_gpiote_init(&gpiote_inst, NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY);
188     NRFX_ASSERT(status == NRFX_SUCCESS);
189     NRFX_LOG_INFO("GPIOTE status: %s",
190                   nrfx_gpiote_init_check(&gpiote_inst) ? "initialized" : "not initialized");
191 
192     uint8_t i;
193     for (i = 0; i < CHANNEL_COUNT; i++)
194     {
195         gpiote_pin_toggle_task_setup(&gpiote_inst, m_out_pins[i]);
196     }
197 
198     uint32_t sampling_index = 0;
199     uint32_t channels_mask = 0;
200     while (1)
201     {
202         switch (m_current_state)
203         {
204             case STATE_SINGLE_CONFIG:
205                 NRFX_LOG_INFO("Single channel SAADC test.");
206 
207                 status = nrfx_saadc_channel_config(&m_single_channel);
208                 NRFX_ASSERT(status == NRFX_SUCCESS);
209 
210                 channels_mask = nrfx_saadc_channels_configured_get();
211                 status = nrfx_saadc_simple_mode_set(channels_mask,
212                                                     RESOLUTION,
213                                                     NRF_SAADC_OVERSAMPLE_DISABLED,
214                                                     saadc_handler);
215                 NRFX_ASSERT(status == NRFX_SUCCESS);
216 
217                 status = nrfx_saadc_buffer_set(m_samples_buffer, 1);
218                 NRFX_ASSERT(status == NRFX_SUCCESS);
219 
220                 m_saadc_ready = true;
221                 m_current_state = STATE_SINGLE_SAMPLING;
222                 break;
223 
224             case STATE_SINGLE_SAMPLING:
225                 if (m_saadc_ready && sampling_index < SAMPLING_ITERATIONS)
226                 {
227                     nrfx_gpiote_out_task_trigger(&gpiote_inst, m_out_pins[0]);
228 
229                     m_saadc_ready = false;
230                     status = nrfx_saadc_offset_calibrate(saadc_handler);
231                     NRFX_ASSERT(status == NRFX_SUCCESS);
232 
233                     sampling_index++;
234                 }
235                 else if (m_saadc_ready && sampling_index == SAMPLING_ITERATIONS)
236                 {
237                     m_current_state = STATE_MULTIPLE_CONFIG;
238                     sampling_index = 0;
239                 }
240                 break;
241 
242             case STATE_MULTIPLE_CONFIG:
243                 NRFX_LOG_INFO("Multiple channels SAADC test.");
244 
245                 status = nrfx_saadc_channels_config(m_multiple_channels, CHANNEL_COUNT);
246                 NRFX_ASSERT(status == NRFX_SUCCESS);
247 
248                 channels_mask = nrfx_saadc_channels_configured_get();
249                 status = nrfx_saadc_simple_mode_set(channels_mask,
250                                                     NRF_SAADC_RESOLUTION_8BIT,
251                                                     NRF_SAADC_OVERSAMPLE_DISABLED,
252                                                     saadc_handler);
253                 NRFX_ASSERT(status == NRFX_SUCCESS);
254 
255                 status = nrfx_saadc_buffer_set(m_samples_buffer, CHANNEL_COUNT);
256                 NRFX_ASSERT(status == NRFX_SUCCESS);
257 
258                 m_current_state = STATE_MULTIPLE_SAMPLING;
259                 break;
260 
261             case STATE_MULTIPLE_SAMPLING:
262                 if (m_saadc_ready && sampling_index < SAMPLING_ITERATIONS)
263                 {
264                     for (i = 0; i < CHANNEL_COUNT; i++)
265                     {
266                         nrfx_gpiote_out_task_trigger(&gpiote_inst, m_out_pins[i]);
267                     }
268 
269                     m_saadc_ready = false;
270                     status = nrfx_saadc_offset_calibrate(saadc_handler);
271                     NRFX_ASSERT(status == NRFX_SUCCESS);
272 
273                     sampling_index++;
274                 }
275                 break;
276 
277             default:
278                 break;
279         }
280         NRFX_EXAMPLE_LOG_PROCESS();
281     }
282 }
283 
284 /** @} */
285