Improve I2C power-cycling logic:
We only power, clock and enable the peripepheral when / if we need it * We no longer automatically turn on the SERIAL PD when the CM3 is running * Make sure the I2C peripheral is accessible (powered and clocked) before any operation * If the peripheral is not accessible, automatically power it up and run the clock * Put SDA, SCL, SDA HP and SCL HP in a low-leakage state when shutting down * Don't automatically fire up the I2C controller when we wake up
This commit is contained in:
parent
0ad4b5f323
commit
34be012661
3 changed files with 108 additions and 14 deletions
|
@ -39,9 +39,55 @@
|
|||
#include "contiki-conf.h"
|
||||
#include "ti-lib.h"
|
||||
#include "board-i2c.h"
|
||||
#include "lpm.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#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);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
|
@ -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_ */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in a new issue