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 <nrfx_uarte.h>
36
37 #define NRFX_LOG_MODULE EXAMPLE
38 #define NRFX_EXAMPLE_CONFIG_LOG_ENABLED 1
39 #define NRFX_EXAMPLE_CONFIG_LOG_LEVEL 3
40 #include <nrfx_log.h>
41
42 /**
43 * @defgroup nrfx_uarte_rx_double_buffered_example RX double-buffered UARTE example
44 * @{
45 * @ingroup nrfx_uarte_examples
46 *
47 * @brief Example showing the functionality of nrfx_uarte driver utilizing double-buffering feature.
48 *
49 * @details Application initializes nrfx_uarte driver, then sends the specified message, which
50 * is stored in @ref m_tx_buffer using UARTE instance. The same instance of UARTE is
51 * configured to receive this message. To perform this operation different buffers are used
52 * and data is transferred as follows:
53 * @ref m_tx_buffer -> @ref m_rx_buffers
54 * To show the double-buffering feature the data is written to the different buffers in the
55 * @ref m_rx_buffers structure.
56 * The @ref uarte_handler() is executed with relevant log messages.
57 */
58
59 /** @brief Symbol specifying UARTE instance to be used. */
60 #define UARTE_INST_IDX 1
61
62 /** @brief Symbol specifying TX pin number of UARTE. */
63 #define UARTE_TX_PIN LOOPBACK_PIN_1A
64
65 /** @brief Symbol specifying RX pin number of UARTE. */
66 #define UARTE_RX_PIN LOOPBACK_PIN_1B
67
68 /** @brief Symbol specifying the first message to be sent via UARTE data transfer as part of @ref m_tx_buffer. */
69 #define MSG1 "Nordic"
70
71 /** @brief Symbol specifying the second message to be sent via UARTE data transfer as part of @ref m_tx_buffer. */
72 #define MSG2 " Semiconductor"
73
74 /** @brief Symbol specifying the third message to be sent via UARTE data transfer as part of @ref m_tx_buffer. */
75 #define MSG3 " nRF"
76
77 /**
78 * @brief Structure containing receive buffers registers.
79 *
80 * @note To show the double-buffered functionality of data pointer register @p buff_2 is prepared to
81 * store @p MSG3 and @p buff_3 is prepared to store @p MSG2.
82 */
83 typedef struct
84 {
85 uint8_t buff_1[sizeof(MSG1)]; ///< RX buffer 1
86 uint8_t buff_2[sizeof(MSG3)]; ///< RX buffer 2
87 uint8_t buff_3[sizeof(MSG2)]; ///< RX buffer 3
88 } rx_buffers_t;
89
90 /**
91 * @brief UARTE transmit buffer, it is later filled with @ref MSG1, @ref MSG2 and @ref MSG3 to store
92 * following message: "Nordic Semiconductor nRF".
93 */
94 static uint8_t m_tx_buffer[sizeof(MSG1) + sizeof(MSG2) + sizeof(MSG3)];
95
96 /** @brief Structure containing receive buffers. */
97 static rx_buffers_t m_rx_buffers;
98
99 /**
100 * @brief Function for showing values of all receive buffers.
101 *
102 * @param[in] p_rx_buff Pointer to the structure with receive buffers.
103 */
rx_buffers_print(rx_buffers_t * p_rx_buff)104 static void rx_buffers_print(rx_buffers_t * p_rx_buff)
105 {
106 NRFX_LOG_INFO("................................");
107 NRFX_LOG_INFO("RX buffer1 - addr: %p | content: %s", p_rx_buff->buff_1, p_rx_buff->buff_1);
108 NRFX_LOG_INFO("RX buffer2 - addr: %p | content: %s", p_rx_buff->buff_2, p_rx_buff->buff_2);
109 NRFX_LOG_INFO("RX buffer3 - addr: %p | content: %s", p_rx_buff->buff_3, p_rx_buff->buff_3);
110 NRFX_LOG_INFO("................................");
111 NRFX_EXAMPLE_LOG_PROCESS();
112 }
113
114 /**
115 * @brief Function for handling UARTE driver events.
116 *
117 * @param[in] p_event Pointer to event structure. Event is allocated on the stack so it is available
118 * only within the context of the event handler.
119 * @param[in] p_context Context passed to the interrupt handler, set on initialization. In this example
120 * p_context is used to pass the address of the UARTE instance that calls this handler.
121 */
uarte_handler(nrfx_uarte_event_t const * p_event,void * p_context)122 static void uarte_handler(nrfx_uarte_event_t const * p_event, void * p_context)
123 {
124 nrfx_err_t status;
125 (void)status;
126
127 nrfx_uarte_t * p_inst = p_context;
128 static uint8_t num_handler_exec = 0;
129
130 switch (num_handler_exec++)
131 {
132 case 0:
133 status = nrfx_uarte_rx(p_inst,
134 m_rx_buffers.buff_3,
135 NRFX_ARRAY_SIZE(m_rx_buffers.buff_3) - 1);
136 NRFX_ASSERT(status == NRFX_SUCCESS);
137 break;
138
139 case 1:
140 status = nrfx_uarte_rx(p_inst,
141 m_rx_buffers.buff_2,
142 NRFX_ARRAY_SIZE(m_rx_buffers.buff_2) - 1);
143 NRFX_ASSERT(status == NRFX_SUCCESS);
144 break;
145 }
146
147 if (p_event->type == NRFX_UARTE_EVT_TX_DONE)
148 {
149 NRFX_LOG_INFO("--> TX done");
150 NRFX_LOG_INFO("--> Bytes transfered: %u", p_event->data.tx.length);
151 nrfx_uarte_uninit(p_inst);
152 }
153 }
154
155 /**
156 * @brief Function for application main entry.
157 *
158 * @return Nothing.
159 */
main(void)160 int main(void)
161 {
162 nrfx_err_t status;
163 (void)status;
164
165 #if defined(__ZEPHYR__)
166 IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_UARTE_INST_GET(UARTE_INST_IDX)), IRQ_PRIO_LOWEST,
167 NRFX_UARTE_INST_HANDLER_GET(UARTE_INST_IDX), 0, 0);
168 #endif
169
170 NRFX_EXAMPLE_LOG_INIT();
171
172 NRFX_LOG_INFO("Starting nrfx_uarte RX double-buffered example.");
173 NRFX_EXAMPLE_LOG_PROCESS();
174
175 nrfx_uarte_t uarte_inst = NRFX_UARTE_INSTANCE(UARTE_INST_IDX);
176 nrfx_uarte_config_t uarte_config = NRFX_UARTE_DEFAULT_CONFIG(UARTE_TX_PIN, UARTE_RX_PIN);
177 uarte_config.p_context = &uarte_inst;
178 status = nrfx_uarte_init(&uarte_inst, &uarte_config, uarte_handler);
179 NRFX_ASSERT(status == NRFX_SUCCESS);
180
181 /* Declaration and filling m_tx_buffer to store desired msg ("Nordic Semiconductor nRF"). */
182 memcpy(m_tx_buffer , MSG1, strlen(MSG1));
183 memcpy(m_tx_buffer + strlen(MSG1) , MSG2, strlen(MSG2));
184 memcpy(m_tx_buffer + strlen(MSG1) + strlen(MSG2), MSG3, strlen(MSG3) + 1);
185 NRFX_LOG_INFO("Content of TX buffer: %s", m_tx_buffer);
186
187 rx_buffers_print(&m_rx_buffers);
188
189 status = nrfx_uarte_rx(&uarte_inst,
190 m_rx_buffers.buff_1,
191 NRFX_ARRAY_SIZE(m_rx_buffers.buff_1) - 1);
192 NRFX_ASSERT(status == NRFX_SUCCESS);
193
194 status = nrfx_uarte_tx(&uarte_inst, m_tx_buffer, NRFX_ARRAY_SIZE(m_tx_buffer), 0);
195 NRFX_ASSERT(status == NRFX_SUCCESS);
196
197 while (nrfx_uarte_tx_in_progress(&uarte_inst))
198 {}
199
200 rx_buffers_print(&m_rx_buffers);
201
202 while (1)
203 {
204 NRFX_EXAMPLE_LOG_PROCESS();
205 }
206 }
207
208 /** @} */
209