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