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' 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/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/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 a168ae6ab..6bb6317ee 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..06b8889ec 100644 --- a/core/sys/cc.h +++ b/core/sys/cc.h @@ -127,14 +127,33 @@ #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 - * 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/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/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 46d8d3bf4..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,66 +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 { \ - SPI_WAITFOREORx(); \ - 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 @@ -101,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 @@ -110,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/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/clock.c b/cpu/cc26xx/clock.c index c96158b48..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()); @@ -155,11 +161,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 +182,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()); + } } /*---------------------------------------------------------------------------*/ /** diff --git a/cpu/cc26xx/dev/cc26xx-rf.c b/cpu/cc26xx/dev/cc26xx-rf.c index f7b28b4e1..34e8d492a 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" @@ -46,6 +47,7 @@ #include "sys/energest.h" #include "sys/clock.h" #include "sys/rtimer.h" +#include "sys/cc.h" #include "lpm.h" #include "ti-lib.h" /*---------------------------------------------------------------------------*/ @@ -68,6 +70,7 @@ #include #include #include +#include /*---------------------------------------------------------------------------*/ #define BUSYWAIT_UNTIL(cond, max_time) \ do { \ @@ -76,10 +79,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 @@ -393,74 +392,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) { @@ -498,16 +429,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; } @@ -516,12 +450,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 @@ -978,8 +916,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); @@ -1002,7 +940,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; @@ -1022,7 +963,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); @@ -1045,7 +986,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 @@ -1160,6 +1103,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"); @@ -1167,7 +1112,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; @@ -1182,7 +1127,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 @@ -1199,7 +1147,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) @@ -1530,7 +1478,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 +1516,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 +1545,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; @@ -1993,6 +1941,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(); @@ -2023,9 +1972,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 @@ -2061,7 +2012,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 +2030,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,13 +2069,17 @@ 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); - 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) { @@ -2132,9 +2087,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..e9c01a7b5 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); @@ -65,22 +68,25 @@ 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); - ti_lib_int_master_enable(); + + /* Re-enable interrupts */ + if(!interrupts_disabled) { + ti_lib_int_master_enable(); + } } /*---------------------------------------------------------------------------*/ rtimer_clock_t 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/dev/oscillators.c b/cpu/cc26xx/dev/oscillators.c new file mode 100644 index 000000000..06f97a92a --- /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_ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/cpu/cc26xx/lpm.c b/cpu/cc26xx/lpm.c index 0322f940c..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; @@ -64,9 +65,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)) /*---------------------------------------------------------------------------*/ @@ -76,49 +74,48 @@ LIST(power_domain_locks_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) { @@ -126,34 +123,76 @@ 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(); } /*---------------------------------------------------------------------------*/ /* - * 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; @@ -182,8 +221,8 @@ lpm_wake_up() 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; @@ -198,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(); @@ -244,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 */ @@ -289,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); @@ -304,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 @@ -329,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) { @@ -362,7 +401,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(); } @@ -396,10 +435,26 @@ 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); - 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 85c20e77b..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 * @@ -134,17 +107,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); - -/** - * \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); +void lpm_shutdown(uint32_t wakeup_pin, uint32_t io_pull, uint32_t wake_on); /** * \brief Register a module for LPM notifications. @@ -159,10 +126,31 @@ void lpm_wake_up(void); */ 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 */ 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_ */ /*---------------------------------------------------------------------------*/ 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; } /*---------------------------------------------------------------------------*/ 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/cpu/cc26xx/ti-lib.h b/cpu/cc26xx/ti-lib.h index e545ac501..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__) @@ -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" diff --git a/cpu/msp430/Makefile.msp430 b/cpu/msp430/Makefile.msp430 index 264538611..2090c2465 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 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/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 903af6631..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 * * @{ @@ -100,7 +94,6 @@ #include "button-sensor.h" #include "batmon-sensor.h" #include "board-peripherals.h" -#include "lpm.h" #include "cc26xx-rf.h" #include "ti-lib.h" @@ -251,8 +244,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); } /*---------------------------------------------------------------------------*/ @@ -369,26 +361,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) { @@ -406,8 +378,6 @@ PROCESS_THREAD(cc26xx_demo_process, ev, data) get_sync_sensor_readings(); init_sensor_readings(); - keep_uart_on(); - while(1) { PROCESS_YIELD(); @@ -462,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); } } 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/examples/cc26xx/cc26xx-web-demo/net-uart.c b/examples/cc26xx/cc26xx-web-demo/net-uart.c index 96463aee0..c3ddf0977 100644 --- a/examples/cc26xx/cc26xx-web-demo/net-uart.c +++ b/examples/cc26xx/cc26xx-web-demo/net-uart.c @@ -59,12 +59,13 @@ #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" +#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]; @@ -148,37 +145,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/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/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 ------- 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 */ /** @} */ /*---------------------------------------------------------------------------*/ /** 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 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(); 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 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 bed78cf46..40832c9bd 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) @@ -99,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-spi.c b/platform/srf06-cc26xx/sensortag/board-spi.c index 01dd65857..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()); @@ -113,6 +149,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); } /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/platform/srf06-cc26xx/sensortag/board.c b/platform/srf06-cc26xx/sensortag/board.c index e397f1266..c060ee58f 100644 --- a/platform/srf06-cc26xx/sensortag/board.c +++ b/platform/srf06-cc26xx/sensortag/board.c @@ -46,17 +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)); } /*---------------------------------------------------------------------------*/ @@ -64,8 +63,6 @@ static void lpm_wakeup_handler(void) { power_domains_on(); - - board_i2c_init(); } /*---------------------------------------------------------------------------*/ static void @@ -77,8 +74,12 @@ 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 */ + board_i2c_shutdown(); } /*---------------------------------------------------------------------------*/ /* @@ -88,13 +89,47 @@ 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); +/*---------------------------------------------------------------------------*/ +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() { /* Disable global interrupts */ - uint8_t int_disabled = ti_lib_int_master_disable(); + bool int_disabled = ti_lib_int_master_disable(); power_domains_on(); @@ -112,37 +147,19 @@ 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); - 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 */ - board_i2c_init(); - - /* 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(); + /* Make sure the external flash is in the lower power mode */ + ext_flash_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/board.h b/platform/srf06-cc26xx/sensortag/board.h index 00afb98f2..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) /** @} */ @@ -156,7 +160,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 /** @} */ /*---------------------------------------------------------------------------*/ /** @@ -183,6 +187,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 * @{ diff --git a/platform/srf06-cc26xx/sensortag/button-sensor.c b/platform/srf06-cc26xx/sensortag/button-sensor.c index e6a9114ea..d0bd14f9c 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) @@ -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/sensortag/buzzer.c b/platform/srf06-cc26xx/sensortag/buzzer.c index 57d063897..d7f48e4de 100644 --- a/platform/srf06-cc26xx/sensortag/buzzer.c +++ b/platform/srf06-cc26xx/sensortag/buzzer.c @@ -46,19 +46,12 @@ #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() { 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,9 +65,28 @@ 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; - 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); @@ -88,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 @@ -101,24 +107,37 @@ 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); /* - * 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); } /*---------------------------------------------------------------------------*/ /** @} */ 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_ */ /*---------------------------------------------------------------------------*/ 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 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 diff --git a/platform/srf06-cc26xx/sensortag/tmp-007-sensor.c b/platform/srf06-cc26xx/sensortag/tmp-007-sensor.c index 8f880cb54..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; @@ -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; diff --git a/platform/srf06-cc26xx/srf06/board.c b/platform/srf06-cc26xx/srf06/board.c index b62f3fc24..62122cdd0 100644 --- a/platform/srf06-cc26xx/srf06/board.c +++ b/platform/srf06-cc26xx/srf06/board.c @@ -45,95 +45,65 @@ #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 * 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); /*---------------------------------------------------------------------------*/ -void -board_init() +static void +configure_unused_pins(void) { - 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)); - - /* 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); - - /* Enable GPIO peripheral */ - ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_GPIO); - - /* 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 */ + /* 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); - /* 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) */ + /* 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); +} +/*---------------------------------------------------------------------------*/ +void +board_init() +{ + uint8_t int_disabled = ti_lib_int_master_disable(); + + /* 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 | + 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); + + /* Apply settings and wait for them to take effect */ + ti_lib_prcm_load_set(); + 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(); 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) diff --git a/platform/srf06-cc26xx/srf06/button-sensor.c b/platform/srf06-cc26xx/srf06/button-sensor.c index 9638d511e..f1f9a05cf 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) @@ -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); } } 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/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(); 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 $@ $<