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