Contiki-NG
board-i2c.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/
3  * Copyright (c) 2017, University of Bristol - http://www.bris.ac.uk/
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holder nor the names of its
15  * contributors may be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29  * OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 /*---------------------------------------------------------------------------*/
32 /**
33  * \addtogroup sensortag-cc26xx-i2c
34  * @{
35  *
36  * \file
37  * Board-specific I2C driver for the Sensortags
38  */
39 /*---------------------------------------------------------------------------*/
40 #include "contiki.h"
41 #include "ti-lib.h"
42 #include "board-i2c.h"
43 #include "lpm.h"
44 #include "rtimer.h"
45 
46 #include <string.h>
47 #include <stdbool.h>
48 /*---------------------------------------------------------------------------*/
49 #define I2C_MAX_WAIT_TIME (RTIMER_SECOND / 10)
50 
51 #define LIMITED_BUSYWAIT(cond) do { \
52  rtimer_clock_t end_time = RTIMER_NOW() + I2C_MAX_WAIT_TIME; \
53  while(cond) { \
54  if(!RTIMER_CLOCK_LT(RTIMER_NOW(), end_time)) { \
55  return false; \
56  } \
57  } \
58  } while(0)
59 /*---------------------------------------------------------------------------*/
60 #define NO_INTERFACE 0xFF
61 /*---------------------------------------------------------------------------*/
62 static uint8_t slave_addr = 0x00;
63 static uint8_t interface = NO_INTERFACE;
64 /*---------------------------------------------------------------------------*/
65 static bool
66 accessible(void)
67 {
68  /* First, check the PD */
69  if(ti_lib_prcm_power_domain_status(PRCM_DOMAIN_SERIAL)
70  != PRCM_DOMAIN_POWER_ON) {
71  return false;
72  }
73 
74  /* Then check the 'run mode' clock gate */
75  if(!(HWREG(PRCM_BASE + PRCM_O_I2CCLKGR) & PRCM_I2CCLKGR_CLK_EN)) {
76  return false;
77  }
78 
79  return true;
80 }
81 /*---------------------------------------------------------------------------*/
82 void
84 {
85  /* First, make sure the SERIAL PD is on */
86  ti_lib_prcm_power_domain_on(PRCM_DOMAIN_SERIAL);
87  while((ti_lib_prcm_power_domain_status(PRCM_DOMAIN_SERIAL)
88  != PRCM_DOMAIN_POWER_ON));
89 
90  /* Enable the clock to I2C */
91  ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_I2C0);
92  ti_lib_prcm_load_set();
93  while(!ti_lib_prcm_load_get());
94 
95  /* Enable and initialize the I2C master module */
96  ti_lib_i2c_master_init_exp_clk(I2C0_BASE, ti_lib_sys_ctrl_clock_get(),
97  true);
98 }
99 /*---------------------------------------------------------------------------*/
100 static bool
101 i2c_status()
102 {
103  uint32_t status;
104 
105  status = ti_lib_i2c_master_err(I2C0_BASE);
106  if(status & (I2C_MSTAT_DATACK_N_M | I2C_MSTAT_ADRACK_N_M)) {
107  ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
108  }
109 
110  return status == I2C_MASTER_ERR_NONE;
111 }
112 /*---------------------------------------------------------------------------*/
113 void
115 {
116  interface = NO_INTERFACE;
117 
118  if(accessible()) {
119  ti_lib_i2c_master_disable(I2C0_BASE);
120  }
121 
122  ti_lib_prcm_peripheral_run_disable(PRCM_PERIPH_I2C0);
123  ti_lib_prcm_load_set();
124  while(!ti_lib_prcm_load_get());
125 
126  /*
127  * Set all pins to GPIO Input and disable the output driver. Set internal
128  * pull to match external pull
129  *
130  * SDA and SCL: external PU resistor
131  * SDA HP and SCL HP: MPU PWR low
132  */
133  ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SDA_HP);
134  ti_lib_ioc_io_port_pull_set(BOARD_IOID_SDA_HP, IOC_IOPULL_DOWN);
135  ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SCL_HP);
136  ti_lib_ioc_io_port_pull_set(BOARD_IOID_SCL_HP, IOC_IOPULL_DOWN);
137 
138  ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SDA);
139  ti_lib_ioc_io_port_pull_set(BOARD_IOID_SDA, IOC_IOPULL_UP);
140  ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SCL);
141  ti_lib_ioc_io_port_pull_set(BOARD_IOID_SCL, IOC_IOPULL_UP);
142 }
143 /*---------------------------------------------------------------------------*/
144 bool
145 board_i2c_write(uint8_t *data, uint8_t len)
146 {
147  uint32_t i;
148  bool success;
149 
150  /* Write slave address */
151  ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, false);
152 
153  /* Write first byte */
154  ti_lib_i2c_master_data_put(I2C0_BASE, data[0]);
155 
156  /* Check if another master has access */
157  LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE));
158 
159  /* Assert RUN + START */
160  ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
161  LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
162  success = i2c_status();
163 
164  for(i = 1; i < len && success; i++) {
165  /* Write next byte */
166  ti_lib_i2c_master_data_put(I2C0_BASE, data[i]);
167  if(i < len - 1) {
168  /* Clear START */
169  ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
170  LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
171  success = i2c_status();
172  }
173  }
174 
175  /* Assert stop */
176  if(success) {
177  /* Assert STOP */
178  ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
179  LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
180  success = i2c_status();
181  LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE));
182  }
183 
184  return success;
185 }
186 /*---------------------------------------------------------------------------*/
187 bool
189 {
190  /* Write slave address */
191  ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, false);
192 
193  /* Write first byte */
194  ti_lib_i2c_master_data_put(I2C0_BASE, data);
195 
196  /* Check if another master has access */
197  LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE));
198 
199  /* Assert RUN + START + STOP */
200  ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);
201  LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
202 
203  return i2c_status();
204 }
205 /*---------------------------------------------------------------------------*/
206 bool
207 board_i2c_read(uint8_t *data, uint8_t len)
208 {
209  uint8_t i;
210  bool success;
211 
212  /* Set slave address */
213  ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, true);
214 
215  /* Check if another master has access */
216  LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE));
217 
218  /* Assert RUN + START + ACK */
219  ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START);
220 
221  i = 0;
222  success = true;
223  while(i < (len - 1) && success) {
224  LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
225  success = i2c_status();
226  if(success) {
227  data[i] = ti_lib_i2c_master_data_get(I2C0_BASE);
228  ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
229  i++;
230  }
231  }
232 
233  if(success) {
234  ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
235  LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
236  success = i2c_status();
237  if(success) {
238  data[len - 1] = ti_lib_i2c_master_data_get(I2C0_BASE);
239  LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE));
240  }
241  }
242 
243  return success;
244 }
245 /*---------------------------------------------------------------------------*/
246 bool
247 board_i2c_write_read(uint8_t *wdata, uint8_t wlen, uint8_t *rdata, uint8_t rlen)
248 {
249  uint32_t i;
250  bool success;
251 
252  /* Set slave address for write */
253  ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, false);
254 
255  /* Write first byte */
256  ti_lib_i2c_master_data_put(I2C0_BASE, wdata[0]);
257 
258  /* Check if another master has access */
259  LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE));
260 
261  /* Assert RUN + START */
262  ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
263  LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
264  success = i2c_status();
265 
266  for(i = 1; i < wlen && success; i++) {
267  /* Write next byte */
268  ti_lib_i2c_master_data_put(I2C0_BASE, wdata[i]);
269 
270  /* Clear START */
271  ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
272  LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
273  success = i2c_status();
274  }
275  if(!success) {
276  return false;
277  }
278 
279  /* Set slave address for read */
280  ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, true);
281 
282  /* Assert ACK */
283  ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START);
284 
285  i = 0;
286  while(i < (rlen - 1) && success) {
287  LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
288  success = i2c_status();
289  if(success) {
290  rdata[i] = ti_lib_i2c_master_data_get(I2C0_BASE);
291  ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
292  i++;
293  }
294  }
295 
296  if(success) {
297  ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
298  LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
299  success = i2c_status();
300  if(success) {
301  rdata[rlen - 1] = ti_lib_i2c_master_data_get(I2C0_BASE);
302  LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE));
303  }
304  }
305 
306  return success;
307 }
308 /*---------------------------------------------------------------------------*/
309 void
310 board_i2c_select(uint8_t new_interface, uint8_t address)
311 {
312  slave_addr = address;
313 
314  if(accessible() == false) {
316  }
317 
318  if(new_interface != interface) {
319  interface = new_interface;
320 
321  ti_lib_i2c_master_disable(I2C0_BASE);
322 
323  if(interface == BOARD_I2C_INTERFACE_0) {
324  ti_lib_ioc_io_port_pull_set(BOARD_IOID_SDA, IOC_NO_IOPULL);
325  ti_lib_ioc_io_port_pull_set(BOARD_IOID_SCL, IOC_NO_IOPULL);
326  ti_lib_ioc_pin_type_i2c(I2C0_BASE, BOARD_IOID_SDA, BOARD_IOID_SCL);
327  ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SDA_HP);
328  ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SCL_HP);
329  } else if(interface == BOARD_I2C_INTERFACE_1) {
330  ti_lib_ioc_io_port_pull_set(BOARD_IOID_SDA_HP, IOC_NO_IOPULL);
331  ti_lib_ioc_io_port_pull_set(BOARD_IOID_SCL_HP, IOC_NO_IOPULL);
332  ti_lib_ioc_pin_type_i2c(I2C0_BASE, BOARD_IOID_SDA_HP, BOARD_IOID_SCL_HP);
333  ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SDA);
334  ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SCL);
335  }
336 
337  /* Enable and initialize the I2C master module */
338  ti_lib_i2c_master_init_exp_clk(I2C0_BASE, ti_lib_sys_ctrl_clock_get(),
339  true);
340  }
341 }
342 /*---------------------------------------------------------------------------*/
343 /** @} */
void board_i2c_shutdown()
Stops the I2C peripheral and restores pins to s/w control.
Definition: board-i2c.c:114
bool board_i2c_read(uint8_t *data, uint8_t len)
Burst read from an I2C device.
Definition: board-i2c.c:207
#define BOARD_IOID_SDA_HP
Interface 1 SDA: MPU.
Definition: board.h:160
Header file with macros which rename TI CC26xxware functions.
Header file for the Sensortag I2C Driver.
bool board_i2c_write_read(uint8_t *wdata, uint8_t wlen, uint8_t *rdata, uint8_t rlen)
Write and read in one operation.
Definition: board-i2c.c:247
bool board_i2c_write_single(uint8_t data)
Single write to an I2C device.
Definition: board-i2c.c:188
bool board_i2c_write(uint8_t *data, uint8_t len)
Burst write to an I2C device.
Definition: board-i2c.c:145
Header file for the real-time timer module.
void board_i2c_select(uint8_t new_interface, uint8_t address)
Select an I2C slave.
Definition: board-i2c.c:310
#define BOARD_IOID_SCL
I2C IOID mappings.
Definition: board.h:132
void board_i2c_wakeup()
Enables the I2C peripheral with defaults.
Definition: board-i2c.c:83
#define BOARD_IOID_SCL_HP
Interface 1 SCL: MPU.
Definition: board.h:161