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, ®_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 *)®ister_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