From b7e7d48f0ba2d2c2e30ce6d08ce4efdd3fcd19f3 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 15:40:14 +0100 Subject: [PATCH 01/38] Add oscillator control wrappers --- cpu/cc26xx/Makefile.cc26xx | 2 +- cpu/cc26xx/dev/oscillators.c | 172 +++++++++++++++++++++++++++++++++++ cpu/cc26xx/dev/oscillators.h | 101 ++++++++++++++++++++ 3 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 cpu/cc26xx/dev/oscillators.c create mode 100644 cpu/cc26xx/dev/oscillators.h diff --git a/cpu/cc26xx/Makefile.cc26xx b/cpu/cc26xx/Makefile.cc26xx index f8bf8de9f..bff19e7bf 100644 --- a/cpu/cc26xx/Makefile.cc26xx +++ b/cpu/cc26xx/Makefile.cc26xx @@ -81,7 +81,7 @@ CONTIKI_CPU_SOURCEFILES += clock.c rtimer-arch.c cc26xx-rtc.c uart.c CONTIKI_CPU_SOURCEFILES += cc26xx-rf.c contiki-watchdog.c CONTIKI_CPU_SOURCEFILES += putchar.c ieee-addr.c batmon-sensor.c CONTIKI_CPU_SOURCEFILES += slip-arch.c slip.c cc26xx-uart.c lpm.c -CONTIKI_CPU_SOURCEFILES += gpio-interrupt.c +CONTIKI_CPU_SOURCEFILES += gpio-interrupt.c oscillators.c DEBUG_IO_SOURCEFILES += dbg-printf.c dbg-snprintf.c dbg-sprintf.c strformat.c diff --git a/cpu/cc26xx/dev/oscillators.c b/cpu/cc26xx/dev/oscillators.c new file mode 100644 index 000000000..156ee5dd1 --- /dev/null +++ b/cpu/cc26xx/dev/oscillators.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * 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 cc26xx-oscillators + * @{ + * + * \file + * Implementation of CC26xxware oscillator control wrappers. + */ +/*---------------------------------------------------------------------------*/ +#include "ti-lib.h" + +#include +/*---------------------------------------------------------------------------*/ +static uint32_t +osc_interface_en(void) +{ + uint32_t smph_clk_state; + + /* Enable OSC DIG interface to change clock sources */ + ti_lib_osc_interface_enable(); + + /* Save the state of the SMPH clock within AUX */ + smph_clk_state = ti_lib_aux_wuc_clock_status(AUX_WUC_SMPH_CLOCK); + + /* Make sure the SMPH clock within AUX is enabled */ + ti_lib_aux_wuc_clock_enable(AUX_WUC_SMPH_CLOCK); + while(ti_lib_aux_wuc_clock_status(AUX_WUC_SMPH_CLOCK) != AUX_WUC_CLOCK_READY); + + return smph_clk_state; +} +/*---------------------------------------------------------------------------*/ +static void +osc_interface_dis(uint32_t smph_clk_state) +{ + /* If the SMPH clock was off, turn it back off */ + if(smph_clk_state == AUX_WUC_CLOCK_OFF) { + ti_lib_aux_wuc_clock_disable(AUX_WUC_SMPH_CLOCK); + } + + /* Disable OSC DIG interface */ + ti_lib_osc_interface_disable(); +} +/*---------------------------------------------------------------------------*/ +void +oscillators_select_lf_xosc(void) +{ + /* Enable the Osc interface and remember the state of the SMPH clock */ + uint32_t smph_clk_state = osc_interface_en(); + + /* Switch LF clock source to the LF XOSC if required */ + if(ti_lib_osc_clock_source_get(OSC_SRC_CLK_LF) != OSC_XOSC_LF) { + ti_lib_osc_clock_source_set(OSC_SRC_CLK_LF, OSC_XOSC_LF); + + /* Wait for LF clock source to become XOSC_LF */ + while(ti_lib_osc_clock_source_get(OSC_SRC_CLK_LF) != OSC_XOSC_LF) ; + + /* Disable the LF clock qualifiers */ + ti_lib_ddi_16_bit_field_write(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_CTL0, + DDI_0_OSC_CTL0_BYPASS_XOSC_LF_CLK_QUAL_M | + DDI_0_OSC_CTL0_BYPASS_RCOSC_LF_CLK_QUAL_M, + DDI_0_OSC_CTL0_BYPASS_RCOSC_LF_CLK_QUAL_S, + 0x3); + } + + /* Restore the SMPH clock and disable the OSC interface */ + osc_interface_dis(smph_clk_state); +} +/*---------------------------------------------------------------------------*/ +void +oscillators_select_lf_rcosc(void) +{ + /* Enable the Osc interface and remember the state of the SMPH clock */ + uint32_t smph_clk_state = osc_interface_en(); + + /* Switch LF clock source to the LF XOSC if required */ + if(ti_lib_osc_clock_source_get(OSC_SRC_CLK_LF) != OSC_RCOSC_LF) { + ti_lib_osc_clock_source_set(OSC_SRC_CLK_LF, OSC_RCOSC_LF); + + /* Wait for LF clock source to become XOSC_LF */ + while(ti_lib_osc_clock_source_get(OSC_SRC_CLK_LF) != OSC_RCOSC_LF) ; + } + + /* Restore the SMPH clock and disable the OSC interface */ + osc_interface_dis(smph_clk_state); +} +/*---------------------------------------------------------------------------*/ +void +oscillators_request_hf_xosc(void) +{ + /* Enable the Osc interface and remember the state of the SMPH clock */ + uint32_t smph_clk_state = osc_interface_en(); + + if(ti_lib_osc_clock_source_get(OSC_SRC_CLK_HF) != OSC_XOSC_HF) { + /* + * Request to switch to the crystal to enable radio operation. It takes a + * while for the XTAL to be ready so instead of performing the actual + * switch, we return and we do other stuff while the XOSC is getting ready. + */ + ti_lib_osc_clock_source_set(OSC_SRC_CLK_MF | OSC_SRC_CLK_HF, OSC_XOSC_HF); + } + + /* Restore the SMPH clock and disable the OSC interface */ + osc_interface_dis(smph_clk_state); +} +/*---------------------------------------------------------------------------*/ +void +oscillators_switch_to_hf_xosc(void) +{ + /* Enable the Osc interface and remember the state of the SMPH clock */ + uint32_t smph_clk_state = osc_interface_en(); + + if(ti_lib_osc_clock_source_get(OSC_SRC_CLK_HF) != OSC_XOSC_HF) { + /* Switch the HF clock source (cc26xxware executes this from ROM) */ + ti_lib_osc_hf_source_switch(); + } + + /* Restore the SMPH clock and disable the OSC interface */ + osc_interface_dis(smph_clk_state); +} +/*---------------------------------------------------------------------------*/ +void +oscillators_switch_to_hf_rc(void) +{ + /* Enable the Osc interface and remember the state of the SMPH clock */ + uint32_t smph_clk_state = osc_interface_en(); + + /* Set all clock sources to the HF RC Osc */ + ti_lib_osc_clock_source_set(OSC_SRC_CLK_MF | OSC_SRC_CLK_HF, OSC_RCOSC_HF); + + /* Check to not enable HF RC oscillator if already enabled */ + if(ti_lib_osc_clock_source_get(OSC_SRC_CLK_HF) != OSC_RCOSC_HF) { + /* Switch the HF clock source (cc26xxware executes this from ROM) */ + ti_lib_osc_hf_source_switch(); + } + + /* Restore the SMPH clock and disable the OSC interface */ + osc_interface_dis(smph_clk_state); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/cpu/cc26xx/dev/oscillators.h b/cpu/cc26xx/dev/oscillators.h new file mode 100644 index 000000000..2de1b5bb7 --- /dev/null +++ b/cpu/cc26xx/dev/oscillators.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/ + * 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 cc26xx + * @{ + * + * \defgroup cc26xx-oscillators CC26XX oscillator control + * + * Wrapper around those CC26xxware OSC functions that we need in Contiki. + * + * All CC26xxware OSC control requires access to the semaphore module within + * AUX. Thus, in addition to enabling the oscillator interface, we need to + * start the clock to SMPH and restore it to its previous state when we are + * done. + * @{ + * + * \file + * Header file for the CC26XX oscillator control + */ +/*---------------------------------------------------------------------------*/ +#ifndef OSCILLATORS_H_ +#define OSCILLATORS_H_ +/*---------------------------------------------------------------------------*/ +/** + * \brief Set the LF clock source to be the LF XOSC + * + * This function is only called once as soon as the system starts. + * + * Do not switch the LF clock source to the RC OSC for normal system operation + * See CC26xx Errata (swrz058) + */ +void oscillators_select_lf_xosc(void); + +/** + * \brief Set the LF clock source to be the LF RCOSC + * + * This function is only called once, when the systen transitions to a full + * shutdown + * + * Do not switch the LF clock source to the RC OSC for normal system operation + * See CC26xx Errata (swrz058) + */ +void oscillators_select_lf_rcosc(void); + +/** + * \brief Requests the HF XOSC as the source for the HF clock, but does not + * perform the actual switch. + * + * This triggers the startup sequence of the HF XOSC and returns so the CPU + * can perform other tasks while the XOSC is starting. + * + * The XOSC is requested as the source for the HF as well as the MF clock. + */ +void oscillators_request_hf_xosc(void); + +/** + * \brief Performs the switch to the XOSC + * + * This function must be preceded by a call to oscillators_request_hf_xosc() + */ +void oscillators_switch_to_hf_xosc(void); + +/** + * \brief Switches MF and HF clock source to be the HF RC OSC + */ +void oscillators_switch_to_hf_rc(void); +/*---------------------------------------------------------------------------*/ +#endif /* OSCILLATORS_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ From 9d97dee00b723c092d3726095539646874081555 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 15:41:35 +0100 Subject: [PATCH 02/38] Clock the GPT module only when we need it --- cpu/cc26xx/clock.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cpu/cc26xx/clock.c b/cpu/cc26xx/clock.c index c96158b48..47563250d 100644 --- a/cpu/cc26xx/clock.c +++ b/cpu/cc26xx/clock.c @@ -155,11 +155,19 @@ clock_wait(clock_time_t i) void clock_delay_usec(uint16_t len) { + uint32_t clock_status; + if(ti_lib_prcm_power_domain_status(PRCM_DOMAIN_PERIPH) != PRCM_DOMAIN_POWER_ON) { power_domain_on(); } + clock_status = HWREG(PRCM_BASE + PRCM_O_GPTCLKGR) & PRCM_GPIOCLKGR_CLK_EN; + + ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_TIMER0); + ti_lib_prcm_load_set(); + while(!ti_lib_prcm_load_get()); + ti_lib_timer_load_set(GPT0_BASE, TIMER_B, len); ti_lib_timer_enable(GPT0_BASE, TIMER_B); @@ -168,6 +176,12 @@ clock_delay_usec(uint16_t len) * function, hence the direct register access here */ while(HWREG(GPT0_BASE + GPT_O_CTL) & GPT_CTL_TBEN); + + if(clock_status == 0) { + ti_lib_prcm_peripheral_run_disable(PRCM_PERIPH_TIMER0); + ti_lib_prcm_load_set(); + while(!ti_lib_prcm_load_get()); + } } /*---------------------------------------------------------------------------*/ /** From 8a42af682dcf702dcda4a277ea43fcb58ddef3a4 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 15:41:53 +0100 Subject: [PATCH 03/38] Make sure PERIPH is on before accessing GPT registers --- cpu/cc26xx/clock.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cpu/cc26xx/clock.c b/cpu/cc26xx/clock.c index 47563250d..701971e16 100644 --- a/cpu/cc26xx/clock.c +++ b/cpu/cc26xx/clock.c @@ -79,8 +79,14 @@ clock_init(void) * Here, we configure GPT0 Timer A, which we subsequently use in * clock_delay_usec * - * First, enable GPT0 in run mode. We don't need it in sleep mode + * We need to access registers, so firstly power up the PD and then enable + * the clock to GPT0. */ + if(ti_lib_prcm_power_domain_status(PRCM_DOMAIN_PERIPH) != + PRCM_DOMAIN_POWER_ON) { + power_domain_on(); + } + ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_TIMER0); ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()); From 3bbf3cc4356df206ad03e0b2aaf41f0c544e716a Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 15:42:21 +0100 Subject: [PATCH 04/38] Add SysCtrl glue macros --- cpu/cc26xx/ti-lib.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpu/cc26xx/ti-lib.h b/cpu/cc26xx/ti-lib.h index e545ac501..899f4a4d6 100644 --- a/cpu/cc26xx/ti-lib.h +++ b/cpu/cc26xx/ti-lib.h @@ -531,6 +531,8 @@ #define ti_lib_sys_ctrl_aon_update(...) SysCtrlAonUpdate(__VA_ARGS__) #define ti_lib_sys_ctrl_set_recharge_before_power_down(...) SysCtrlSetRechargeBeforePowerDown(__VA_ARGS__) #define ti_lib_sys_ctrl_adjust_recharge_after_power_down(...) SysCtrlAdjustRechargeAfterPowerDown(__VA_ARGS__) +#define ti_lib_sys_ctrl_dcdc_voltage_conditional_control(...) SysCtrl_DCDC_VoltageConditionalControl(__VA_ARGS__) +#define ti_lib_sys_ctrl_reset_source_get(...) SysCtrlResetSourceGet(__VA_ARGS__) /*---------------------------------------------------------------------------*/ /* ssi.h */ #include "driverlib/ssi.h" From cee6c190c56df214e9da4f55827ffc1ea5cba6e2 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 15:43:33 +0100 Subject: [PATCH 05/38] Use the BMP in 'forced' mode and reduce startup delay In forced mode, the BMP will turn itself off after a reading --- platform/srf06-cc26xx/sensortag/bmp-280-sensor.c | 5 +++-- platform/srf06-cc26xx/sensortag/bmp-280-sensor.h | 10 ++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/platform/srf06-cc26xx/sensortag/bmp-280-sensor.c b/platform/srf06-cc26xx/sensortag/bmp-280-sensor.c index a3b85ccc2..067fe79b9 100644 --- a/platform/srf06-cc26xx/sensortag/bmp-280-sensor.c +++ b/platform/srf06-cc26xx/sensortag/bmp-280-sensor.c @@ -136,7 +136,7 @@ static int enabled = SENSOR_STATUS_DISABLED; static uint8_t sensor_value[SENSOR_DATA_BUF_SIZE]; /*---------------------------------------------------------------------------*/ /* Wait SENSOR_STARTUP_DELAY clock ticks for the sensor to be ready - ~80ms */ -#define SENSOR_STARTUP_DELAY 11 +#define SENSOR_STARTUP_DELAY 3 static struct ctimer startup_timer; /*---------------------------------------------------------------------------*/ @@ -187,7 +187,7 @@ enable_sensor(bool enable) if(enable) { /* Enable forced mode */ - val = PM_NORMAL | OSRSP(1) | OSRST(1); + val = PM_FORCED | OSRSP(1) | OSRST(1); } else { val = PM_OFF; } @@ -345,6 +345,7 @@ configure(int type, int enable) case SENSORS_HW_INIT: enabled = SENSOR_STATUS_INITIALISED; init(); + enable_sensor(0); break; case SENSORS_ACTIVE: /* Must be initialised first */ diff --git a/platform/srf06-cc26xx/sensortag/bmp-280-sensor.h b/platform/srf06-cc26xx/sensortag/bmp-280-sensor.h index e27013c40..8bff65787 100644 --- a/platform/srf06-cc26xx/sensortag/bmp-280-sensor.h +++ b/platform/srf06-cc26xx/sensortag/bmp-280-sensor.h @@ -42,12 +42,10 @@ * * Once the sensor is stable, the driver will generate a sensors_changed event. * - * Once a reading has been taken, the caller has two options: - * - Turn the sensor off by calling SENSORS_DEACTIVATE, but in order to take - * subsequent readings SENSORS_ACTIVATE must be called again - * - Leave the sensor on. In this scenario, the caller can simply keep calling - * value() for subsequent readings, but having the sensor on will consume - * energy + * We take readings in "Forced" mode. In this mode, the BMP will take a single + * measurement and it will then automatically go to sleep. + * + * SENSORS_ACTIVATE must be called again to trigger a new reading cycle * @{ * * \file From 883c30b4ac9bcbcd0b07c96799e947793d064001 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 15:44:18 +0100 Subject: [PATCH 06/38] Handle the configuration of the TMP_RDY pin --- platform/srf06-cc26xx/sensortag/tmp-007-sensor.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/srf06-cc26xx/sensortag/tmp-007-sensor.c b/platform/srf06-cc26xx/sensortag/tmp-007-sensor.c index 8f880cb54..7e3529e5e 100644 --- a/platform/srf06-cc26xx/sensortag/tmp-007-sensor.c +++ b/platform/srf06-cc26xx/sensortag/tmp-007-sensor.c @@ -267,6 +267,10 @@ configure(int type, int enable) { switch(type) { case SENSORS_HW_INIT: + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_TMP_RDY); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_TMP_RDY, IOC_IOPULL_UP); + ti_lib_ioc_io_hyst_set(BOARD_IOID_TMP_RDY, IOC_HYST_ENABLE); + enable_sensor(false); enabled = SENSOR_STATUS_INITIALISED; break; From 0b6813513c42d4223b33e892e500a70e3b9d0b43 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 15:45:11 +0100 Subject: [PATCH 07/38] Undefine CTS/RTS pins for the SmartRF --- platform/srf06-cc26xx/srf06/board.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/srf06-cc26xx/srf06/board.h b/platform/srf06-cc26xx/srf06/board.h index 42c060b9b..b222bb17c 100644 --- a/platform/srf06-cc26xx/srf06/board.h +++ b/platform/srf06-cc26xx/srf06/board.h @@ -107,8 +107,8 @@ */ #define BOARD_IOID_UART_RX IOID_2 #define BOARD_IOID_UART_TX IOID_3 -#define BOARD_IOID_UART_CTS IOID_0 -#define BOARD_IOID_UART_RTS IOID_21 +#define BOARD_IOID_UART_CTS IOID_UNUSED +#define BOARD_IOID_UART_RTS IOID_UNUSED #define BOARD_UART_RX (1 << BOARD_IOID_UART_RX) #define BOARD_UART_TX (1 << BOARD_IOID_UART_TX) #define BOARD_UART_CTS (1 << BOARD_IOID_UART_CTS) From 7641aa89f20179f9ee029c04ef791f0875acc820 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 15:46:43 +0100 Subject: [PATCH 08/38] Tidy-up macro semicol usage --- platform/srf06-cc26xx/sensortag/tmp-007-sensor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/srf06-cc26xx/sensortag/tmp-007-sensor.c b/platform/srf06-cc26xx/sensortag/tmp-007-sensor.c index 7e3529e5e..1c462a0e0 100644 --- a/platform/srf06-cc26xx/sensortag/tmp-007-sensor.c +++ b/platform/srf06-cc26xx/sensortag/tmp-007-sensor.c @@ -88,7 +88,7 @@ #define SWAP(v) ((LO_UINT16(v) << 8) | HI_UINT16(v)) /*---------------------------------------------------------------------------*/ -#define SELECT() board_i2c_select(BOARD_I2C_INTERFACE_0, SENSOR_I2C_ADDRESS); +#define SELECT() board_i2c_select(BOARD_I2C_INTERFACE_0, SENSOR_I2C_ADDRESS) /*---------------------------------------------------------------------------*/ static uint8_t buf[DATA_SIZE]; static uint16_t val; @@ -124,7 +124,7 @@ enable_sensor(bool enable) { bool success; - SELECT() + SELECT(); if(enable) { val = TMP007_VAL_CONFIG_ON; From 3ab1b836c487aa623490f0850c79f0be54489b9c Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 15:51:42 +0100 Subject: [PATCH 09/38] Configure button pins with hysterisis --- platform/srf06-cc26xx/sensortag/button-sensor.c | 2 +- platform/srf06-cc26xx/srf06/button-sensor.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/srf06-cc26xx/sensortag/button-sensor.c b/platform/srf06-cc26xx/sensortag/button-sensor.c index e6a9114ea..7b53e8a79 100644 --- a/platform/srf06-cc26xx/sensortag/button-sensor.c +++ b/platform/srf06-cc26xx/sensortag/button-sensor.c @@ -55,7 +55,7 @@ /*---------------------------------------------------------------------------*/ #define BUTTON_GPIO_CFG (IOC_CURRENT_2MA | IOC_STRENGTH_AUTO | \ IOC_IOPULL_UP | IOC_SLEW_DISABLE | \ - IOC_HYST_DISABLE | IOC_BOTH_EDGES | \ + IOC_HYST_ENABLE | IOC_BOTH_EDGES | \ IOC_INT_ENABLE | IOC_IOMODE_NORMAL | \ IOC_NO_WAKE_UP | IOC_INPUT_ENABLE | \ IOC_JTAG_DISABLE) diff --git a/platform/srf06-cc26xx/srf06/button-sensor.c b/platform/srf06-cc26xx/srf06/button-sensor.c index 9638d511e..53112a23c 100644 --- a/platform/srf06-cc26xx/srf06/button-sensor.c +++ b/platform/srf06-cc26xx/srf06/button-sensor.c @@ -55,7 +55,7 @@ /*---------------------------------------------------------------------------*/ #define BUTTON_GPIO_CFG (IOC_CURRENT_2MA | IOC_STRENGTH_AUTO | \ IOC_IOPULL_UP | IOC_SLEW_DISABLE | \ - IOC_HYST_DISABLE | IOC_BOTH_EDGES | \ + IOC_HYST_ENABLE | IOC_BOTH_EDGES | \ IOC_INT_ENABLE | IOC_IOMODE_NORMAL | \ IOC_NO_WAKE_UP | IOC_INPUT_ENABLE | \ IOC_JTAG_DISABLE) From 00a6c31158aea7a18789256a18fdd000fff5ffc7 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:03:48 +0100 Subject: [PATCH 10/38] Improve OPT sensor driver and usage * Query the sensor about its state, rather than using variables in the driver * Correctly put the sensor to deep sleep * Fix doxygen comments * Don't turn off the sensor in examples since it is no longer needed --- examples/cc26xx/cc26xx-demo.c | 3 +- .../cc26xx/cc26xx-web-demo/cc26xx-web-demo.c | 3 +- .../srf06-cc26xx/sensortag/opt-3001-sensor.c | 134 ++++++++++++------ .../srf06-cc26xx/sensortag/opt-3001-sensor.h | 16 ++- 4 files changed, 105 insertions(+), 51 deletions(-) diff --git a/examples/cc26xx/cc26xx-demo.c b/examples/cc26xx/cc26xx-demo.c index 903af6631..ff7ea9a38 100644 --- a/examples/cc26xx/cc26xx-demo.c +++ b/examples/cc26xx/cc26xx-demo.c @@ -251,8 +251,7 @@ get_light_reading() printf("OPT: Light Read Error\n"); } - SENSORS_DEACTIVATE(opt_3001_sensor); - + /* The OPT will turn itself off, so we don't need to call its DEACTIVATE */ ctimer_set(&opt_timer, next, init_opt_reading, NULL); } /*---------------------------------------------------------------------------*/ diff --git a/examples/cc26xx/cc26xx-web-demo/cc26xx-web-demo.c b/examples/cc26xx/cc26xx-web-demo/cc26xx-web-demo.c index 6cae9611d..d2c2bf77b 100644 --- a/examples/cc26xx/cc26xx-web-demo/cc26xx-web-demo.c +++ b/examples/cc26xx/cc26xx-web-demo/cc26xx-web-demo.c @@ -574,8 +574,6 @@ get_light_reading() value = opt_3001_sensor.value(0); - SENSORS_DEACTIVATE(opt_3001_sensor); - if(value != CC26XX_SENSOR_READING_ERROR) { opt_reading.raw = value; @@ -587,6 +585,7 @@ get_light_reading() value % 100); } + /* The OPT will turn itself off, so we don't need to call its DEACTIVATE */ ctimer_set(&opt_timer, next, init_light_reading, NULL); } /*---------------------------------------------------------------------------*/ diff --git a/platform/srf06-cc26xx/sensortag/opt-3001-sensor.c b/platform/srf06-cc26xx/sensortag/opt-3001-sensor.c index 7cb41bf6d..f1cbf695e 100644 --- a/platform/srf06-cc26xx/sensortag/opt-3001-sensor.c +++ b/platform/srf06-cc26xx/sensortag/opt-3001-sensor.c @@ -69,16 +69,42 @@ #define REG_MANUFACTURER_ID 0x7E #define REG_DEVICE_ID 0x7F /*---------------------------------------------------------------------------*/ -/* Register values */ -#define MANUFACTURER_ID 0x5449 /* TI */ -#define DEVICE_ID 0x3001 /* Opt 3001 */ -#define CONFIG_RESET 0xC810 -#define CONFIG_TEST 0xCC10 -#define CONFIG_ENABLE 0x10CC /* 0xCC10 */ -#define CONFIG_DISABLE 0x108C /* 0xC810 */ -/*---------------------------------------------------------------------------*/ -/* Bit values */ -#define DATA_RDY_BIT 0x0080 /* Data ready */ +/* + * Configuration Register Bits and Masks. + * We use uint16_t to read from / write to registers, meaning that the + * register's MSB is the variable's LSB. + */ +#define CONFIG_RN 0x00F0 /* [15..12] Range Number */ +#define CONFIG_CT 0x0008 /* [11] Conversion Time */ +#define CONFIG_M 0x0006 /* [10..9] Mode of Conversion */ +#define CONFIG_OVF 0x0001 /* [8] Overflow */ +#define CONFIG_CRF 0x8000 /* [7] Conversion Ready Field */ +#define CONFIG_FH 0x4000 /* [6] Flag High */ +#define CONFIG_FL 0x2000 /* [5] Flag Low */ +#define CONFIG_L 0x1000 /* [4] Latch */ +#define CONFIG_POL 0x0800 /* [3] Polarity */ +#define CONFIG_ME 0x0400 /* [2] Mask Exponent */ +#define CONFIG_FC 0x0300 /* [1..0] Fault Count */ + +/* Possible Values for CT */ +#define CONFIG_CT_100 0x0000 +#define CONFIG_CT_800 CONFIG_CT + +/* Possible Values for M */ +#define CONFIG_M_CONTI 0x0004 +#define CONFIG_M_SINGLE 0x0002 +#define CONFIG_M_SHUTDOWN 0x0000 + +/* Reset Value for the register 0xC810. All zeros except: */ +#define CONFIG_RN_RESET 0x00C0 +#define CONFIG_CT_RESET CONFIG_CT_800 +#define CONFIG_L_RESET 0x1000 +#define CONFIG_DEFAULTS (CONFIG_RN_RESET | CONFIG_CT_100 | CONFIG_L_RESET) + +/* Enable / Disable */ +#define CONFIG_ENABLE_CONTINUOUS (CONFIG_M_CONTI | CONFIG_DEFAULTS) +#define CONFIG_ENABLE_SINGLE_SHOT (CONFIG_M_SINGLE | CONFIG_DEFAULTS) +#define CONFIG_DISABLE CONFIG_DEFAULTS /*---------------------------------------------------------------------------*/ /* Register length */ #define REGISTER_LENGTH 2 @@ -86,24 +112,22 @@ /* Sensor data size */ #define DATA_LENGTH 2 /*---------------------------------------------------------------------------*/ -#define SENSOR_STATUS_DISABLED 0 -#define SENSOR_STATUS_NOT_READY 1 -#define SENSOR_STATUS_ENABLED 2 +/* + * SENSOR_STATE_SLEEPING and SENSOR_STATE_ACTIVE are mutually exclusive. + * SENSOR_STATE_DATA_READY can be ORd with both of the above. For example the + * sensor may be sleeping but with a conversion ready to read out. + */ +#define SENSOR_STATE_SLEEPING 0 +#define SENSOR_STATE_ACTIVE 1 +#define SENSOR_STATE_DATA_READY 2 -static int enabled = SENSOR_STATUS_DISABLED; +static int state = SENSOR_STATE_SLEEPING; /*---------------------------------------------------------------------------*/ /* Wait SENSOR_STARTUP_DELAY for the sensor to be ready - 125ms */ #define SENSOR_STARTUP_DELAY (CLOCK_SECOND >> 3) static struct ctimer startup_timer; /*---------------------------------------------------------------------------*/ -static void -notify_ready(void *not_used) -{ - enabled = SENSOR_STATUS_ENABLED; - sensors_changed(&opt_3001_sensor); -} -/*---------------------------------------------------------------------------*/ /** * \brief Select the sensor on the I2C bus */ @@ -114,6 +138,28 @@ select(void) board_i2c_select(BOARD_I2C_INTERFACE_0, OPT3001_I2C_ADDRESS); } /*---------------------------------------------------------------------------*/ +static void +notify_ready(void *not_used) +{ + /* + * Depending on the CONFIGURATION.CONVERSION_TIME bits, a conversion will + * take either 100 or 800 ms. Here we inspect the CONVERSION_READY bit and + * if the reading is ready we notify, otherwise we just reschedule ourselves + */ + uint16_t val; + + select(); + + sensor_common_read_reg(REG_CONFIGURATION, (uint8_t *)&val, REGISTER_LENGTH); + + if(val & CONFIG_CRF) { + sensors_changed(&opt_3001_sensor); + state = SENSOR_STATE_DATA_READY; + } else { + ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL); + } +} +/*---------------------------------------------------------------------------*/ /** * \brief Turn the sensor on/off * \param enable TRUE: on, FALSE: off @@ -122,13 +168,20 @@ static void enable_sensor(bool enable) { uint16_t val; + uint16_t had_data_ready = state & SENSOR_STATE_DATA_READY; select(); if(enable) { - val = CONFIG_ENABLE; + val = CONFIG_ENABLE_SINGLE_SHOT; + + /* Writing CONFIG_ENABLE_SINGLE_SHOT to M bits will clear CRF bits */ + state = SENSOR_STATE_ACTIVE; } else { val = CONFIG_DISABLE; + + /* Writing CONFIG_DISABLE to M bits will not clear CRF bits */ + state = SENSOR_STATE_SLEEPING | had_data_ready; } sensor_common_write_reg(REG_CONFIGURATION, (uint8_t *)&val, REGISTER_LENGTH); @@ -145,15 +198,15 @@ read_data(uint16_t *raw_data) bool success; uint16_t val; + if((state & SENSOR_STATE_DATA_READY) != SENSOR_STATE_DATA_READY) { + return false; + } + select(); success = sensor_common_read_reg(REG_CONFIGURATION, (uint8_t *)&val, REGISTER_LENGTH); - if(success) { - success = (val & DATA_RDY_BIT) == DATA_RDY_BIT; - } - if(success) { success = sensor_common_read_reg(REG_RESULT, (uint8_t *)&val, DATA_LENGTH); } @@ -196,14 +249,9 @@ value(int type) uint16_t raw_val; float converted_val; - if(enabled != SENSOR_STATUS_ENABLED) { - PRINTF("Sensor disabled or starting up (%d)\n", enabled); - return CC26XX_SENSOR_READING_ERROR; - } - rv = read_data(&raw_val); - if(rv == 0) { + if(rv == false) { return CC26XX_SENSOR_READING_ERROR; } @@ -229,30 +277,38 @@ value(int type) static int configure(int type, int enable) { + int rv = 0; + switch(type) { case SENSORS_HW_INIT: + /* + * Device reset won't reset the sensor, so we put it to sleep here + * explicitly + */ + enable_sensor(0); + rv = 0; break; case SENSORS_ACTIVE: if(enable) { enable_sensor(1); ctimer_set(&startup_timer, SENSOR_STARTUP_DELAY, notify_ready, NULL); - enabled = SENSOR_STATUS_NOT_READY; + rv = 1; } else { ctimer_stop(&startup_timer); enable_sensor(0); - enabled = SENSOR_STATUS_DISABLED; + rv = 0; } break; default: break; } - return enabled; + return rv; } /*---------------------------------------------------------------------------*/ /** * \brief Returns the status of the sensor - * \param type SENSORS_ACTIVE or SENSORS_READY - * \return 1 if the sensor is enabled + * \param type ignored + * \return The state of the sensor SENSOR_STATE_xyz */ static int status(int type) @@ -260,12 +316,10 @@ status(int type) switch(type) { case SENSORS_ACTIVE: case SENSORS_READY: - return enabled; - break; default: break; } - return SENSOR_STATUS_DISABLED; + return state; } /*---------------------------------------------------------------------------*/ SENSORS_SENSOR(opt_3001_sensor, "OPT3001", value, configure, status); diff --git a/platform/srf06-cc26xx/sensortag/opt-3001-sensor.h b/platform/srf06-cc26xx/sensortag/opt-3001-sensor.h index 205ab00ff..a4160b729 100644 --- a/platform/srf06-cc26xx/sensortag/opt-3001-sensor.h +++ b/platform/srf06-cc26xx/sensortag/opt-3001-sensor.h @@ -40,14 +40,16 @@ * sequence, but the call will not wait for it to complete so that the CPU can * perform other tasks or drop to a low power mode. * - * Once the sensor is stable, the driver will generate a sensors_changed event. + * Once the reading and conversion are complete, the driver will generate a + * sensors_changed event. * - * Once a reading has been taken, the caller has two options: - * - Turn the sensor off by calling SENSORS_DEACTIVATE, but in order to take - * subsequent readings SENSORS_ACTIVATE must be called again - * - Leave the sensor on. In this scenario, the caller can simply keep calling - * value() for subsequent readings, but having the sensor on will consume - * energy + * We use single-shot readings. In this mode, the hardware automatically goes + * back to its shutdown mode after the conversion is finished. However, it will + * still respond to I2C operations, so the last conversion can still be read + * out. + * + * In order to take a new reading, the caller has to use SENSORS_ACTIVATE + * again. * @{ * * \file From 7a189d010b57aa7e4e1d1640b43c67504174f181 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:06:45 +0100 Subject: [PATCH 11/38] Don't power on SERIAL in the Srf's board_init --- platform/srf06-cc26xx/srf06/board.c | 30 ++++++----------------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/platform/srf06-cc26xx/srf06/board.c b/platform/srf06-cc26xx/srf06/board.c index b62f3fc24..1b9d79665 100644 --- a/platform/srf06-cc26xx/srf06/board.c +++ b/platform/srf06-cc26xx/srf06/board.c @@ -45,29 +45,15 @@ #include #include /*---------------------------------------------------------------------------*/ -#define PRCM_DOMAINS (PRCM_DOMAIN_RFCORE | PRCM_DOMAIN_SERIAL | \ - PRCM_DOMAIN_PERIPH | PRCM_DOMAIN_CPU | \ - PRCM_DOMAIN_SYSBUS | PRCM_DOMAIN_VIMS) -/*---------------------------------------------------------------------------*/ -#define LPM_DOMAINS (PRCM_DOMAIN_SERIAL | PRCM_DOMAIN_PERIPH) -/*---------------------------------------------------------------------------*/ static void -power_domains_on(void) +wakeup_handler(void) { - /* Turn on relevant power domains */ - ti_lib_prcm_power_domain_on(LPM_DOMAINS); - - /* Wait for domains to power on */ - while((ti_lib_prcm_power_domain_status(LPM_DOMAINS) + /* Turn on the PERIPH PD */ + ti_lib_prcm_power_domain_on(PRCM_DOMAIN_PERIPH); + while((ti_lib_prcm_power_domain_status(PRCM_DOMAIN_PERIPH) != PRCM_DOMAIN_POWER_ON)); } /*---------------------------------------------------------------------------*/ -static void -lpm_wakeup_handler(void) -{ - power_domains_on(); -} -/*---------------------------------------------------------------------------*/ /* * Declare a data structure to register with LPM. * We don't care about what power mode we'll drop to, we don't care about @@ -81,12 +67,8 @@ board_init() { uint8_t int_disabled = ti_lib_int_master_disable(); - /* Turn on all power domains */ - ti_lib_prcm_power_domain_on(PRCM_DOMAINS); - - /* Wait for power on domains */ - while((ti_lib_prcm_power_domain_status(PRCM_DOMAINS) - != PRCM_DOMAIN_POWER_ON)); + /* Turn on relevant PDs */ + wakeup_handler(); /* Configure all clock domains to run at full speed */ ti_lib_prcm_clock_configure_set(PRCM_DOMAIN_SYSBUS | PRCM_DOMAIN_CPU | From 450550a7d1bdfb4a37bf542dd39e42abb69200f8 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:07:46 +0100 Subject: [PATCH 12/38] Explicitly configure Srf pins for unused peripherals --- platform/srf06-cc26xx/srf06/board.c | 53 ++++++++++++----------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/platform/srf06-cc26xx/srf06/board.c b/platform/srf06-cc26xx/srf06/board.c index 1b9d79665..02689acda 100644 --- a/platform/srf06-cc26xx/srf06/board.c +++ b/platform/srf06-cc26xx/srf06/board.c @@ -62,6 +62,24 @@ wakeup_handler(void) */ LPM_MODULE(srf_module, NULL, NULL, lpm_wakeup_handler); /*---------------------------------------------------------------------------*/ +static void +configure_unused_pins(void) +{ + /* Turn off 3.3-V domain (lcd/sdcard power, output low) */ + ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_3V3_EN); + ti_lib_gpio_pin_write(BOARD_3V3_EN, 0); + + /* Accelerometer (PWR output low, CSn output, high) */ + ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_ACC_PWR); + ti_lib_gpio_pin_write(BOARD_ACC_PWR, 0); + + /* Ambient light sensor (off, output low) */ + ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_ALS_PWR); + ti_lib_gpio_pin_write(BOARD_ALS_PWR, 0); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_ALS_OUT); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_ALS_OUT, IOC_NO_IOPULL); +} +/*---------------------------------------------------------------------------*/ void board_init() { @@ -81,41 +99,12 @@ board_init() /* Apply settings and wait for them to take effect */ ti_lib_prcm_load_set(); - while(!ti_lib_prcm_load_get()) ; - - /* Keys (input pullup) */ - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_KEY_UP); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_KEY_DOWN); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_KEY_LEFT); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_KEY_RIGHT); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_KEY_SELECT); - - /* Turn off 3.3V domain (Powers the LCD and SD card reader): Output, low */ - ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_3V3_EN); - ti_lib_gpio_pin_write(BOARD_3V3_EN, 0); - - /* LCD CSn (output high) */ - ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_LCD_CS); - ti_lib_gpio_pin_write(BOARD_LCD_CS, 1); - - /* SD Card reader CSn (output high) */ - ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_SDCARD_CS); - ti_lib_gpio_pin_write(BOARD_SDCARD_CS, 1); - - /* Accelerometer (PWR output low, CSn output high) */ - ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_ACC_PWR); - ti_lib_gpio_pin_write(BOARD_ACC_PWR, 0); - ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_ACC_CS); - ti_lib_gpio_pin_write(BOARD_IOID_ACC_CS, 1); - - /* Ambient light sensor (off, output low) */ - ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_ALS_PWR); - ti_lib_gpio_pin_write(BOARD_ALS_PWR, 0); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_ALS_OUT); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_ALS_OUT, IOC_NO_IOPULL); + while(!ti_lib_prcm_load_get()); lpm_register_module(&srf_module); + configure_unused_pins(); + /* Re-enable interrupt if initially enabled. */ if(!int_disabled) { ti_lib_int_master_enable(); From 3f310e462f130cb54f73f26455580fee0eb8342b Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:08:10 +0100 Subject: [PATCH 13/38] Tidy-up clock configuration --- platform/srf06-cc26xx/srf06/board.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/platform/srf06-cc26xx/srf06/board.c b/platform/srf06-cc26xx/srf06/board.c index 02689acda..b7555f0a6 100644 --- a/platform/srf06-cc26xx/srf06/board.c +++ b/platform/srf06-cc26xx/srf06/board.c @@ -90,9 +90,8 @@ board_init() /* Configure all clock domains to run at full speed */ ti_lib_prcm_clock_configure_set(PRCM_DOMAIN_SYSBUS | PRCM_DOMAIN_CPU | - PRCM_DOMAIN_CPU | PRCM_DOMAIN_TIMER | - PRCM_DOMAIN_SERIAL | PRCM_DOMAIN_PERIPH, - PRCM_CLOCK_DIV_1); + PRCM_DOMAIN_TIMER | PRCM_DOMAIN_SERIAL | + PRCM_DOMAIN_PERIPH, PRCM_CLOCK_DIV_1); /* Enable GPIO peripheral */ ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_GPIO); From 3877190196a57e25726834daded94064c01378fe Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:09:50 +0100 Subject: [PATCH 14/38] Change function to static --- cpu/cc26xx/lpm.c | 14 ++++---------- cpu/cc26xx/lpm.h | 9 --------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/cpu/cc26xx/lpm.c b/cpu/cc26xx/lpm.c index 0322f940c..4d1cdd3e0 100644 --- a/cpu/cc26xx/lpm.c +++ b/cpu/cc26xx/lpm.c @@ -143,17 +143,11 @@ shutdown_now(void) } /*---------------------------------------------------------------------------*/ /* - * We'll get called on three occasions: - * - While running - * - While sleeping - * - While deep sleeping - * - * For the former two, we don't need to do anything. For the latter, we - * notify all modules that we're back on and rely on them to restore clocks + * Notify all modules that we're back on and rely on them to restore clocks * and power domains as required. */ -void -lpm_wake_up() +static void +wake_up(void) { lpm_registered_module_t *module; @@ -362,7 +356,7 @@ lpm_drop() * the chip properly, and then we will enable the global interrupt without * unpending events so the handlers can fire */ - lpm_wake_up(); + wake_up(); ti_lib_int_master_enable(); } diff --git a/cpu/cc26xx/lpm.h b/cpu/cc26xx/lpm.h index 85c20e77b..6b603377e 100644 --- a/cpu/cc26xx/lpm.h +++ b/cpu/cc26xx/lpm.h @@ -137,15 +137,6 @@ void lpm_sleep(void); */ void lpm_shutdown(uint32_t wakeup_pin); -/** - * \brief Wake up from sleep mode - * - * This function must be called at the start of any interrupt context which - * may bring us out of sleep. Current interrupts do this already, but make sure - * to do the same when adding new ISRs - */ -void lpm_wake_up(void); - /** * \brief Register a module for LPM notifications. * \param module A pointer to the data structure with the module definition From ad52d68a0ce0a757fee88729b20eab0f52414d7a Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:10:45 +0100 Subject: [PATCH 15/38] Add function to configure a pin to a default state --- cpu/cc26xx/lpm.c | 11 +++++++++++ cpu/cc26xx/lpm.h | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/cpu/cc26xx/lpm.c b/cpu/cc26xx/lpm.c index 4d1cdd3e0..28a7d7582 100644 --- a/cpu/cc26xx/lpm.c +++ b/cpu/cc26xx/lpm.c @@ -396,6 +396,17 @@ lpm_init() list_init(power_domain_locks_list); } /*---------------------------------------------------------------------------*/ +void +lpm_pin_set_default_state(uint32_t ioid) +{ + if(ioid == IOID_UNUSED) { + return; + } + + ti_lib_ioc_port_configure_set(ioid, IOC_PORT_GPIO, IOC_STD_OUTPUT); + ti_lib_gpio_dir_mode_set((1 << ioid), GPIO_DIR_MODE_IN); +} +/*---------------------------------------------------------------------------*/ /** * @} * @} diff --git a/cpu/cc26xx/lpm.h b/cpu/cc26xx/lpm.h index 6b603377e..757215cdd 100644 --- a/cpu/cc26xx/lpm.h +++ b/cpu/cc26xx/lpm.h @@ -154,6 +154,18 @@ void lpm_register_module(lpm_registered_module_t *module); * \brief Initialise the low-power mode management module */ void lpm_init(void); + +/** + * \brief Sets an IOID to a default state + * \param ioid IOID_0... + * + * This will set ioid to sw control, input, no pull. Input buffer and output + * driver will both be disabled + * + * The function will do nothing if ioid == IOID_UNUSED, so the caller does not + * have to check board configuration before calling this. + */ +void lpm_pin_set_default_state(uint32_t ioid); /*---------------------------------------------------------------------------*/ #endif /* LPM_H_ */ /*---------------------------------------------------------------------------*/ From bd79e18e1e315f0d11a95ebd903d36dad9d5d52f Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:13:09 +0100 Subject: [PATCH 16/38] Switch between oscillator's using the dedicated module's functions --- cpu/cc26xx/dev/cc26xx-rf.c | 81 ++++---------------------------------- 1 file changed, 7 insertions(+), 74 deletions(-) diff --git a/cpu/cc26xx/dev/cc26xx-rf.c b/cpu/cc26xx/dev/cc26xx-rf.c index f7b28b4e1..97b1aafc4 100644 --- a/cpu/cc26xx/dev/cc26xx-rf.c +++ b/cpu/cc26xx/dev/cc26xx-rf.c @@ -39,6 +39,7 @@ #include "contiki.h" #include "dev/radio.h" #include "dev/cc26xx-rf.h" +#include "dev/oscillators.h" #include "net/packetbuf.h" #include "net/rime/rimestats.h" #include "net/linkaddr.h" @@ -393,74 +394,6 @@ static int on(void); static int off(void); static void setup_interrupts(void); /*---------------------------------------------------------------------------*/ -/* Select the HF XOSC as the source for the HF clock, but don't switch yet */ -static void -request_hf_xosc(void) -{ - /* Enable OSC DIG interface to change clock sources */ - ti_lib_osc_interface_enable(); - - /* Make sure the SMPH clock within AUX is enabled */ - ti_lib_aux_wuc_clock_enable(AUX_WUC_SMPH_CLOCK); - while(ti_lib_aux_wuc_clock_status(AUX_WUC_SMPH_CLOCK) != AUX_WUC_CLOCK_READY); - - if(ti_lib_osc_clock_source_get(OSC_SRC_CLK_HF) != OSC_XOSC_HF) { - /* - * Request to switch to the crystal to enable radio operation. It takes a - * while for the XTAL to be ready so instead of performing the actual - * switch, we return and we do other stuff while the XOSC is getting ready. - */ - ti_lib_osc_clock_source_set(OSC_SRC_CLK_MF | OSC_SRC_CLK_HF, OSC_XOSC_HF); - } - - /* Disable OSC DIG interface */ - ti_lib_osc_interface_disable(); -} -/*---------------------------------------------------------------------------*/ -/* - * Switch to the XOSC. This will block until the XOSC is ready, so this must - * be preceded by a call to select_hf_xosc() - */ -static void -switch_to_hf_xosc(void) -{ - /* Enable OSC DIG interface to change clock sources */ - ti_lib_osc_interface_enable(); - - /* Make sure the SMPH clock within AUX is enabled */ - ti_lib_aux_wuc_clock_enable(AUX_WUC_SMPH_CLOCK); - while(ti_lib_aux_wuc_clock_status(AUX_WUC_SMPH_CLOCK) != AUX_WUC_CLOCK_READY); - - if(ti_lib_osc_clock_source_get(OSC_SRC_CLK_HF) != OSC_XOSC_HF) { - /* Switch the HF clock source (cc26xxware executes this from ROM) */ - ti_lib_osc_hf_source_switch(); - } - - /* Disable OSC DIG interface */ - ti_lib_osc_interface_disable(); -} -/*---------------------------------------------------------------------------*/ -static void -switch_to_hf_rc_osc(void) -{ - /* Enable OSC DIG interface to change clock sources */ - ti_lib_osc_interface_enable(); - - /* Make sure the SMPH clock within AUX is enabled */ - ti_lib_aux_wuc_clock_enable(AUX_WUC_SMPH_CLOCK); - while(ti_lib_aux_wuc_clock_status(AUX_WUC_SMPH_CLOCK) != AUX_WUC_CLOCK_READY); - - /* Set all clock sources to the HF RC Osc */ - ti_lib_osc_clock_source_set(OSC_SRC_CLK_MF | OSC_SRC_CLK_HF, OSC_RCOSC_HF); - - /* Check to not enable HF RC oscillator if already enabled */ - if(ti_lib_osc_clock_source_get(OSC_SRC_CLK_HF) != OSC_RCOSC_HF) { - /* Switch the HF clock source (cc26xxware executes this from ROM) */ - ti_lib_osc_hf_source_switch(); - } - ti_lib_osc_interface_disable(); -} -/*---------------------------------------------------------------------------*/ static uint8_t rf_is_accessible(void) { @@ -1530,7 +1463,7 @@ on(void) * Request the HF XOSC as the source for the HF clock. Needed before we can * use the FS. This will only request, it will _not_ perform the switch. */ - request_hf_xosc(); + oscillators_request_hf_xosc(); /* * If we are in the middle of a BLE operation, we got called by ContikiMAC @@ -1568,7 +1501,7 @@ on(void) * This will block until the XOSC is actually ready, but give how we * requested it early on, this won't be too long a wait/ */ - switch_to_hf_xosc(); + oscillators_switch_to_hf_xosc(); if(rf_radio_setup(RF_MODE_IEEE) != RF_CMD_OK) { PRINTF("on: radio_setup() failed\n"); @@ -1597,7 +1530,7 @@ off(void) power_down(); /* Switch HF clock source to the RCOSC to preserve power */ - switch_to_hf_rc_osc(); + oscillators_switch_to_hf_rc(); /* We pulled the plug, so we need to restore the status manually */ GET_FIELD(cmd_ieee_rx_buf, radioOp, status) = IDLE; @@ -2061,7 +1994,7 @@ PROCESS_THREAD(cc26xx_rf_ble_beacon_process, ev, data) } } else { /* Request the HF XOSC to source the HF clock. */ - request_hf_xosc(); + oscillators_request_hf_xosc(); /* We were off: Boot the CPE */ if(power_up() != RF_CMD_OK) { @@ -2079,7 +2012,7 @@ PROCESS_THREAD(cc26xx_rf_ble_beacon_process, ev, data) } /* Trigger a switch to the XOSC, so that we can use the FS */ - switch_to_hf_xosc(); + oscillators_switch_to_hf_xosc(); } /* Enter BLE mode */ @@ -2118,7 +2051,7 @@ PROCESS_THREAD(cc26xx_rf_ble_beacon_process, ev, data) power_down(); /* Switch HF clock source to the RCOSC to preserve power */ - switch_to_hf_rc_osc(); + oscillators_switch_to_hf_rc(); } etimer_set(&ble_adv_et, BLE_ADV_DUTY_CYCLE); From 5644e95fb6b261a7cdcb792e67e239918d35666c Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:15:33 +0100 Subject: [PATCH 17/38] Fix global interrupt manipulation --- cpu/cc26xx/dev/cc26xx-rf.c | 61 ++++++++++++++++++------- cpu/cc26xx/dev/cc26xx-rtc.c | 11 ++++- platform/srf06-cc26xx/sensortag/board.c | 3 +- 3 files changed, 56 insertions(+), 19 deletions(-) diff --git a/cpu/cc26xx/dev/cc26xx-rf.c b/cpu/cc26xx/dev/cc26xx-rf.c index 97b1aafc4..e034cc830 100644 --- a/cpu/cc26xx/dev/cc26xx-rf.c +++ b/cpu/cc26xx/dev/cc26xx-rf.c @@ -69,6 +69,7 @@ #include #include #include +#include /*---------------------------------------------------------------------------*/ #define BUSYWAIT_UNTIL(cond, max_time) \ do { \ @@ -431,16 +432,19 @@ static uint_fast8_t rf_send_cmd(uint32_t cmd, uint32_t *status) { uint32_t timeout_count = 0; + bool interrupts_disabled; /* * Make sure ContikiMAC doesn't turn us off from within an interrupt while * we are accessing RF Core registers */ - ti_lib_int_master_disable(); + interrupts_disabled = ti_lib_int_master_disable(); if(!rf_is_accessible()) { PRINTF("rf_send_cmd: RF was off\n"); - ti_lib_int_master_enable(); + if(!interrupts_disabled) { + ti_lib_int_master_enable(); + } return RF_CMD_ERROR; } @@ -449,12 +453,16 @@ rf_send_cmd(uint32_t cmd, uint32_t *status) *status = HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDSTA); if(++timeout_count > 50000) { PRINTF("rf_send_cmd: Timeout\n"); - ti_lib_int_master_enable(); + if(!interrupts_disabled) { + ti_lib_int_master_enable(); + } return RF_CMD_ERROR; } } while(*status == RF_CMD_STATUS_PENDING); - ti_lib_int_master_enable(); + if(!interrupts_disabled) { + ti_lib_int_master_enable(); + } /* * If we reach here the command is no longer pending. It is either completed @@ -911,8 +919,8 @@ static int power_up(void) { uint32_t cmd_status; + bool interrupts_disabled = ti_lib_int_master_disable(); - ti_lib_int_master_disable(); ti_lib_int_pend_clear(INT_RF_CPE0); ti_lib_int_pend_clear(INT_RF_CPE1); ti_lib_int_disable(INT_RF_CPE0); @@ -935,7 +943,10 @@ power_up(void) HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIEN) = 0x0; ti_lib_int_enable(INT_RF_CPE0); ti_lib_int_enable(INT_RF_CPE1); - ti_lib_int_master_enable(); + + if(!interrupts_disabled) { + ti_lib_int_master_enable(); + } /* Let CPE boot */ HWREG(RFC_PWR_NONBUF_BASE + RFC_PWR_O_PWMCLKEN) = RF_CORE_CLOCKS_MASK; @@ -955,7 +966,7 @@ power_up(void) static void power_down(void) { - ti_lib_int_master_disable(); + bool interrupts_disabled = ti_lib_int_master_disable(); ti_lib_int_disable(INT_RF_CPE0); ti_lib_int_disable(INT_RF_CPE1); @@ -978,7 +989,9 @@ power_down(void) ti_lib_int_pend_clear(INT_RF_CPE1); ti_lib_int_enable(INT_RF_CPE0); ti_lib_int_enable(INT_RF_CPE1); - ti_lib_int_master_enable(); + if(!interrupts_disabled) { + ti_lib_int_master_enable(); + } } /*---------------------------------------------------------------------------*/ static int @@ -1093,6 +1106,8 @@ cc26xx_rf_cpe0_isr(void) static void setup_interrupts(void) { + bool interrupts_disabled; + /* We are already turned on by the caller, so this should not happen */ if(!rf_is_accessible()) { PRINTF("setup_interrupts: No access\n"); @@ -1100,7 +1115,7 @@ setup_interrupts(void) } /* Disable interrupts */ - ti_lib_int_master_disable(); + interrupts_disabled = ti_lib_int_master_disable(); /* Set all interrupt channels to CPE0 channel, error to CPE1 */ HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEISL) = ERROR_IRQ; @@ -1115,7 +1130,10 @@ setup_interrupts(void) ti_lib_int_pend_clear(INT_RF_CPE1); ti_lib_int_enable(INT_RF_CPE0); ti_lib_int_enable(INT_RF_CPE1); - ti_lib_int_master_enable(); + + if(!interrupts_disabled) { + ti_lib_int_master_enable(); + } } /*---------------------------------------------------------------------------*/ static uint8_t @@ -1926,6 +1944,7 @@ PROCESS_THREAD(cc26xx_rf_ble_beacon_process, ev, data) uint8_t was_on; int j; uint32_t cmd_status; + bool interrupts_disabled; PROCESS_BEGIN(); @@ -1956,9 +1975,11 @@ PROCESS_THREAD(cc26xx_rf_ble_beacon_process, ev, data) * Under ContikiMAC, some IEEE-related operations will be called from an * interrupt context. We need those to see that we are in BLE mode. */ - ti_lib_int_master_disable(); + interrupts_disabled = ti_lib_int_master_disable(); ble_mode_on = 1; - ti_lib_int_master_enable(); + if(!interrupts_disabled) { + ti_lib_int_master_enable(); + } /* * Send BLE_ADV_MESSAGES beacon bursts. Each burst on all three @@ -2055,9 +2076,13 @@ PROCESS_THREAD(cc26xx_rf_ble_beacon_process, ev, data) } etimer_set(&ble_adv_et, BLE_ADV_DUTY_CYCLE); - ti_lib_int_master_disable(); + interrupts_disabled = ti_lib_int_master_disable(); + ble_mode_on = 0; - ti_lib_int_master_enable(); + + if(!interrupts_disabled) { + ti_lib_int_master_enable(); + } /* Wait unless this is the last burst */ if(i < BLE_ADV_MESSAGES - 1) { @@ -2065,9 +2090,13 @@ PROCESS_THREAD(cc26xx_rf_ble_beacon_process, ev, data) } } - ti_lib_int_master_disable(); + interrupts_disabled = ti_lib_int_master_disable(); + ble_mode_on = 0; - ti_lib_int_master_enable(); + + if(!interrupts_disabled) { + ti_lib_int_master_enable(); + } } PROCESS_END(); } diff --git a/cpu/cc26xx/dev/cc26xx-rtc.c b/cpu/cc26xx/dev/cc26xx-rtc.c index b1b01ea6e..9c3d58756 100644 --- a/cpu/cc26xx/dev/cc26xx-rtc.c +++ b/cpu/cc26xx/dev/cc26xx-rtc.c @@ -44,6 +44,7 @@ #include "ti-lib.h" #include +#include /*---------------------------------------------------------------------------*/ #define cc26xx_rtc_isr(...) AONRTCIntHandler(__VA_ARGS__) /*---------------------------------------------------------------------------*/ @@ -54,9 +55,11 @@ void cc26xx_rtc_init(void) { uint32_t compare_value; + bool interrupts_disabled; /* Disable and clear interrupts */ - ti_lib_int_master_disable(); + interrupts_disabled = ti_lib_int_master_disable(); + ti_lib_aon_rtc_disable(); ti_lib_aon_rtc_event_clear(AON_RTC_CH0); @@ -80,7 +83,11 @@ cc26xx_rtc_init(void) ti_lib_aon_rtc_enable(); ti_lib_int_enable(INT_AON_RTC); - ti_lib_int_master_enable(); + + /* Re-enable interrupts */ + if(!interrupts_disabled) { + ti_lib_int_master_enable(); + } } /*---------------------------------------------------------------------------*/ rtimer_clock_t diff --git a/platform/srf06-cc26xx/sensortag/board.c b/platform/srf06-cc26xx/sensortag/board.c index e397f1266..f2322082a 100644 --- a/platform/srf06-cc26xx/sensortag/board.c +++ b/platform/srf06-cc26xx/sensortag/board.c @@ -48,6 +48,7 @@ #include /*---------------------------------------------------------------------------*/ #define PRCM_DOMAINS (PRCM_DOMAIN_SERIAL | PRCM_DOMAIN_PERIPH) +#include /*---------------------------------------------------------------------------*/ static void power_domains_on(void) @@ -94,7 +95,7 @@ void board_init() { /* Disable global interrupts */ - uint8_t int_disabled = ti_lib_int_master_disable(); + bool int_disabled = ti_lib_int_master_disable(); power_domains_on(); From cf991607066f26575ec024bd0f3e63dd82c490bf Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:18:27 +0100 Subject: [PATCH 18/38] Change lpm_shutdown() API call: So that the caller can specify pin pull and wakeup state --- cpu/cc26xx/lpm.h | 5 ++++- platform/srf06-cc26xx/sensortag/button-sensor.c | 2 +- platform/srf06-cc26xx/srf06/button-sensor.c | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cpu/cc26xx/lpm.h b/cpu/cc26xx/lpm.h index 757215cdd..7a4dae7a8 100644 --- a/cpu/cc26xx/lpm.h +++ b/cpu/cc26xx/lpm.h @@ -134,8 +134,11 @@ void lpm_sleep(void); /** * \brief Put the chip in shutdown power mode * \param wakeup_pin The GPIO pin which will wake us up. Must be IOID_0 etc... + * \param io_pull Pull configuration for the shutdown pin: IOC_NO_IOPULL, + * IOC_IOPULL_UP or IOC_IOPULL_DOWN + * \param wake_on High or Low (IOC_WAKE_ON_LOW or IOC_WAKE_ON_HIGH) */ -void lpm_shutdown(uint32_t wakeup_pin); +void lpm_shutdown(uint32_t wakeup_pin, uint32_t io_pull, uint32_t wake_on); /** * \brief Register a module for LPM notifications. diff --git a/platform/srf06-cc26xx/sensortag/button-sensor.c b/platform/srf06-cc26xx/sensortag/button-sensor.c index 7b53e8a79..d0bd14f9c 100644 --- a/platform/srf06-cc26xx/sensortag/button-sensor.c +++ b/platform/srf06-cc26xx/sensortag/button-sensor.c @@ -116,7 +116,7 @@ button_press_handler(uint8_t ioid) sensors_changed(&button_right_sensor); } } else { - lpm_shutdown(BOARD_IOID_KEY_RIGHT); + lpm_shutdown(BOARD_IOID_KEY_RIGHT, IOC_IOPULL_UP, IOC_WAKE_ON_LOW); } } } diff --git a/platform/srf06-cc26xx/srf06/button-sensor.c b/platform/srf06-cc26xx/srf06/button-sensor.c index 53112a23c..f1f9a05cf 100644 --- a/platform/srf06-cc26xx/srf06/button-sensor.c +++ b/platform/srf06-cc26xx/srf06/button-sensor.c @@ -137,7 +137,7 @@ button_press_handler(uint8_t ioid) sensors_changed(&button_right_sensor); } } else { - lpm_shutdown(BOARD_IOID_KEY_RIGHT); + lpm_shutdown(BOARD_IOID_KEY_RIGHT, IOC_IOPULL_UP, IOC_WAKE_ON_LOW); } } From 437821746228aa947599130cc120076eeb937977 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:23:15 +0100 Subject: [PATCH 19/38] Improve sensortag external flash power management: * Explicitly put in deep sleep on device startup * Verify that the flash has actually dropped to deep sleep * Update CLK pin to match the one used on the v1.2 sensortag Obsoletes and Closes #988 --- platform/srf06-cc26xx/sensortag/board.c | 3 + platform/srf06-cc26xx/sensortag/board.h | 2 +- platform/srf06-cc26xx/sensortag/ext-flash.c | 108 +++++++++++--------- platform/srf06-cc26xx/sensortag/ext-flash.h | 13 +++ 4 files changed, 79 insertions(+), 47 deletions(-) diff --git a/platform/srf06-cc26xx/sensortag/board.c b/platform/srf06-cc26xx/sensortag/board.c index f2322082a..458438ef1 100644 --- a/platform/srf06-cc26xx/sensortag/board.c +++ b/platform/srf06-cc26xx/sensortag/board.c @@ -142,6 +142,9 @@ board_init() buzzer_init(); + /* Make sure the external flash is in the lower power mode */ + ext_flash_init(); + lpm_register_module(&sensortag_module); /* Re-enable interrupt if initially enabled. */ diff --git a/platform/srf06-cc26xx/sensortag/board.h b/platform/srf06-cc26xx/sensortag/board.h index 00afb98f2..d2b8549ea 100644 --- a/platform/srf06-cc26xx/sensortag/board.h +++ b/platform/srf06-cc26xx/sensortag/board.h @@ -156,7 +156,7 @@ */ #define BOARD_IOID_FLASH_CS IOID_14 #define BOARD_FLASH_CS (1 << BOARD_IOID_FLASH_CS) -#define BOARD_SPI_CLK_FLASH IOID_11 +#define BOARD_IOID_SPI_CLK_FLASH IOID_17 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/platform/srf06-cc26xx/sensortag/ext-flash.c b/platform/srf06-cc26xx/sensortag/ext-flash.c index 83d2758a4..d896473d3 100644 --- a/platform/srf06-cc26xx/sensortag/ext-flash.c +++ b/platform/srf06-cc26xx/sensortag/ext-flash.c @@ -72,7 +72,7 @@ /* Part specific constants */ #define BLS_MANUFACTURER_ID 0xEF -#define BLS_DEVICE_ID 0x11 +#define BLS_DEVICE_ID 0x12 #define BLS_PROGRAM_PAGE_SIZE 256 #define BLS_ERASE_SECTOR_SIZE 4096 @@ -140,50 +140,8 @@ wait_ready(void) } /*---------------------------------------------------------------------------*/ /** - * \brief Put the device in power save mode. No access to data; only - * the status register is accessible. - * \return True when SPI transactions succeed - */ -static bool -power_down(void) -{ - uint8_t cmd; - bool success; - - cmd = BLS_CODE_DP; - select(); - success = board_spi_write(&cmd, sizeof(cmd)); - deselect(); - - return success; -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Take device out of power save mode and prepare it for normal operation - * \return True if the command was written successfully - */ -static bool -power_standby(void) -{ - uint8_t cmd; - bool success; - - cmd = BLS_CODE_RDP; - select(); - success = board_spi_write(&cmd, sizeof(cmd)); - - if(success) { - success = wait_ready() == 0; - } - - deselect(); - - return success; -} -/*---------------------------------------------------------------------------*/ -/** - * Verify the flash part. - * @return True when successful. + * \brief Verify the flash part. + * \return True when successful. */ static bool verify_part(void) @@ -210,6 +168,57 @@ verify_part(void) return true; } /*---------------------------------------------------------------------------*/ +/** + * \brief Put the device in power save mode. No access to data; only + * the status register is accessible. + */ +static void +power_down(void) +{ + uint8_t cmd; + uint8_t i; + + cmd = BLS_CODE_DP; + select(); + board_spi_write(&cmd, sizeof(cmd)); + deselect(); + + i = 0; + while(i < 10) { + if(!verify_part()) { + /* Verify Part failed: Device is powered down */ + return; + } + i++; + } + + /* Should not be required */ + deselect(); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Take device out of power save mode and prepare it for normal operation + * \return True if the command was written successfully + */ +static bool +power_standby(void) +{ + uint8_t cmd; + bool success; + + cmd = BLS_CODE_RDP; + select(); + success = board_spi_write(&cmd, sizeof(cmd)); + + if(success) { + success = wait_ready() == 0; + } + + deselect(); + + return success; +} +/*---------------------------------------------------------------------------*/ /** * \brief Enable write. * \return Zero when successful. @@ -232,7 +241,7 @@ write_enable(void) bool ext_flash_open() { - board_spi_open(4000000, BOARD_SPI_CLK_FLASH); + board_spi_open(4000000, BOARD_IOID_SPI_CLK_FLASH); /* GPIO pin configuration */ ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_FLASH_CS); @@ -406,4 +415,11 @@ ext_flash_test(void) return ret; } /*---------------------------------------------------------------------------*/ +void +ext_flash_init() +{ + ext_flash_open(); + ext_flash_close(); +} +/*---------------------------------------------------------------------------*/ /** @} */ diff --git a/platform/srf06-cc26xx/sensortag/ext-flash.h b/platform/srf06-cc26xx/sensortag/ext-flash.h index ca2ef80ea..3038872cd 100644 --- a/platform/srf06-cc26xx/sensortag/ext-flash.h +++ b/platform/srf06-cc26xx/sensortag/ext-flash.h @@ -54,6 +54,8 @@ bool ext_flash_open(void); /** * \brief Close the storage driver + * + * This call will put the device in its lower power mode (power down). */ void ext_flash_close(void); @@ -94,6 +96,17 @@ bool ext_flash_write(size_t offset, size_t length, const uint8_t *buf); * \return True when successful. */ bool ext_flash_test(void); + +/** + * \brief Initialise the external flash + * + * This function will explicitly put the part in its lowest power mode + * (power-down). + * + * In order to perform any operation, the caller must first wake the device + * up by calling ext_flash_open() + */ +void ext_flash_init(void); /*---------------------------------------------------------------------------*/ #endif /* EXT_FLASH_H_ */ /*---------------------------------------------------------------------------*/ From d1a1c16bd045b37c2d54dcb9fc781939e723c3ef Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:25:17 +0100 Subject: [PATCH 20/38] Define pins for more sensortag peripherals --- platform/srf06-cc26xx/sensortag/board.h | 38 +++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/platform/srf06-cc26xx/sensortag/board.h b/platform/srf06-cc26xx/sensortag/board.h index d2b8549ea..2d26e7a36 100644 --- a/platform/srf06-cc26xx/sensortag/board.h +++ b/platform/srf06-cc26xx/sensortag/board.h @@ -183,6 +183,44 @@ #define BOARD_MPU_POWER (1 << BOARD_IOID_MPU_POWER) /** @} */ /*---------------------------------------------------------------------------*/ +/** + * \brief Board devpack IOID mappings (LCD etc.) + * + * Those values are not meant to be modified by the user + * @{ + */ +#define BOARD_IOID_AUDIOFS_TDO IOID_16 +#define BOARD_IOID_DEVPACK_CS IOID_20 +#define BOARD_IOID_DEVPK_LCD_EXTCOMIN IOID_22 +#define BOARD_IOID_AUDIODO IOID_22 +#define BOARD_IOID_DP2 IOID_23 +#define BOARD_IOID_DP1 IOID_24 +#define BOARD_IOID_DP0 IOID_25 +#define BOARD_IOID_DP3 IOID_27 +#define BOARD_IOID_DEVPK_ID IOID_30 +#define BOARD_DEVPACK_CS (1 << BOARD_IOID_DEVPACK_CS) +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \brief TMP Sensor + * + * Those values are not meant to be modified by the user + * @{ + */ +#define BOARD_IOID_TMP_RDY IOID_1 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \brief Digital Microphone + * + * Those values are not meant to be modified by the user + * @{ + */ +#define BOARD_IOID_MIC_POWER IOID_13 +#define BOARD_IOID_AUDIO_DI IOID_2 +#define BOARD_IOID_AUDIO_CLK IOID_11 +/** @} */ +/*---------------------------------------------------------------------------*/ /** * \name Device string used on startup * @{ From 0ad4b5f323af5fd601d426273b3a03efb05f4b37 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:26:28 +0100 Subject: [PATCH 21/38] Add the ability to put the I2C in a known/default state --- platform/srf06-cc26xx/sensortag/board-i2c.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/platform/srf06-cc26xx/sensortag/board-i2c.h b/platform/srf06-cc26xx/sensortag/board-i2c.h index bed78cf46..c159bc527 100644 --- a/platform/srf06-cc26xx/sensortag/board-i2c.h +++ b/platform/srf06-cc26xx/sensortag/board-i2c.h @@ -48,13 +48,15 @@ #define BOARD_I2C_INTERFACE_0 0 #define BOARD_I2C_INTERFACE_1 1 /*---------------------------------------------------------------------------*/ -#define board_i2c_deselect(...) -/*---------------------------------------------------------------------------*/ /** - * \brief Initialise the I2C controller with defaults for the sensortag + * \brief Put the I2C controller in a known state + * + * In this state, pins SDA and SCL will be under i2c control and pins SDA HP + * and SCL HP will be configured as gpio inputs. This is equal to selecting + * BOARD_I2C_INTERFACE_0, but without selecting a slave device address */ -void board_i2c_init(void); - +#define board_i2c_deselect() board_i2c_select(BOARD_I2C_INTERFACE_0, 0) +/*---------------------------------------------------------------------------*/ /** * \brief Select an I2C slave * \param interface The I2C interface to be used (BOARD_I2C_INTERFACE_0 or _1) From 34be0126611db8f7a35bc8a18f0a5166809f078a Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:34:42 +0100 Subject: [PATCH 22/38] 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 --- platform/srf06-cc26xx/sensortag/board-i2c.c | 94 ++++++++++++++++++--- platform/srf06-cc26xx/sensortag/board-i2c.h | 21 +++++ platform/srf06-cc26xx/sensortag/board.c | 7 +- 3 files changed, 108 insertions(+), 14 deletions(-) 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(); From 6611acadc78c2409c6b44f88e42ceb2e6f4ab14c Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:36:27 +0100 Subject: [PATCH 23/38] Don't fire-up SERIAL automatically --- platform/srf06-cc26xx/sensortag/board.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/platform/srf06-cc26xx/sensortag/board.c b/platform/srf06-cc26xx/sensortag/board.c index 89184ae93..ed030efd9 100644 --- a/platform/srf06-cc26xx/sensortag/board.c +++ b/platform/srf06-cc26xx/sensortag/board.c @@ -46,18 +46,16 @@ #include #include -/*---------------------------------------------------------------------------*/ -#define PRCM_DOMAINS (PRCM_DOMAIN_SERIAL | PRCM_DOMAIN_PERIPH) #include /*---------------------------------------------------------------------------*/ static void power_domains_on(void) { - /* Turn on relevant power domains */ - ti_lib_prcm_power_domain_on(PRCM_DOMAINS); + /* Turn on the PERIPH PD */ + ti_lib_prcm_power_domain_on(PRCM_DOMAIN_PERIPH); /* Wait for domains to power on */ - while((ti_lib_prcm_power_domain_status(PRCM_DOMAINS) + while((ti_lib_prcm_power_domain_status(PRCM_DOMAIN_PERIPH) != PRCM_DOMAIN_POWER_ON)); } /*---------------------------------------------------------------------------*/ From 0e92b508b39738ed84bd37e0d7bce10edcd18421 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:36:55 +0100 Subject: [PATCH 24/38] Don't clock GPT0 on device startup --- platform/srf06-cc26xx/sensortag/board.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/platform/srf06-cc26xx/sensortag/board.c b/platform/srf06-cc26xx/sensortag/board.c index ed030efd9..096e8e5fc 100644 --- a/platform/srf06-cc26xx/sensortag/board.c +++ b/platform/srf06-cc26xx/sensortag/board.c @@ -112,11 +112,6 @@ board_init() ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()); - /* Enable GPT0 module - Wait for the clock to be enabled */ - ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_TIMER0); - ti_lib_prcm_load_set(); - while(!ti_lib_prcm_load_get()); - /* Keys (input pullup) */ ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_KEY_LEFT); ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_KEY_RIGHT); From b3ac3ac0c106423d5188de1c3f128fb135e714cd Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:38:07 +0100 Subject: [PATCH 25/38] Add function to unregister a module from LPM --- cpu/cc26xx/lpm.c | 6 ++++++ cpu/cc26xx/lpm.h | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/cpu/cc26xx/lpm.c b/cpu/cc26xx/lpm.c index 28a7d7582..6526a8eeb 100644 --- a/cpu/cc26xx/lpm.c +++ b/cpu/cc26xx/lpm.c @@ -390,6 +390,12 @@ lpm_register_module(lpm_registered_module_t *module) } /*---------------------------------------------------------------------------*/ void +lpm_unregister_module(lpm_registered_module_t *module) +{ + list_remove(modules_list, module); +} +/*---------------------------------------------------------------------------*/ +void lpm_init() { list_init(modules_list); diff --git a/cpu/cc26xx/lpm.h b/cpu/cc26xx/lpm.h index 7a4dae7a8..eaecebb16 100644 --- a/cpu/cc26xx/lpm.h +++ b/cpu/cc26xx/lpm.h @@ -153,6 +153,15 @@ void lpm_shutdown(uint32_t wakeup_pin, uint32_t io_pull, uint32_t wake_on); */ void lpm_register_module(lpm_registered_module_t *module); +/** + * \brief Unregister a module from LPM notifications. + * \param module A pointer to the data structure with the module definition + * + * When a previously registered module is no longer interested in LPM + * notifications, this function can be used to unregister it. + */ +void lpm_unregister_module(lpm_registered_module_t *module); + /** * \brief Initialise the low-power mode management module */ From 421fbfae25bd762b043841b0c7f9ae25f75e5cde Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:42:03 +0100 Subject: [PATCH 26/38] Change the LPM locks API: Instead of using a separate data structure to request that a PD remain powered during deep sleep, we do the same within the main LPM data structure through an additional field. This allows us to maintain only one linked list of LPM modules and overall improves code clarity --- cpu/cc26xx/dev/cc26xx-rf.c | 2 +- cpu/cc26xx/lpm.c | 4 -- cpu/cc26xx/lpm.h | 55 ++++++---------------- cpu/cc26xx/slip-arch.c | 4 ++ examples/cc26xx/cc26xx-demo.c | 21 --------- examples/cc26xx/cc26xx-web-demo/net-uart.c | 27 ++--------- platform/srf06-cc26xx/sensortag/board.c | 3 +- platform/srf06-cc26xx/sensortag/buzzer.c | 16 +++++-- platform/srf06-cc26xx/srf06/board.c | 2 +- 9 files changed, 38 insertions(+), 96 deletions(-) diff --git a/cpu/cc26xx/dev/cc26xx-rf.c b/cpu/cc26xx/dev/cc26xx-rf.c index e034cc830..87ade4186 100644 --- a/cpu/cc26xx/dev/cc26xx-rf.c +++ b/cpu/cc26xx/dev/cc26xx-rf.c @@ -1150,7 +1150,7 @@ request(void) return LPM_MODE_MAX_SUPPORTED; } /*---------------------------------------------------------------------------*/ -LPM_MODULE(cc26xx_rf_lpm_module, request, NULL, NULL); +LPM_MODULE(cc26xx_rf_lpm_module, request, NULL, NULL, LPM_DOMAIN_NONE); /*---------------------------------------------------------------------------*/ static int init(void) diff --git a/cpu/cc26xx/lpm.c b/cpu/cc26xx/lpm.c index 6526a8eeb..320ccdd03 100644 --- a/cpu/cc26xx/lpm.c +++ b/cpu/cc26xx/lpm.c @@ -64,9 +64,6 @@ static unsigned long irq_energest = 0; /*---------------------------------------------------------------------------*/ LIST(modules_list); /*---------------------------------------------------------------------------*/ -/* Control what power domains we are allow to run under what mode */ -LIST(power_domain_locks_list); - /* PDs that may stay on in deep sleep */ #define LOCKABLE_DOMAINS ((uint32_t)(PRCM_DOMAIN_SERIAL | PRCM_DOMAIN_PERIPH)) /*---------------------------------------------------------------------------*/ @@ -399,7 +396,6 @@ void lpm_init() { list_init(modules_list); - list_init(power_domain_locks_list); } /*---------------------------------------------------------------------------*/ void diff --git a/cpu/cc26xx/lpm.h b/cpu/cc26xx/lpm.h index eaecebb16..8b701baff 100644 --- a/cpu/cc26xx/lpm.h +++ b/cpu/cc26xx/lpm.h @@ -49,17 +49,22 @@ #include /*---------------------------------------------------------------------------*/ -#define LPM_MODE_SLEEP PWRCTRL_ACTIVE -#define LPM_MODE_DEEP_SLEEP PWRCTRL_POWER_DOWN -#define LPM_MODE_SHUTDOWN PWRCTRL_SHUTDOWN +#define LPM_MODE_SLEEP 1 +#define LPM_MODE_DEEP_SLEEP 2 +#define LPM_MODE_SHUTDOWN 3 #define LPM_MODE_MAX_SUPPORTED LPM_MODE_DEEP_SLEEP /*---------------------------------------------------------------------------*/ +#define LPM_DOMAIN_NONE 0 +#define LPM_DOMAIN_SERIAL PRCM_DOMAIN_SERIAL +#define LPM_DOMAIN_PERIPH PRCM_DOMAIN_PERIPH +/*---------------------------------------------------------------------------*/ typedef struct lpm_registered_module { struct lpm_registered_module *next; uint8_t (*request_max_pm)(void); void (*shutdown)(uint8_t mode); void (*wakeup)(void); + uint32_t domain_lock; } lpm_registered_module_t; /*---------------------------------------------------------------------------*/ /** @@ -78,46 +83,14 @@ typedef struct lpm_registered_module { * woken up. This can be used to e.g. turn a peripheral back on. This * function is in charge of turning power domains back on. This * function will normally be called within an interrupt context. + * \param l Power domain locks, if any are required. The module can request + * that the SERIAL or PERIPH PD be kept powered up at the transition + * to deep sleep. This field can be a bitwise OR of LPM_DOMAIN_x, so + * if required multiple domains can be kept powered. */ -#define LPM_MODULE(n, m, s, w) static lpm_registered_module_t n = \ - { NULL, m, s, w } +#define LPM_MODULE(n, m, s, w, l) static lpm_registered_module_t n = \ + { NULL, m, s, w, l } /*---------------------------------------------------------------------------*/ -/** - * - * \brief Data type used to control whether a PD will get shut down when the - * CM3 drops to deep sleep - * - * Modules using these facilities must allocate a variable of this type, but - * they must not try to manipulate it directly. Instead, the respective - * functions must be used - * - * \sa lpm_pd_lock_obtain(), lpm_pd_lock_release() - */ -typedef struct lpm_power_domain_lock { - struct lpm_power_domain_lock *next; - uint32_t domains; -} lpm_power_domain_lock_t; -/*---------------------------------------------------------------------------*/ -/** - * \brief Prohibit a PD from turning off in standby mode - * \param lock A pointer to a lpm_power_domain_lock_t - * \param domains Bitwise OR from PRCM_DOMAIN_PERIPH, PRCM_DOMAIN_SERIAL - * - * The caller is responsible for allocating lpm_power_domain_lock_t - * - * Only the domains listed above can be locked / released, but a single lock - * can be used for multiple domains - */ -void lpm_pd_lock_obtain(lpm_power_domain_lock_t *lock, uint32_t domains); - -/** - * \brief Permit a PD to turn off in standby mode - * \param pd A pointer to a previously used lock - * - * \sa lpm_pd_lock_obtain() - */ -void lpm_pd_lock_release(lpm_power_domain_lock_t *pd); - /** * \brief Drop the cortex to sleep / deep sleep and shut down peripherals * diff --git a/cpu/cc26xx/slip-arch.c b/cpu/cc26xx/slip-arch.c index 268c84548..ebd6f91c8 100644 --- a/cpu/cc26xx/slip-arch.c +++ b/cpu/cc26xx/slip-arch.c @@ -58,6 +58,10 @@ slip_arch_writeb(unsigned char c) void slip_arch_init(unsigned long ubr) { + /* + * Enable an input handler. In doing so, the driver will make sure that UART + * RX stays operational during deep sleep + */ cc26xx_uart_set_input(slip_input_byte); } /*---------------------------------------------------------------------------*/ diff --git a/examples/cc26xx/cc26xx-demo.c b/examples/cc26xx/cc26xx-demo.c index ff7ea9a38..de5ce5810 100644 --- a/examples/cc26xx/cc26xx-demo.c +++ b/examples/cc26xx/cc26xx-demo.c @@ -100,7 +100,6 @@ #include "button-sensor.h" #include "batmon-sensor.h" #include "board-peripherals.h" -#include "lpm.h" #include "cc26xx-rf.h" #include "ti-lib.h" @@ -368,26 +367,6 @@ init_sensor_readings(void) #endif } /*---------------------------------------------------------------------------*/ -static lpm_power_domain_lock_t lock; -/*---------------------------------------------------------------------------*/ -/* - * In order to maintain UART input operation: - * - Keep the uart clocked in sleep and deep sleep - * - Keep the serial PD on in deep sleep - */ -static void -keep_uart_on(void) -{ - /* Keep the serial PD on */ - lpm_pd_lock_obtain(&lock, PRCM_DOMAIN_SERIAL); - - /* Keep the UART clock on during Sleep and Deep Sleep */ - ti_lib_prcm_peripheral_sleep_enable(PRCM_PERIPH_UART0); - ti_lib_prcm_peripheral_deep_sleep_enable(PRCM_PERIPH_UART0); - ti_lib_prcm_load_set(); - while(!ti_lib_prcm_load_get()); -} -/*---------------------------------------------------------------------------*/ PROCESS_THREAD(cc26xx_demo_process, ev, data) { diff --git a/examples/cc26xx/cc26xx-web-demo/net-uart.c b/examples/cc26xx/cc26xx-web-demo/net-uart.c index 96463aee0..a0ddf1263 100644 --- a/examples/cc26xx/cc26xx-web-demo/net-uart.c +++ b/examples/cc26xx/cc26xx-web-demo/net-uart.c @@ -59,10 +59,10 @@ #include "contiki-conf.h" #include "sys/process.h" #include "dev/serial-line.h" +#include "dev/cc26xx-uart.h" #include "net/ip/uip.h" #include "net/ip/uip-udp-packet.h" #include "net/ip/uiplib.h" -#include "lpm.h" #include "net-uart.h" #include "httpd-simple.h" @@ -148,37 +148,16 @@ net_input(void) return; } /*---------------------------------------------------------------------------*/ -/* - * In order to maintain UART input operation: - * - Keep the uart clocked in sleep and deep sleep - * - Keep the serial PD on in deep sleep - */ -static lpm_power_domain_lock_t lock; -/*---------------------------------------------------------------------------*/ static void release_uart(void) { - /* Release serial PD lock */ - lpm_pd_lock_release(&lock); - - /* Let the UART turn off during Sleep and Deep Sleep */ - ti_lib_prcm_peripheral_sleep_disable(PRCM_PERIPH_UART0); - ti_lib_prcm_peripheral_deep_sleep_disable(PRCM_PERIPH_UART0); - ti_lib_prcm_load_set(); - while(!ti_lib_prcm_load_get()); + cc26xx_uart_set_input(NULL); } /*---------------------------------------------------------------------------*/ static void keep_uart_on(void) { - /* Keep the serial PD on */ - lpm_pd_lock_obtain(&lock, PRCM_DOMAIN_SERIAL); - - /* Keep the UART clock on during Sleep and Deep Sleep */ - ti_lib_prcm_peripheral_sleep_enable(PRCM_PERIPH_UART0); - ti_lib_prcm_peripheral_deep_sleep_enable(PRCM_PERIPH_UART0); - ti_lib_prcm_load_set(); - while(!ti_lib_prcm_load_get()); + cc26xx_uart_set_input(serial_line_input_byte); } /*---------------------------------------------------------------------------*/ static int diff --git a/platform/srf06-cc26xx/sensortag/board.c b/platform/srf06-cc26xx/sensortag/board.c index 096e8e5fc..e421c734c 100644 --- a/platform/srf06-cc26xx/sensortag/board.c +++ b/platform/srf06-cc26xx/sensortag/board.c @@ -88,7 +88,8 @@ shutdown_handler(uint8_t mode) * wake up so we can turn power domains back on for I2C and SSI, and to make * sure everything on the board is off before CM3 shutdown. */ -LPM_MODULE(sensortag_module, NULL, shutdown_handler, lpm_wakeup_handler); +LPM_MODULE(sensortag_module, NULL, shutdown_handler, lpm_wakeup_handler, + LPM_DOMAIN_NONE); /*---------------------------------------------------------------------------*/ void board_init() diff --git a/platform/srf06-cc26xx/sensortag/buzzer.c b/platform/srf06-cc26xx/sensortag/buzzer.c index 57d063897..a5c9001a5 100644 --- a/platform/srf06-cc26xx/sensortag/buzzer.c +++ b/platform/srf06-cc26xx/sensortag/buzzer.c @@ -46,7 +46,7 @@ #include /*---------------------------------------------------------------------------*/ static uint8_t buzzer_on; -static lpm_power_domain_lock_t lock; +LPM_MODULE(buzzer_module, NULL, NULL, NULL, LPM_DOMAIN_PERIPH); /*---------------------------------------------------------------------------*/ void buzzer_init() @@ -74,7 +74,12 @@ buzzer_start(int freq) buzzer_on = 1; - lpm_pd_lock_obtain(&lock, PRCM_DOMAIN_PERIPH); + /* + * Register ourself with LPM. This will keep the PERIPH PD powered on + * during deep sleep, allowing the buzzer to keep working while the chip is + * being power-cycled + */ + lpm_register_module(&buzzer_module); /* Stop the timer */ ti_lib_timer_disable(GPT0_BASE, TIMER_A); @@ -101,7 +106,12 @@ buzzer_stop() { buzzer_on = 0; - lpm_pd_lock_release(&lock); + /* + * Unregister the buzzer module from LPM. This will effectively release our + * lock for the PERIPH PD allowing it to be powered down (unless some other + * module keeps it on) + */ + lpm_unregister_module(&buzzer_module); /* Stop the timer */ ti_lib_timer_disable(GPT0_BASE, TIMER_A); diff --git a/platform/srf06-cc26xx/srf06/board.c b/platform/srf06-cc26xx/srf06/board.c index b7555f0a6..62122cdd0 100644 --- a/platform/srf06-cc26xx/srf06/board.c +++ b/platform/srf06-cc26xx/srf06/board.c @@ -60,7 +60,7 @@ wakeup_handler(void) * getting notified before deep sleep. All we need is to be notified when we * wake up so we can turn power domains back on */ -LPM_MODULE(srf_module, NULL, NULL, lpm_wakeup_handler); +LPM_MODULE(srf_module, NULL, NULL, wakeup_handler, LPM_DOMAIN_NONE); /*---------------------------------------------------------------------------*/ static void configure_unused_pins(void) From e893c914b68411ea8a758ed3e42f0bec47839550 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:43:08 +0100 Subject: [PATCH 27/38] Set SPI pins to a low leakage state --- platform/srf06-cc26xx/sensortag/board-spi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/platform/srf06-cc26xx/sensortag/board-spi.c b/platform/srf06-cc26xx/sensortag/board-spi.c index 01dd65857..7644a5c3d 100644 --- a/platform/srf06-cc26xx/sensortag/board-spi.c +++ b/platform/srf06-cc26xx/sensortag/board-spi.c @@ -113,6 +113,16 @@ board_spi_close() ti_lib_rom_prcm_peripheral_run_disable(PRCM_PERIPH_SSI0); ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()); + + /* Restore pins to a low-consumption state */ + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SPI_MISO); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_SPI_MISO, IOC_IOPULL_DOWN); + + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SPI_MOSI); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_SPI_MOSI, IOC_IOPULL_DOWN); + + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_SPI_CLK_FLASH); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_SPI_CLK_FLASH, IOC_IOPULL_DOWN); } /*---------------------------------------------------------------------------*/ /** @} */ From 2cc59c524afd27e9520a0bb5c638df03a5260012 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:45:13 +0100 Subject: [PATCH 28/38] Configure pins for unused tag peripherals --- platform/srf06-cc26xx/sensortag/board.c | 55 ++++++++++++++++-------- platform/srf06-cc26xx/sensortag/buzzer.c | 49 ++++++++++++--------- 2 files changed, 65 insertions(+), 39 deletions(-) diff --git a/platform/srf06-cc26xx/sensortag/board.c b/platform/srf06-cc26xx/sensortag/board.c index e421c734c..53ae9a84b 100644 --- a/platform/srf06-cc26xx/sensortag/board.c +++ b/platform/srf06-cc26xx/sensortag/board.c @@ -91,6 +91,39 @@ shutdown_handler(uint8_t mode) LPM_MODULE(sensortag_module, NULL, shutdown_handler, lpm_wakeup_handler, LPM_DOMAIN_NONE); /*---------------------------------------------------------------------------*/ +static void +configure_unused_pins(void) +{ + /* DP[0..3] */ + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DP0); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_DP0, IOC_IOPULL_DOWN); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DP1); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_DP1, IOC_IOPULL_DOWN); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DP2); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_DP2, IOC_IOPULL_DOWN); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DP3); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_DP3, IOC_IOPULL_DOWN); + + /* Devpack ID */ + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DEVPK_ID); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_DEVPK_ID, IOC_IOPULL_UP); + + /* Digital Microphone */ + ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_MIC_POWER); + ti_lib_gpio_pin_clear((1 << BOARD_IOID_MIC_POWER)); + ti_lib_ioc_io_drv_strength_set(BOARD_IOID_MIC_POWER, IOC_CURRENT_2MA, + IOC_STRENGTH_MIN); + + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_AUDIO_DI); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_AUDIO_DI, IOC_IOPULL_DOWN); + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_AUDIO_CLK); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_AUDIO_CLK, IOC_IOPULL_DOWN); + + /* UART over Devpack - TX only (ToDo: Map all UART pins to Debugger) */ + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_DP5_UARTTX); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_DP5_UARTTX, IOC_IOPULL_DOWN); +} +/*---------------------------------------------------------------------------*/ void board_init() { @@ -113,26 +146,7 @@ board_init() ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()); - /* Keys (input pullup) */ - ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_KEY_LEFT); - ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_KEY_RIGHT); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_KEY_LEFT, IOC_IOPULL_UP); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_KEY_RIGHT, IOC_IOPULL_UP); - /* I2C controller */ - - /* Sensor interface */ - ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_MPU_INT); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_MPU_INT, IOC_IOPULL_DOWN); - - ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_REED_RELAY); - ti_lib_ioc_io_port_pull_set(BOARD_IOID_REED_RELAY, IOC_IOPULL_DOWN); - - ti_lib_rom_ioc_pin_type_gpio_output(BOARD_IOID_MPU_POWER); - - /* 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(); @@ -142,6 +156,9 @@ board_init() lpm_register_module(&sensortag_module); + /* For unsupported peripherals, select a default pin configuration */ + configure_unused_pins(); + /* Re-enable interrupt if initially enabled. */ if(!int_disabled) { ti_lib_int_master_enable(); diff --git a/platform/srf06-cc26xx/sensortag/buzzer.c b/platform/srf06-cc26xx/sensortag/buzzer.c index a5c9001a5..d7f48e4de 100644 --- a/platform/srf06-cc26xx/sensortag/buzzer.c +++ b/platform/srf06-cc26xx/sensortag/buzzer.c @@ -52,13 +52,6 @@ void buzzer_init() { buzzer_on = 0; - - /* Drive the I/O ID with GPT0 / Timer A */ - ti_lib_ioc_port_configure_set(BOARD_IOID_BUZZER, IOC_PORT_MCU_PORT_EVENT0, - IOC_STD_OUTPUT); - - /* GPT0 / Timer A: PWM, Interrupt Enable */ - HWREG(GPT0_BASE + GPT_O_TAMR) = (TIMER_CFG_A_PWM & 0xFF) | GPT_TAMR_TAPWMIE; } /*---------------------------------------------------------------------------*/ uint8_t @@ -72,6 +65,20 @@ buzzer_start(int freq) { uint32_t load; + /* Enable GPT0 clocks under active, sleep, deep sleep */ + ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_TIMER0); + ti_lib_prcm_peripheral_sleep_enable(PRCM_PERIPH_TIMER0); + ti_lib_prcm_peripheral_deep_sleep_enable(PRCM_PERIPH_TIMER0); + ti_lib_prcm_load_set(); + while(!ti_lib_prcm_load_get()); + + /* Drive the I/O ID with GPT0 / Timer A */ + ti_lib_ioc_port_configure_set(BOARD_IOID_BUZZER, IOC_PORT_MCU_PORT_EVENT0, + IOC_STD_OUTPUT); + + /* GPT0 / Timer A: PWM, Interrupt Enable */ + HWREG(GPT0_BASE + GPT_O_TAMR) = (TIMER_CFG_A_PWM & 0xFF) | GPT_TAMR_TAPWMIE; + buzzer_on = 1; /* @@ -93,12 +100,6 @@ buzzer_start(int freq) /* Start */ ti_lib_timer_enable(GPT0_BASE, TIMER_A); } - - /* Run in sleep mode */ - ti_lib_prcm_peripheral_sleep_enable(PRCM_PERIPH_TIMER0); - ti_lib_prcm_peripheral_deep_sleep_enable(PRCM_PERIPH_TIMER0); - ti_lib_prcm_load_set(); - while(!ti_lib_prcm_load_get()); } /*---------------------------------------------------------------------------*/ void @@ -117,18 +118,26 @@ buzzer_stop() ti_lib_timer_disable(GPT0_BASE, TIMER_A); /* - * Stop running in sleep mode. - * ToDo: Currently GPT0 is in use by clock_delay_usec (GPT0/TB) and by this - * module here (GPT0/TA). clock_delay_usec will never need GPT0/TB in sleep - * mode and we control TA here. Thus, with the current setup, it's OK to - * control whether GPT0 runs in sleep mode in this module here. However, if - * some other module at some point starts using GPT0, we should change this - * to happen through an umbrella module + * Stop the module clock: + * + * Currently GPT0 is in use by clock_delay_usec (GPT0/TB) and by this + * module here (GPT0/TA). + * + * clock_delay_usec + * - is definitely not running when we enter here and + * - handles the module clock internally + * + * Thus, we can safely change the state of module clocks here. */ + ti_lib_prcm_peripheral_run_disable(PRCM_PERIPH_TIMER0); ti_lib_prcm_peripheral_sleep_disable(PRCM_PERIPH_TIMER0); ti_lib_prcm_peripheral_deep_sleep_disable(PRCM_PERIPH_TIMER0); ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()); + + /* Un-configure the pin */ + ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_BUZZER); + ti_lib_ioc_io_input_set(BOARD_IOID_BUZZER, IOC_INPUT_DISABLE); } /*---------------------------------------------------------------------------*/ /** @} */ From dcf0d110507e23c10e9b5c01b04dec3025a9ac89 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:47:23 +0100 Subject: [PATCH 29/38] Re-map tag UART-related IOID defines --- platform/srf06-cc26xx/sensortag/board.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/platform/srf06-cc26xx/sensortag/board.h b/platform/srf06-cc26xx/sensortag/board.h index 2d26e7a36..fc293f5c0 100644 --- a/platform/srf06-cc26xx/sensortag/board.h +++ b/platform/srf06-cc26xx/sensortag/board.h @@ -100,12 +100,16 @@ * Those values are not meant to be modified by the user * @{ */ -#define BOARD_IOID_UART_RX IOID_17 +#define BOARD_IOID_DP4_UARTRX IOID_28 +#define BOARD_IOID_DP5_UARTTX IOID_29 + +#define BOARD_IOID_UART_RX BOARD_IOID_DP4_UARTRX #define BOARD_IOID_UART_TX IOID_16 + #define BOARD_IOID_UART_CTS IOID_UNUSED #define BOARD_IOID_UART_RTS IOID_UNUSED -#define BOARD_UART_RXD (1 << BOARD_IOID_UART_RXD) -#define BOARD_UART_TXD (1 << BOARD_IOID_UART_TXD) +#define BOARD_UART_RX (1 << BOARD_IOID_UART_RX) +#define BOARD_UART_TX (1 << BOARD_IOID_UART_TX) #define BOARD_UART_CTS (1 << BOARD_IOID_UART_CTS) #define BOARD_UART_RTS (1 << BOARD_IOID_UART_RTS) /** @} */ From eb5b11a85ade6eb683f796a34ccfb669311b6134 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:49:00 +0100 Subject: [PATCH 30/38] Re-order instructions in the RTC startup sequence --- cpu/cc26xx/dev/cc26xx-rtc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cpu/cc26xx/dev/cc26xx-rtc.c b/cpu/cc26xx/dev/cc26xx-rtc.c index 9c3d58756..e9c01a7b5 100644 --- a/cpu/cc26xx/dev/cc26xx-rtc.c +++ b/cpu/cc26xx/dev/cc26xx-rtc.c @@ -68,18 +68,17 @@ cc26xx_rtc_init(void) /* Setup the wakeup event */ ti_lib_aon_event_mcu_wake_up_set(AON_EVENT_MCU_WU0, AON_EVENT_RTC0); ti_lib_aon_event_mcu_wake_up_set(AON_EVENT_MCU_WU1, AON_EVENT_RTC2); + ti_lib_aon_rtc_combined_event_config(AON_RTC_CH0 | AON_RTC_CH2); /* Configure channel 2 in continuous compare, 128 ticks / sec */ + ti_lib_aon_rtc_inc_value_ch2_set(RTIMER_SECOND / CLOCK_SECOND); + ti_lib_aon_rtc_mode_ch2_set(AON_RTC_MODE_CH2_CONTINUOUS); compare_value = (RTIMER_SECOND / CLOCK_SECOND) + ti_lib_aon_rtc_current_compare_value_get(); ti_lib_aon_rtc_compare_value_set(AON_RTC_CH2, compare_value); - ti_lib_aon_rtc_inc_value_ch2_set(RTIMER_SECOND / CLOCK_SECOND); - ti_lib_aon_rtc_mode_ch2_set(AON_RTC_MODE_CH2_CONTINUOUS); - /* Enable event generation for channels 0 and 2 and enable the RTC */ - ti_lib_aon_rtc_combined_event_config(AON_RTC_CH0 | AON_RTC_CH2); + /* Enable channel 2 and the RTC */ ti_lib_aon_rtc_channel_enable(AON_RTC_CH2); - ti_lib_aon_rtc_enable(); ti_lib_int_enable(INT_AON_RTC); From 6e7d52b5df237ebb25a69e86f1bcdfb67397cde1 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:51:32 +0100 Subject: [PATCH 31/38] Improve MPU power-cycling logic: * Keep MPU_PWR low when the sensor is not in use * Deselect the sensor when not in use, in order to restore the I2C ping state * Explicitly control the MPU_INT pin * Don't shutdown the sensor when it's shut down * Remove explicit shutdown-related API extension. It is no longer required --- platform/srf06-cc26xx/sensortag/board.c | 3 +- .../srf06-cc26xx/sensortag/mpu-9250-sensor.c | 92 +++++++------------ .../srf06-cc26xx/sensortag/mpu-9250-sensor.h | 2 - 3 files changed, 37 insertions(+), 60 deletions(-) diff --git a/platform/srf06-cc26xx/sensortag/board.c b/platform/srf06-cc26xx/sensortag/board.c index 53ae9a84b..c060ee58f 100644 --- a/platform/srf06-cc26xx/sensortag/board.c +++ b/platform/srf06-cc26xx/sensortag/board.c @@ -74,7 +74,8 @@ shutdown_handler(uint8_t mode) SENSORS_DEACTIVATE(opt_3001_sensor); SENSORS_DEACTIVATE(tmp_007_sensor); SENSORS_DEACTIVATE(hdc_1000_sensor); - mpu_9250_sensor.configure(MPU_9250_SENSOR_SHUTDOWN, 0); + SENSORS_DEACTIVATE(mpu_9250_sensor); + ti_lib_gpio_pin_clear(BOARD_MPU_POWER); } /* In all cases, stop the I2C */ diff --git a/platform/srf06-cc26xx/sensortag/mpu-9250-sensor.c b/platform/srf06-cc26xx/sensortag/mpu-9250-sensor.c index fd7bff688..275f2b352 100644 --- a/platform/srf06-cc26xx/sensortag/mpu-9250-sensor.c +++ b/platform/srf06-cc26xx/sensortag/mpu-9250-sensor.c @@ -212,12 +212,12 @@ static uint8_t acc_range_reg; static uint8_t val; static uint8_t interrupt_status; /*---------------------------------------------------------------------------*/ -#define SENSOR_STATUS_DISABLED 0 -#define SENSOR_STATUS_BOOTING 1 -#define SENSOR_STATUS_ENABLED 2 +#define SENSOR_STATE_DISABLED 0 +#define SENSOR_STATE_BOOTING 1 +#define SENSOR_STATE_ENABLED 2 -static int enabled = SENSOR_STATUS_DISABLED; -static int elements; +static int state = SENSOR_STATE_DISABLED; +static int elements = MPU_9250_SENSOR_TYPE_NONE; /*---------------------------------------------------------------------------*/ /* 3 16-byte words for all sensor readings */ #define SENSOR_DATA_BUF_SIZE 3 @@ -289,7 +289,9 @@ static void select_axes(void) { val = ~mpu_config; + SENSOR_SELECT(); sensor_common_write_reg(PWR_MGMT_2, &val, 1); + SENSOR_DESELECT(); } /*---------------------------------------------------------------------------*/ static void @@ -334,37 +336,6 @@ acc_set_range(uint8_t new_range) return success; } /*---------------------------------------------------------------------------*/ -/** - * \brief Initialise the MPU - * \return True if success - */ -static bool -init_sensor(void) -{ - bool ret; - - interrupt_status = false; - acc_range = ACC_RANGE_INVALID; - mpu_config = 0; /* All axes off */ - - /* Device reset */ - val = 0x80; - SENSOR_SELECT(); - ret = sensor_common_write_reg(PWR_MGMT_1, &val, 1); - SENSOR_DESELECT(); - - if(ret) { - delay_ms(200); - - /* Initial configuration */ - acc_set_range(ACC_RANGE_8G); - /* Power save */ - sensor_sleep(); - } - - return ret; -} -/*---------------------------------------------------------------------------*/ /** * \brief Check whether a data or wake on motion interrupt has occurred * \return Return the interrupt status @@ -450,13 +421,13 @@ gyro_read(uint16_t *data) /* Burst read of all gyroscope values */ success = sensor_common_read_reg(GYRO_XOUT_H, (uint8_t *)data, DATA_SIZE); - SENSOR_DESELECT(); - if(success) { convert_to_le((uint8_t *)data, DATA_SIZE); } else { sensor_common_set_error_data((uint8_t *)data, DATA_SIZE); } + + SENSOR_DESELECT(); } else { success = false; } @@ -514,15 +485,13 @@ gyro_convert(int16_t raw_data) static void notify_ready(void *not_used) { - enabled = SENSOR_STATUS_ENABLED; + state = SENSOR_STATE_ENABLED; sensors_changed(&mpu_9250_sensor); } /*---------------------------------------------------------------------------*/ static void initialise(void *not_used) { - init_sensor(); - /* Configure the accelerometer range */ if((elements & MPU_9250_SENSOR_TYPE_ACC) != 0) { acc_set_range(MPU_9250_SENSOR_ACC_RANGE); @@ -537,7 +506,7 @@ static void power_up(void) { ti_lib_gpio_pin_write(BOARD_MPU_POWER, 1); - enabled = SENSOR_STATUS_BOOTING; + state = SENSOR_STATE_BOOTING; ctimer_set(&startup_timer, SENSOR_BOOT_DELAY, initialise, NULL); } @@ -553,7 +522,7 @@ value(int type) int rv; float converted_val = 0; - if(enabled == SENSOR_STATUS_DISABLED) { + if(state == SENSOR_STATE_DISABLED) { PRINTF("MPU: Sensor Disabled\n"); return CC26XX_SENSOR_READING_ERROR; } @@ -632,33 +601,42 @@ configure(int type, int enable) { switch(type) { case SENSORS_HW_INIT: + ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_MPU_INT); + ti_lib_ioc_io_port_pull_set(BOARD_IOID_MPU_INT, IOC_IOPULL_DOWN); + ti_lib_ioc_io_hyst_set(BOARD_IOID_MPU_INT, IOC_HYST_ENABLE); + + ti_lib_rom_ioc_pin_type_gpio_output(BOARD_IOID_MPU_POWER); + ti_lib_ioc_io_drv_strength_set(BOARD_IOID_MPU_POWER, IOC_CURRENT_4MA, + IOC_STRENGTH_MAX); + ti_lib_gpio_pin_clear(BOARD_MPU_POWER); elements = MPU_9250_SENSOR_TYPE_NONE; break; case SENSORS_ACTIVE: - if((enable & MPU_9250_SENSOR_TYPE_ACC) != 0 || - (enable & MPU_9250_SENSOR_TYPE_GYRO) != 0) { + if(((enable & MPU_9250_SENSOR_TYPE_ACC) != 0) || + ((enable & MPU_9250_SENSOR_TYPE_GYRO) != 0)) { PRINTF("MPU: Enabling\n"); elements = enable & MPU_9250_SENSOR_TYPE_ALL; power_up(); - enabled = SENSOR_STATUS_BOOTING; + state = SENSOR_STATE_BOOTING; } else { PRINTF("MPU: Disabling\n"); - ctimer_stop(&startup_timer); - elements = MPU_9250_SENSOR_TYPE_NONE; - enable_sensor(0); - while(ti_lib_i2c_master_busy(I2C0_BASE)); - enabled = SENSOR_STATUS_DISABLED; + if(HWREG(GPIO_BASE + GPIO_O_DOUT31_0) & BOARD_MPU_POWER) { + /* Then check our state */ + elements = MPU_9250_SENSOR_TYPE_NONE; + ctimer_stop(&startup_timer); + sensor_sleep(); + while(ti_lib_i2c_master_busy(I2C0_BASE)); + state = SENSOR_STATE_DISABLED; + ti_lib_gpio_pin_clear(BOARD_MPU_POWER); + } } break; - case MPU_9250_SENSOR_SHUTDOWN: - ti_lib_gpio_pin_write(BOARD_MPU_POWER, 0); - break; default: break; } - return enabled; + return state; } /*---------------------------------------------------------------------------*/ /** @@ -672,12 +650,12 @@ status(int type) switch(type) { case SENSORS_ACTIVE: case SENSORS_READY: - return enabled; + return state; break; default: break; } - return SENSOR_STATUS_DISABLED; + return SENSOR_STATE_DISABLED; } /*---------------------------------------------------------------------------*/ SENSORS_SENSOR(mpu_9250_sensor, "MPU9250", value, configure, status); diff --git a/platform/srf06-cc26xx/sensortag/mpu-9250-sensor.h b/platform/srf06-cc26xx/sensortag/mpu-9250-sensor.h index 46836a538..c6c4d5534 100644 --- a/platform/srf06-cc26xx/sensortag/mpu-9250-sensor.h +++ b/platform/srf06-cc26xx/sensortag/mpu-9250-sensor.h @@ -86,8 +86,6 @@ #define MPU_9250_SENSOR_TYPE_NONE 0 #define MPU_9250_SENSOR_TYPE_ALL (MPU_9250_SENSOR_TYPE_ACC | \ MPU_9250_SENSOR_TYPE_GYRO) - -#define MPU_9250_SENSOR_SHUTDOWN 0xFF /*---------------------------------------------------------------------------*/ /* Accelerometer range */ #define MPU_9250_SENSOR_ACC_RANGE_2G 0 From 34f52ed08ef99de80c9cdc806c19f12717a65c1a Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 16:56:32 +0100 Subject: [PATCH 32/38] Improve the LPM module: * Implement new style of PD locks * Use our own shutdown sequence rather than the one provided by cc26xxware * Shutdown from within the interrupt that requested it. This allows shutdown to take place even if the code is stuck in a loop somewhere else * Improve DCDC/GLDO/uLDO switching logic * Explicitly handle oscillators and retentions --- cpu/cc26xx/lpm.c | 196 +++++++++++++++++++++++++++++------------------ 1 file changed, 122 insertions(+), 74 deletions(-) diff --git a/cpu/cc26xx/lpm.c b/cpu/cc26xx/lpm.c index 320ccdd03..f9d309f74 100644 --- a/cpu/cc26xx/lpm.c +++ b/cpu/cc26xx/lpm.c @@ -49,6 +49,7 @@ #include "dev/leds.h" #include "dev/watchdog.h" #include "dev/cc26xx-rtc.h" +#include "dev/oscillators.h" /*---------------------------------------------------------------------------*/ #if ENERGEST_CONF_ON static unsigned long irq_energest = 0; @@ -73,49 +74,48 @@ LIST(modules_list); */ #define STANDBY_MIN_DURATION (RTIMER_SECOND >> 8) /*---------------------------------------------------------------------------*/ -/* Variables used by the power on/off (Power mode: SHUTDOWN) functionality */ -static uint8_t shutdown_requested; -static uint32_t pin; -/*---------------------------------------------------------------------------*/ void -lpm_pd_lock_obtain(lpm_power_domain_lock_t *lock, uint32_t domains) -{ - /* We only accept locks for specific PDs */ - domains &= LOCKABLE_DOMAINS; - - if(domains == 0) { - return; - } - - lock->domains = domains; - - list_add(power_domain_locks_list, lock); -} -/*---------------------------------------------------------------------------*/ -void -lpm_pd_lock_release(lpm_power_domain_lock_t *lock) -{ - lock->domains = 0; - - list_remove(power_domain_locks_list, lock); -} -/*---------------------------------------------------------------------------*/ -void -lpm_shutdown(uint32_t wakeup_pin) -{ - shutdown_requested = 1; - pin = wakeup_pin; -} -/*---------------------------------------------------------------------------*/ -static void -shutdown_now(void) +lpm_shutdown(uint32_t wakeup_pin, uint32_t io_pull, uint32_t wake_on) { lpm_registered_module_t *module; - int i; - rtimer_clock_t t0; - uint32_t io_cfg = (IOC_STD_INPUT & ~IOC_IOPULL_M) | IOC_IOPULL_UP | - IOC_WAKE_ON_LOW; + int i, j; + uint32_t io_cfg = (IOC_STD_INPUT & ~IOC_IOPULL_M) | io_pull | + wake_on; + /* This procedure may not be interrupted */ + ti_lib_int_master_disable(); + + /* Disable the RTC */ + ti_lib_aon_rtc_disable(); + ti_lib_aon_rtc_event_clear(AON_RTC_CH0); + ti_lib_aon_rtc_event_clear(AON_RTC_CH1); + ti_lib_aon_rtc_event_clear(AON_RTC_CH2); + + /* Reset AON even fabric to default wakeup sources */ + for(i = AON_EVENT_MCU_WU0; i <= AON_EVENT_MCU_WU3; i++) { + ti_lib_aon_event_mcu_wake_up_set(i, AON_EVENT_NULL); + } + for(i = AON_EVENT_AUX_WU0; i <= AON_EVENT_AUX_WU2; i++) { + ti_lib_aon_event_aux_wake_up_set(i, AON_EVENT_NULL); + } + + ti_lib_sys_ctrl_aon_sync(); + + watchdog_periodic(); + + /* fade away....... */ + j = 1000; + + for(i = j; i > 0; --i) { + leds_on(LEDS_ALL); + clock_delay_usec(i); + leds_off(LEDS_ALL); + clock_delay_usec(j - i); + } + + leds_off(LEDS_ALL); + + /* Notify all modules that we're shutting down */ for(module = list_head(modules_list); module != NULL; module = module->next) { if(module->shutdown) { @@ -123,20 +123,68 @@ shutdown_now(void) } } - leds_off(LEDS_ALL); + /* Configure the wakeup trigger */ + ti_lib_gpio_dir_mode_set((1 << wakeup_pin), GPIO_DIR_MODE_IN); + ti_lib_ioc_port_configure_set(wakeup_pin, IOC_PORT_GPIO, io_cfg); - for(i = 0; i < 5; i++) { - t0 = RTIMER_NOW(); - leds_toggle(LEDS_ALL); - while(RTIMER_CLOCK_LT(RTIMER_NOW(), (t0 + (RTIMER_SECOND >> 3)))); - } + /* Freeze I/O latches in AON */ + ti_lib_aon_ioc_freeze_enable(); - leds_off(LEDS_ALL); + /* Turn off RFCORE, SERIAL and PERIPH PDs. This will happen immediately */ + ti_lib_prcm_power_domain_off(PRCM_DOMAIN_RFCORE | PRCM_DOMAIN_SERIAL | + PRCM_DOMAIN_PERIPH); - ti_lib_gpio_dir_mode_set((1 << pin), GPIO_DIR_MODE_IN); - ti_lib_ioc_port_configure_set(pin, IOC_PORT_GPIO, io_cfg); + oscillators_switch_to_hf_rc(); + oscillators_select_lf_rcosc(); - ti_lib_pwr_ctrl_state_set(LPM_MODE_SHUTDOWN); + /* Configure clock sources for MCU and AUX: No clock */ + ti_lib_aon_wuc_mcu_power_down_config(AONWUC_NO_CLOCK); + ti_lib_aon_wuc_aux_power_down_config(AONWUC_NO_CLOCK); + + /* Disable retentions: SRAM, CPU, AUX, RFCORE - possibly not required */ + ti_lib_aon_wuc_mcu_sram_config(0); + ti_lib_prcm_retention_disable(PRCM_DOMAIN_CPU); + ti_lib_aon_wuc_aux_sram_config(false); + ti_lib_prcm_retention_disable(PRCM_DOMAIN_RFCORE); + + /* + * Request CPU, SYSBYS and VIMS PD off. + * This will only happen when the CM3 enters deep sleep + */ + ti_lib_prcm_power_domain_off(PRCM_DOMAIN_CPU | PRCM_DOMAIN_VIMS | + PRCM_DOMAIN_SYSBUS); + + /* Request JTAG domain power off */ + ti_lib_aon_wuc_jtag_power_off(); + + /* Turn off AUX */ + ti_lib_aux_wuc_power_ctrl(AUX_WUC_POWER_OFF); + ti_lib_aon_wuc_domain_power_down_enable(); + while(ti_lib_aon_wuc_power_status() & AONWUC_AUX_POWER_ON); + + /* + * Request MCU VD power off. + * This will only happen when the CM3 enters deep sleep + */ + ti_lib_prcm_mcu_power_off(); + + /* Set MCU wakeup to immediate and disable virtual power off */ + ti_lib_aon_wuc_mcu_wake_up_config(MCU_IMM_WAKE_UP); + ti_lib_aon_wuc_mcu_power_off_config(MCU_VIRT_PWOFF_DISABLE); + + /* Latch the IOs in the padring and enable I/O pad sleep mode */ + ti_lib_pwr_ctrl_io_freeze_enable(); + + /* Turn off VIMS cache, CRAM and TRAM - possibly not required */ + ti_lib_prcm_retention_disable(PRCM_DOMAIN_VIMS); + ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_OFF); + + /* Enable shutdown and sync AON */ + ti_lib_aon_wuc_shut_down_enable(); + ti_lib_sys_ctrl_aon_sync(); + + /* Deep Sleep */ + ti_lib_prcm_deep_sleep(); } /*---------------------------------------------------------------------------*/ /* @@ -173,8 +221,8 @@ wake_up(void) ti_lib_aon_ioc_freeze_disable(); ti_lib_sys_ctrl_aon_sync(); - /* Power up AUX and allow it to go to sleep */ - ti_lib_aon_wuc_aux_wakeup_event(AONWUC_AUX_ALLOW_SLEEP); + /* Check operating conditions, optimally choose DCDC versus GLDO */ + ti_lib_sys_ctrl_dcdc_voltage_conditional_control(); /* Notify all registered modules that we've just woken up */ for(module = list_head(modules_list); module != NULL; @@ -189,16 +237,11 @@ void lpm_drop() { lpm_registered_module_t *module; - lpm_power_domain_lock_t *lock; uint8_t max_pm = LPM_MODE_MAX_SUPPORTED; uint8_t module_pm; uint32_t domains = LOCKABLE_DOMAINS; - if(shutdown_requested) { - shutdown_now(); - } - if(RTIMER_CLOCK_LT(cc26xx_rtc_get_next_trigger(), RTIMER_NOW() + STANDBY_MIN_DURATION)) { lpm_sleep(); @@ -235,26 +278,21 @@ lpm_drop() * This is a chance for modules to delay us a little bit until an ongoing * operation has finished (e.g. uart TX) or to configure themselves for * deep sleep. + * + * At this stage, we also collect power domain locks, if any. + * The argument to PRCMPowerDomainOff() is a bitwise OR, so every time + * we encounter a lock we just clear the respective bits in the 'domains' + * variable as required by the lock. In the end the domains variable will + * just hold whatever has not been cleared */ for(module = list_head(modules_list); module != NULL; module = module->next) { if(module->shutdown) { module->shutdown(max_pm); } - } - /* - * Iterate PD locks to see what we can and cannot turn off. - * - * The argument to PRCMPowerDomainOff() is a bitwise OR, so every time - * we encounter a lock we just clear the respective bits in the 'domains' - * variable as required by the lock. In the end the domains variable will - * just hold whatever has not been cleared - */ - for(lock = list_head(power_domain_locks_list); lock != NULL; - lock = lock->next) { /* Clear the bits specified in the lock */ - domains &= ~lock->domains; + domains &= ~module->domain_lock; } /* Pat the dog: We don't want it to shout right after we wake up */ @@ -280,6 +318,20 @@ lpm_drop() ti_lib_prcm_power_domain_off(domains); } + /* + * Before entering Deep Sleep, we must switch off the HF XOSC. The HF XOSC + * is predominantly controlled by the RF driver. In a build with radio + * cycling (e.g. ContikiMAC), the RF driver will request the XOSC before + * using the Freq. Synth, and switch back to the RC when it is about to + * turn back off. + * + * If the radio is on, we won't even reach here, and if it's off the HF + * clock source should already be the HF RC. + * + * Nevertheless, request the switch to the HF RC explicitly here. + */ + oscillators_switch_to_hf_rc(); + /* Configure clock sources for MCU and AUX: No clock */ ti_lib_aon_wuc_mcu_power_down_config(AONWUC_NO_CLOCK); ti_lib_aon_wuc_aux_power_down_config(AONWUC_NO_CLOCK); @@ -295,11 +347,7 @@ lpm_drop() ti_lib_aon_wuc_aux_sram_config(false); /* Disable retention in the RFCORE RAM */ - HWREG(PRCM_BASE + PRCM_O_RAMRETEN) &= ~PRCM_RAMRETEN_RFC; - - /* Disable retention of VIMS RAM (TRAM and CRAM) */ - //TODO: This can probably be removed, we are calling ti_lib_prcm_retention_disable(PRCM_DOMAIN_VIMS); further down - HWREG(PRCM_BASE + PRCM_O_RAMRETEN) &= ~PRCM_RAMRETEN_VIMS_M; + ti_lib_prcm_retention_disable(PRCM_DOMAIN_RFCORE); /* * Always turn off RFCORE, CPU, SYSBUS and VIMS. RFCORE should be off @@ -320,7 +368,7 @@ lpm_drop() ti_lib_sys_ctrl_set_recharge_before_power_down(false); /* - * If both PERIPH and SERIAL PDs are off, request the uLDO for as the power + * If both PERIPH and SERIAL PDs are off, request the uLDO as the power * source while in deep sleep. */ if(domains == LOCKABLE_DOMAINS) { From 07272b7cd6d605c44a50fc1630181472dbf50764 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 17:03:26 +0100 Subject: [PATCH 33/38] Improve UART power-cycling logic: * Only enable TX by default. * Add some magic for RX handling. When an input handler is registered: * Automatically enable RX-related and interrupts * Automatically lock the SERIAL PD on under all power modes * Automatically enable the UART clock under sleep and deep sleep * Automatically undo all of the above when the input handler becomes NULL * As a result, modules / examples that need UART RX no longer need to clock the UART and manipulate the SERIAL PD. They simply have to specify an input handler * Don't automatically power on the UART whenever the CM3 is active * Before accessing the UART, make sure it is powered and clocked * Avoid falling edge glitches * Fix garbage characters / Explicitly wait for UART TX to complete --- cpu/cc26xx/dev/cc26xx-uart.c | 322 +++++++++++++++++++++++++---------- cpu/cc26xx/dev/cc26xx-uart.h | 23 +++ cpu/cc26xx/putchar.c | 21 ++- 3 files changed, 271 insertions(+), 95 deletions(-) diff --git a/cpu/cc26xx/dev/cc26xx-uart.c b/cpu/cc26xx/dev/cc26xx-uart.c index 5a45bb03b..6773b9836 100644 --- a/cpu/cc26xx/dev/cc26xx-uart.c +++ b/cpu/cc26xx/dev/cc26xx-uart.c @@ -40,6 +40,7 @@ #include "sys/energest.h" #include +#include /*---------------------------------------------------------------------------*/ /* Which events to trigger a UART interrupt */ #define CC26XX_UART_RX_INTERRUPT_TRIGGERS (UART_INT_RX | UART_INT_RT) @@ -53,35 +54,98 @@ /*---------------------------------------------------------------------------*/ static int (*input_handler)(unsigned char c); /*---------------------------------------------------------------------------*/ -static void -power_domain_on(void) +static bool +usable(void) { + if(BOARD_IOID_UART_RX == IOID_UNUSED || + BOARD_IOID_UART_TX == IOID_UNUSED || + CC26XX_UART_CONF_ENABLE == 0) { + return false; + } + + return true; +} +/*---------------------------------------------------------------------------*/ +static void +power_and_clock(void) +{ + /* Power on the SERIAL PD */ ti_lib_prcm_power_domain_on(PRCM_DOMAIN_SERIAL); while(ti_lib_prcm_power_domain_status(PRCM_DOMAIN_SERIAL) != PRCM_DOMAIN_POWER_ON); + + /* Enable UART clock in active mode */ + ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_UART0); + ti_lib_prcm_load_set(); + while(!ti_lib_prcm_load_get()); +} +/*---------------------------------------------------------------------------*/ +/* + * Returns 0 if either the SERIAL PD is off, or the PD is on but the run mode + * clock is gated. If this function would return 0, accessing UART registers + * will return a precise bus fault. If this function returns 1, it is safe to + * access UART registers. + * + * This function only checks the 'run mode' clock gate, since it can only ever + * be called with the MCU in run mode. + */ +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_UARTCLKGR) & PRCM_UARTCLKGR_CLK_EN)) { + return false; + } + + return true; } /*---------------------------------------------------------------------------*/ static void -configure_baud_rate(void) +disable_interrupts(void) { + /* Acknowledge UART interrupts */ + ti_lib_int_disable(INT_UART0); + + /* Disable all UART module interrupts */ + ti_lib_uart_int_disable(UART0_BASE, CC26XX_UART_INTERRUPT_ALL); + + /* Clear all UART interrupts */ + ti_lib_uart_int_clear(UART0_BASE, CC26XX_UART_INTERRUPT_ALL); +} +/*---------------------------------------------------------------------------*/ +static void +enable_interrupts(void) +{ + /* Clear all UART interrupts */ + ti_lib_uart_int_clear(UART0_BASE, CC26XX_UART_INTERRUPT_ALL); + + /* Enable RX-related interrupts only if we have an input handler */ + if(input_handler) { + /* Configure which interrupts to generate: FIFO level or after RX timeout */ + ti_lib_uart_int_enable(UART0_BASE, CC26XX_UART_RX_INTERRUPT_TRIGGERS); + + /* Acknowledge UART interrupts */ + ti_lib_int_enable(INT_UART0); + } +} +/*---------------------------------------------------------------------------*/ +static void +configure(void) +{ + uint32_t ctl_val = UART_CTL_UARTEN | UART_CTL_TXE; /* - * Configure the UART for 115,200, 8-N-1 operation. - * This function uses SysCtrlClockGet() to get the system clock - * frequency. This could be also be a variable or hard coded value - * instead of a function call. + * Make sure the TX pin is output / high before assigning it to UART control + * to avoid falling edge glitches */ - ti_lib_uart_config_set_exp_clk(UART0_BASE, - ti_lib_sys_ctrl_peripheral_clock_get( - PRCM_PERIPH_UART0, - SYSCTRL_SYSBUS_ON), - CC26XX_UART_CONF_BAUD_RATE, - (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | - UART_CONFIG_PAR_NONE)); -} -/*---------------------------------------------------------------------------*/ -static void -configure_registers(void) -{ + ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_UART_TX); + ti_lib_gpio_pin_write(BOARD_UART_TX, 1); + /* * Map UART signals to the correct GPIO pins and configure them as * hardware controlled. @@ -89,7 +153,14 @@ configure_registers(void) ti_lib_ioc_pin_type_uart(UART0_BASE, BOARD_IOID_UART_RX, BOARD_IOID_UART_TX, BOARD_IOID_UART_CTS, BOARD_IOID_UART_RTS); - configure_baud_rate(); + /* Configure the UART for 115,200, 8-N-1 operation. */ + ti_lib_uart_config_set_exp_clk(UART0_BASE, + ti_lib_sys_ctrl_peripheral_clock_get( + PRCM_PERIPH_UART0, + SYSCTRL_SYSBUS_ON), + CC26XX_UART_CONF_BAUD_RATE, + (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | + UART_CONFIG_PAR_NONE)); /* * Generate an RX interrupt at FIFO 1/2 full. @@ -97,116 +168,138 @@ configure_registers(void) */ ti_lib_uart_fifo_level_set(UART0_BASE, UART_FIFO_TX7_8, UART_FIFO_RX4_8); - /* Configure which interrupts to generate: FIFO level or after RX timeout */ - ti_lib_uart_int_enable(UART0_BASE, CC26XX_UART_RX_INTERRUPT_TRIGGERS); -} -/*---------------------------------------------------------------------------*/ -static void -uart_on(void) -{ - power_domain_on(); + /* Enable FIFOs */ + HWREG(UART0_BASE + UART_O_LCRH) |= UART_LCRH_FEN; - /* Configure baud rate and enable */ - if((HWREG(UART0_BASE + UART_O_CTL) & UART_CTL_UARTEN) == 0) { - configure_registers(); - - /* Enable UART */ - ti_lib_uart_enable(UART0_BASE); + if(input_handler) { + ctl_val += UART_CTL_RXE; } -} -/*---------------------------------------------------------------------------*/ -static uint8_t -lpm_permit_max_pm_handler(void) -{ - return LPM_MODE_MAX_SUPPORTED; + + /* Enable TX, RX (conditionally), and the UART. */ + HWREG(UART0_BASE + UART_O_CTL) = ctl_val; } /*---------------------------------------------------------------------------*/ static void lpm_drop_handler(uint8_t mode) { - /* Do nothing if the PD is off */ - if(ti_lib_prcm_power_domain_status(PRCM_DOMAIN_SERIAL) - != PRCM_DOMAIN_POWER_ON) { - return; + /* + * First, wait for any outstanding TX to complete. If we have an input + * handler, the SERIAL PD will be kept on and the UART module clock will + * be enabled under sleep as well as deep sleep. In theory, this means that + * we shouldn't lose any outgoing bytes, but we actually do on occasion. + * This byte loss may (or may not) be related to the freezing of IO latches + * between MCU and AON when we drop to deep sleep. This here is essentially a + * workaround + */ + if(accessible() == true) { + while(ti_lib_uart_busy(UART0_BASE)); } - /* Wait for outstanding TX to complete */ - while(ti_lib_uart_busy(UART0_BASE)); - /* - * Check our clock gate under Deep Sleep. If it's off, we can shut down. If - * it's on, this means that some other code module wants UART functionality - * during deep sleep, so we stay enabled + * If we have a registered input_handler then we need to retain RX + * capability. Thus, if this is not a shutdown notification and we have an + * input handler, we do nothing */ - if((HWREG(PRCM_BASE + PRCM_O_UARTCLKGDS) & 1) == 0) { - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_UART_RX); - ti_lib_ioc_pin_type_gpio_input(BOARD_IOID_UART_TX); - - ti_lib_uart_disable(UART0_BASE); - } -} -/*---------------------------------------------------------------------------*/ -static void -lpm_wakeup_handler(void) -{ - uart_on(); -} -/*---------------------------------------------------------------------------*/ -/* Declare a data structure to register with LPM. */ -LPM_MODULE(uart_module, lpm_permit_max_pm_handler, - lpm_drop_handler, lpm_wakeup_handler); -/*---------------------------------------------------------------------------*/ -void -cc26xx_uart_init() -{ - /* Exit without initialising if ports are misconfigured */ - if(BOARD_IOID_UART_RX == IOID_UNUSED || - BOARD_IOID_UART_TX == IOID_UNUSED) { + if((mode != LPM_MODE_SHUTDOWN) && (input_handler != NULL)) { return; } - /* Enable the serial domain and wait for domain to be on */ - power_domain_on(); + /* + * If we reach here, we either don't care about staying awake or we have + * received a shutdown notification + * + * Only touch UART registers if the module is powered and clocked + */ + if(accessible() == true) { + /* Disable the module */ + ti_lib_uart_disable(UART0_BASE); - /* Enable the UART clock when running and sleeping */ - ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_UART0); + /* Disable all UART interrupts and clear all flags */ + disable_interrupts(); + } - /* Apply clock settings and wait for them to take effect */ + /* + * Always stop the clock in run mode. Also stop in Sleep and Deep Sleep if + * this is a request for full shutdown + */ + ti_lib_prcm_peripheral_run_disable(PRCM_PERIPH_UART0); + if(mode == LPM_MODE_SHUTDOWN) { + ti_lib_prcm_peripheral_sleep_disable(PRCM_PERIPH_UART0); + ti_lib_prcm_peripheral_deep_sleep_disable(PRCM_PERIPH_UART0); + } ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()); - /* Disable Interrupts */ - ti_lib_int_master_disable(); + /* Set pins to low leakage configuration in preparation for deep sleep */ + lpm_pin_set_default_state(BOARD_IOID_UART_TX); + lpm_pin_set_default_state(BOARD_IOID_UART_RX); + lpm_pin_set_default_state(BOARD_IOID_UART_CTS); + lpm_pin_set_default_state(BOARD_IOID_UART_RTS); +} +/*---------------------------------------------------------------------------*/ +/* Declare a data structure to register with LPM. */ +LPM_MODULE(uart_module, NULL, lpm_drop_handler, NULL, LPM_DOMAIN_NONE); +/*---------------------------------------------------------------------------*/ +static void +enable(void) +{ + power_and_clock(); /* Make sure the peripheral is disabled */ ti_lib_uart_disable(UART0_BASE); - /* Disable all UART module interrupts */ - ti_lib_uart_int_disable(UART0_BASE, CC26XX_UART_INTERRUPT_ALL); + /* Disable all UART interrupts and clear all flags */ + disable_interrupts(); - configure_registers(); + /* Setup pins, Baud rate and FIFO levels */ + configure(); - /* Acknowledge UART interrupts */ - ti_lib_int_enable(INT_UART0); + /* Enable UART interrupts */ + enable_interrupts(); +} +/*---------------------------------------------------------------------------*/ +void +cc26xx_uart_init() +{ + bool interrupts_disabled; - /* Re-enable processor interrupts */ - ti_lib_int_master_enable(); + /* Return early if disabled by user conf or if ports are misconfigured */ + if(usable() == false) { + return; + } - /* Enable UART */ - ti_lib_uart_enable(UART0_BASE); + /* Disable Interrupts */ + interrupts_disabled = ti_lib_int_master_disable(); /* Register ourselves with the LPM module */ lpm_register_module(&uart_module); + + /* Only TX and EN to start with. RX will be enabled only if needed */ + input_handler = NULL; + + /* + * init() won't actually fire up the UART. We turn it on only when (and if) + * it gets requested, either to enable input or to send out a character + * + * Thus, we simply re-enable processor interrupts here + */ + if(!interrupts_disabled) { + ti_lib_int_master_enable(); + } } /*---------------------------------------------------------------------------*/ void cc26xx_uart_write_byte(uint8_t c) { - if(ti_lib_prcm_power_domain_status(PRCM_DOMAIN_SERIAL) - != PRCM_DOMAIN_POWER_ON) { + /* Return early if disabled by user conf or if ports are misconfigured */ + if(usable() == false) { return; } + if(accessible() == false) { + enable(); + } + ti_lib_uart_char_put(UART0_BASE, c); } /*---------------------------------------------------------------------------*/ @@ -214,9 +307,52 @@ void cc26xx_uart_set_input(int (*input)(unsigned char c)) { input_handler = input; + + /* Return early if disabled by user conf or if ports are misconfigured */ + if(usable() == false) { + return; + } + + if(input == NULL) { + /* Let the SERIAL PD power down */ + uart_module.domain_lock = LPM_DOMAIN_NONE; + + /* Disable module clocks under sleep and deep sleep */ + ti_lib_prcm_peripheral_sleep_disable(PRCM_PERIPH_UART0); + ti_lib_prcm_peripheral_deep_sleep_disable(PRCM_PERIPH_UART0); + } else { + /* Request the SERIAL PD to stay on during deep sleep */ + uart_module.domain_lock = LPM_DOMAIN_SERIAL; + + /* Enable module clocks under sleep and deep sleep */ + ti_lib_prcm_peripheral_sleep_enable(PRCM_PERIPH_UART0); + ti_lib_prcm_peripheral_deep_sleep_enable(PRCM_PERIPH_UART0); + } + + ti_lib_prcm_load_set(); + while(!ti_lib_prcm_load_get()); + + enable(); + return; } /*---------------------------------------------------------------------------*/ +uint8_t +cc26xx_uart_busy(void) +{ + /* Return early if disabled by user conf or if ports are misconfigured */ + if(usable() == false) { + return UART_IDLE; + } + + /* If the UART is not accessible, it is not busy */ + if(accessible() == false) { + return UART_IDLE; + } + + return ti_lib_uart_busy(UART0_BASE); +} +/*---------------------------------------------------------------------------*/ void cc26xx_uart_isr(void) { @@ -225,6 +361,8 @@ cc26xx_uart_isr(void) ENERGEST_ON(ENERGEST_TYPE_IRQ); + power_and_clock(); + /* Read out the masked interrupt status */ flags = ti_lib_uart_int_status(UART0_BASE, true); diff --git a/cpu/cc26xx/dev/cc26xx-uart.h b/cpu/cc26xx/dev/cc26xx-uart.h index 4647b9339..8ff04502f 100644 --- a/cpu/cc26xx/dev/cc26xx-uart.h +++ b/cpu/cc26xx/dev/cc26xx-uart.h @@ -63,9 +63,32 @@ void cc26xx_uart_write_byte(uint8_t b); /** * \brief Assigns a callback to be called when the UART receives a byte * \param input A pointer to the function + * + * If \e input is NULL, the UART driver will assume that RX functionality is + * not required and it will be disabled. It will also disable the module's + * clocks under sleep and deep sleep and allow the SERIAL PD to be powered off. + * + * If \e input is not NULL, the UART driver will assume that RX is in fact + * required and it will be enabled. The module's clocks will be enabled under + * sleep and deep sleep and the driver will not allow the SERIAL PD to turn + * off during deep sleep, so that the UART can still receive bytes. + * + * \note This has a significant impact on overall energy consumption, so you + * should only enabled UART RX input when it's actually required. */ void cc26xx_uart_set_input(int (*input)(unsigned char c)); +/** + * \brief Returns the UART busy status + * \return UART_IDLE or UART_BUSY + * + * ti_lib_uart_busy() will access UART registers. It is our responsibility + * to first make sure the UART is accessible before calling it. Hence this + * wrapper. + * + * Return values are defined in CC26xxware's uart.h + */ +uint8_t cc26xx_uart_busy(void); /** @} */ /*---------------------------------------------------------------------------*/ #endif /* CC26XX_UART_H_ */ diff --git a/cpu/cc26xx/putchar.c b/cpu/cc26xx/putchar.c index 0f91deea5..7cbd1901a 100644 --- a/cpu/cc26xx/putchar.c +++ b/cpu/cc26xx/putchar.c @@ -29,6 +29,7 @@ */ /*---------------------------------------------------------------------------*/ #include "cc26xx-uart.h" +#include "ti-lib.h" #include /*---------------------------------------------------------------------------*/ @@ -47,9 +48,16 @@ puts(const char *str) return 0; } for(i = 0; i < strlen(str); i++) { - putchar(str[i]); + cc26xx_uart_write_byte(str[i]); } - putchar('\n'); + cc26xx_uart_write_byte('\n'); + + /* + * Wait for the line to go out. This is to prevent garbage when used between + * UART on/off cycles + */ + while(cc26xx_uart_busy() == UART_BUSY); + return i; } /*---------------------------------------------------------------------------*/ @@ -62,9 +70,16 @@ dbg_send_bytes(const unsigned char *s, unsigned int len) if(i >= len) { break; } - putchar(*s++); + cc26xx_uart_write_byte(*s++); i++; } + + /* + * Wait for the buffer to go out. This is to prevent garbage when used + * between UART on/off cycles + */ + while(cc26xx_uart_busy() == UART_BUSY); + return i; } /*---------------------------------------------------------------------------*/ From 019143226bcf5a3754b794cfb028ef3b11400eb3 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 17:04:44 +0100 Subject: [PATCH 34/38] Adjust main: * Re-order OSC, VIMS cache, I/O latch configuration instructions * Don't automatically enable UART RX: Let the example decide this --- platform/srf06-cc26xx/contiki-main.c | 55 +++++++++------------------- 1 file changed, 18 insertions(+), 37 deletions(-) diff --git a/platform/srf06-cc26xx/contiki-main.c b/platform/srf06-cc26xx/contiki-main.c index f2f6bbe21..9df0aac7b 100644 --- a/platform/srf06-cc26xx/contiki-main.c +++ b/platform/srf06-cc26xx/contiki-main.c @@ -46,6 +46,7 @@ #include "lpm.h" #include "gpio-interrupt.h" #include "dev/watchdog.h" +#include "dev/oscillators.h" #include "ieee-addr.h" #include "vims.h" #include "cc26xx-model.h" @@ -119,23 +120,6 @@ set_rf_params(void) #endif } /*---------------------------------------------------------------------------*/ -static void -select_lf_xosc(void) -{ - ti_lib_osc_interface_enable(); - - /* Make sure the SMPH clock within AUX is enabled */ - ti_lib_aux_wuc_clock_enable(AUX_WUC_SMPH_CLOCK); - while(ti_lib_aux_wuc_clock_status(AUX_WUC_SMPH_CLOCK) != AUX_WUC_CLOCK_READY); - - /* Switch LF clock source to the LF RCOSC if required */ - if(ti_lib_osc_clock_source_get(OSC_SRC_CLK_LF) != OSC_XOSC_LF) { - ti_lib_osc_clock_source_set(OSC_SRC_CLK_LF, OSC_XOSC_LF); - } - - ti_lib_osc_interface_disable(); -} -/*---------------------------------------------------------------------------*/ /** * \brief Main function for CC26xx-based platforms * @@ -144,41 +128,39 @@ select_lf_xosc(void) int main(void) { + /* Enable flash cache and prefetch. */ + ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_ENABLED); + ti_lib_vims_configure(VIMS_BASE, true, true); + + ti_lib_int_master_disable(); + /* Set the LF XOSC as the LF system clock source */ - select_lf_xosc(); - - /* - * Make sure to open the latches - this will be important when returning - * from shutdown - */ - ti_lib_pwr_ctrl_io_freeze_disable(); - - /* Use DCDC instead of LDO to save current */ - ti_lib_pwr_ctrl_source_set(PWRCTRL_PWRSRC_DCDC); + oscillators_select_lf_xosc(); lpm_init(); board_init(); - /* Enable flash cache and prefetch. */ - ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_ENABLED); - ti_lib_vims_configure(VIMS_BASE, true, true); - gpio_interrupt_init(); - /* Clock must always be enabled for the semaphore module */ - HWREG(AUX_WUC_BASE + AUX_WUC_O_MODCLKEN1) = AUX_WUC_MODCLKEN1_SMPH; - leds_init(); + /* + * Disable I/O pad sleep mode and open I/O latches in the AON IOC interface + * This is only relevant when returning from shutdown (which is what froze + * latches in the first place. Before doing these things though, we should + * allow software to first regain control of pins + */ + ti_lib_pwr_ctrl_io_freeze_disable(); + fade(LEDS_RED); + ti_lib_int_master_enable(); + cc26xx_rtc_init(); clock_init(); rtimer_init(); - board_init(); - watchdog_init(); process_init(); @@ -187,7 +169,6 @@ main(void) /* Character I/O Initialisation */ #if CC26XX_UART_CONF_ENABLE cc26xx_uart_init(); - cc26xx_uart_set_input(serial_line_input_byte); #endif serial_line_init(); From 7e00eeb76aeae5efe1fe45e6e9ba99d9cb73e908 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 17:05:46 +0100 Subject: [PATCH 35/38] Achieve lowest consumption with the CC26xx demo: This changes the CC26xx simple demo so that a devices running this firmware will achieve the lowest possible energy consumption without requiring any changes to the example --- examples/cc26xx/README.md | 2 -- examples/cc26xx/cc26xx-demo.c | 10 ---------- 2 files changed, 12 deletions(-) diff --git a/examples/cc26xx/README.md b/examples/cc26xx/README.md index bd1be685b..411bc9407 100644 --- a/examples/cc26xx/README.md +++ b/examples/cc26xx/README.md @@ -6,8 +6,6 @@ boards. More specifically, the example demonstrates: * How to take sensor readings * How to use buttons and the reed relay (triggered by holding a magnet near S3 on the SensorTag). -* How to keep a power domain powered and a peripheral clocked under low power - operation * How to send out BLE advertisements. The device will periodically send out BLE beacons with the platform name as payload. Those beacons/BLE ADV packets can be captured with any BLE capable device. Two such applications for iOS are the diff --git a/examples/cc26xx/cc26xx-demo.c b/examples/cc26xx/cc26xx-demo.c index de5ce5810..b7bf56132 100644 --- a/examples/cc26xx/cc26xx-demo.c +++ b/examples/cc26xx/cc26xx-demo.c @@ -77,12 +77,6 @@ * - The example also shows how to retrieve the duration of a * button press (in ticks). The driver will generate a * sensors_changed event upon button release - * - UART : Receiving an entire line of text over UART (ending - * in \\r) will cause CC26XX_DEMO_LEDS_SERIAL_IN to toggle - * This also demonstrates how a code module can influence - * low-power operation: In this example we keep the UART on - * and capable to RX even with the chip in deep sleep. - * see keep_uart_on() and the UART driver * - Reed Relay : Will toggle the sensortag buzzer on/off * * @{ @@ -384,8 +378,6 @@ PROCESS_THREAD(cc26xx_demo_process, ev, data) get_sync_sensor_readings(); init_sensor_readings(); - keep_uart_on(); - while(1) { PROCESS_YIELD(); @@ -440,8 +432,6 @@ PROCESS_THREAD(cc26xx_demo_process, ev, data) button_select_sensor.value(BUTTON_SENSOR_VALUE_DURATION)); #endif } - } else if(ev == serial_line_event_message) { - leds_toggle(CC26XX_DEMO_LEDS_SERIAL_IN); } } From 78d04f812b570320e3a920ac260db2e23b27353b Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 15:48:44 +0100 Subject: [PATCH 36/38] Fix typo in macro --- cpu/cc26xx/ti-lib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu/cc26xx/ti-lib.h b/cpu/cc26xx/ti-lib.h index 899f4a4d6..61ad146fe 100644 --- a/cpu/cc26xx/ti-lib.h +++ b/cpu/cc26xx/ti-lib.h @@ -148,7 +148,7 @@ #include "driverlib/aux_wuc.h" #define ti_lib_aux_wuc_clock_enable(...) AUXWUCClockEnable(__VA_ARGS__) -#define ti_lib_aux_wuc_clock_disble(...) AUXWUCClockDisable(__VA_ARGS__) +#define ti_lib_aux_wuc_clock_disable(...) AUXWUCClockDisable(__VA_ARGS__) #define ti_lib_aux_wuc_clock_status(...) AUXWUCClockStatus(__VA_ARGS__) #define ti_lib_aux_wuc_clock_freq_req(...) AUXWUCClockFreqReq(__VA_ARGS__) #define ti_lib_aux_wuc_power_ctrl(...) AUXWUCPowerCtrl(__VA_ARGS__) From 7ae3cd49ba78d9ca7497c3a68677a48c4ec07496 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 15 May 2015 11:38:20 +0100 Subject: [PATCH 37/38] Make sure SSI0 is powered and clocked before accessing it * Fail all SSI0 operations if the module is not powered and clocked * Make sure SERIAL is powered before trying to enable run mode clock --- platform/srf06-cc26xx/sensortag/board-spi.c | 38 ++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/platform/srf06-cc26xx/sensortag/board-spi.c b/platform/srf06-cc26xx/sensortag/board-spi.c index 7644a5c3d..640f8266c 100644 --- a/platform/srf06-cc26xx/sensortag/board-spi.c +++ b/platform/srf06-cc26xx/sensortag/board-spi.c @@ -40,12 +40,35 @@ #include "ti-lib.h" #include "board-spi.h" #include "board.h" + +#include /*---------------------------------------------------------------------------*/ #define CPU_FREQ 48000000ul /*---------------------------------------------------------------------------*/ +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_SSICLKGR) & PRCM_SSICLKGR_CLK_EN_SSI0)) { + return false; + } + + return true; +} +/*---------------------------------------------------------------------------*/ int board_spi_write(const uint8_t *buf, size_t len) { + if(accessible() == false) { + return 0; + } + while(len > 0) { uint32_t ul; @@ -61,6 +84,10 @@ board_spi_write(const uint8_t *buf, size_t len) int board_spi_read(uint8_t *buf, size_t len) { + if(accessible() == false) { + return 0; + } + while(len > 0) { uint32_t ul; @@ -79,6 +106,10 @@ board_spi_read(uint8_t *buf, size_t len) void board_spi_flush() { + if(accessible() == false) { + return; + } + uint32_t ul; while(ti_lib_rom_ssi_data_get_non_blocking(SSI0_BASE, &ul)); } @@ -88,7 +119,12 @@ board_spi_open(uint32_t bit_rate, uint32_t clk_pin) { uint32_t buf; - /* SPI power */ + /* 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 clock in active mode */ ti_lib_rom_prcm_peripheral_run_enable(PRCM_PERIPH_SSI0); ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()); From 1cf37e0c1a49078ef2e926b8b9ffb2b537df5772 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 15 May 2015 23:36:54 +0100 Subject: [PATCH 38/38] Tidy-up code style --- cpu/cc26xx/dev/oscillators.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpu/cc26xx/dev/oscillators.c b/cpu/cc26xx/dev/oscillators.c index 156ee5dd1..06f97a92a 100644 --- a/cpu/cc26xx/dev/oscillators.c +++ b/cpu/cc26xx/dev/oscillators.c @@ -81,7 +81,7 @@ oscillators_select_lf_xosc(void) ti_lib_osc_clock_source_set(OSC_SRC_CLK_LF, OSC_XOSC_LF); /* Wait for LF clock source to become XOSC_LF */ - while(ti_lib_osc_clock_source_get(OSC_SRC_CLK_LF) != OSC_XOSC_LF) ; + while(ti_lib_osc_clock_source_get(OSC_SRC_CLK_LF) != OSC_XOSC_LF); /* Disable the LF clock qualifiers */ ti_lib_ddi_16_bit_field_write(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_CTL0, @@ -106,7 +106,7 @@ oscillators_select_lf_rcosc(void) ti_lib_osc_clock_source_set(OSC_SRC_CLK_LF, OSC_RCOSC_LF); /* Wait for LF clock source to become XOSC_LF */ - while(ti_lib_osc_clock_source_get(OSC_SRC_CLK_LF) != OSC_RCOSC_LF) ; + while(ti_lib_osc_clock_source_get(OSC_SRC_CLK_LF) != OSC_RCOSC_LF); } /* Restore the SMPH clock and disable the OSC interface */