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