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_twim.h>
36 #include <nrfx_twis.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_twim_twis_txrx_example TX-RX TWIM with TWIS example
45  * @{
46  * @ingroup nrfx_twim_twis_examples
47  *
48  * @brief Example showing the functionality of nrfx_twim and nrfx_twis drivers, when TWI transfer is
49  *        performed in TX-RX mode.
50  *
51  * @details Application initializes nrfx_twim and nrfx_twis drivers. Main purpose of this example is
52  *          to emulate a typical situation, when the user has to read data from particular registers
53  *          of the slave (usual sensor->controller communication using two wire interface).
54  *          The example works as a simple simulation in which the user can communicate with the
55  *          drone by reading the values from its individual registers. @ref m_drone_reg is used as
56  *          an internal register map of the drone. In the first operation, which is write operation (TX)
57  *          user should define the register number from which data will be read in the read
58  *          operation (RX). @ref twim_handler() is executed with relevant log messages.
59  *          @ref twis_handler() is used to prepare data for receiving and sending.
60  *          @ref register_read() function is used to write data from particular registers to buffer
61  *          in master device and print content of that buffer.
62  */
63 
64 /** @brief Symbol specifying pin number of master SCL. */
65 #define MASTER_SCL_PIN LOOPBACK_PIN_1A
66 
67 /** @brief Symbol specifying pin number of master SDA. */
68 #define MASTER_SDA_PIN LOOPBACK_PIN_2A
69 
70 /** @brief Symbol specifying pin number of slave SCL. */
71 #define SLAVE_SCL_PIN LOOPBACK_PIN_1B
72 
73 /** @brief Symbol specifying pin number of slave SDA. */
74 #define SLAVE_SDA_PIN LOOPBACK_PIN_2B
75 
76 #if defined(NRF52_SERIES) || defined(__NRFX_DOXYGEN__)
77 /** @brief Symbol specifying TWIM instance to be used. */
78 #define TWIM_INST_IDX 0
79 
80 /** @brief Symbol specifying TWIS instance to be used. */
81 #define TWIS_INST_IDX 1
82 #else
83 #define TWIM_INST_IDX 1
84 #define TWIS_INST_IDX 2
85 #endif
86 
87 /** @brief Symbol specifying drone (slave) address on TWI bus. */
88 #define DRONE_IDX 0x01U
89 
90 /** @brief Symbol specifying drone mass [kg], it is used to calculate accelerations. */
91 #define DRONE_MASS 10U
92 
93 /** @brief Drone registers names */
94 typedef enum
95 {
96     DRONE_REG_ID,         ///< Drone identifier.
97     DRONE_REG_MASS,       ///< Drone mass.
98     DRONE_REG_FORCE_X,    ///< Force that acts on the drone along X axis.
99     DRONE_REG_FORCE_Y,    ///< Force that acts on the drone along Y axis.
100     DRONE_REG_FORCE_Z,    ///< Force that acts on the drone along Z axis.
101     DRONE_REG_ACC_X,      ///< Acceleration of the drone along X axis.
102     DRONE_REG_ACC_Y,      ///< Acceleration of the drone along Y axis.
103     DRONE_REG_ACC_Z,      ///< Acceleration of the drone along Z axis.
104     DRONE_REG_ADDT_DATA0, ///< Additional data 0.
105     DRONE_REG_ADDT_DATA1, ///< Additional data 1.
106     DRONE_REG_ADDT_DATA2, ///< Additional data 2.
107     DRONE_REG_ADDT_DATA3, ///< Additional data 3.
108 } drone_reg_name_t;
109 
110 /** @brief Structure for the drone register map */
111 typedef struct
112 {
113     uint8_t drone_idx;          ///< Drone identifier.
114     uint8_t mass;               ///< Drone mass.
115     uint8_t force[3];           ///< Forces that acts on the drone along X, Y, Z axes.
116     uint8_t acceleration[3];    ///< Accelerations of the drone along X, Y, Z axes.
117     uint8_t additional_data[4]; ///< Additional data.
118 } drone_reg_map_t;
119 
120 /**
121  * @brief Union containing a drone register map structure, used to refer to individual elements
122  *        of the structure.
123  */
124 typedef union
125 {
126     drone_reg_map_t register_map;                   ///< Drone register map.
127     uint8_t         bytes[sizeof(drone_reg_map_t)]; ///< Array for referring to individual structure elements.
128 } drone_regs_t;
129 
130 /**
131  * @brief Macro for creating register map structure with the default configuration.
132  *
133  * This configuration sets up drone registers with the following options:
134  * - X, Y, Z forces set to 50, 100, 150
135  * - accelerations calculated with the use of @p _mass parameter
136  * - additional data set to 0xEF, 0xBE, 0xAD, 0xDE
137  *
138  * @param[in] _id   Drone identifier.
139  * @param[in] _mass Drone mass.
140  */
141 #define DRONE_DEFAULT_CONFIG(_id, _mass)                             \
142 {                                                                    \
143     .drone_idx       = (_id),                                        \
144     .mass            = (_mass),                                      \
145     .force           = {50, 100, 150},                               \
146     .acceleration    = {50 / (_mass), 100 / (_mass), 150 / (_mass)}, \
147     .additional_data = {0xEF, 0xBE, 0xAD, 0xDE},                     \
148 }
149 
150 /** @brief Union containing drone register map structure. */
151 static drone_regs_t m_drone_reg = {.register_map = DRONE_DEFAULT_CONFIG(DRONE_IDX, DRONE_MASS)};
152 
153 /** @brief Structure containing TWIS driver instance. */
154 static nrfx_twis_t m_twis_inst = NRFX_TWIS_INSTANCE(TWIS_INST_IDX);
155 
156 /** @brief Structure containing TWIM driver instance. */
157 static nrfx_twim_t m_twim_inst = NRFX_TWIM_INSTANCE(TWIM_INST_IDX);
158 
159 /**
160  * @brief Function for showing values of all drone registers.
161  *
162  * @param[in] p_drone_regs Pointer to the union with drone register map structure.
163  */
drone_reg_print(drone_regs_t * p_drone_regs)164 static void drone_reg_print(drone_regs_t * p_drone_regs)
165 {
166     NRFX_LOG_INFO("................................");
167     NRFX_LOG_INFO("DRONE REGISTERS:    DEC\t|  HEX");
168     NRFX_LOG_INFO("drone_idx:          %d \t|  0x%X", p_drone_regs->bytes[DRONE_REG_ID],
169                                                       p_drone_regs->bytes[DRONE_REG_ID]);
170     NRFX_LOG_INFO("drone_mass:         %d \t|  0x%X", p_drone_regs->bytes[DRONE_REG_MASS],
171                                                       p_drone_regs->bytes[DRONE_REG_MASS]);
172     NRFX_LOG_INFO("x_force:            %d \t|  0x%X", p_drone_regs->bytes[DRONE_REG_FORCE_X],
173                                                       p_drone_regs->bytes[DRONE_REG_FORCE_X]);
174     NRFX_LOG_INFO("y_force:            %d \t|  0x%X", p_drone_regs->bytes[DRONE_REG_FORCE_Y],
175                                                       p_drone_regs->bytes[DRONE_REG_FORCE_Y]);
176     NRFX_LOG_INFO("z_force:            %d \t|  0x%X", p_drone_regs->bytes[DRONE_REG_FORCE_Z],
177                                                       p_drone_regs->bytes[DRONE_REG_FORCE_Z]);
178     NRFX_LOG_INFO("x_acceleration:     %d \t|  0x%X", p_drone_regs->bytes[DRONE_REG_ACC_X],
179                                                       p_drone_regs->bytes[DRONE_REG_ACC_X]);
180     NRFX_LOG_INFO("y_acceleration:     %d \t|  0x%X", p_drone_regs->bytes[DRONE_REG_ACC_Y],
181                                                       p_drone_regs->bytes[DRONE_REG_ACC_Y]);
182     NRFX_LOG_INFO("z_acceleration:     %d \t|  0x%X", p_drone_regs->bytes[DRONE_REG_ACC_Z],
183                                                       p_drone_regs->bytes[DRONE_REG_ACC_Z]);
184     NRFX_LOG_INFO("additional_data[0]: %d \t|  0x%X", p_drone_regs->bytes[DRONE_REG_ADDT_DATA0],
185                                                       p_drone_regs->bytes[DRONE_REG_ADDT_DATA0]);
186     NRFX_LOG_INFO("additional_data[1]: %d \t|  0x%X", p_drone_regs->bytes[DRONE_REG_ADDT_DATA1],
187                                                       p_drone_regs->bytes[DRONE_REG_ADDT_DATA1]);
188     NRFX_LOG_INFO("additional_data[2]: %d \t|  0x%X", p_drone_regs->bytes[DRONE_REG_ADDT_DATA2],
189                                                       p_drone_regs->bytes[DRONE_REG_ADDT_DATA2]);
190     NRFX_LOG_INFO("additional_data[3]: %d \t|  0x%X", p_drone_regs->bytes[DRONE_REG_ADDT_DATA3],
191                                                       p_drone_regs->bytes[DRONE_REG_ADDT_DATA3]);
192     NRFX_LOG_INFO("................................");
193     NRFX_EXAMPLE_LOG_PROCESS();
194 }
195 
196 /**
197  * @brief Function for reading values of particular registers from slave and
198  *        writing them to the @p rx_buffer.
199  *
200  * @param [in] slave_addr    Slave address.
201  * @param [in] reg_num       Register number to read (or start reading from, if @p bytes_to_read is
202  *                           bigger than 1).
203  * @param [in] rx_buffer     Pointer to the buffer where received data will be stored.
204  * @param [in] bytes_to_read Number of bytes to transfer.
205  */
register_read(uint8_t slave_addr,uint32_t reg_num,uint8_t * rx_buffer,uint8_t bytes_to_read)206 void register_read(uint8_t   slave_addr,
207                    uint32_t  reg_num,
208                    uint8_t * rx_buffer,
209                    uint8_t   bytes_to_read)
210 {
211     nrfx_twim_xfer_desc_t twim_xfer_desc = NRFX_TWIM_XFER_DESC_TXRX(slave_addr,
212                                                                     (uint8_t *)&reg_num,
213                                                                     sizeof(drone_reg_name_t),
214                                                                     rx_buffer,
215                                                                     bytes_to_read);
216     NRFX_EXAMPLE_LOG_PROCESS();
217     nrfx_err_t status = nrfx_twim_xfer(&m_twim_inst, &twim_xfer_desc, 0);
218     NRFX_ASSERT(status == NRFX_SUCCESS);
219 
220     while (nrfx_twim_is_busy(&m_twim_inst))
221     {}
222 }
223 
224 /**
225  * @brief Function for handling TWIM driver events.
226  *
227  * @param[in] p_event   Event information structure.
228  * @param[in] p_context General purpose parameter set during initialization of the TWIM.
229  *                      This parameter can be used to pass additional information to the
230  *                      handler function.
231  */
twim_handler(nrfx_twim_evt_t const * p_event,void * p_context)232 static void twim_handler(nrfx_twim_evt_t const * p_event, void * p_context)
233 {
234     if (p_event->type == NRFX_TWIM_EVT_DONE)
235     {
236         char * p_msg = p_context;
237         NRFX_LOG_INFO("%s", p_msg);
238     }
239     else
240     {
241         NRFX_LOG_INFO("--> Master event: %d.", p_event->type);
242     }
243 }
244 
245 /**
246  * @brief Function for handling TWIS driver events.
247  *
248  * @param[in] p_event Event information structure.
249  */
twis_handler(nrfx_twis_evt_t const * p_event)250 static void twis_handler(nrfx_twis_evt_t const * p_event)
251 {
252     nrfx_err_t status;
253     (void)status;
254 
255     /* Variable to store register number sent in the last TX. */
256     static uint8_t reg_buff;
257 
258     switch (p_event->type)
259     {
260         case NRFX_TWIS_EVT_WRITE_REQ:
261             status = nrfx_twis_rx_prepare(&m_twis_inst, &reg_buff, sizeof(reg_buff));
262             NRFX_ASSERT(status == NRFX_SUCCESS);
263             break;
264 
265         case NRFX_TWIS_EVT_READ_REQ:
266             status = nrfx_twis_tx_prepare(&m_twis_inst,
267                                           &m_drone_reg.bytes[reg_buff],
268                                           sizeof(m_drone_reg) - reg_buff);
269             NRFX_ASSERT(status == NRFX_SUCCESS);
270             break;
271 
272         default:
273             break;
274     }
275 }
276 
277 /**
278  * @brief Function for application main entry.
279  *
280  * @return Nothing.
281  */
main(void)282 int main(void)
283 {
284     nrfx_err_t status;
285     (void)status;
286 
287 #if defined(__ZEPHYR__)
288     IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_TWIM_INST_GET(TWIM_INST_IDX)), IRQ_PRIO_LOWEST,
289                 NRFX_TWIM_INST_HANDLER_GET(TWIM_INST_IDX), 0, 0);
290 
291     IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_TWIS_INST_GET(TWIS_INST_IDX)), IRQ_PRIO_LOWEST,
292                 NRFX_TWIS_INST_HANDLER_GET(TWIS_INST_IDX), 0, 0);
293 #endif
294 
295     NRFX_EXAMPLE_LOG_INIT();
296 
297     NRFX_LOG_INFO("Starting nrfx_twim_twis txrx example.");
298     NRFX_EXAMPLE_LOG_PROCESS();
299 
300     /* Buffer for storing values that will be sent from slave to master (drone->controller). */
301     uint32_t drone_ctrl_buffer = 0;
302 
303     void * p_context = "--> Master event: done - transfer completed";
304     nrfx_twim_config_t twim_config = NRFX_TWIM_DEFAULT_CONFIG(MASTER_SCL_PIN, MASTER_SDA_PIN);
305     status = nrfx_twim_init(&m_twim_inst, &twim_config, twim_handler, p_context);
306     NRFX_ASSERT(status == NRFX_SUCCESS);
307 
308     nrfx_twis_config_t twis_config = NRFX_TWIS_DEFAULT_CONFIG(SLAVE_SCL_PIN,
309                                                               SLAVE_SDA_PIN,
310                                                               DRONE_IDX);
311     status = nrfx_twis_init(&m_twis_inst, &twis_config, twis_handler);
312     NRFX_ASSERT(status == NRFX_SUCCESS);
313 
314     drone_reg_print(&m_drone_reg);
315 
316     nrfx_twim_enable(&m_twim_inst);
317     nrfx_twis_enable(&m_twis_inst);
318 
319     NRFX_LOG_INFO("Reading value of DRONE_REG_FORCE_X register:");
320     register_read(DRONE_IDX, DRONE_REG_FORCE_X, (uint8_t *)&drone_ctrl_buffer, 1);
321     NRFX_LOG_INFO("ctrl buff: 0x%X", drone_ctrl_buffer);
322     NRFX_LOG_INFO("...");
323     drone_ctrl_buffer = 0;
324 
325     NRFX_LOG_INFO("Reading value of DRONE_REG_ACC_Y register:");
326     register_read(DRONE_IDX, DRONE_REG_ACC_Y, (uint8_t *)&drone_ctrl_buffer, 1);
327     NRFX_LOG_INFO("ctrl buff: 0x%X", drone_ctrl_buffer);
328     NRFX_LOG_INFO("...");
329     drone_ctrl_buffer = 0;
330 
331     NRFX_LOG_INFO("Reading values of DRONE_REG_DATA registers:");
332     register_read(DRONE_IDX, DRONE_REG_ADDT_DATA0, (uint8_t *)&drone_ctrl_buffer, 4);
333     NRFX_LOG_INFO("ctrl buff: 0x%X", drone_ctrl_buffer);
334     NRFX_LOG_INFO("...");
335     drone_ctrl_buffer = 0;
336 
337     while (1)
338     {
339         NRFX_EXAMPLE_LOG_PROCESS();
340     }
341 }
342 
343 /** @} */
344