diff --git a/platform/srf06-cc26xx/sensortag/board-i2c.c b/platform/srf06-cc26xx/sensortag/board-i2c.c index 0e1f544a6..da17c4139 100644 --- a/platform/srf06-cc26xx/sensortag/board-i2c.c +++ b/platform/srf06-cc26xx/sensortag/board-i2c.c @@ -39,9 +39,55 @@ #include "contiki-conf.h" #include "ti-lib.h" #include "board-i2c.h" +#include "lpm.h" + +#include +#include +/*---------------------------------------------------------------------------*/ +#define NO_INTERFACE 0xFF /*---------------------------------------------------------------------------*/ static uint8_t slave_addr = 0x00; -static uint8_t interface = 0xFF; +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()); + + /* Reset the I2C controller */ + HWREG(PRCM_BASE + PRCM_O_RESETI2C) = PRCM_RESETI2C_I2C; + + /* Enable and initialize the I2C master module */ + ti_lib_i2c_master_init_exp_clk(I2C0_BASE, + ti_lib_sys_ctrl_peripheral_clock_get( + PRCM_PERIPH_I2C0, SYSCTRL_SYSBUS_ON), + true); +} /*---------------------------------------------------------------------------*/ static bool i2c_status() @@ -57,21 +103,34 @@ i2c_status() } /*---------------------------------------------------------------------------*/ void -board_i2c_init() +board_i2c_shutdown() { - /* The I2C peripheral must be enabled */ - ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_I2C0); + 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()); - /* Reset the I2C controller */ - HWREG(PRCM_BASE + PRCM_O_RESETI2C) = PRCM_RESETI2C_I2C; + /* + * Set all pins to GPIO Input and disable the output driver. Set internal + * pull to match external pull + * + * SDA and SCL: external PU resistor + * SDA HP and SCL HP: MPU PWR low + */ + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SDA_HP); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_SDA_HP, IOC_IOPULL_DOWN); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SCL_HP); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_SCL_HP, IOC_IOPULL_DOWN); - /* Enable and initialize the I2C master module */ - ti_lib_i2c_master_init_exp_clk(I2C0_BASE, - ti_lib_sys_ctrl_peripheral_clock_get( - PRCM_PERIPH_I2C0, SYSCTRL_SYSBUS_ON), - true); + 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 @@ -248,8 +307,15 @@ board_i2c_select(uint8_t new_interface, uint8_t address) { slave_addr = address; + if(accessible() == false) { + board_i2c_wakeup(); + } + if(new_interface != interface) { interface = new_interface; + + ti_lib_i2c_master_disable(I2C0_BASE); + if(interface == BOARD_I2C_INTERFACE_0) { 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); @@ -263,6 +329,12 @@ board_i2c_select(uint8_t new_interface, uint8_t address) ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SDA); ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SCL); } + + /* Enable and initialize the I2C master module */ + ti_lib_i2c_master_init_exp_clk(I2C0_BASE, + ti_lib_sys_ctrl_peripheral_clock_get( + PRCM_PERIPH_I2C0, SYSCTRL_SYSBUS_ON), + true); } } /*---------------------------------------------------------------------------*/ diff --git a/platform/srf06-cc26xx/sensortag/board-i2c.h b/platform/srf06-cc26xx/sensortag/board-i2c.h index c159bc527..40832c9bd 100644 --- a/platform/srf06-cc26xx/sensortag/board-i2c.h +++ b/platform/srf06-cc26xx/sensortag/board-i2c.h @@ -101,6 +101,27 @@ bool board_i2c_write_single(uint8_t data); */ bool board_i2c_write_read(uint8_t *wdata, uint8_t wlen, uint8_t *rdata, uint8_t rlen); + +/** + * \brief Enables the I2C peripheral with defaults + * + * This function is called to wakeup and initialise the I2C. + * + * This function can be called explicitly, but it will also be called + * automatically by board_i2c_select() when required. One of those two + * functions MUST be called before any other I2C operation after a chip + * sleep / wakeup cycle or after a call to board_i2c_shutdown(). Failing to do + * so will lead to a bus fault. + */ +void board_i2c_wakeup(void); + +/** + * \brief Stops the I2C peripheral and restores pins to s/w control + * + * This function is called automatically by the board's LPM logic, but it + * can also be called explicitly. + */ +void board_i2c_shutdown(void); /*---------------------------------------------------------------------------*/ #endif /* BOARD_I2C_H_ */ /*---------------------------------------------------------------------------*/ diff --git a/platform/srf06-cc26xx/sensortag/board.c b/platform/srf06-cc26xx/sensortag/board.c index 458438ef1..89184ae93 100644 --- a/platform/srf06-cc26xx/sensortag/board.c +++ b/platform/srf06-cc26xx/sensortag/board.c @@ -65,8 +65,6 @@ static void lpm_wakeup_handler(void) { power_domains_on(); - - board_i2c_init(); } /*---------------------------------------------------------------------------*/ static void @@ -80,6 +78,9 @@ shutdown_handler(uint8_t mode) SENSORS_DEACTIVATE(hdc_1000_sensor); mpu_9250_sensor.configure(MPU_9250_SENSOR_SHUTDOWN, 0); } + + /* In all cases, stop the I2C */ + board_i2c_shutdown(); } /*---------------------------------------------------------------------------*/ /* @@ -125,7 +126,6 @@ board_init() ti_lib_ioc_io_port_pull_set(BOARD_IOID_KEY_RIGHT, IOC_IOPULL_UP); /* I2C controller */ - board_i2c_init(); /* Sensor interface */ ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_MPU_INT); @@ -139,6 +139,7 @@ board_init() /* Flash interface */ ti_lib_rom_ioc_pin_type_gpio_output(BOARD_IOID_FLASH_CS); ti_lib_gpio_pin_write(BOARD_FLASH_CS, 1); + board_i2c_wakeup(); buzzer_init();