Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add board-i2c library for the launchpad #2599

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion platform/srf06-cc26xx/launchpad/Makefile.launchpad
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ CFLAGS += -DBOARD_LAUNCHPAD=1
CONTIKI_TARGET_DIRS += launchpad common

BOARD_SOURCEFILES += board.c launchpad-sensors.c leds-arch.c button-sensor.c
BOARD_SOURCEFILES += ext-flash.c board-spi.c
BOARD_SOURCEFILES += ext-flash.c board-spi.c board-i2c.c

### Signal that we can be programmed with cc2538-bsl
BOARD_SUPPORTS_BSL=1
323 changes: 323 additions & 0 deletions platform/srf06-cc26xx/launchpad/board-i2c.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,323 @@
/*
* Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/
* Copyright (c) 2017, University of Bristol - http://www.bris.ac.uk/
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*---------------------------------------------------------------------------*/
/**
* \addtogroup sensortag-cc26xx-i2c
* @{
*
* \file
* Board-specific I2C driver for the Sensortags
*/
/*---------------------------------------------------------------------------*/
#include "contiki-conf.h"
#include "ti-lib.h"
#include "board-i2c.h"
#include "lpm.h"
#include "rtimer.h"

#include <string.h>
#include <stdbool.h>
/*---------------------------------------------------------------------------*/
#define I2C_MAX_WAIT_TIME (RTIMER_SECOND / 10)

#define LIMITED_BUSYWAIT(cond) do { \
rtimer_clock_t end_time = RTIMER_NOW() + I2C_MAX_WAIT_TIME; \
while(cond) { \
if(!RTIMER_CLOCK_LT(RTIMER_NOW(), end_time)) { \
return false; \
} \
} \
} while(0)
/*---------------------------------------------------------------------------*/
#define NO_INTERFACE 0xFF
/*---------------------------------------------------------------------------*/
static uint8_t slave_addr = 0x00;
static uint8_t interface = NO_INTERFACE;
/*---------------------------------------------------------------------------*/
static bool
accessible(void)
{
/* First, check the PD */
if(ti_lib_prcm_power_domain_status(PRCM_DOMAIN_SERIAL)
!= PRCM_DOMAIN_POWER_ON) {
return false;
}

/* Then check the 'run mode' clock gate */
if(!(HWREG(PRCM_BASE + PRCM_O_I2CCLKGR) & PRCM_I2CCLKGR_CLK_EN)) {
return false;
}

return true;
}
/*---------------------------------------------------------------------------*/
void
board_i2c_wakeup()
{
/* First, make sure the SERIAL PD is on */
ti_lib_prcm_power_domain_on(PRCM_DOMAIN_SERIAL);
while((ti_lib_prcm_power_domain_status(PRCM_DOMAIN_SERIAL)
!= PRCM_DOMAIN_POWER_ON));

/* Enable the clock to I2C */
ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_I2C0);
ti_lib_prcm_load_set();
while(!ti_lib_prcm_load_get());

/* Enable and initialize the I2C master module */
ti_lib_i2c_master_init_exp_clk(I2C0_BASE, ti_lib_sys_ctrl_clock_get(),
true);
}
/*---------------------------------------------------------------------------*/
static bool
i2c_status()
{
uint32_t status;

status = ti_lib_i2c_master_err(I2C0_BASE);
if(status & (I2C_MSTAT_DATACK_N_M | I2C_MSTAT_ADRACK_N_M)) {
ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
}

return status == I2C_MASTER_ERR_NONE;
}
/*---------------------------------------------------------------------------*/
void
board_i2c_shutdown()
{
interface = NO_INTERFACE;

if(accessible()) {
ti_lib_i2c_master_disable(I2C0_BASE);
}

ti_lib_prcm_peripheral_run_disable(PRCM_PERIPH_I2C0);
ti_lib_prcm_load_set();
while(!ti_lib_prcm_load_get());

/*
* Set all pins to GPIO Input and disable the output driver. Set internal
* pull to match external pull
*
* SDA and SCL: external PU resistor
*/
ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SDA);
ti_lib_ioc_io_port_pull_set(BOARD_IOID_SDA, IOC_IOPULL_UP);
ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SCL);
ti_lib_ioc_io_port_pull_set(BOARD_IOID_SCL, IOC_IOPULL_UP);
}
/*---------------------------------------------------------------------------*/
bool
board_i2c_write(uint8_t *data, uint8_t len)
{
uint32_t i;
bool success;

/* Write slave address */
ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, false);

