Contiki-NG
Loading...
Searching...
No Matches
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/*---------------------------------------------------------------------------*/
62static uint8_t slave_addr = 0x00;
63static uint8_t interface = NO_INTERFACE;
64/*---------------------------------------------------------------------------*/
65static bool
66accessible(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/*---------------------------------------------------------------------------*/
82void
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/*---------------------------------------------------------------------------*/
100static bool
101i2c_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/*---------------------------------------------------------------------------*/
113void
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/*---------------------------------------------------------------------------*/
144bool
145board_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/*---------------------------------------------------------------------------*/
187bool
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/*---------------------------------------------------------------------------*/
206bool
207board_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/*---------------------------------------------------------------------------*/
246bool
247board_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/*---------------------------------------------------------------------------*/
309void
310board_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/** @} */
Header file for the Sensortag I2C Driver.
#define BOARD_IOID_SCL
I2C IOID mappings.
Definition board.h:132
#define BOARD_IOID_SDA_HP
Interface 1 SDA: MPU.
Definition board.h:160
#define BOARD_IOID_SCL_HP
Interface 1 SCL: MPU.
Definition board.h:161
void board_i2c_select(uint8_t new_interface, uint8_t address)
Select an I2C slave.
Definition board-i2c.c:310
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
void board_i2c_wakeup()
Enables the I2C peripheral with defaults.
Definition board-i2c.c:83
void board_i2c_shutdown()
Stops the I2C peripheral and restores pins to s/w control.
Definition board-i2c.c:114
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_read(uint8_t *data, uint8_t len)
Burst read from an I2C device.
Definition board-i2c.c:207
Header file for the real-time timer module.
Header file with macros which rename TI CC26xxware functions.