From 268330c7e5d36d6fec61bcca4e88d80e6140be03 Mon Sep 17 00:00:00 2001 From: Antonio Lignan Date: Tue, 13 Sep 2016 18:30:38 +0200 Subject: [PATCH] Zoul: power management driver for the RE-Mote revision B --- examples/zolertia/zoul/rev-b/Makefile | 14 + examples/zolertia/zoul/rev-b/Makefile.target | 1 + examples/zolertia/zoul/rev-b/project-conf.h | 54 ++++ .../zolertia/zoul/rev-b/test-power-mgmt.c | 244 +++++++++++++++ platform/zoul/remote-reva/power-mgmt.c | 2 +- platform/zoul/remote-reva/power-mgmt.h | 2 +- .../zoul/remote-revb/Makefile.remote-revb | 2 +- platform/zoul/remote-revb/power-mgmt.c | 291 ++++++++++++++++++ platform/zoul/remote-revb/power-mgmt.h | 194 ++++++++++++ 9 files changed, 801 insertions(+), 3 deletions(-) create mode 100644 examples/zolertia/zoul/rev-b/Makefile create mode 100644 examples/zolertia/zoul/rev-b/Makefile.target create mode 100644 examples/zolertia/zoul/rev-b/project-conf.h create mode 100644 examples/zolertia/zoul/rev-b/test-power-mgmt.c create mode 100644 platform/zoul/remote-revb/power-mgmt.c create mode 100644 platform/zoul/remote-revb/power-mgmt.h diff --git a/examples/zolertia/zoul/rev-b/Makefile b/examples/zolertia/zoul/rev-b/Makefile new file mode 100644 index 000000000..ddb6bda4b --- /dev/null +++ b/examples/zolertia/zoul/rev-b/Makefile @@ -0,0 +1,14 @@ +DEFINES+=PROJECT_CONF_H=\"project-conf.h\" + +CONTIKI_PROJECT = test-power-mgmt + +BOARD ?= remote-revb + +# Works in Linux and probably on OSX too (RTCC example) +CFLAGS = -DDATE="\"`date +"%02u %02d %02m %02y %02H %02M %02S"`\"" + +all: $(CONTIKI_PROJECT) + +CONTIKI = ../../../.. +CONTIKI_WITH_RIME = 1 +include $(CONTIKI)/Makefile.include diff --git a/examples/zolertia/zoul/rev-b/Makefile.target b/examples/zolertia/zoul/rev-b/Makefile.target new file mode 100644 index 000000000..75430a6e4 --- /dev/null +++ b/examples/zolertia/zoul/rev-b/Makefile.target @@ -0,0 +1 @@ +TARGET = zoul diff --git a/examples/zolertia/zoul/rev-b/project-conf.h b/examples/zolertia/zoul/rev-b/project-conf.h new file mode 100644 index 000000000..39e389032 --- /dev/null +++ b/examples/zolertia/zoul/rev-b/project-conf.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016, Zolertia + * 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 remote-examples + * @{ + * + * \defgroup remote-power-mgmt-revb-test RE-Mote rev.B power management test + * + * Test the RE-Mote revision B power management implementation + * @{ + * + * \file + * Project specific configuration defines for the basic RE-Mote examples + */ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ + +#define BROADCAST_CHANNEL 129 +#define NETSTACK_CONF_RDC nullrdc_driver + +#endif /* PROJECT_CONF_H_ */ + +/** + * @} + * @} + */ diff --git a/examples/zolertia/zoul/rev-b/test-power-mgmt.c b/examples/zolertia/zoul/rev-b/test-power-mgmt.c new file mode 100644 index 000000000..fb83c1e6f --- /dev/null +++ b/examples/zolertia/zoul/rev-b/test-power-mgmt.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2016, Zolertia - http://www.zolertia.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 Institute 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 INSTITUTE 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 INSTITUTE 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 remote-power-mgmt-revb-test + * @{ + * + * Test the RE-Mote's power management features, shutdown mode and battery + * management. + * + * @{ + * + * \author + * Aitor Mejias + * Antonio Lignan + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "cpu.h" +#include "sys/process.h" +#include "dev/leds.h" +#include "dev/sys-ctrl.h" +#include "lib/list.h" +#include "power-mgmt.h" +#include "rtcc.h" +#include +#include +#include +/*---------------------------------------------------------------------------*/ +static struct etimer et; +/*---------------------------------------------------------------------------*/ +/* RE-Mote revision B, low-power PIC version */ +#define PM_EXPECTED_VERSION 0x20 +/*---------------------------------------------------------------------------*/ +#ifndef DATE +#define DATE "Unknown" +#endif +/*---------------------------------------------------------------------------*/ +#define TEST_LEDS_FAIL leds_off(LEDS_ALL); \ + leds_on(LEDS_RED); \ + PROCESS_EXIT(); +/*---------------------------------------------------------------------------*/ +#define TEST_ALARM_SECOND 15 +/*---------------------------------------------------------------------------*/ +PROCESS(test_remote_pm, "RE-Mote rev.B Power Management Test"); +AUTOSTART_PROCESSES(&test_remote_pm); +/*---------------------------------------------------------------------------*/ +static uint8_t rtc_buffer[sizeof(simple_td_map)]; +static simple_td_map *simple_td = (simple_td_map *)rtc_buffer; +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(test_remote_pm, ev, data) +{ + static uint8_t aux; + static uint16_t voltage; + static uint32_t cycles; + static char *next; + + PROCESS_BEGIN(); + + aux = 0; + cycles = 0; + + /* Initialize the power management block and signal the low-power PIC */ + if(pm_enable() != PM_SUCCESS) { + printf("PM: Failed to initialize\n"); + TEST_LEDS_FAIL; + } + + printf("PM: enabled!\n"); + + /* Retrieve the firmware version and check expected */ + if((pm_get_fw_ver(&aux) == PM_ERROR) || + (aux != PM_EXPECTED_VERSION)) { + printf("PM: unexpected version 0x%02X\n", aux); + TEST_LEDS_FAIL; + } + + printf("PM: firmware version 0x%02X OK\n", aux); + + /* Read the battery voltage level */ + if(pm_get_voltage(&voltage) != PM_SUCCESS) { + printf("PM: error retrieving voltage\n"); + TEST_LEDS_FAIL; + } + + printf("PM: Voltage (raw) = %u\n", voltage); + + /* Note: if running the following test while the RE-Mote is powered over USB + * will show the command execution, but it will not put the board in shutdown + * mode. If powering the RE-Mote with an external battery the shutdown mode + * will operate as intended, and the RE-Mote will restart and run the tests + * from the start after waking-up off the shutdown mode. + * + * The first test shows how to use the "soft" shutdown mode, being the low + * power PIC the one counting cycles and restarting the system off shutdown + * mode. + * + * Each restart cycle is tracked by the low-power PIC, we can use this value + * to determine how many times we have entered shutdown mode, thus choosing + * a specific configuration or behaviour. For the next examples we are going + * to trigger a "soft" mode each even number, and "hard" if odd. + */ + + cycles = pm_get_num_cycles(); + printf("PM: cycle number %lu\n", cycles); + + if((cycles % 2) == 0) { + /* Set the timeout */ + if(pm_set_timeout(PM_SOFT_SHTDN_5_7_SEC) != PM_SUCCESS) { + printf("PM: error setting timeout for soft shutdown mode\n"); + TEST_LEDS_FAIL; + } + + printf("PM: Soft shutdown, timeout set to %lu\n", pm_get_timeout()); + + leds_off(LEDS_ALL); + leds_on(LEDS_PURPLE); + + /* Wait just enough to be able to check the LED result */ + etimer_set(&et, CLOCK_SECOND * 3); + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); + + /* Enter soft shut*/ + if(pm_shutdown_now(PM_SOFT_SLEEP_CONFIG) == PM_SUCCESS) { + printf("PM: Good night!\n"); + } else { + printf("PM: error shutting down the system!\n"); + TEST_LEDS_FAIL; + } + + /* Exit and wait the next cycle */ + PROCESS_EXIT(); + } + + /* Configure the RTCC to schedule a "hard" restart of the shutdown mode, + * waking up from a RTCC interrupt to the low-power PIC + */ + printf("PM: System date: %s\n", DATE); + if(strcmp("Unknown", DATE) == 0) { + printf("PM: could not retrieve date from system\n"); + TEST_LEDS_FAIL; + } + + /* Configure RTC and return structure with all parameters */ + rtcc_init(); + + /* Configure the RTC with the current values */ + simple_td->weekdays = (uint8_t)strtol(DATE, &next, 10); + simple_td->day = (uint8_t)strtol(next, &next, 10); + simple_td->months = (uint8_t)strtol(next, &next, 10); + simple_td->years = (uint8_t)strtol(next, &next, 10); + simple_td->hours = (uint8_t)strtol(next, &next, 10); + simple_td->minutes = (uint8_t)strtol(next, &next, 10); + simple_td->seconds = (uint8_t)strtol(next, NULL, 10); + + simple_td->miliseconds = 0; + simple_td->mode = RTCC_24H_MODE; + simple_td->century = RTCC_CENTURY_20XX; + + if(rtcc_set_time_date(simple_td) == AB08_ERROR) { + printf("PM: Time and date configuration failed\n"); + TEST_LEDS_FAIL; + } else { + if(rtcc_get_time_date(simple_td) == AB08_ERROR) { + printf("PM: Couldn't read time and date\n"); + TEST_LEDS_FAIL; + } + } + + printf("PM: Configured time: "); + rtcc_print(RTCC_PRINT_DATE_DEC); + + /* Configure the RTCC to trigger an alarm tick */ + printf("\nPM: Setting an alarm to tick in %u seconds\n", TEST_ALARM_SECOND); + if(rtcc_date_increment_seconds(simple_td, TEST_ALARM_SECOND) == AB08_ERROR) { + printf("PM: could not increment the next alarm date\n"); + TEST_LEDS_FAIL; + } + + /* Set the timeout to zero to avoid the PIC being awake while waiting for the + * RTCC system to kick-in + */ + if(pm_set_timeout(0x00) != PM_SUCCESS) { + printf("PM: couldn't clear the shutdown period\n"); + TEST_LEDS_FAIL; + } + + /* We use the RTCC_REPEAT_DAY as we want the RTCC to match the given date */ + if(rtcc_set_alarm_time_date(simple_td, RTCC_ALARM_ON, RTCC_REPEAT_DAY, + RTCC_TRIGGER_INT2) == AB08_ERROR) { + printf("PM: couldn't set the alarm\n"); + TEST_LEDS_FAIL; + } + + printf("PM: Alarm set to match: "); + rtcc_print(RTCC_PRINT_ALARM_DEC); + + leds_off(LEDS_ALL); + leds_on(LEDS_BLUE); + + etimer_set(&et, CLOCK_SECOND * 3); + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); + + if(pm_shutdown_now(PM_HARD_SLEEP_CONFIG) == PM_SUCCESS) { + printf("PM: good night!\n"); + } else { + printf("PM: error shutting down the system!\n"); + TEST_LEDS_FAIL; + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +/** +* @} +* @} +*/ diff --git a/platform/zoul/remote-reva/power-mgmt.c b/platform/zoul/remote-reva/power-mgmt.c index b0a09100b..43a4f84c7 100644 --- a/platform/zoul/remote-reva/power-mgmt.c +++ b/platform/zoul/remote-reva/power-mgmt.c @@ -29,7 +29,7 @@ */ /*---------------------------------------------------------------------------*/ /** - * \addtogroup remote-power-mgmt + * \addtogroup remote-power-mgmt-reva * @{ * * RE-Mote power management and shutdown mode diff --git a/platform/zoul/remote-reva/power-mgmt.h b/platform/zoul/remote-reva/power-mgmt.h index 0504f9dba..1f765eb36 100644 --- a/platform/zoul/remote-reva/power-mgmt.h +++ b/platform/zoul/remote-reva/power-mgmt.h @@ -32,7 +32,7 @@ * \addtogroup remote * @{ * - * \defgroup remote-power-mgmt RE-Mote power management driver + * \defgroup remote-power-mgmt-reva RE-Mote power management driver * * The power management module is composed by a nano-watt (gating) timer and an * ultra-low power MCU, driving the RE-Mote power supply when connected to an diff --git a/platform/zoul/remote-revb/Makefile.remote-revb b/platform/zoul/remote-revb/Makefile.remote-revb index 34f526c65..ce4070ecf 100644 --- a/platform/zoul/remote-revb/Makefile.remote-revb +++ b/platform/zoul/remote-revb/Makefile.remote-revb @@ -1,2 +1,2 @@ MOTELIST_ZOLERTIA = remote -BOARD_SOURCEFILES += board.c antenna-sw.c rtcc.c leds-res-arch.c +BOARD_SOURCEFILES += board.c antenna-sw.c rtcc.c leds-res-arch.c power-mgmt.c diff --git a/platform/zoul/remote-revb/power-mgmt.c b/platform/zoul/remote-revb/power-mgmt.c new file mode 100644 index 000000000..0de8a8903 --- /dev/null +++ b/platform/zoul/remote-revb/power-mgmt.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2016, Zolertia - http://www.zolertia.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 Institute 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 INSTITUTE 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 INSTITUTE 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 remote-power-mgmt-revb + * @{ + * RE-Mote power management functions. + * + * @{ + * + * \author + * Aitor Mejias + * Antonio Lignan + */ +/* -------------------------------------------------------------------------- */ +#include +#include +#include "contiki.h" +#include "dev/gpio.h" +#include "sys/rtimer.h" +#include "power-mgmt.h" +#include "dev/i2c.h" +/* -------------------------------------------------------------------------- */ +#define DEBUG 0 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif +/* -------------------------------------------------------------------------- */ +#define PM_ENABLE_LINE_SET GPIO_SET_PIN(PM_ENABLE_PORT_BASE, \ + PM_ENABLE_PIN_MASK) +#define PM_ENABLE_LINE_CLR GPIO_CLR_PIN(PM_ENABLE_PORT_BASE, \ + PM_ENABLE_PIN_MASK) +#define PM_ENABLE_AS_OUTPUT GPIO_SET_OUTPUT(PM_ENABLE_PORT_BASE, \ + PM_ENABLE_PIN_MASK) +#define PM_ENABLE_LINE_CMD PM_ENABLE_LINE_SET; \ + clock_delay_usec(100); + +/* -------------------------------------------------------------------------- */ +#define PM_NUMBITS(X) (1 << ((X)-1)) +/* -------------------------------------------------------------------------- */ +static uint8_t initialized = 0; +static uint8_t lbuf[5]; +/* -------------------------------------------------------------------------- */ +int8_t +pm_enable(void) +{ + /* Set as output/low to set IDLE state */ + GPIO_SOFTWARE_CONTROL(PM_ENABLE_PORT_BASE, PM_ENABLE_PIN_MASK); + PM_ENABLE_AS_OUTPUT; + + i2c_init(I2C_SDA_PORT, I2C_SDA_PIN, I2C_SCL_PORT, I2C_SCL_PIN, + I2C_SCL_NORMAL_BUS_SPEED); + initialized = 1; + return PM_SUCCESS; +} +/* -------------------------------------------------------------------------- */ +static int +pm_write_byte(uint8_t reg, uint8_t val) +{ + if(!initialized) { + return PM_ERROR; + } + lbuf[0] = reg; + lbuf[1] = val; + PM_ENABLE_LINE_CMD; + + if(i2c_burst_send(PWR_MNGMT_ADDR, lbuf, 2) == I2C_MASTER_ERR_NONE) { + PM_ENABLE_LINE_CLR; + return PM_SUCCESS; + } + PM_ENABLE_LINE_CLR; + return PM_ERROR; +} +/*---------------------------------------------------------------------------*/ +static int +pm_read_byte(uint8_t reg, uint8_t *val, uint8_t len) +{ + /* Detect valid register parameter */ + if((reg < PM_VBAT) || (reg >= PM_MAX_COMMANDS) || (!len)) { + PRINTF("PM: invalid settings/not initialized\n"); + return PM_ERROR; + } + + PM_ENABLE_LINE_CMD; + + if(i2c_single_send(PWR_MNGMT_ADDR, reg) == I2C_MASTER_ERR_NONE) { + if(i2c_burst_receive(PWR_MNGMT_ADDR, val, len) == I2C_MASTER_ERR_NONE) { + printf("PM: Data 0x%02X\n", *val); + PM_ENABLE_LINE_CLR; + return PM_SUCCESS; + } + } + PRINTF("PM: Error reading the registers\n"); + PM_ENABLE_LINE_CLR; + return PM_ERROR; +} +/* -------------------------------------------------------------------------- */ +int8_t +pm_reset_system(void) +{ + if(!initialized) { + return PM_ERROR; + } + + /* Reset the low-power PIC and the whole board as a bonus */ + lbuf[0] = PM_CMD_RST_HARD; + lbuf[1] = 1; + PM_ENABLE_LINE_CMD; + + if(i2c_burst_send(PWR_MNGMT_ADDR, lbuf, 2) == I2C_MASTER_ERR_NONE) { + clock_delay_usec(1000); + PM_ENABLE_LINE_CLR; + return PM_SUCCESS; + } + PM_ENABLE_LINE_CLR; + return PM_ERROR; +} +/* -------------------------------------------------------------------------- */ +int8_t +pm_set_timeout(uint32_t time) +{ + if(!initialized) { + return PM_ERROR; + } + + if(time > PM_SOFT_SHTDN_28_DAYS) { + PRINTF("PM: maximum timeout is %u\n", (uint32_t)PM_SOFT_SHTDN_28_DAYS); + return PM_ERROR; + } + + lbuf[0] = PM_SOFT_TIME; + lbuf[1] = (uint8_t)(time >> 24); + lbuf[2] = (uint8_t)(time >> 16) & 0xFF; + lbuf[3] = (uint8_t)(time >> 8) & 0xFF; + lbuf[4] = (uint8_t)(time & 0xFF); + PRINTF("PM: Timeout 0x%02x%02x%02x%02x\n", lbuf[1], lbuf[2], lbuf[3], lbuf[4]); + + PM_ENABLE_LINE_CMD; + + if(i2c_burst_send(PWR_MNGMT_ADDR, lbuf, 5) == I2C_MASTER_ERR_NONE) { + PM_ENABLE_LINE_CLR; + return PM_SUCCESS; + } + + PRINTF("PM: error setting the timeout\n"); + PM_ENABLE_LINE_CLR; + return PM_ERROR; +} +/* -------------------------------------------------------------------------- */ +uint32_t +pm_get_timeout(void) +{ + uint32_t retval = 0; + PM_ENABLE_LINE_CMD; + + if(i2c_single_send(PWR_MNGMT_ADDR, PM_SOFT_TIME) == I2C_MASTER_ERR_NONE) { + if(i2c_burst_receive(PWR_MNGMT_ADDR, lbuf, 4) == I2C_MASTER_ERR_NONE) { + retval |= ((uint32_t)lbuf[0] << 24); + retval |= ((uint32_t)lbuf[1] << 16); + retval |= ((uint32_t)lbuf[2] << 8); + retval |= lbuf[3]; + } + } + + PM_ENABLE_LINE_CLR; + PRINTF("PM: Timeout 0x%02x%02x%02x%02x\n", lbuf[0], lbuf[1], lbuf[2], lbuf[3]); + + retval *= PM_SOFT_SHTDN_INTERVAL; + retval /= 100; + return retval; +} +/* -------------------------------------------------------------------------- */ +uint32_t +pm_get_num_cycles(void) +{ + uint32_t retval = 0; + PM_ENABLE_LINE_CMD; + + if(i2c_single_send(PWR_MNGMT_ADDR, PM_GET_NUM_CYCLES) == I2C_MASTER_ERR_NONE) { + if(i2c_burst_receive(PWR_MNGMT_ADDR, lbuf, 4) == I2C_MASTER_ERR_NONE) { + retval |= ((uint32_t)lbuf[0] << 24); + retval |= ((uint32_t)lbuf[1] << 16); + retval |= ((uint32_t)lbuf[2] << 8); + retval |= lbuf[3]; + } + } + PM_ENABLE_LINE_CLR; + PRINTF("PM: Sleep cycles: 0x%02x%02x%02x%02x\n", lbuf[0], lbuf[1], lbuf[2], + lbuf[3]); + return retval; +} +/* -------------------------------------------------------------------------- */ +int8_t +pm_shutdown_now(uint8_t type) +{ + if(!initialized) { + PRINTF("PM: Not initialized\n"); + return PM_ERROR; + } + + if((type != PM_HARD_SLEEP_CONFIG) && (type != PM_SOFT_SLEEP_CONFIG)) { + PRINTF("PM: Invalid shutdown mode type\n"); + return PM_ERROR; + } + + PM_ENABLE_LINE_CMD; + + if(type == PM_HARD_SLEEP_CONFIG) { + pm_write_byte(PM_HARD_SLEEP_CONFIG, PM_ENABLE); + PM_ENABLE_LINE_CLR; + return PM_SUCCESS; + } + + /* Soft sleep */ + pm_write_byte(PM_SOFT_SLEEP_CONFIG, PM_ENABLE); + PM_ENABLE_LINE_CLR; + return PM_SUCCESS; +} +/* -------------------------------------------------------------------------- */ +int8_t +pm_get_voltage(uint16_t *state) +{ + if(!initialized) { + return PM_ERROR; + } + + PM_ENABLE_LINE_CMD; + if(i2c_single_send(PWR_MNGMT_ADDR, PM_GET_VDD) == I2C_MASTER_ERR_NONE) { + /* Read two bytes only */ + if(i2c_burst_receive(PWR_MNGMT_ADDR, lbuf, 2) == I2C_MASTER_ERR_NONE) { + *state = (uint16_t)lbuf[0] << 8; + *state += lbuf[1]; + + /* Delay required for the command to finish */ + clock_delay_usec(3000); + + PRINTF("PM: Voltage %u [%u][%u]\n", *state, lbuf[0], lbuf[1]); + PM_ENABLE_LINE_CLR; + return PM_SUCCESS; + } + } + PM_ENABLE_LINE_CLR; + return PM_ERROR; +} +/* -------------------------------------------------------------------------- */ +int8_t +pm_get_fw_ver(uint8_t *fwver) +{ + if((!initialized) || (fwver == NULL)) { + return PM_ERROR; + } + + if(pm_read_byte(PM_FW_VERSION, fwver, 1) == PM_SUCCESS) { + return PM_SUCCESS; + } + return PM_ERROR; +} +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/platform/zoul/remote-revb/power-mgmt.h b/platform/zoul/remote-revb/power-mgmt.h new file mode 100644 index 000000000..de4ece3cd --- /dev/null +++ b/platform/zoul/remote-revb/power-mgmt.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2016, Zolertia - http://www.zolertia.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 Institute 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 INSTITUTE 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 INSTITUTE 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 remote + * @{ + * + * \defgroup remote-power-mgmt-revb RE-Mote power management driver + * + * Driver control the power management of the RE-Mote rev B platform. This + * driver is an I2C communication with external power manager chip + * that controls few functions of the board. Note the driver will work if + * powered both over USB and external battery, but the shutdown mode will only + * be actually working with external battery + * + * @{ + * + * \file + * Header file for the RE-Mote Power Management driver + * + * \ingroup remote-power-mgmt-revb + * @{ + */ +/* -------------------------------------------------------------------------- */ +#ifndef POWER_MGMT_H_ +#define POWER_MGMT_H_ +#include "dev/gpio.h" +/* -------------------------------------------------------------------------- */ +/** + * \name Power management controller + * @{ + */ +/* -------------------------------------------------------------------------- */ +#define PWR_MNGMT_ADDR 0x7F /**< Power Management slave address */ +/** @} */ +/* -------------------------------------------------------------------------- */ +#define PM_ENABLE_PORT_BASE GPIO_PORT_TO_BASE(PM_ENABLE_PORT) +#define PM_ENABLE_PIN_MASK GPIO_PIN_MASK(PM_ENABLE_PIN) +/* -------------------------------------------------------------------------- */ +/** \name Power Management return values + * @{ + */ +#define PM_SUCCESS 0 +#define PM_ERROR (-1) +/** @} */ +/* -------------------------------------------------------------------------- */ +/** \name Power Management Registers + * @{ + */ +typedef enum { + PM_VBAT = 34, /* Connect/Disconnect battery, it can be "1" (ON) or "0" (OFF) */ + PM_CURRENT_CHARGE, /* register with pm_charge_current_states options */ + PM_CHARGE_ENABLE, /* Enable the current charge mode on the battery */ + PM_SYSOFF, /* Control SYSOFF pin on the battery charger */ + PM_EXTERNAL_REFERENCE, /* Use reference fot vdd. 0: internal 1:External */ + PM_HARD_SLEEP_CONFIG, /* Disconnect Battery until event ext2 on RTCC. */ + PM_SOFT_SLEEP_CONFIG, /* Disconnect Batt without RTCC until PM_SOFT_TIME val */ + PM_SOFT_TIME, /* Time Out used by system time on hard/soft config */ + PM_GET_VDD, /* Command to get the current VDD on the system */ + PM_FW_VERSION, /* Get the Firmware version */ + PM_GET_NUM_CYCLES, /* Obtain the current sleep cycles at moment */ + PM_CMD_RST_HARD, /* Disconnect and reconnect the battery */ + PM_MAX_COMMANDS /* Maximum register commands. Register not valid */ +} pm_registers_t; +/** @} */ +/* -------------------------------------------------------------------------- */ +/** \name Power Management status and masks + * @{ + */ +#define PM_ENABLE 1 /* Pin status on */ +#define PM_DISABLE 0 /* Pin status off */ + +#define BATT_CHARGED_VAL 0 +#define BATT_UNCHARGED_VAL 1 + +#define PM_REFERENCE_INTERNAL 0 +#define PM_REFERENCE_EXTERNAL 1 + +/* The PIC interval time is 57.20ms given in PM_SOFT_SHTDN_INTERVAL, to set a + * timeout period (using the soft shutdown mode) then calculate the time using + * this value as base, i.e 10 minutes would be roughly 600000/57.20 ~10490. + * The maximum value is 28 days! + */ +#define PM_SOFT_SHTDN_INTERVAL 5720 + +#define PM_SOFT_SHTDN_0_5_SEC 8 +#define PM_SOFT_SHTDN_1_SEC 17 +#define PM_SOFT_SHTDN_1_4_SEC 25 +#define PM_SOFT_SHTDN_5_7_SEC 100 +#define PM_SOFT_SHTDN_30_SEC 524 +#define PM_SOFT_SHTDN_1_MIN 1049 +#define PM_SOFT_SHTDN_5_MIN 5245 +#define PM_SOFT_SHTDN_10_MIN 10490 +#define PM_SOFT_SHTDN_1_H 62937 +#define PM_SOFT_SHTDN_24_H 1510490 +#define PM_SOFT_SHTDN_7_DAYS 10573427 +#define PM_SOFT_SHTDN_14_DAYS 21146853 +#define PM_SOFT_SHTDN_28_DAYS 42383709 +#define PM_SOFT_SHTDN_TEST 0xCC00FFEE + +typedef enum { + PM_USB100 = 0, /* 100mA chage */ + PM_USB500, /* 500mA chage */ + PM_USBEXT, /* USB set by external resistor to ILIM (1K) */ + PM_USBSUSPEND /* USB in suspend mode */ +} pm_charge_current_states; + +/** @} */ +/* -------------------------------------------------------------------------- */ +/** \name Power Management functions + * @{ + */ +/** \brief Initializes the Power Management driver + * \return PM_SUCCESS if initialized, else PM_ERROR + */ +int8_t pm_enable(void); + +/** \brief Gets the current firmware version of power management module + * \param fwver pointer to get the value of firmware + * \return PM_SUCCESS if success, else PM_ERROR + */ +int8_t pm_get_fw_ver(uint8_t *fwver); + +/** \brief Disconnects the board battery and enter shutdown mode + * PM_SOFT/HARD_SLEEP_CONFIG + * \param type Hard shutdown (RTCC based) or soft (PIC-governed) + * \return Value byte of the register requested. + */ +int8_t pm_shutdown_now(uint8_t type); + +/** \brief Configure Internal Timeout for Hard and Soft shutdown modes. + * In Hard mode, any positive value counts as internal security timeout. + * In Soft mode, this value is needed. + * \param time value as timeout maximum + * \return PM_SUCCESS if success, else PM_ERROR + */ +int8_t pm_set_timeout(uint32_t time); + +/** \brief Gets the current timeout value configured in power management module + * \return value with timeout. + */ +uint32_t pm_get_timeout(void); + +/** \brief Gets current cycles. incremented each shutdown cycle + * \return Number of shutdown cycles + */ +uint32_t pm_get_num_cycles(void); + +/** \brief Reads the voltage of the external battery if connected to VIN pin + * \param state pointer to get the voltage value + * \return PM_SUCCESS if success, else PM_ERROR + */ +int8_t pm_get_voltage(uint16_t *state); + +/** \brief Restarts the on-board low-power PIC, provoking a board reset + * \return PM_SUCCESS if success, else PM_ERROR + */ +int8_t pm_reset_system(void); +/* -------------------------------------------------------------------------- */ +/** @} */ +#endif /* POWER_MGMT_H_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + * @} + */