/* Write first byte */
ti_lib_i2c_master_data_put(I2C0_BASE, data[0]);

/* Check if another master has access */
LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE));

/* Assert RUN + START */
ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
success = i2c_status();

for(i = 1; i < len && success; i++) {
/* Write next byte */
ti_lib_i2c_master_data_put(I2C0_BASE, data[i]);
if(i < len - 1) {
/* Clear START */
ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
success = i2c_status();
}
}

/* Assert stop */
if(success) {
/* Assert STOP */
ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
success = i2c_status();
LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE));
}

return success;
}
/*---------------------------------------------------------------------------*/
bool
board_i2c_write_single(uint8_t data)
{
/* Write slave address */
ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, false);

/* Write first byte */
ti_lib_i2c_master_data_put(I2C0_BASE, data);

/* Check if another master has access */
LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE));

/* Assert RUN + START + STOP */
ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);
LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));

return i2c_status();
}
/*---------------------------------------------------------------------------*/
bool
board_i2c_read(uint8_t *data, uint8_t len)
{
uint8_t i;
bool success;

/* Set slave address */
ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, true);

/* Check if another master has access */
LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE));

/* Assert RUN + START + ACK */
ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START);

i = 0;
success = true;
while(i < (len - 1) && success) {
LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
success = i2c_status();
if(success) {
data[i] = ti_lib_i2c_master_data_get(I2C0_BASE);
ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
i++;
}
}

if(success) {
ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
success = i2c_status();
if(success) {
data[len - 1] = ti_lib_i2c_master_data_get(I2C0_BASE);
LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE));
}
}

return success;
}
/*---------------------------------------------------------------------------*/
bool
board_i2c_write_read(uint8_t *wdata, uint8_t wlen, uint8_t *rdata, uint8_t rlen)
{
uint32_t i;
bool success;

/* Set slave address for write */
ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, false);

/* Write first byte */
ti_lib_i2c_master_data_put(I2C0_BASE, wdata[0]);

/* Check if another master has access */
LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE));

/* Assert RUN + START */
ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
success = i2c_status();

for(i = 1; i < wlen && success; i++) {
/* Write next byte */
ti_lib_i2c_master_data_put(I2C0_BASE, wdata[i]);

/* Clear START */
ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
success = i2c_status();
}
if(!success) {
return false;
}

/* Set slave address for read */
ti_lib_i2c_master_slave_addr_set(I2C0_BASE, slave_addr, true);

/* Assert ACK */
ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START);

i = 0;
while(i < (rlen - 1) && success) {
LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
success = i2c_status();
if(success) {
rdata[i] = ti_lib_i2c_master_data_get(I2C0_BASE);
ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
i++;
}
}

if(success) {
ti_lib_i2c_master_control(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
LIMITED_BUSYWAIT(ti_lib_i2c_master_busy(I2C0_BASE));
success = i2c_status();
if(success) {
rdata[rlen - 1] = ti_lib_i2c_master_data_get(I2C0_BASE);
LIMITED_BUSYWAIT(ti_lib_i2c_master_bus_busy(I2C0_BASE));
}
}

return success;
}
/*---------------------------------------------------------------------------*/
void
board_i2c_select(uint8_t address)
{
slave_addr = address;

if(accessible() == false) {
board_i2c_wakeup();
}

ti_lib_i2c_master_disable(I2C0_BASE);

ti_lib_ioc_io_port_pull_set(BOARD_IOID_SDA, IOC_NO_IOPULL);
ti_lib_ioc_io_port_pull_set(BOARD_IOID_SCL, IOC_NO_IOPULL);
ti_lib_ioc_pin_type_i2c(I2C0_BASE, BOARD_IOID_SDA, BOARD_IOID_SCL);

/* Enable and initialize the I2C master module */
ti_lib_i2c_master_init_exp_clk(I2C0_BASE, ti_lib_sys_ctrl_clock_get(),
true);
}
/*---------------------------------------------------------------------------*/
/** @} */
Loading