diff --git a/Makefile b/Makefile index 7c3873052..93ad8d3f5 100644 --- a/Makefile +++ b/Makefile @@ -66,6 +66,7 @@ tests/nvm-write.obj: src/maca.o src/nvm.o tests/rftest-rx.obj: src/maca.o src/nvm.o tests/rftest-tx.obj: src/maca.o src/nvm.o tests/tmr-ints.obj: src/isr.o +tests/sleep.obj: src/isr.o src/maca.o src/nvm.o NOTHUMB_CPPFLAGS := $(DBGFLAGS) $(OPTFLAGS) $(RELFLAGS) \ -D__KERNEL__ -DTEXT_BASE=$(TEXT_BASE) \ diff --git a/include/crm.h b/include/crm.h new file mode 100644 index 000000000..e7b80710f --- /dev/null +++ b/include/crm.h @@ -0,0 +1,36 @@ +#ifndef CRM_H +#define CRM_H + +#define CRM_BASE (0x80003000) +#define CRM_SYS_CNTL (CRM_BASE+0x00) +#define CRM_WU_CNTL (CRM_BASE+0x04) +#define CRM_SLEEP_CNTL (CRM_BASE+0x08) +#define CRM_BS_CNTL (CRM_BASE+0x0c) +#define CRM_COP_CNTL (CRM_BASE+0x10) +#define CRM_COP_SERVICE (CRM_BASE+0x14) +#define CRM_STATUS (CRM_BASE+0x18) +#define CRM_MOD_STATUS (CRM_BASE+0x1c) +#define CRM_WU_COUNT (CRM_BASE+0x20) +#define CRM_WU_TIMEOUT (CRM_BASE+0x24) +#define CRM_RTC_COUNT (CRM_BASE+0x28) +#define CRM_RTC_TIMEOUT (CRM_BASE+0x2c) +#define CRM_CAL_CNTL (CRM_BASE+0x34) +#define CRM_CAL_COUNT (CRM_BASE+0x38) +#define CRM_RINGOSC_CTNL (CRM_BASE+0x3c) +#define CRM_XTAL_CNTL (CRM_BASE+0x40) +#define CRM_XTAL32_CNTL (CRM_BASE+0x44) +#define CRM_VREG_CNTL (CRM_BASE+0x48) +#define CRM_SW_RST (CRM_BASE+0x50) + +/* wu_cntl bit locations */ +#define EXT_WU_IEN 20 /* 4 bits */ +#define EXT_WU_EN 4 /* 4 bits */ +#define EXT_WU_EDGE 8 /* 4 bits */ +#define EXT_WU_POL 12 /* 4 bits */ + +/* status bit locations */ +#define EXT_WU_EVT 4 /* 4 bits */ + +#define enable_wu_en(k) (set_bit(reg32(CRM_WU_CNTL),(EXT_WU_EN+k-4))) + +#endif diff --git a/include/isr.h b/include/isr.h index 22e1772be..ec4049b89 100644 --- a/include/isr.h +++ b/include/isr.h @@ -5,9 +5,11 @@ #define INTBASE (0x80020000) #define INTENNUM_OFF (0x8) +#define INTDISNUM_OFF (0xc) #define INTSRC_OFF (0x30) #define INTENNUM INTBASE + INTENNUM_OFF +#define INTDISNUM INTBASE + INTDISNUM_OFF #define INTSRC INTBASE + INTSRC_OFF #define enable_tmr_irq() *(volatile uint32_t *)(INTENNUM) = 5; diff --git a/include/maca.h b/include/maca.h index e9079ea9d..3091685ce 100644 --- a/include/maca.h +++ b/include/maca.h @@ -412,6 +412,8 @@ void init_phy(void); void vreg_init(void); void ResumeMACASync(void); void radio_init(void); +void radio_off(void); +void radio_on(void); uint32_t init_from_flash(uint32_t addr); void set_power(uint8_t power); void set_channel(uint8_t chan); diff --git a/src/maca.c b/src/maca.c index 6f0608aba..9416e4dd4 100644 --- a/src/maca.c +++ b/src/maca.c @@ -146,6 +146,19 @@ void vreg_init(void) { *(volatile uint32_t *)(0x80003048) = 0x00000ff8; /* start the regulators */ } +void radio_off(void) { + /* turn off the radio regulators */ + reg(0x80003048) = 0x00000f00; + /* hold the maca in reset */ + maca_reset = maca_reset_rst; +} + +void radio_on(void) { + /* turn the radio regulators back on */ + reg(0x80003048) = 0x00000f78; + /* reinitialize the phy */ + init_phy(); +} /* radio_init has been tested to be good */ void radio_init(void) { diff --git a/tests/sleep.c b/tests/sleep.c new file mode 100644 index 000000000..e7b61b965 --- /dev/null +++ b/tests/sleep.c @@ -0,0 +1,217 @@ +#define GPIO_PAD_DIR0 0x80000000 +#define GPIO_DATA0 0x80000008 + +#define GPIO_FUNC_SEL0 0x80000018 /* GPIO 15 - 0; 2 bit blocks */ + +#define GPIO_PAD_PU_EN0 0x80000010 +#define GPIO_PAD_PU_EN1 0x80000014 +#define ADC_CONTROL 0x80000018 + +#define CRM_WU_CNTL 0x80003004 +#define CRM_WU_TIMEOUT 0x80003024 +#define CRM_SLEEP_CNTL 0x80003008 +#define CRM_STATUS 0x80003018 +#define CRM_XTAL_CNTL 0x80000040 + +#define BASE_UART1 0x80005000 +#define UART1_CON 0x80005000 +#define UART1_STAT 0x80005004 +#define UART1_DATA 0x80005008 +#define UR1CON 0x8000500c +#define UT1CON 0x80005010 +#define UART1_CTS 0x80005014 +#define UART1_BR 0x80005018 + +#define DELAY 400000 + +#include "embedded_types.h" +#include "isr.h" +#include "utils.h" +#include "maca.h" + +void putc(uint8_t c); +void puts(uint8_t *s); +void put_hex(uint8_t x); +void put_hex16(uint16_t x); +void put_hex32(uint32_t x); + +const uint8_t hex[16]={'0','1','2','3','4','5','6','7', + '8','9','a','b','c','d','e','f'}; + + +typedef void (*pfCallback_t)(void); + +typedef struct +{ + uint8_t sleepType:1;// 0 hibernate / 1 doze + uint8_t ramRet:2; + uint8_t mcuRet:1; + uint8_t digPadRet:1; + pfCallback_t pfToDoBeforeSleep; +}crmSleepCtrl_t; + +void do_nothing(void) { + return; +} + +void (*crm_gotosleep)(crmSleepCtrl_t *foo) = 0x0000364d; + +__attribute__ ((section ("startup"))) void main(void) { + crmSleepCtrl_t crmSleepCtrl; + + reg32(GPIO_PAD_DIR0) = 0x00000100; + + reg32(GPIO_DATA0) = 0x00000100; + + + /* Restore UART regs. to default */ + /* in case there is still bootloader state leftover */ + + *(volatile uint32_t *)UART1_CON = 0x0000c800; /* mask interrupts, 16 bit sample --- helps explain the baud rate */ + + /* INC = 767; MOD = 9999 works: 115200 @ 24 MHz 16 bit sample */ + #define INC 767 + #define MOD 9999 + *(volatile uint32_t *)UART1_BR = INC<<16 | MOD; + + /* see Section 11.5.1.2 Alternate Modes */ + /* you must enable the peripheral first BEFORE setting the function in GPIO_FUNC_SEL */ + /* From the datasheet: "The peripheral function will control operation of the pad IF */ + /* THE PERIPHERAL IS ENABLED. */ + *(volatile uint32_t *)UART1_CON = 0x00000003; /* enable receive and transmit */ + *(volatile uint32_t *)GPIO_FUNC_SEL0 = ( (0x01 << (14*2)) | (0x01 << (15*2)) ); /* set GPIO15-14 to UART (UART1 TX and RX)*/ + + reg32(0x00401ffc) = 0x01234567; + reg32(0x00407ffc) = 0xdeadbeef; + reg32(0x0040fffc) = 0xface00ff; + reg32(0x00410000) = 0xabcd0123; + + puts("sleep test\n\r"); + puts("0x00401ffc: "); + put_hex32(reg32(0x00401ffc)); + puts("\r\n"); + puts("0x00407ffc: "); + put_hex32(reg32(0x00407ffc)); + puts("\r\n"); + puts("0x0040fffc: "); + put_hex32(reg32(0x0040fffc)); + puts("\r\n"); + puts("0x00410000: "); + put_hex32(reg32(0x00410000)); + puts("\r\n"); + + /* radio must be OFF before sleeping */ + /* otherwise MCU will not wake up properly */ + /* this is undocumented behavior */ + radio_off(); + + /* disable all pullups */ + /* seems to make a slight difference (2.0uA vs 1.95uA)*/ +// reg32(GPIO_PAD_PU_EN0) = 0; +// reg32(GPIO_PAD_PU_EN1) = 0; +// reg16(ADC_CONTROL) = 0; /* internal Vref2 */ + +// reg16(CRM_XTAL_CNTL) = 0x052; /* default is 0xf52 */ /* doesn't anything w.r.t. power */ + + /* go to sleep */ +// reg32(CRM_WU_CNTL) = 0; /* don't wake up */ + reg32(CRM_WU_CNTL) = 0x1; /* enable wakeup from wakeup timer */ +// reg32(CRM_WU_TIMEOUT) = 1875000; /* wake 10 sec later if doze */ + reg32(CRM_WU_TIMEOUT) = 20000; /* wake 10 sec later if hibernate w/2kHz*/ + +// reg32(CRM_SLEEP_CNTL) = 1; /* hibernate, RAM page 0 only, don't retain state, don't power GPIO */ /* approx. 2.0uA */ +// reg32(CRM_SLEEP_CNTL) = 0x41; /* hibernate, RAM page 0 only, retain state, don't power GPIO */ /* approx. 10.0uA */ +// reg32(CRM_SLEEP_CNTL) = 0x51; /* hibernate, RAM page 0&1 only, retain state, don't power GPIO */ /* approx. 11.7uA */ +// reg32(CRM_SLEEP_CNTL) = 0x61; /* hibernate, RAM page 0,1,2 only, retain state, don't power GPIO */ /* approx. 13.9uA */ +// reg32(CRM_SLEEP_CNTL) = 0x71; /* hibernate, all RAM pages, retain state, don't power GPIO */ /* approx. 16.1uA - possibly with periodic refresh*/ + reg32(CRM_SLEEP_CNTL) = 0xf1; /* hibernate, all RAM pages, retain state, power GPIO */ /* approx. 16.1uA - possibly with periodic refresh*/ + +// reg32(CRM_SLEEP_CNTL) = 2; /* doze , RAM page 0 only, don't retain state, don't power GPIO */ /* approx. 69.2 uA */ +// reg32(CRM_SLEEP_CNTL) = 0x42; /* doze , RAM page 0 only, retain state, don't power GPIO */ /* approx. 77.3uA */ +// reg32(CRM_SLEEP_CNTL) = 0x52; /* doze , RAM page 0&1 only, retain state, don't power GPIO */ /* approx. 78.9uA */ +// reg32(CRM_SLEEP_CNTL) = 0x62; /* doze , RAM page 0,1,2 only, retain state, don't power GPIO */ /* approx. 81.2uA */ +// reg32(CRM_SLEEP_CNTL) = 0x72; /* doze , all RAM pages, retain state, don't power GPIO */ /* approx. 83.4uA - possibly with periodic refresh*/ +// reg32(CRM_SLEEP_CNTL) = 0xf2; /* doze , all RAM pages, retain state, power GPIO */ /* approx. 82.8uA - possibly with periodic refresh*/ + + +/* crmSleepCtrl.sleepType = 0; */ +/* crmSleepCtrl.ramRet = 3; */ +/* crmSleepCtrl.mcuRet = 1; */ +/* crmSleepCtrl.digPadRet = 1; */ +/* crmSleepCtrl.pfToDoBeforeSleep = do_nothing; */ + +/* crm_gotosleep(&crmSleepCtrl); */ + + /* wait for the sleep cycle to complete */ + while((reg32(CRM_STATUS) & 0x1) == 0) { continue; } + /* write 1 to sleep_sync --- this clears the bit (it's a r1wc bit) and powers down */ + reg32(CRM_STATUS) = 1; + + /* asleep */ + + /* wait for the awake cycle to complete */ + while((reg32(CRM_STATUS) & 0x1) == 0) { continue; } + /* write 1 to sleep_sync --- this clears the bit (it's a r1wc bit) and finishes wakeup */ + reg32(CRM_STATUS) = 1; + + puts("\n\r\n\r\n\r"); + puts("0x00401ffc: "); + put_hex32(reg32(0x00401ffc)); + puts("\r\n"); + puts("0x00407ffc: "); + put_hex32(reg32(0x00407ffc)); + puts("\r\n"); + puts("0x0040fffc: "); + put_hex32(reg32(0x0040fffc)); + puts("\r\n"); + puts("0x00410000: "); + put_hex32(reg32(0x00410000)); + puts("\r\n"); + + + volatile uint32_t i; + while(1) { + + reg32(GPIO_DATA0) = 0x00000100; + + for(i=0; i> 4]); + putc(hex[x & 15]); +} + +void put_hex16(uint16_t x) +{ + put_hex((x >> 8) & 0xFF); + put_hex((x) & 0xFF); +} + +void put_hex32(uint32_t x) +{ + put_hex((x >> 24) & 0xFF); + put_hex((x >> 16) & 0xFF); + put_hex((x >> 8) & 0xFF); + put_hex((x) & 0xFF); +}