From e9ac3797302f0f15bfac50e2a002cc399ecb0d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20=27Morty=27=20Str=C3=BCbe?= Date: Thu, 9 Oct 2014 09:02:09 +0200 Subject: [PATCH 01/46] [MSP430] Add gstabs debug information (dwarf is broken) Currently there is an linker error when compiling with debug information. This is only the case for dwarf (the default). Everything is fine with stabs, thus allowing to debug and use all the other nice tools like "objdump -S". --- cpu/msp430/Makefile.msp430 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpu/msp430/Makefile.msp430 b/cpu/msp430/Makefile.msp430 index 182cd19dd..27aea66e3 100644 --- a/cpu/msp430/Makefile.msp430 +++ b/cpu/msp430/Makefile.msp430 @@ -4,6 +4,8 @@ ifdef nodeid CFLAGS += -DNODEID=$(nodeid) endif +CFLAGS += -gstabs+ + .SUFFIXES: ### Define the CPU directory From 1e39c9a454612e535878350873a3fcc76a2edc88 Mon Sep 17 00:00:00 2001 From: William Huang Date: Mon, 21 Jul 2014 23:25:12 -0400 Subject: [PATCH 02/46] fixed SPI_FLUSH. current implementation waits for rx buffer to fill first. Thus, if we call SPI_FLUSH to make sure the rx fifo is empty when the rx fifo is already empty, we enter an infinite loop --- cpu/cc2538/spi-arch.h | 1 - 1 file changed, 1 deletion(-) diff --git a/cpu/cc2538/spi-arch.h b/cpu/cc2538/spi-arch.h index 53d7fe78d..c42aa5b04 100644 --- a/cpu/cc2538/spi-arch.h +++ b/cpu/cc2538/spi-arch.h @@ -63,7 +63,6 @@ #error "You must include spi-arch.h before spi.h for the CC2538." #endif #define SPI_FLUSH() do { \ - SPI_WAITFOREORx(); \ while (REG(SSI0_BASE + SSI_SR) & SSI_SR_RNE) { \ SPI_RXBUF; \ } \ From 67427b9b8639d550362888d97899e122a6e6d647 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Fri, 3 Apr 2015 21:08:36 +0200 Subject: [PATCH 03/46] Improve multichannel support for Cooja. * Fix CCA detection in Cooja in the case when the receiver swicthes on the right channel during an ongoing transmission. Always add a connection on transmission, even when the channel is not correct. Initially the connection is in a dormant state; this mimics what Cooja is doing when the receiver radio is turned off; when the receiver is turned on and switched to the right channel, `updateSignalStrengths()` is called, and the connection starts to recieve PHY-level traffic. * Add "channel" property for DGRM edges. * Avoid cross-channel interference on DGRM and MRM radio mediums --- .../apps/mrm/java/org/contikios/mrm/MRM.java | 9 +++-- .../radiomediums/AbstractRadioMedium.java | 10 +++-- .../radiomediums/DGRMDestinationRadio.java | 13 ++++++- .../radiomediums/DirectedGraphMedium.java | 38 ++++++++++++++----- .../contikios/cooja/radiomediums/UDGM.java | 7 ++++ 5 files changed, 60 insertions(+), 17 deletions(-) diff --git a/tools/cooja/apps/mrm/java/org/contikios/mrm/MRM.java b/tools/cooja/apps/mrm/java/org/contikios/mrm/MRM.java index 70e304d02..a19dcee58 100644 --- a/tools/cooja/apps/mrm/java/org/contikios/mrm/MRM.java +++ b/tools/cooja/apps/mrm/java/org/contikios/mrm/MRM.java @@ -169,6 +169,7 @@ public class MRM extends AbstractRadioMedium { if (sender.getChannel() >= 0 && recv.getChannel() >= 0 && sender.getChannel() != recv.getChannel()) { + newConnection.addInterfered(recv); continue; } final Radio recvFinal = recv; @@ -313,15 +314,15 @@ public class MRM extends AbstractRadioMedium { /* Interfering/colliding radio connections */ for (RadioConnection conn : conns) { for (Radio intfRadio : ((MRMRadioConnection) conn).getInterfered()) { - double signalStrength = ((MRMRadioConnection) conn).getInterferenceSignalStrength(intfRadio); - if (intfRadio.getCurrentSignalStrength() < signalStrength) { - intfRadio.setCurrentSignalStrength(signalStrength); - } if (conn.getSource().getChannel() >= 0 && intfRadio.getChannel() >= 0 && conn.getSource().getChannel() != intfRadio.getChannel()) { continue; } + double signalStrength = ((MRMRadioConnection) conn).getInterferenceSignalStrength(intfRadio); + if (intfRadio.getCurrentSignalStrength() < signalStrength) { + intfRadio.setCurrentSignalStrength(signalStrength); + } if (!intfRadio.isInterfered()) { /*logger.warn("Radio was not interfered: " + intfRadio);*/ diff --git a/tools/cooja/java/org/contikios/cooja/radiomediums/AbstractRadioMedium.java b/tools/cooja/java/org/contikios/cooja/radiomediums/AbstractRadioMedium.java index 0aed97d52..fce97e927 100644 --- a/tools/cooja/java/org/contikios/cooja/radiomediums/AbstractRadioMedium.java +++ b/tools/cooja/java/org/contikios/cooja/radiomediums/AbstractRadioMedium.java @@ -236,8 +236,9 @@ public abstract class AbstractRadioMedium extends RadioMedium { case RECEPTION_STARTED: case RECEPTION_INTERFERED: case RECEPTION_FINISHED: + break; + case UNKNOWN: - return; case HW_ON: { /* Update signal strengths */ updateSignalStrengths(); @@ -292,7 +293,7 @@ public abstract class AbstractRadioMedium extends RadioMedium { break; case TRANSMISSION_FINISHED: { /* Remove radio connection */ - + /* Connection */ RadioConnection connection = getActiveConnectionFrom(radio); if (connection == null) { @@ -322,7 +323,10 @@ public abstract class AbstractRadioMedium extends RadioMedium { COUNTER_RX += connection.getDestinations().length; COUNTER_INTERFERED += connection.getInterfered().length; for (Radio intRadio : connection.getInterferedNonDestinations()) { - intRadio.signalReceptionEnd(); + + if (intRadio.isInterfered()) { + intRadio.signalReceptionEnd(); + } } /* Update signal strengths */ diff --git a/tools/cooja/java/org/contikios/cooja/radiomediums/DGRMDestinationRadio.java b/tools/cooja/java/org/contikios/cooja/radiomediums/DGRMDestinationRadio.java index fb182f2d4..1147890c8 100644 --- a/tools/cooja/java/org/contikios/cooja/radiomediums/DGRMDestinationRadio.java +++ b/tools/cooja/java/org/contikios/cooja/radiomediums/DGRMDestinationRadio.java @@ -42,6 +42,7 @@ public class DGRMDestinationRadio extends DestinationRadio { public double signal = AbstractRadioMedium.SS_STRONG; /* RSSI */ public long delay = 0; /* EXPERIMENTAL: Propagation delay (us). */ public int lqi = 105; + public int channel = -1; /* not set by default */ public DGRMDestinationRadio() { super(); @@ -50,12 +51,17 @@ public class DGRMDestinationRadio extends DestinationRadio { super(dest); } + public int getChannel() { + return channel; + } + protected Object clone() { DGRMDestinationRadio clone = new DGRMDestinationRadio(this.radio); clone.ratio = this.ratio; clone.delay = this.delay; clone.signal = this.signal; clone.lqi = this.lqi; + clone.channel = this.channel; return clone; } @@ -75,10 +81,13 @@ public class DGRMDestinationRadio extends DestinationRadio { element.setText("" + lqi); config.add(element); - element = new Element("delay"); element.setText("" + delay); config.add(element); + + element = new Element("channel"); + element.setText("" + channel); + config.add(element); return config; } @@ -96,6 +105,8 @@ public class DGRMDestinationRadio extends DestinationRadio { lqi = Integer.parseInt(element.getText()); } else if (element.getName().equals("delay")) { delay = Long.parseLong(element.getText()); + } else if (element.getName().equals("channel")) { + channel = Integer.parseInt(element.getText()); } } return true; diff --git a/tools/cooja/java/org/contikios/cooja/radiomediums/DirectedGraphMedium.java b/tools/cooja/java/org/contikios/cooja/radiomediums/DirectedGraphMedium.java index 23db83c3c..57876357c 100644 --- a/tools/cooja/java/org/contikios/cooja/radiomediums/DirectedGraphMedium.java +++ b/tools/cooja/java/org/contikios/cooja/radiomediums/DirectedGraphMedium.java @@ -166,6 +166,19 @@ public class DirectedGraphMedium extends AbstractRadioMedium { DGRMDestinationRadio dstRadios[] = getPotentialDestinations(conn.getSource()); if (dstRadios == null) continue; for (DGRMDestinationRadio dstRadio : dstRadios) { + + int activeSourceChannel = conn.getSource().getChannel(); + int edgeChannel = dstRadio.channel; + int activeDstChannel = dstRadio.radio.getChannel(); + if (activeSourceChannel != -1) { + if (edgeChannel != -1 && activeSourceChannel != edgeChannel) { + continue; + } + if (activeDstChannel != -1 && activeSourceChannel != activeDstChannel) { + continue; + } + } + if (dstRadio.radio.getCurrentSignalStrength() < dstRadio.signal) { dstRadio.radio.setCurrentSignalStrength(dstRadio.signal); } @@ -247,13 +260,27 @@ public class DirectedGraphMedium extends AbstractRadioMedium { /*logger.info(source + ": " + destinations.length + " potential destinations");*/ for (DGRMDestinationRadio dest: destinations) { - + if (dest.radio == source) { /* Fail: cannot receive our own transmission */ /*logger.info(source + ": Fail, receiver is sender");*/ continue; } + int srcc = source.getChannel(); + int dstc = dest.radio.getChannel(); + int edgeChannel = dest.getChannel(); + + if (edgeChannel >= 0 && dstc >= 0 && edgeChannel != dstc) { + /* Fail: the edge is configured for a different radio channel */ + continue; + } + + if (srcc >= 0 && dstc >= 0 && srcc != dstc) { + /* Fail: radios are on different (but configured) channels */ + newConn.addInterfered(dest.radio); + continue; + } if (!dest.radio.isRadioOn()) { /* Fail: radio is off */ @@ -268,14 +295,7 @@ public class DirectedGraphMedium extends AbstractRadioMedium { newConn.addInterfered(dest.radio); continue; } - - int srcc = source.getChannel(); - int dstc = dest.radio.getChannel(); - if ( srcc >= 0 && dstc >= 0 && srcc != dstc) { - /* Fail: radios are on different (but configured) channels */ - continue; - } - + if (dest.radio.isReceiving()) { /* Fail: radio is already actively receiving */ /*logger.info(source + ": Fail, receiving");*/ diff --git a/tools/cooja/java/org/contikios/cooja/radiomediums/UDGM.java b/tools/cooja/java/org/contikios/cooja/radiomediums/UDGM.java index e0ff8af38..9d7b752fc 100644 --- a/tools/cooja/java/org/contikios/cooja/radiomediums/UDGM.java +++ b/tools/cooja/java/org/contikios/cooja/radiomediums/UDGM.java @@ -192,6 +192,13 @@ public class UDGM extends AbstractRadioMedium { if (sender.getChannel() >= 0 && recv.getChannel() >= 0 && sender.getChannel() != recv.getChannel()) { + + /* Add the connection in a dormant state; + it will be activated later when the radio will be + turned on and switched to the right channel. This behavior + is consistent with the case when receiver is turned off. */ + newConnection.addInterfered(recv); + continue; } Position recvPos = recv.getPosition(); From b7e7d48f0ba2d2c2e30ce6d08ce4efdd3fcd19f3 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 1 May 2015 15:40:14 +0100 Subject: [PATCH 04/46] 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 05/46] 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 06/46] 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 07/46] 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 08/46] 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 09/46] 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 10/46] 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 11/46] 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 12/46] 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 13/46] 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 14/46] 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 15/46] 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 16/46] 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 17/46] 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 18/46] 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 19/46] 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 20/46] 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 21/46] 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 22/46] 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 23/46] 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 24/46] 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 25/46] 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 26/46] 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 27/46] 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 28/46] 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 29/46] 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 30/46] 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 31/46] 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 32/46] 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 33/46] 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 34/46] 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 35/46] 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 36/46] 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 37/46] 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 38/46] 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 39/46] 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 40/46] 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 41/46] 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 */ From e88b3908ad28d162b790748f25102df00f090455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= Date: Sun, 17 May 2015 01:43:43 +0200 Subject: [PATCH 42/46] cc2538dk: README: Add URL of Sourcery G++ Lite 2008q3-66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the URL of the older Sourcery G++ Lite 2008q3-66 arm-none-eabi toolchain mentioned by README.md so that users can easily find it if needed. Signed-off-by: Benoît Thébaudeau --- platform/cc2538dk/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/cc2538dk/README.md b/platform/cc2538dk/README.md index 91e8b7e7c..e5fc755c0 100644 --- a/platform/cc2538dk/README.md +++ b/platform/cc2538dk/README.md @@ -76,7 +76,7 @@ The toolchain used to build contiki is arm-gcc, also used by other arm-based Con The platform is currently being used/tested with "GNU Tools for ARM Embedded Processors". This is the recommended version and the one being used by Contiki's regression tests on Travis. -The older version (Sourcery G++ Lite 2008q3-66) shown above should still work, but the port is no longer being tested with it. +The older version (Sourcery G++ Lite 2008q3-66) shown above should still work, but the port is no longer being tested with it. Drivers ------- From c4f8f0acfbd3bd688ea6ff8db0f9b4334f7ce028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20=27Morty=27=20Str=C3=BCbe?= Date: Fri, 8 May 2015 10:48:41 +0200 Subject: [PATCH 43/46] Add regression-test for tools --- regression-tests/20-compile-tools/Makefile | 72 ++++++++++++++++++++++ tools/Makefile | 4 +- tools/stm32w/Makefile | 25 ++++++++ 3 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 regression-tests/20-compile-tools/Makefile create mode 100644 tools/stm32w/Makefile diff --git a/regression-tests/20-compile-tools/Makefile b/regression-tests/20-compile-tools/Makefile new file mode 100644 index 000000000..7ec956683 --- /dev/null +++ b/regression-tests/20-compile-tools/Makefile @@ -0,0 +1,72 @@ +# Copyright (c) 2014, Friedrich-Alexander University Erlangen-Nuremberg +# 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 University 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 UNIVERSITY 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. + +TOOLS=sky tools stm32w z80=hex2bin sensinode=nano_programmer +FAILTOOLS=stm32w=uip6_bridge sky=uip6-bridge sensinode=nano_usb_programmer + + +TOOLSDIR=../../tools +LOGS=$(patsubst %,%.log, $(TOOLS)) + +all: summary + +FRC: + + +sky.log: RMFILES=serialdump-linux +stm32w.log: RMFILES=serialdump-linux + + +tools.log: + @$(MAKE) -C $(TOOLSDIR) > $@ 2>&1 && $(RM) $@.failed || touch $@.failed + + +%.log: FRC + @( cd $(TOOLSDIR)/$(subst =,/,$*) && $(RM) $(RMFILES) ) + @touch $@ + @$(MAKE) -C $(TOOLSDIR)/$(subst =,/,$*) > $@ 2>&1 && $(RM) $@.failed || touch $@.failed + + +summary: $(LOGS) + @(\ + for T in $(TOOLS) ; do \ + if [ -f $$T.log.failed ] ; then \ + echo tools/$$T: FAIL ಠ_ಠ >> $@;\ + cat $$T.log >> $@;\ + else \ + echo tools/$$T: OK >> $@;\ + fi\ + done \ + ) + @echo "Info: The following tools need fixing and are not tested:" $(subst =,/,$(FAILTOOLS)) >> $@ + @echo $@ + +clean: + @make -C $(DOCDIR) clean + + +.PHONY: %.log diff --git a/tools/Makefile b/tools/Makefile index a1529c352..87f14d317 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,4 +1,4 @@ -all: codeprop tunslip +all: tunslip gitclean: @git clean -d -x -n .. @@ -20,4 +20,4 @@ cleantargets: @rm -f -v ${addprefix ../examples/*/*., ${shell ls ../platform/}} @rm -f -v ${addprefix ../examples/*/*/*., ${shell ls ../platform/}} cleandone: - @echo ${info All done!} \ No newline at end of file + @echo ${info All done!} diff --git a/tools/stm32w/Makefile b/tools/stm32w/Makefile new file mode 100644 index 000000000..be3caa44b --- /dev/null +++ b/tools/stm32w/Makefile @@ -0,0 +1,25 @@ +ifndef HOST_OS + ifeq ($(OS),Windows_NT) + HOST_OS := Windows + else + HOST_OS := $(shell uname) + endif +endif + +ifeq ($(HOST_OS),Windows) + SERIALDUMP = serialdump-windows +endif + +ifeq ($(HOST_OS),Darwin) + SERIALDUMP = serialdump-macos +endif + +ifndef SERIALDUMP + # Assume Linux + SERIALDUMP = serialdump-linux +endif + +all: $(SERIALDUMP) + +$(SERIALDUMP): serialdump.c + $(CC) -O2 -o $@ $< From 0dab6926b30647e4c3bb1b56f39ccef761733ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20=27Morty=27=20Str=C3=BCbe?= Date: Mon, 1 Dec 2014 13:58:34 +0100 Subject: [PATCH 44/46] Move MAX, MIN and ABS to sys/cc.h --- apps/er-coap/er-coap-engine.c | 1 + apps/er-coap/er-coap-separate.c | 1 + apps/er-coap/er-coap.c | 1 + apps/er-coap/er-coap.h | 4 ---- apps/mqtt/mqtt.c | 3 +-- apps/rest-engine/rest-engine.h | 4 ---- apps/shell/shell-power.c | 1 + apps/shell/shell-sky.c | 3 +-- apps/shell/shell-tcpsend.c | 5 +---- apps/shell/shell-time.c | 6 +----- apps/telnetd/telnetd.c | 2 +- core/lib/settings.c | 4 ---- core/net/ip/tcp-socket.c | 2 +- core/net/ipv4/uip.c | 3 ++- core/net/ipv6/uip6.c | 2 +- core/net/mac/contikimac/contikimac.c | 4 ---- core/net/mac/cxmac/cxmac.c | 5 +---- core/net/rime/broadcast-announcement.c | 2 -- core/net/rime/ipolite.c | 9 +-------- core/net/rime/polite-announcement.c | 4 +--- core/net/rime/polite.c | 10 +--------- core/sys/cc.h | 13 +++++++++++++ cpu/avr/dev/usb/compiler.h | 3 --- cpu/cc26xx/dev/cc26xx-rf.c | 5 +---- cpu/rl78/adf7023/ADF7023.c | 4 +--- examples/cc26xx/cc26xx-web-demo/net-uart.c | 5 +---- .../resources/res-plugtest-large-update.c | 1 + examples/sky/sky-collect.c | 3 +-- examples/tcp-socket/tcp-server.c | 2 +- platform/avr-ravenlcd/lcd.c | 2 +- platform/avr-ravenusb/cdc_task.c | 5 +++-- platform/cooja/contiki-cooja-main.c | 3 +-- platform/exp5438/hal_lcd.h | 12 ------------ 33 files changed, 41 insertions(+), 93 deletions(-) diff --git a/apps/er-coap/er-coap-engine.c b/apps/er-coap/er-coap-engine.c index 76a230545..4871368b4 100644 --- a/apps/er-coap/er-coap-engine.c +++ b/apps/er-coap/er-coap-engine.c @@ -36,6 +36,7 @@ * Matthias Kovatsch */ +#include "sys/cc.h" #include #include #include diff --git a/apps/er-coap/er-coap-separate.c b/apps/er-coap/er-coap-separate.c index d35566d79..5e2242b9c 100644 --- a/apps/er-coap/er-coap-separate.c +++ b/apps/er-coap/er-coap-separate.c @@ -36,6 +36,7 @@ * Matthias Kovatsch */ +#include "sys/cc.h" #include #include #include "er-coap-separate.h" diff --git a/apps/er-coap/er-coap.c b/apps/er-coap/er-coap.c index f73b04186..34c671623 100644 --- a/apps/er-coap/er-coap.c +++ b/apps/er-coap/er-coap.c @@ -39,6 +39,7 @@ #include #include #include "contiki.h" +#include "sys/cc.h" #include "contiki-net.h" #include "er-coap.h" diff --git a/apps/er-coap/er-coap.h b/apps/er-coap/er-coap.h index 48f6e4b4a..69ea8b363 100644 --- a/apps/er-coap/er-coap.h +++ b/apps/er-coap/er-coap.h @@ -79,10 +79,6 @@ enum { OPTION_MAP_SIZE = sizeof(uint8_t) * 8 }; #define SET_OPTION(packet, opt) ((packet)->options[opt / OPTION_MAP_SIZE] |= 1 << (opt % OPTION_MAP_SIZE)) #define IS_OPTION(packet, opt) ((packet)->options[opt / OPTION_MAP_SIZE] & (1 << (opt % OPTION_MAP_SIZE))) -#ifndef MIN -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#endif /* MIN */ - /* parsed message struct */ typedef struct { uint8_t *buffer; /* pointer to CoAP header / incoming packet buffer / memory to serialize packet */ diff --git a/apps/mqtt/mqtt.c b/apps/mqtt/mqtt.c index 112c584cb..f56df3a16 100644 --- a/apps/mqtt/mqtt.c +++ b/apps/mqtt/mqtt.c @@ -57,13 +57,12 @@ #include "lib/assert.h" #include "lib/list.h" +#include "sys/cc.h" #include #include #include /*---------------------------------------------------------------------------*/ -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -/*---------------------------------------------------------------------------*/ #define DEBUG 0 #if DEBUG #define PRINTF(...) PRINTF(__VA_ARGS__) diff --git a/apps/rest-engine/rest-engine.h b/apps/rest-engine/rest-engine.h index 3a2848f58..41e181c33 100644 --- a/apps/rest-engine/rest-engine.h +++ b/apps/rest-engine/rest-engine.h @@ -62,10 +62,6 @@ #define REST_MAX_CHUNK_SIZE 64 #endif -#ifndef MIN -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#endif /* MIN */ - struct resource_s; struct periodic_resource_s; diff --git a/apps/shell/shell-power.c b/apps/shell/shell-power.c index c4414c9a1..0e5cb0aed 100644 --- a/apps/shell/shell-power.c +++ b/apps/shell/shell-power.c @@ -42,6 +42,7 @@ #include "sys/energest.h" #include +#include "sys/cc.h" struct power_msg { uint16_t len; diff --git a/apps/shell/shell-sky.c b/apps/shell/shell-sky.c index 65c4859ed..a25b15957 100644 --- a/apps/shell/shell-sky.c +++ b/apps/shell/shell-sky.c @@ -38,6 +38,7 @@ */ #include "contiki.h" +#include "sys/cc.h" #include "shell-sky.h" #include "dev/watchdog.h" @@ -84,8 +85,6 @@ SHELL_COMMAND(rfchannel_command, "rfchannel : change CC2420 radio channel (11 - 26)", &shell_rfchannel_process); /*---------------------------------------------------------------------------*/ -#define MAX(a, b) ((a) > (b)? (a): (b)) -#define MIN(a, b) ((a) < (b)? (a): (b)) struct spectrum { int channel[16]; }; diff --git a/apps/shell/shell-tcpsend.c b/apps/shell/shell-tcpsend.c index 923cda181..7ef93b671 100644 --- a/apps/shell/shell-tcpsend.c +++ b/apps/shell/shell-tcpsend.c @@ -36,13 +36,10 @@ #include #include "contiki.h" +#include "sys/cc.h" #include "shell.h" #include "telnet.h" -#ifndef MIN -#define MIN(a, b) ((a) < (b)? (a) : (b)) -#endif /* MIN */ - /*---------------------------------------------------------------------------*/ PROCESS(shell_tcpsend_process, "tcpsend"); SHELL_COMMAND(tcpsend_command, diff --git a/apps/shell/shell-time.c b/apps/shell/shell-time.c index 0c3ac03c1..fb2b7e7f1 100644 --- a/apps/shell/shell-time.c +++ b/apps/shell/shell-time.c @@ -38,6 +38,7 @@ */ #include "contiki.h" +#include "sys/cc.h" #include "shell-time.h" #include "sys/clock.h" @@ -51,11 +52,6 @@ #define MAX_COMMANDLENGTH 64 #define PERIOD_INTERVAL 60 -#ifndef MIN -#define MIN(a, b) ((a) < (b)? (a) : (b)) -#endif /* MIN */ - - /*---------------------------------------------------------------------------*/ PROCESS(shell_time_process, "time"); SHELL_COMMAND(time_command, diff --git a/apps/telnetd/telnetd.c b/apps/telnetd/telnetd.c index 95786442b..c168b19b8 100644 --- a/apps/telnetd/telnetd.c +++ b/apps/telnetd/telnetd.c @@ -33,6 +33,7 @@ #include +#include "sys/cc.h" #include "contiki-lib.h" #include "contiki-net.h" #include "lib/petsciiconv.h" @@ -103,7 +104,6 @@ static uint8_t connected; #define MAX_SILENCE_TIME (CLOCK_SECOND * 30) -#define MIN(a, b) ((a) < (b)? (a): (b)) /*---------------------------------------------------------------------------*/ static void buf_init(struct telnetd_buf *buf) diff --git a/core/lib/settings.c b/core/lib/settings.c index b085f7219..1b97b28b5 100644 --- a/core/lib/settings.c +++ b/core/lib/settings.c @@ -65,10 +65,6 @@ #define SETTINGS_BOTTOM_ADDR (SETTINGS_TOP_ADDR + 1 - SETTINGS_MAX_SIZE) #endif -#ifndef MIN -#define MIN(a,b) ((a)<(b)?a:b) -#endif - typedef struct { #if SETTINGS_CONF_SUPPORT_LARGE_VALUES uint8_t size_extra; diff --git a/core/net/ip/tcp-socket.c b/core/net/ip/tcp-socket.c index 285be2768..eac008cde 100644 --- a/core/net/ip/tcp-socket.c +++ b/core/net/ip/tcp-socket.c @@ -30,6 +30,7 @@ */ #include "contiki.h" +#include "sys/cc.h" #include "contiki-net.h" #include "lib/list.h" @@ -39,7 +40,6 @@ #include #include -#define MIN(a, b) ((a) < (b) ? (a) : (b)) static void relisten(struct tcp_socket *s); diff --git a/core/net/ipv4/uip.c b/core/net/ipv4/uip.c index 9668d1f2b..1c3c24aaf 100644 --- a/core/net/ipv4/uip.c +++ b/core/net/ipv4/uip.c @@ -78,6 +78,8 @@ #include "net/ipv4/uip-neighbor.h" #include +#include "sys/cc.h" + /*---------------------------------------------------------------------------*/ /* Variable definitions. */ @@ -1953,7 +1955,6 @@ void uip_send(const void *data, int len) { int copylen; -#define MIN(a,b) ((a) < (b)? (a): (b)) copylen = MIN(len, UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN - (int)((char *)uip_sappdata - (char *)&uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN])); if(copylen > 0) { diff --git a/core/net/ipv6/uip6.c b/core/net/ipv6/uip6.c index c88822fbf..73abd1115 100644 --- a/core/net/ipv6/uip6.c +++ b/core/net/ipv6/uip6.c @@ -71,6 +71,7 @@ * the packet back to the peer. */ +#include "sys/cc.h" #include "net/ip/uip.h" #include "net/ip/uipopt.h" #include "net/ipv6/uip-icmp6.h" @@ -2332,7 +2333,6 @@ void uip_send(const void *data, int len) { int copylen; -#define MIN(a,b) ((a) < (b)? (a): (b)) if(uip_sappdata != NULL) { copylen = MIN(len, UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN - diff --git a/core/net/mac/contikimac/contikimac.c b/core/net/mac/contikimac/contikimac.c index 32cc65bbf..7aea60928 100644 --- a/core/net/mac/contikimac/contikimac.c +++ b/core/net/mac/contikimac/contikimac.c @@ -229,10 +229,6 @@ static struct compower_activity current_packet; #define DEFAULT_STREAM_TIME (4 * CYCLE_TIME) -#ifndef MIN -#define MIN(a, b) ((a) < (b)? (a) : (b)) -#endif /* MIN */ - #if CONTIKIMAC_CONF_BROADCAST_RATE_LIMIT static struct timer broadcast_rate_timer; static int broadcast_rate_counter; diff --git a/core/net/mac/cxmac/cxmac.c b/core/net/mac/cxmac/cxmac.c index 770a5c19d..e07fde3d9 100644 --- a/core/net/mac/cxmac/cxmac.c +++ b/core/net/mac/cxmac/cxmac.c @@ -52,6 +52,7 @@ #include "sys/rtimer.h" #include "contiki-conf.h" +#include "sys/cc.h" #ifdef EXPERIMENT_SETUP #include "experiment-setup.h" @@ -215,10 +216,6 @@ static linkaddr_t is_streaming_to, is_streaming_to_too; static rtimer_clock_t stream_until; #define DEFAULT_STREAM_TIME (RTIMER_ARCH_SECOND) -#ifndef MIN -#define MIN(a, b) ((a) < (b)? (a) : (b)) -#endif /* MIN */ - /*---------------------------------------------------------------------------*/ static void on(void) diff --git a/core/net/rime/broadcast-announcement.c b/core/net/rime/broadcast-announcement.c index b865c507b..945d0a78d 100644 --- a/core/net/rime/broadcast-announcement.c +++ b/core/net/rime/broadcast-announcement.c @@ -92,8 +92,6 @@ static struct broadcast_announcement_state { #define PRINTF(...) #endif -#define MIN(a, b) ((a)<(b)?(a):(b)) - /*---------------------------------------------------------------------------*/ static void send_adv(void *ptr) diff --git a/core/net/rime/ipolite.c b/core/net/rime/ipolite.c index d667a0714..11fbd6b17 100644 --- a/core/net/rime/ipolite.c +++ b/core/net/rime/ipolite.c @@ -42,20 +42,13 @@ * @{ */ +#include "sys/cc.h" #include "net/rime/rime.h" #include "net/rime/ipolite.h" #include "lib/random.h" #include -#ifndef MAX -#define MAX(a, b) ((a) > (b)? (a) : (b)) -#endif /* MAX */ - -#ifndef MIN -#define MIN(a, b) ((a) < (b)? (a) : (b)) -#endif /* MIN */ - #define DEBUG 0 #if DEBUG #include diff --git a/core/net/rime/polite-announcement.c b/core/net/rime/polite-announcement.c index 1383eaf43..d678931d8 100644 --- a/core/net/rime/polite-announcement.c +++ b/core/net/rime/polite-announcement.c @@ -43,7 +43,7 @@ */ #include "contiki.h" - +#include "sys/cc.h" #include "lib/list.h" #include "net/rime/rime.h" #include "net/rime/announcement.h" @@ -90,8 +90,6 @@ static struct polite_announcement_state { #define PRINTF(...) #endif -#define MIN(a, b) ((a)<(b)?(a):(b)) - /*---------------------------------------------------------------------------*/ static void send_adv(clock_time_t interval) diff --git a/core/net/rime/polite.c b/core/net/rime/polite.c index 531ae6228..6d0afed9b 100644 --- a/core/net/rime/polite.c +++ b/core/net/rime/polite.c @@ -42,21 +42,13 @@ * @{ */ +#include "sys/cc.h" #include "net/rime/rime.h" #include "net/rime/polite.h" #include "lib/random.h" #include -#ifndef MAX -#define MAX(a,b) ((a) > (b)? (a) : (b)) -#endif /* MAX */ - -#ifndef MIN -#define MIN(a, b) ((a) < (b)? (a) : (b)) -#endif /* MIN */ - - /*---------------------------------------------------------------------------*/ static void recv(struct abc_conn *abc) diff --git a/core/sys/cc.h b/core/sys/cc.h index 90ef3e710..9416ea090 100644 --- a/core/sys/cc.h +++ b/core/sys/cc.h @@ -127,6 +127,19 @@ #define NULL 0 #endif /* NULL */ +#ifndef MAX +#define MAX(n, m) (((n) < (m)) ? (m) : (n)) +#endif + +#ifndef MIN +#define MIN(n, m) (((n) < (m)) ? (n) : (m)) +#endif + +#ifndef ABS +#define ABS(n) (((n) < 0) ? -(n) : (n)) +#endif + + #define CC_CONCAT2(s1, s2) s1##s2 /** * A C preprocessing macro for concatenating to diff --git a/cpu/avr/dev/usb/compiler.h b/cpu/avr/dev/usb/compiler.h index aaa9f1ede..50a02a92d 100644 --- a/cpu/avr/dev/usb/compiler.h +++ b/cpu/avr/dev/usb/compiler.h @@ -280,9 +280,6 @@ typedef char r_uart_ptchar; #define OUT_X(addrx,value) (*addrx = value) #define IN_X(addrx) (*addrx) -# define Max(a, b) ( (a)>(b) ? (a) : (b) ) // Take the max between a and b -# define Min(a, b) ( (a)<(b) ? (a) : (b) ) // Take the min between a and b - // Align on the upper value on a boundary // i.e. Upper(0, 4)= 4 // Upper(1, 4)= 4 diff --git a/cpu/cc26xx/dev/cc26xx-rf.c b/cpu/cc26xx/dev/cc26xx-rf.c index f7b28b4e1..45eb9adad 100644 --- a/cpu/cc26xx/dev/cc26xx-rf.c +++ b/cpu/cc26xx/dev/cc26xx-rf.c @@ -46,6 +46,7 @@ #include "sys/energest.h" #include "sys/clock.h" #include "sys/rtimer.h" +#include "sys/cc.h" #include "lpm.h" #include "ti-lib.h" /*---------------------------------------------------------------------------*/ @@ -76,10 +77,6 @@ while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))); \ } while(0) /*---------------------------------------------------------------------------*/ -#ifndef MIN -#define MIN(n, m) (((n) < (m)) ? (n) : (m)) -#endif -/*---------------------------------------------------------------------------*/ #ifdef __GNUC__ #define CC_ALIGN_ATTR(n) __attribute__ ((aligned(n))) #else diff --git a/cpu/rl78/adf7023/ADF7023.c b/cpu/rl78/adf7023/ADF7023.c index c8f30be38..a82c1638d 100644 --- a/cpu/rl78/adf7023/ADF7023.c +++ b/cpu/rl78/adf7023/ADF7023.c @@ -45,6 +45,7 @@ #include "sfrs-ext.h" #include "contiki.h" /* for clock_wait() and CLOCK_SECOND. */ +#include "sys/cc.h" /******************************************************************************/ /*************************** Macros Definitions *******************************/ @@ -91,9 +92,6 @@ while(condition) { body; break_loop(); } \ } while(0) -#undef MIN -#define MIN(x, y) (((x) < (y)) ? (x) : (y)) - /******************************************************************************/ /************************ Variables Definitions *******************************/ /******************************************************************************/ diff --git a/examples/cc26xx/cc26xx-web-demo/net-uart.c b/examples/cc26xx/cc26xx-web-demo/net-uart.c index 96463aee0..043a50cf1 100644 --- a/examples/cc26xx/cc26xx-web-demo/net-uart.c +++ b/examples/cc26xx/cc26xx-web-demo/net-uart.c @@ -65,6 +65,7 @@ #include "lpm.h" #include "net-uart.h" #include "httpd-simple.h" +#include "sys/cc.h" #include "ti-lib.h" @@ -86,10 +87,6 @@ #define ADDRESS_CONVERSION_OK 1 #define ADDRESS_CONVERSION_ERROR 0 /*---------------------------------------------------------------------------*/ -#ifndef MIN -#define MIN(n, m) (((n) < (m)) ? (n) : (m)) -#endif -/*---------------------------------------------------------------------------*/ static struct uip_udp_conn *udp_conn = NULL; static uint8_t buffer[MAX_MSG_SIZE]; diff --git a/examples/er-rest-example/resources/res-plugtest-large-update.c b/examples/er-rest-example/resources/res-plugtest-large-update.c index e48d08b5f..12c7d1e9f 100644 --- a/examples/er-rest-example/resources/res-plugtest-large-update.c +++ b/examples/er-rest-example/resources/res-plugtest-large-update.c @@ -37,6 +37,7 @@ */ #include +#include "sys/cc.h" #include "rest-engine.h" #include "er-coap.h" #include "er-plugtest.h" diff --git a/examples/sky/sky-collect.c b/examples/sky/sky-collect.c index d49dc8184..04cedf696 100644 --- a/examples/sky/sky-collect.c +++ b/examples/sky/sky-collect.c @@ -38,6 +38,7 @@ */ #include "contiki.h" +#include "sys/cc.h" #include "net/netstack.h" #include "net/rime/rime.h" #include "net/rime/collect.h" @@ -120,8 +121,6 @@ PROCESS_THREAD(depth_blink_process, ev, data) PROCESS_END(); } /*---------------------------------------------------------------------------*/ -#define MAX(a, b) ((a) > (b)? (a): (b)) -#define MIN(a, b) ((a) < (b)? (a): (b)) struct spectrum { int channel[16]; }; diff --git a/examples/tcp-socket/tcp-server.c b/examples/tcp-socket/tcp-server.c index f2e776784..e25d65579 100644 --- a/examples/tcp-socket/tcp-server.c +++ b/examples/tcp-socket/tcp-server.c @@ -30,6 +30,7 @@ */ #include "contiki-net.h" +#include "sys/cc.h" #include #include @@ -104,7 +105,6 @@ PROCESS_THREAD(tcp_server_process, ev, data) while(bytes_to_send > 0) { PROCESS_PAUSE(); int len, tosend; -#define MIN(a,b) ((a)<(b)?(a):(b)) tosend = MIN(bytes_to_send, sizeof(outputbuf)); len = tcp_socket_send(&socket, (uint8_t *)"", tosend); bytes_to_send -= len; diff --git a/platform/avr-ravenlcd/lcd.c b/platform/avr-ravenlcd/lcd.c index 0fe92b80a..3c4f9e230 100644 --- a/platform/avr-ravenlcd/lcd.c +++ b/platform/avr-ravenlcd/lcd.c @@ -411,7 +411,7 @@ lcd_num_putdec(int numb, lcd_padding_t padding) } /* Convert to BCD */ - bcd = itobcd(abs(numb)); + bcd = itobcd(ABS(numb)); /* Print */ return lcd_num_print(bcd, (bool)(numb<0), padding); diff --git a/platform/avr-ravenusb/cdc_task.c b/platform/avr-ravenusb/cdc_task.c index eb2ef3d8b..64af3741e 100644 --- a/platform/avr-ravenusb/cdc_task.c +++ b/platform/avr-ravenusb/cdc_task.c @@ -48,6 +48,7 @@ #include "contiki.h" +#include "sys/cc.h" #include "usb_drv.h" #include "usb_descriptors.h" #include "usb_specific_request.h" @@ -753,7 +754,7 @@ uint16_t p=(uint16_t)&__bss_end; radio_get_rssi_value(&RSSI); RSSI*=3; #endif - maxRSSI[i-11]=Max(maxRSSI[i-11],RSSI); + maxRSSI[i-11]=MAX(maxRSSI[i-11],RSSI); accRSSI[i-11]+=RSSI; } if(j&(1<<7)) { @@ -774,7 +775,7 @@ uint16_t p=(uint16_t)&__bss_end; #endif PRINTF_P(PSTR("\n")); for(i=11;i<=26;i++) { - uint8_t activity=Min(maxRSSI[i-11],accRSSI[i-11]/(1<<7)); + uint8_t activity=MIN(maxRSSI[i-11],accRSSI[i-11]/(1<<7)); PRINTF_P(PSTR(" %d: %02ddB "),i, -91+(maxRSSI[i-11]-1)); for(;activity--;maxRSSI[i-11]--) { PRINTF_P(PSTR("#")); diff --git a/platform/cooja/contiki-cooja-main.c b/platform/cooja/contiki-cooja-main.c index 084c605cc..eddfe1adf 100644 --- a/platform/cooja/contiki-cooja-main.c +++ b/platform/cooja/contiki-cooja-main.c @@ -40,6 +40,7 @@ #include #include "contiki.h" +#include "sys/cc.h" #include "sys/clock.h" #include "sys/etimer.h" @@ -136,8 +137,6 @@ long referenceVar; static struct cooja_mt_thread rtimer_thread; static struct cooja_mt_thread process_run_thread; -#define MIN(a, b) ( (a)<(b) ? (a) : (b) ) - /*---------------------------------------------------------------------------*/ #if NETSTACK_CONF_WITH_IPV4 static void diff --git a/platform/exp5438/hal_lcd.h b/platform/exp5438/hal_lcd.h index 5d76c6c6a..6842c4952 100644 --- a/platform/exp5438/hal_lcd.h +++ b/platform/exp5438/hal_lcd.h @@ -37,18 +37,6 @@ #ifndef HAL_LCD_H #define HAL_LCD_H -#ifndef MIN -# define MIN(n, m) (((n) < (m)) ? (n) : (m)) -#endif - -#ifndef MAX -# define MAX(n, m) (((n) < (m)) ? (m) : (n)) -#endif - -#ifndef ABS -# define ABS(n) (((n) < 0) ? -(n) : (n)) -#endif - #define LCD_BACKLT_OUT P8OUT #define LCD_BACKLT_DIR P8DIR #define LCD_BACKLT_SEL P8SEL From 038ee9f82b4dc57eeb86f43af48d6491e788c7ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20=27Morty=27=20Str=C3=BCbe?= Date: Mon, 11 May 2015 08:41:05 +0200 Subject: [PATCH 45/46] Add to regrssion: compile-tool sto .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 95c670a89..2d970757e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -106,6 +106,7 @@ env: ## of environment variable defined below - BUILD_TYPE='doxygen' BUILD_CATEGORY='doxygen' - BUILD_TYPE='compile-base' BUILD_CATEGORY='compile' + - BUILD_TYPE='compile-tools' BUILD_CATEGORY='compile' - BUILD_TYPE='collect' - BUILD_TYPE='collect-lossy' - BUILD_TYPE='rpl' From a388a1bcd79fe7384f0cca2d0fb5c52c479775e9 Mon Sep 17 00:00:00 2001 From: Ulf Knoblich Date: Wed, 18 Mar 2015 19:43:02 +0100 Subject: [PATCH 46/46] CC2538: added support for SSI1 --- core/dev/spi.h | 36 ++-- core/sys/cc.h | 10 +- cpu/cc2538/dev/spi.c | 313 +++++++++++++++++++++++++++------- cpu/cc2538/dev/ssi.h | 6 + cpu/cc2538/spi-arch.h | 179 ++++++++++++++----- platform/cc2538dk/dev/board.h | 116 ++++++++----- 6 files changed, 487 insertions(+), 173 deletions(-) diff --git a/core/dev/spi.h b/core/dev/spi.h index 1ccbe2bc0..5960c411b 100644 --- a/core/dev/spi.h +++ b/core/dev/spi.h @@ -57,36 +57,36 @@ extern unsigned char spi_busy; void spi_init(void); /* Write one character to SPI */ -#define SPI_WRITE(data) \ - do { \ - SPI_WAITFORTx_BEFORE(); \ - SPI_TXBUF = data; \ - SPI_WAITFOREOTx(); \ +#define SPI_WRITE(data) \ + do { \ + SPI_WAITFORTx_BEFORE(); \ + SPI_TXBUF = data; \ + SPI_WAITFOREOTx(); \ } while(0) /* Write one character to SPI - will not wait for end useful for multiple writes with wait after final */ -#define SPI_WRITE_FAST(data) \ - do { \ - SPI_WAITFORTx_BEFORE(); \ - SPI_TXBUF = data; \ - SPI_WAITFORTx_AFTER(); \ +#define SPI_WRITE_FAST(data) \ + do { \ + SPI_WAITFORTx_BEFORE(); \ + SPI_TXBUF = data; \ + SPI_WAITFORTx_AFTER(); \ } while(0) /* Read one character from SPI */ -#define SPI_READ(data) \ - do { \ - SPI_TXBUF = 0; \ - SPI_WAITFOREORx(); \ - data = SPI_RXBUF; \ +#define SPI_READ(data) \ + do { \ + SPI_TXBUF = 0; \ + SPI_WAITFOREORx(); \ + data = SPI_RXBUF; \ } while(0) /* Flush the SPI read register */ #ifndef SPI_FLUSH #define SPI_FLUSH() \ - do { \ - SPI_RXBUF; \ - } while(0); + do { \ + SPI_RXBUF; \ + } while(0) #endif #endif /* SPI_H_ */ diff --git a/core/sys/cc.h b/core/sys/cc.h index 90ef3e710..6bd87c288 100644 --- a/core/sys/cc.h +++ b/core/sys/cc.h @@ -129,12 +129,18 @@ #define CC_CONCAT2(s1, s2) s1##s2 /** - * A C preprocessing macro for concatenating to - * strings. + * A C preprocessing macro for concatenating two preprocessor tokens. * * We need use two macros (CC_CONCAT and CC_CONCAT2) in order to allow * concatenation of two \#defined macros. */ #define CC_CONCAT(s1, s2) CC_CONCAT2(s1, s2) +#define CC_CONCAT_EXT_2(s1, s2) CC_CONCAT2(s1, s2) + +/** + * A C preprocessing macro for concatenating three preprocessor tokens. + */ +#define CC_CONCAT3(s1, s2, s3) s1##s2##s3 +#define CC_CONCAT_EXT_3(s1, s2, s3) CC_CONCAT3(s1, s2, s3) #endif /* CC_H_ */ diff --git a/cpu/cc2538/dev/spi.c b/cpu/cc2538/dev/spi.c index bff1783b5..6b363bd7b 100644 --- a/cpu/cc2538/dev/spi.c +++ b/cpu/cc2538/dev/spi.c @@ -1,5 +1,9 @@ /* * Copyright (c) 2013, University of Michigan. + * + * Copyright (c) 2015, Weptech elektronik GmbH + * Author: Ulf Knoblich, ulf.knoblich@weptech.de + * * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,102 +45,281 @@ #include "dev/spi.h" #include "dev/ssi.h" #include "dev/gpio.h" +/*---------------------------------------------------------------------------*/ +/* Check port / pin settings for SPI0 and provide default values for spi_cfg */ +#ifndef SPI0_CLK_PORT +#define SPI0_CLK_PORT (-1) +#endif +#ifndef SPI0_CLK_PIN +#define SPI0_CLK_PIN (-1) +#endif +#if SPI0_CLK_PORT >= 0 && SPI0_CLK_PIN < 0 || \ + SPI0_CLK_PORT < 0 && SPI0_CLK_PIN >= 0 +#error Both SPI0_CLK_PORT and SPI0_CLK_PIN must be valid or invalid +#endif -#define SPI_CLK_PORT_BASE GPIO_PORT_TO_BASE(SPI_CLK_PORT) -#define SPI_CLK_PIN_MASK GPIO_PIN_MASK(SPI_CLK_PIN) -#define SPI_MOSI_PORT_BASE GPIO_PORT_TO_BASE(SPI_MOSI_PORT) -#define SPI_MOSI_PIN_MASK GPIO_PIN_MASK(SPI_MOSI_PIN) -#define SPI_MISO_PORT_BASE GPIO_PORT_TO_BASE(SPI_MISO_PORT) -#define SPI_MISO_PIN_MASK GPIO_PIN_MASK(SPI_MISO_PIN) +#ifndef SPI0_TX_PORT +#define SPI0_TX_PORT (-1) +#endif +#ifndef SPI0_TX_PIN +#define SPI0_TX_PIN (-1) +#endif +#if SPI0_TX_PORT >= 0 && SPI0_TX_PIN < 0 || \ + SPI0_TX_PORT < 0 && SPI0_TX_PIN >= 0 +#error Both SPI0_TX_PORT and SPI0_TX_PIN must be valid or invalid +#endif -/** - * \brief Initialize the SPI bus. - * - * This SPI init() function uses the following defines to set the pins: - * SPI_CLK_PORT SPI_CLK_PIN - * SPI_MOSI_PORT SPI_MOSI_PIN - * SPI_MISO_PORT SPI_MISO_PIN - * - * This sets the mode to Motorola SPI with the following format options: - * Clock phase: 1; data captured on second (rising) edge - * Clock polarity: 1; clock is high when idle - * Data size: 8 bits - */ +#ifndef SPI0_RX_PORT +#define SPI0_RX_PORT (-1) +#endif +#ifndef SPI0_RX_PIN +#define SPI0_RX_PIN (-1) +#endif +#if SPI0_RX_PORT >= 0 && SPI0_RX_PIN < 0 || \ + SPI0_RX_PORT < 0 && SPI0_RX_PIN >= 0 +#error Both SPI0_RX_PORT and SPI0_RX_PIN must be valid or invalid +#endif + +/* Here we check that either all or none of the ports are defined. As + we did already check that both ports + pins are either defined or + not for every pin, this means that we can check for an incomplete + configuration by only looking at the port defines */ +/* If some SPI0 pads are valid */ +#if SPI0_CLK_PORT >= 0 || SPI0_TX_PORT >= 0 || SPI0_RX_PORT >= 0 +/* but not all */ +#if SPI0_CLK_PORT < 0 || SPI0_TX_PORT < 0 || SPI0_RX_PORT < 0 +#error Some SPI0 pad definitions are invalid +#endif +#define SPI0_PADS_VALID +#endif +/*---------------------------------------------------------------------------*/ +/* Check port / pin settings for SPI1 and provide default values for spi_cfg */ +#ifndef SPI1_CLK_PORT +#define SPI1_CLK_PORT (-1) +#endif +#ifndef SPI1_CLK_PIN +#define SPI1_CLK_PIN (-1) +#endif +#if SPI1_CLK_PORT >= 0 && SPI1_CLK_PIN < 0 || \ + SPI1_CLK_PORT < 0 && SPI1_CLK_PIN >= 0 +#error Both SPI1_CLK_PORT and SPI1_CLK_PIN must be valid or invalid +#endif + +#ifndef SPI1_TX_PORT +#define SPI1_TX_PORT (-1) +#endif +#ifndef SPI1_TX_PIN +#define SPI1_TX_PIN (-1) +#endif +#if SPI1_TX_PORT >= 0 && SPI1_TX_PIN < 0 || \ + SPI1_TX_PORT < 0 && SPI1_TX_PIN >= 0 +#error Both SPI1_TX_PORT and SPI1_TX_PIN must be valid or invalid +#endif + +#ifndef SPI1_RX_PORT +#define SPI1_RX_PORT (-1) +#endif +#ifndef SPI1_RX_PIN +#define SPI1_RX_PIN (-1) +#endif +#if SPI1_RX_PORT >= 0 && SPI1_RX_PIN < 0 || \ + SPI1_RX_PORT < 0 && SPI1_RX_PIN >= 0 +#error Both SPI1_RX_PORT and SPI1_RX_PIN must be valid or invalid +#endif + +/* If some SPI1 pads are valid */ +#if SPI1_CLK_PORT >= 0 || SPI1_TX_PORT >= 0 || SPI1_RX_PORT >= 0 +/* but not all */ +#if SPI1_CLK_PORT < 0 || SPI1_TX_PORT < 0 || SPI1_RX_PORT < 0 +#error Some SPI1 pad definitions are invalid +#endif +#define SPI1_PADS_VALID +#endif + +#ifdef SPI_DEFAULT_INSTANCE +#if SPI_DEFAULT_INSTANCE == 0 +#ifndef SPI0_PADS_VALID +#error SPI_DEFAULT_INSTANCE is set to SPI0, but its pads are not valid +#endif +#elif SPI_DEFAULT_INSTANCE == 1 +#ifndef SPI1_PADS_VALID +#error SPI_DEFAULT_INSTANCE is set to SPI1, but its pads are not valid +#endif +#endif +#endif + +#if (SPI0_CPRS_CPSDVSR & 1) == 1 || SPI0_CPRS_CPSDVSR < 2 || SPI0_CPRS_CPSDVSR > 254 +#error SPI0_CPRS_CPSDVSR must be an even number between 2 and 254 +#endif + +#if (SPI1_CPRS_CPSDVSR & 1) == 1 || SPI1_CPRS_CPSDVSR < 2 || SPI1_CPRS_CPSDVSR > 254 +#error SPI1_CPRS_CPSDVSR must be an even number between 2 and 254 +#endif + +/*---------------------------------------------------------------------------*/ +typedef struct { + int8_t port; + int8_t pin; +} spi_pad_t; +typedef struct { + uint32_t base; + uint32_t ioc_ssirxd_ssi; + uint32_t ioc_pxx_sel_ssi_clkout; + uint32_t ioc_pxx_sel_ssi_txd; + uint8_t ssi_cprs_cpsdvsr; + spi_pad_t clk; + spi_pad_t tx; + spi_pad_t rx; +} spi_regs_t; +/*---------------------------------------------------------------------------*/ +static const spi_regs_t spi_regs[SSI_INSTANCE_COUNT] = { + { + .base = SSI0_BASE, + .ioc_ssirxd_ssi = IOC_SSIRXD_SSI0, + .ioc_pxx_sel_ssi_clkout = IOC_PXX_SEL_SSI0_CLKOUT, + .ioc_pxx_sel_ssi_txd = IOC_PXX_SEL_SSI0_TXD, + .ssi_cprs_cpsdvsr = SPI0_CPRS_CPSDVSR, + .clk = { SPI0_CLK_PORT, SPI0_CLK_PIN }, + .tx = { SPI0_TX_PORT, SPI0_TX_PIN }, + .rx = { SPI0_RX_PORT, SPI0_RX_PIN } + }, { + .base = SSI1_BASE, + .ioc_ssirxd_ssi = IOC_SSIRXD_SSI1, + .ioc_pxx_sel_ssi_clkout = IOC_PXX_SEL_SSI1_CLKOUT, + .ioc_pxx_sel_ssi_txd = IOC_PXX_SEL_SSI1_TXD, + .ssi_cprs_cpsdvsr = SPI1_CPRS_CPSDVSR, + .clk = { SPI1_CLK_PORT, SPI1_CLK_PIN }, + .tx = { SPI1_TX_PORT, SPI1_TX_PIN }, + .rx = { SPI1_RX_PORT, SPI1_RX_PIN } + } +}; +/*---------------------------------------------------------------------------*/ +/* Deprecated function call provided for compatibility reasons */ +#ifdef SPI_DEFAULT_INSTANCE void spi_init(void) { - spi_enable(); + spix_init(SPI_DEFAULT_INSTANCE); +} +#endif /* #ifdef SPI_DEFAULT_INSTANCE */ +/*---------------------------------------------------------------------------*/ +void +spix_init(uint8_t spi) +{ + const spi_regs_t *regs; + + if(spi >= SSI_INSTANCE_COUNT) { + return; + } + + regs = &spi_regs[spi]; + + if(regs->clk.port < 0) { + /* Port / pin configuration invalid. We checked for completeness + above. If clk.port is < 0, this means that all other defines are + < 0 as well */ + return; + } + + spix_enable(spi); /* Start by disabling the peripheral before configuring it */ - REG(SSI0_BASE + SSI_CR1) = 0; + REG(regs->base + SSI_CR1) = 0; /* Set the IO clock as the SSI clock */ - REG(SSI0_BASE + SSI_CC) = 1; + REG(regs->base + SSI_CC) = 1; /* Set the mux correctly to connect the SSI pins to the correct GPIO pins */ - ioc_set_sel(SPI_CLK_PORT, SPI_CLK_PIN, IOC_PXX_SEL_SSI0_CLKOUT); - ioc_set_sel(SPI_MOSI_PORT, SPI_MOSI_PIN, IOC_PXX_SEL_SSI0_TXD); - REG(IOC_SSIRXD_SSI0) = (SPI_MISO_PORT * 8) + SPI_MISO_PIN; + ioc_set_sel(regs->clk.port, + regs->clk.pin, + regs->ioc_pxx_sel_ssi_clkout); + ioc_set_sel(regs->tx.port, + regs->tx.pin, + regs->ioc_pxx_sel_ssi_txd); + REG(regs->ioc_ssirxd_ssi) = (regs->rx.port * 8) + regs->rx.pin; /* Put all the SSI gpios into peripheral mode */ - GPIO_PERIPHERAL_CONTROL(SPI_CLK_PORT_BASE, SPI_CLK_PIN_MASK); - GPIO_PERIPHERAL_CONTROL(SPI_MOSI_PORT_BASE, SPI_MOSI_PIN_MASK); - GPIO_PERIPHERAL_CONTROL(SPI_MISO_PORT_BASE, SPI_MISO_PIN_MASK); + GPIO_PERIPHERAL_CONTROL(GPIO_PORT_TO_BASE(regs->clk.port), + GPIO_PIN_MASK(regs->clk.pin)); + GPIO_PERIPHERAL_CONTROL(GPIO_PORT_TO_BASE(regs->tx.port), + GPIO_PIN_MASK(regs->tx.pin)); + GPIO_PERIPHERAL_CONTROL(GPIO_PORT_TO_BASE(regs->rx.port), + GPIO_PIN_MASK(regs->rx.pin)); /* Disable any pull ups or the like */ - ioc_set_over(SPI_CLK_PORT, SPI_CLK_PIN, IOC_OVERRIDE_DIS); - ioc_set_over(SPI_MOSI_PORT, SPI_MOSI_PIN, IOC_OVERRIDE_DIS); - ioc_set_over(SPI_MISO_PORT, SPI_MISO_PIN, IOC_OVERRIDE_DIS); + ioc_set_over(regs->clk.port, regs->clk.pin, IOC_OVERRIDE_DIS); + ioc_set_over(regs->tx.port, regs->tx.pin, IOC_OVERRIDE_DIS); + ioc_set_over(regs->rx.port, regs->rx.pin, IOC_OVERRIDE_DIS); /* Configure the clock */ - REG(SSI0_BASE + SSI_CPSR) = 2; + REG(regs->base + SSI_CPSR) = regs->ssi_cprs_cpsdvsr; - /* Configure the default SPI options. + /* + * Configure the default SPI options. * mode: Motorola frame format * clock: High when idle * data: Valid on rising edges of the clock * bits: 8 byte data */ - REG(SSI0_BASE + SSI_CR0) = SSI_CR0_SPH | SSI_CR0_SPO | (0x07); + REG(regs->base + SSI_CR0) = SSI_CR0_SPH | SSI_CR0_SPO | (0x07); /* Enable the SSI */ - REG(SSI0_BASE + SSI_CR1) |= SSI_CR1_SSE; + REG(regs->base + SSI_CR1) |= SSI_CR1_SSE; } /*---------------------------------------------------------------------------*/ void -spi_cs_init(uint8_t port, uint8_t pin) +spix_enable(uint8_t spi) { - GPIO_SOFTWARE_CONTROL(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin)); + if(spi >= SSI_INSTANCE_COUNT) { + return; + } + REG(SYS_CTRL_RCGCSSI) |= (1 << spi); +} +/*---------------------------------------------------------------------------*/ +void +spix_disable(uint8_t spi) +{ + if(spi >= SSI_INSTANCE_COUNT) { + return; + } + REG(SYS_CTRL_RCGCSSI) &= ~(1 << spi); +} +/*---------------------------------------------------------------------------*/ +void +spix_set_mode(uint8_t spi, + uint32_t frame_format, + uint32_t clock_polarity, + uint32_t clock_phase, + uint32_t data_size) +{ + const spi_regs_t *regs; + + if(spi >= SSI_INSTANCE_COUNT) { + return; + } + + regs = &spi_regs[spi]; + + /* Disable the SSI peripheral to configure it */ + REG(regs->base + SSI_CR1) = 0; + + /* Configure the SSI options */ + REG(regs->base + SSI_CR0) = clock_phase | + clock_polarity | + frame_format | + (data_size - 1); + + /* Re-enable the SSI */ + REG(regs->base + SSI_CR1) |= SSI_CR1_SSE; +} +/*---------------------------------------------------------------------------*/ +void +spix_cs_init(uint8_t port, uint8_t pin) +{ + GPIO_SOFTWARE_CONTROL(GPIO_PORT_TO_BASE(port), + GPIO_PIN_MASK(pin)); ioc_set_over(port, pin, IOC_OVERRIDE_DIS); GPIO_SET_OUTPUT(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin)); GPIO_SET_PIN(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin)); } -/*---------------------------------------------------------------------------*/ -void -spi_enable(void) -{ - /* Enable the clock for the SSI peripheral */ - REG(SYS_CTRL_RCGCSSI) |= 1; -} -/*---------------------------------------------------------------------------*/ -void -spi_disable(void) -{ - /* Gate the clock for the SSI peripheral */ - REG(SYS_CTRL_RCGCSSI) &= ~1; -} -/*---------------------------------------------------------------------------*/ -void -spi_set_mode(uint32_t frame_format, uint32_t clock_polarity, - uint32_t clock_phase, uint32_t data_size) -{ - /* Disable the SSI peripheral to configure it */ - REG(SSI0_BASE + SSI_CR1) = 0; - - /* Configure the SSI options */ - REG(SSI0_BASE + SSI_CR0) = clock_phase | clock_polarity | frame_format | (data_size - 1); - - /* Re-enable the SSI */ - REG(SSI0_BASE + SSI_CR1) |= SSI_CR1_SSE; -} /** @} */ diff --git a/cpu/cc2538/dev/ssi.h b/cpu/cc2538/dev/ssi.h index da41a5b0a..ca06969ee 100644 --- a/cpu/cc2538/dev/ssi.h +++ b/cpu/cc2538/dev/ssi.h @@ -45,6 +45,12 @@ #ifndef SSI_H_ #define SSI_H_ +/*---------------------------------------------------------------------------*/ +/** \name Number of SSI instances supported by this CPU. + * @{ + */ +#define SSI_INSTANCE_COUNT 2 +/** @} */ /*---------------------------------------------------------------------------*/ /** \name Base register memory locations. * @{ diff --git a/cpu/cc2538/spi-arch.h b/cpu/cc2538/spi-arch.h index ddbf9daac..137220b2f 100644 --- a/cpu/cc2538/spi-arch.h +++ b/cpu/cc2538/spi-arch.h @@ -1,5 +1,9 @@ /* * Copyright (c) 2013, University of Michigan. + * + * Copyright (c) 2015, Weptech elektronik GmbH + * Author: Ulf Knoblich, ulf.knoblich@weptech.de + * * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,65 +38,144 @@ * Header file for the cc2538 SPI driver, including macros for the * implementation of the low-level SPI primitives such as waiting for the TX * FIFO to be ready, inserting into the TX FIFO, etc. + * + * It supports the usage of SSI_NUM_INSTANCES instances by providing new + * functions calls like + * + * - spix_init(uint8_t instance) + * - spix_enable(uint8_t instance) + * - spix_disable(uint8_t instance) + * - spix_set_mode(unit8_t instance, ...) + * + * and new macros like + * + * - SPIX_WAITFORTxREADY(x) + * - SPIX_WAITFOREOTx(x) + * - SPIX_WAITFOREORx(x) + * - SPIX_FLUSH(x) + * + * Some of the old functions and macros are still supported. + * When using these deprecated functions, the SSI module to use + * has to be be selected by means of the macro SPI_CONF_DEFAULT_INSTANCE. + * + * This SPI driver depends on the following defines: + * + * For the SSI0 module: + * + * - SPI0_CKL_PORT + * - SPI0_CLK_PIN + * - SPI0_TX_PORT + * - SPI0_TX_PIN + * - SPI0_RX_PORT + * - SPI0_RX_PIN + * + * For the SSI1 module: + * + * - SPI1_CKL_PORT + * - SPI1_CLK_PIN + * - SPI1_TX_PORT + * - SPI1_TX_PIN + * - SPI1_RX_PORT + * - SPI1_RX_PIN */ #ifndef SPI_ARCH_H_ #define SPI_ARCH_H_ +#include "contiki.h" + #include "dev/ssi.h" - -#define SPI_WAITFORTxREADY() do { \ - while(!(REG(SSI0_BASE + SSI_SR) & SSI_SR_TNF)); \ -} while(0) - -#define SPI_TXBUF REG(SSI0_BASE + SSI_DR) - -#define SPI_RXBUF REG(SSI0_BASE + SSI_DR) - -#define SPI_WAITFOREOTx() do { \ - while(REG(SSI0_BASE + SSI_SR) & SSI_SR_BSY); \ -} while(0) - -#define SPI_WAITFOREORx() do { \ - while(!(REG(SSI0_BASE + SSI_SR) & SSI_SR_RNE)); \ -} while(0) - -#ifdef SPI_FLUSH -#error "You must include spi-arch.h before spi.h for the CC2538." +/*---------------------------------------------------------------------------*/ +/* The SPI instance to use when using the deprecated SPI API. */ +#ifdef SPI_CONF_DEFAULT_INSTANCE +#if SPI_CONF_DEFAULT_INSTANCE > (SSI_INSTANCE_COUNT - 1) +#error Invalid SPI_CONF_DEFAULT_INSTANCE: valid values are 0 and 1 +#else +#define SPI_DEFAULT_INSTANCE SPI_CONF_DEFAULT_INSTANCE +#endif +#endif +/*---------------------------------------------------------------------------*/ +/* Default values for the clock rate divider */ +#ifdef SPI0_CONF_CPRS_CPSDVSR +#define SPI0_CPRS_CPSDVSR SPI0_CONF_CPRS_CPSDVSR +#else +#define SPI0_CPRS_CPSDVSR 2 #endif -#define SPI_FLUSH() do { \ - while (REG(SSI0_BASE + SSI_SR) & SSI_SR_RNE) { \ - SPI_RXBUF; \ - } \ -} while(0) -#define SPI_CS_CLR(port, pin) do { \ - GPIO_CLR_PIN(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin)); \ +#ifdef SPI1_CONF_CPRS_CPSDVSR +#define SPI1_CPRS_CPSDVSR SPI1_CONF_CPRS_CPSDVSR +#else +#define SPI1_CPRS_CPSDVSR 2 +#endif +/*---------------------------------------------------------------------------*/ +/* New API macros */ +#define SPIX_WAITFORTxREADY(spi) do { \ + while(!(REG(CC_CONCAT3(SSI, spi, _BASE) + SSI_SR) & SSI_SR_TNF)) ; \ } while(0) - -#define SPI_CS_SET(port, pin) do { \ - GPIO_SET_PIN(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin)); \ +#define SPIX_BUF(spi) REG(CC_CONCAT3(SSI, spi, _BASE) + SSI_DR) +#define SPIX_WAITFOREOTx(spi) do { \ + while(REG(CC_CONCAT3(SSI, spi, _BASE) + SSI_SR) & SSI_SR_BSY) ; \ } while(0) +#define SPIX_WAITFOREORx(spi) do { \ + while(!(REG(CC_CONCAT3(SSI, spi, _BASE) + SSI_SR) & SSI_SR_RNE)) ; \ +} while(0) +#define SPIX_FLUSH(spi) do { \ + while(REG(CC_CONCAT3(SSI, spi, _BASE) + SSI_SR) & SSI_SR_RNE) { \ + SPIX_BUF(spi); \ + } \ +} while(0) +#define SPIX_CS_CLR(port, pin) do { \ + GPIO_CLR_PIN(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin)); \ +} while(0) +#define SPIX_CS_SET(port, pin) do { \ + GPIO_SET_PIN(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin)); \ +} while(0) +/*---------------------------------------------------------------------------*/ +/* Deprecated macros provided for compatibility reasons */ +#ifdef SPI_DEFAULT_INSTANCE +#define SPI_WAITFORTxREADY() SPIX_WAITFORTxREADY(SPI_DEFAULT_INSTANCE) +#define SPI_TXBUF SPIX_BUF(SPI_DEFAULT_INSTANCE) +#define SPI_RXBUF SPI_TXBUF +#define SPI_WAITFOREOTx() SPIX_WAITFOREOTx(SPI_DEFAULT_INSTANCE) +#define SPI_WAITFOREORx() SPIX_WAITFOREORx(SPI_DEFAULT_INSTANCE) +#ifdef SPI_FLUSH +#error You must include spi-arch.h before spi.h for the CC2538 +#else +#define SPI_FLUSH() SPIX_FLUSH(SPI_DEFAULT_INSTANCE) +#endif +#define SPI_CS_CLR(port, pin) SPIX_CS_CLR(port, pin) +#define SPI_CS_SET(port, pin) SPIX_CS_SET(port, pin) +#endif /* #ifdef SPI_DEFAULT_INSTANCE */ /*---------------------------------------------------------------------------*/ /** \name Arch-specific SPI functions * @{ */ /** - * \brief Configure a GPIO to be the chip select pin + * \brief Initialize the SPI bus for the instance given + * + * This sets the mode to Motorola SPI with the following format options: + * Clock phase: 1; data captured on second (rising) edge + * Clock polarity: 1; clock is high when idle + * Data size: 8 bits + * + * Use spix_set_mode() to change the spi mode. */ -void spi_cs_init(uint8_t port, uint8_t pin); - -/** \brief Enables the SPI peripheral - */ -void spi_enable(void); - -/** \brief Disables the SPI peripheral - * \note Call this function to save power when the SPI is unused. - */ -void spi_disable(void); +void spix_init(uint8_t spi); /** - * \brief Configure the SPI data and clock polarity and the data size. + * \brief Enables the SPI peripheral for the instance given + */ +void spix_enable(uint8_t spi); + +/** + * \brief Disables the SPI peripheral for the instance given + * \note Call this function to save power when the SPI is unused. + */ +void spix_disable(uint8_t spi); + +/** + * \brief Configure the SPI data and clock polarity and the data size for the + * instance given * * This function configures the SSI peripheral to use a particular SPI * configuration that a slave device requires. It should always be called @@ -100,6 +183,7 @@ void spi_disable(void); * * See section 19.4.4 in the CC2538 user guide for more information. * + * \param spi The SSI instance to use. * \param frame_format Set the SSI frame format. Use SSI_CR0_FRF_MOTOROLA, * SSI_CR0_FRF_TI, or SSI_CR0_FRF_MICROWIRE. * \param clock_polarity In Motorola mode, set whether the clock is high or low @@ -109,8 +193,17 @@ void spi_disable(void); * \param data_size The number of bits in each "byte" of data. Must be * between 4 and 16, inclusive. */ -void spi_set_mode(uint32_t frame_format, uint32_t clock_polarity, - uint32_t clock_phase, uint32_t data_size); +void spix_set_mode(uint8_t spi, uint32_t frame_format, + uint32_t clock_polarity, uint32_t clock_phase, + uint32_t data_size); + +/** + * \brief Configure a GPIO to be the chip select pin. + * + * Even if this function does not depend on the SPI instance used, we rename + * it to reflect the new naming convention. + */ +void spix_cs_init(uint8_t port, uint8_t pin); /** @} */ diff --git a/platform/cc2538dk/dev/board.h b/platform/cc2538dk/dev/board.h index d5514839d..2d9c5ac48 100644 --- a/platform/cc2538dk/dev/board.h +++ b/platform/cc2538dk/dev/board.h @@ -28,7 +28,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ -/** +/** * \addtogroup cc2538dk * @{ * @@ -78,28 +78,28 @@ #undef LEDS_RED #undef LEDS_CONF_ALL -#define LEDS_YELLOW 2 /**< LED2 (Yellow) -> PC1 */ -#define LEDS_GREEN 4 /**< LED3 (Green) -> PC2 */ -#define LEDS_ORANGE 8 /**< LED4 (Orange) -> PC3 */ +#define LEDS_YELLOW 2 /**< LED2 (Yellow) -> PC1 */ +#define LEDS_GREEN 4 /**< LED3 (Green) -> PC2 */ +#define LEDS_ORANGE 8 /**< LED4 (Orange) -> PC3 */ #if USB_SERIAL_CONF_ENABLE -#define LEDS_CONF_ALL 14 -#define LEDS_RED LEDS_ORANGE +#define LEDS_CONF_ALL 14 +#define LEDS_RED LEDS_ORANGE #else -#define LEDS_CONF_ALL 15 -#define LEDS_RED 1 /**< LED1 (Red) -> PC0 */ +#define LEDS_CONF_ALL 15 +#define LEDS_RED 1 /**< LED1 (Red) -> PC0 */ #endif /* Notify various examples that we have LEDs */ -#define PLATFORM_HAS_LEDS 1 +#define PLATFORM_HAS_LEDS 1 /** @} */ /*---------------------------------------------------------------------------*/ /** \name USB configuration * * The USB pullup is driven by PC0 and is shared with LED1 */ -#define USB_PULLUP_PORT GPIO_C_NUM -#define USB_PULLUP_PIN 0 +#define USB_PULLUP_PORT GPIO_C_NUM +#define USB_PULLUP_PIN 0 /** @} */ /*---------------------------------------------------------------------------*/ /** \name UART configuration @@ -115,17 +115,17 @@ * UART1_* below. * @{ */ -#define UART0_RX_PORT GPIO_A_NUM -#define UART0_RX_PIN 0 +#define UART0_RX_PORT GPIO_A_NUM +#define UART0_RX_PIN 0 -#define UART0_TX_PORT GPIO_A_NUM -#define UART0_TX_PIN 1 +#define UART0_TX_PORT GPIO_A_NUM +#define UART0_TX_PIN 1 -#define UART1_CTS_PORT GPIO_B_NUM -#define UART1_CTS_PIN 0 +#define UART1_CTS_PORT GPIO_B_NUM +#define UART1_CTS_PIN 0 -#define UART1_RTS_PORT GPIO_D_NUM -#define UART1_RTS_PIN 3 +#define UART1_RTS_PORT GPIO_D_NUM +#define UART1_RTS_PIN 3 /** @} */ /*---------------------------------------------------------------------------*/ /** \name SmartRF Button configuration @@ -139,32 +139,32 @@ * @{ */ /** BUTTON_SELECT -> PA3 */ -#define BUTTON_SELECT_PORT GPIO_A_NUM -#define BUTTON_SELECT_PIN 3 -#define BUTTON_SELECT_VECTOR NVIC_INT_GPIO_PORT_A +#define BUTTON_SELECT_PORT GPIO_A_NUM +#define BUTTON_SELECT_PIN 3 +#define BUTTON_SELECT_VECTOR NVIC_INT_GPIO_PORT_A /** BUTTON_LEFT -> PC4 */ -#define BUTTON_LEFT_PORT GPIO_C_NUM -#define BUTTON_LEFT_PIN 4 -#define BUTTON_LEFT_VECTOR NVIC_INT_GPIO_PORT_C +#define BUTTON_LEFT_PORT GPIO_C_NUM +#define BUTTON_LEFT_PIN 4 +#define BUTTON_LEFT_VECTOR NVIC_INT_GPIO_PORT_C /** BUTTON_RIGHT -> PC5 */ -#define BUTTON_RIGHT_PORT GPIO_C_NUM -#define BUTTON_RIGHT_PIN 5 -#define BUTTON_RIGHT_VECTOR NVIC_INT_GPIO_PORT_C +#define BUTTON_RIGHT_PORT GPIO_C_NUM +#define BUTTON_RIGHT_PIN 5 +#define BUTTON_RIGHT_VECTOR NVIC_INT_GPIO_PORT_C /** BUTTON_UP -> PC6 */ -#define BUTTON_UP_PORT GPIO_C_NUM -#define BUTTON_UP_PIN 6 -#define BUTTON_UP_VECTOR NVIC_INT_GPIO_PORT_C +#define BUTTON_UP_PORT GPIO_C_NUM +#define BUTTON_UP_PIN 6 +#define BUTTON_UP_VECTOR NVIC_INT_GPIO_PORT_C /** BUTTON_DOWN -> PC7 */ -#define BUTTON_DOWN_PORT GPIO_C_NUM -#define BUTTON_DOWN_PIN 7 -#define BUTTON_DOWN_VECTOR NVIC_INT_GPIO_PORT_C +#define BUTTON_DOWN_PORT GPIO_C_NUM +#define BUTTON_DOWN_PIN 7 +#define BUTTON_DOWN_VECTOR NVIC_INT_GPIO_PORT_C /* Notify various examples that we have Buttons */ -#define PLATFORM_HAS_BUTTON 1 +#define PLATFORM_HAS_BUTTON 1 /** @} */ /*---------------------------------------------------------------------------*/ /** @@ -176,23 +176,49 @@ * ADC inputs can only be on port A. * @{ */ -#define ADC_ALS_PWR_PORT GPIO_A_NUM /**< ALS power GPIO control port */ -#define ADC_ALS_PWR_PIN 7 /**< ALS power GPIO control pin */ -#define ADC_ALS_OUT_PIN 6 /**< ALS output ADC input pin on port A */ +#define ADC_ALS_PWR_PORT GPIO_A_NUM /**< ALS power GPIO control port */ +#define ADC_ALS_PWR_PIN 7 /**< ALS power GPIO control pin */ +#define ADC_ALS_OUT_PIN 6 /**< ALS output ADC input pin on port A */ /** @} */ /*---------------------------------------------------------------------------*/ /** * \name SPI configuration * - * These values configure which CC2538 pins to use for the SPI lines. + * These values configure which CC2538 pins to use for the SPI lines. Both + * SPI instances can be used independently by providing the corresponding + * port / pin macros. * @{ */ -#define SPI_CLK_PORT GPIO_A_NUM /**< Clock port */ -#define SPI_CLK_PIN 2 /**< Clock pin */ -#define SPI_MOSI_PORT GPIO_A_NUM /**< MOSI port */ -#define SPI_MOSI_PIN 4 /**< MOSI pin */ -#define SPI_MISO_PORT GPIO_A_NUM /**< MISO port */ -#define SPI_MISO_PIN 5 /**< MISO pin */ +#define SPI0_IN_USE 0 +#define SPI1_IN_USE 0 +#if SPI0_IN_USE +/** Clock port SPI0 */ +#define SPI0_CLK_PORT GPIO_A_NUM +/** Clock pin SPI0 */ +#define SPI0_CLK_PIN 2 +/** TX port SPI0 (master mode: MOSI) */ +#define SPI0_TX_PORT GPIO_A_NUM +/** TX pin SPI0 */ +#define SPI0_TX_PIN 4 +/** RX port SPI0 (master mode: MISO */ +#define SPI0_RX_PORT GPIO_A_NUM +/** RX pin SPI0 */ +#define SPI0_RX_PIN 5 +#endif /* #if SPI0_IN_USE */ +#if SPI1_IN_USE +/** Clock port SPI1 */ +#define SPI1_CLK_PORT GPIO_A_NUM +/** Clock pin SPI1 */ +#define SPI1_CLK_PIN 2 +/** TX port SPI1 (master mode: MOSI) */ +#define SPI1_TX_PORT GPIO_A_NUM +/** TX pin SPI1 */ +#define SPI1_TX_PIN 4 +/** RX port SPI1 (master mode: MISO) */ +#define SPI1_RX_PORT GPIO_A_NUM +/** RX pin SPI1 */ +#define SPI1_RX_PIN 5 +#endif /* #if SPI1_IN_USE */ /** @} */ /*---------------------------------------------------------------------------*/ /**