cc3200: Add preliminary low power deep sleep support.

pull/1137/merge
danicampora 2015-02-27 16:50:06 +01:00
rodzic 0475de1350
commit d226dd2f59
14 zmienionych plików z 951 dodań i 27 usunięć

Wyświetl plik

@ -94,6 +94,7 @@ APP_MODS_SRC_C = $(addprefix mods/,\
pybpin.c \
pybrtc.c \
pybsd.c \
pybsleep.c \
pybsystick.c \
pybuart.c \
pybwdt.c \

Wyświetl plik

@ -34,14 +34,21 @@
#include "py/obj.h"
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "pin.h"
#include "gpio.h"
#include "pybpin.h"
#define PIN(p_pin_name, p_port, p_bit, p_pin_num) \
{ \
{ &pin_type }, \
.name = MP_QSTR_ ## p_pin_name, \
.port = PORT_A ## p_port, \
.bit = (p_bit), \
.pin_num = (p_pin_num) \
.name = MP_QSTR_ ## p_pin_name, \
.port = PORT_A ## p_port, \
.type = PIN_TYPE_STD, \
.bit = (p_bit), \
.pin_num = (p_pin_num), \
.af = PIN_MODE_0, \
.strength = PIN_STRENGTH_4MA, \
.mode = GPIO_DIR_MODE_IN, \
.used = false \
}

Wyświetl plik

@ -38,7 +38,7 @@
///
/// This module provides network drivers and routing configuration.
void mod_network_init(void) {
void mod_network_init0(void) {
mp_obj_list_init(&MP_STATE_PORT(mod_network_nic_list), 0);
}

Wyświetl plik

@ -70,7 +70,7 @@ typedef struct _mod_network_socket_obj_t {
extern const mod_network_nic_type_t mod_network_nic_type_wlan;
void mod_network_init(void);
void mod_network_init0(void);
void mod_network_register_nic(mp_obj_t nic);
mp_obj_t mod_network_find_nic(const uint8_t *ip);

Wyświetl plik

@ -42,6 +42,7 @@
#include "rom_map.h"
#include "interrupt.h"
#include "pin.h"
#include "gpio.h"
#include "prcm.h"
#include "adc.h"
#include "pybadc.h"
@ -117,7 +118,7 @@ STATIC mp_obj_t adc_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw,
self->num = num;
// configure the pin in analog mode
pin_config (pin, 0, 0, PIN_TYPE_ANALOG, PIN_STRENGTH_2MA);
pin_config ((pin_obj_t *)pin, PIN_MODE_0, GPIO_DIR_MODE_IN, PYBPIN_ANALOG_TYPE, PIN_STRENGTH_2MA);
// enable the ADC channel
MAP_ADCChannelEnable(ADC_BASE, channel);

Wyświetl plik

@ -303,7 +303,7 @@ extint_obj_t* extint_register(mp_obj_t pin_obj, uint32_t intmode, uint32_t pull,
self->callback = NULL;
// before enabling the interrupt, configure the gpio pin
pin_config(pin, PIN_MODE_0, GPIO_DIR_MODE_IN, pull, PIN_STRENGTH_4MA);
pin_config ((pin_obj_t *)pin, PIN_MODE_0, GPIO_DIR_MODE_IN, pull, PIN_STRENGTH_4MA);
MAP_GPIOIntTypeSet(pin->port, pin->bit, intmode);
switch (pin->port) {

Wyświetl plik

@ -42,6 +42,7 @@
#include "prcm.h"
#include "gpio.h"
#include "pybpin.h"
#include "pybsleep.h"
#include "mpexception.h"
@ -78,7 +79,13 @@
/// 2. Supply a string which matches a CPU pin name
/// 3. Provide a pin number
STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *pin, mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args);
STATIC void pin_obj_configure (const pin_obj_t *self);
void pin_init0(void) {
}
// C API used to convert a user-supplied pin name into an ordinal pin number.
@ -116,11 +123,26 @@ void pin_verify_af (uint af) {
}
}
void pin_config(const pin_obj_t *self, uint af, uint mode, uint type, uint strength) {
void pin_config (pin_obj_t *self, uint af, uint mode, uint type, uint strength) {
// configure the pin in analog mode
((pin_obj_t *)self)->af = af;
((pin_obj_t *)self)->mode = mode;
((pin_obj_t *)self)->type = type;
((pin_obj_t *)self)->strength = strength;
pin_obj_configure ((const pin_obj_t *)self);
// mark the pin as used
((pin_obj_t *)self)->used = true;
// register it with the sleep module
pybsleep_add (self, (WakeUpCB_t)pin_obj_configure);
}
STATIC void pin_obj_configure (const pin_obj_t *self) {
// Skip all this if the pin is to be used in analog mode
if (type != PIN_TYPE_ANALOG) {
// PIN_MODE_0 means it stays as a Pin, else, another peripheral will take control of it
if (af == PIN_MODE_0) {
if (self->type != PYBPIN_ANALOG_TYPE) {
// verify the alternate function
pin_verify_af (self->af);
// PIN_MODE_0 means it stays as a pin, else, another peripheral will take control of it
if (self->af == PIN_MODE_0) {
// enable the peripheral clock for the GPIO port of this pin
switch (self->port) {
case PORT_A0:
@ -139,14 +161,12 @@ void pin_config(const pin_obj_t *self, uint af, uint mode, uint type, uint stren
break;
}
// configure the direction
MAP_GPIODirModeSet(self->port, self->bit, mode);
MAP_GPIODirModeSet(self->port, self->bit, self->mode);
}
// verify the alternate function
pin_verify_af (af);
// now set the alternate function, strenght and type
MAP_PinModeSet (self->pin_num, af);
MAP_PinModeSet (self->pin_num, self->af);
}
MAP_PinConfigSet(self->pin_num, strength, type);
MAP_PinConfigSet(self->pin_num, self->strength, self->type);
}
/// \method print()
@ -201,8 +221,6 @@ STATIC void pin_print(void (*print)(void *env, const char *fmt, ...), void *env,
print(env, ", strength=Pin.%s)", qstr_str(str_qst));
}
STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *pin, mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args);
/// \classmethod \constructor(id, ...)
/// Create a new Pin object associated with the id. If additional arguments are given,
/// they are used to initialise the pin. See `init`.
@ -280,7 +298,7 @@ STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *self, mp_uint_t n_args, con
}
// configure the pin as requested
pin_config (self, af, mode, type, strength);
pin_config ((pin_obj_t *)self, af, mode, type, strength);
return mp_const_none;
}

Wyświetl plik

@ -30,12 +30,19 @@
#include MICROPY_PIN_DEFS_PORT_H
#define PYBPIN_ANALOG_TYPE 0xFF
typedef struct {
mp_obj_base_t base;
qstr name;
uint32_t port;
uint32_t bit : 8;
uint32_t pin_num : 7;
uint16_t type;
uint8_t bit;
uint8_t pin_num;
uint8_t af;
uint8_t strength;
uint8_t mode;
bool used;
} pin_obj_t;
extern const mp_obj_type_t pin_type;
@ -58,7 +65,7 @@ MP_DECLARE_CONST_FUN_OBJ(pin_init_obj);
void pin_init0(void);
void pin_verify_af (uint af);
void pin_config(const pin_obj_t *self, uint af, uint mode, uint type, uint strength);
void pin_config(pin_obj_t *self, uint af, uint mode, uint type, uint strength);
const pin_obj_t *pin_find(mp_obj_t user_obj);
const pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name);
const pin_obj_t *pin_find_pin(const mp_obj_dict_t *named_pins, uint pin_num);

Wyświetl plik

@ -138,7 +138,7 @@ STATIC mp_obj_t pybsd_make_new (mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_
// card detect pin was provided
if (n_args == 7) {
pybsd_obj.pin_sd_detect = (pin_obj_t *)pin_find(args[6]);
pin_config(pybsd_obj.pin_sd_detect, PIN_MODE_0, GPIO_DIR_MODE_IN, PIN_TYPE_STD_PU, PIN_STRENGTH_4MA);
pin_config (pybsd_obj.pin_sd_detect, PIN_MODE_0, GPIO_DIR_MODE_IN, PIN_TYPE_STD_PU, PIN_STRENGTH_4MA);
}
pybsd_obj.pinsset = true;
}

Wyświetl plik

@ -0,0 +1,845 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2015 Daniel Campora
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <std.h>
#include <stdint.h>
#include <string.h>
#include "py/mpstate.h"
#include MICROPY_HAL_H
#include "hw_types.h"
#include "pybsleep.h"
/* Storage memory for Cortex M4 registers. To make implementation independent of
CPU, register specific constructs must be made part of platform services.
*/
typedef struct {
uint32_t msp;
uint32_t psp;
uint32_t psr;
uint32_t primask;
uint32_t faultmask;
uint32_t basepri;
uint32_t control;
}arm_cm4_core_regs;
//static arm_cm4_core_regs vault_arm_registers;
#define BACK_UP_ARM_REGISTERS() { \
__asm(" push {r0-r12, LR} \n" \
" ldr r1, pxVaultRegistersSave \n" \
" mrs r0, msp \n" \
" str r0, [r1] \n" \
" mrs r0, psp \n" \
" str r0, [r1, #4] \n" \
" mrs r0, primask \n" \
" str r0, [r1, #12] \n" \
" mrs r0, faultmask \n" \
" str r0, [r1, #16] \n" \
" mrs r0, basepri \n" \
" str r0, [r1, #20] \n" \
" mrs r0, control \n" \
" str r0, [r1, #24] \n" \
"pxVaultRegistersSave: .word vault_arm_registers \n"); \
}
#define RESTORE_ARM_REGISTERS() { \
__asm(" ldr r1, pxVaultRegistersLoad \n" \
" ldr r0, [r1, #24] \n" \
" msr control, r0 \n" \
" ldr r0, [r1] \n" \
" msr msp, r0 \n" \
" ldr r0, [r1,#4] \n" \
" msr psp, r0 \n" \
" ldr r0, [r1, #12] \n" \
" msr primask, r0 \n" \
" ldr r0, [r1, #16] \n" \
" msr faultmask, r0 \n" \
" ldr r0, [r1, #20] \n" \
" msr basepri, r0 \n" \
" pop {r0-r12, LR} \n" \
"pxVaultRegistersLoad: .word vault_arm_registers \n"); \
}
#if 0
/* Called directly by boot ROM after waking from S3 state */
void resume_from_S3(void)
{
/* Jump from ROM context hence introduce the sync barriers */
INTRODUCE_SYNC_BARRIER(); /* Data and instruction sync barriers */
RESTORE_ARM_REGISTERS(); /* Core registers and code is in assembly */
INTRODUCE_SYNC_BARRIER(); /* Data and instruction sync barriers */
pform->pm_ops->restore_soc_data();
make_modules_to_M0_no_irq(pform->used_list_len); /* Wake up all */
pform->pm_ops->handle_S3_wakeup(); /* Should be last statement */
return;
}
static void enter_into_S3(void)
{
pform->pm_ops->back_up_soc_data();
INTRODUCE_SYNC_BARRIER(); /* Data and instruction sync barriers */
BACK_UP_ARM_REGISTERS(); /* Core registers and code is in assembly */
cc_enter_S3(resume_from_S3, vault_arm_registers.psp/*save_restore[1]*/);
/* Introducing delays to facilitate CPU to fade away ........ */
asm(" NOP"); asm(" NOP"); asm(" NOP"); asm(" NOP"); asm(" NOP");
asm(" NOP"); asm(" NOP"); asm(" NOP"); asm(" NOP"); asm(" NOP");
asm(" NOP"); asm(" NOP"); asm(" NOP"); asm(" NOP"); asm(" NOP");
}
static void apply_io_park(u8 pin_num,
enum io_park_state park_value)
{
u32 pin_strength, pin_type;
if(DONT_CARE != park_value) {
/* Change the pin mode to GPIO to be safe */
//MAP_PinModeSet(pin_num, PIN_MODE_0);
/* First apply PullUp/PullDn (or no pull) according
to the default levels specified in the user supplied
parking table */
MAP_PinConfigGet(pin_num, &pin_strength, &pin_type);
if(NO_PULL_HIZ != park_value) {
MAP_PinConfigSet(pin_num, pin_strength, park_value);
} else {
MAP_PinConfigSet(pin_num, pin_strength, PIN_TYPE_STD);
}
/* One by one HiZ all the IOs,
by writing the register that drives IOEN_N control
pin of the IOs. This register and the signal path is
always-on and hence not get lost during True-LPDS */
MAP_PinDirModeSet(pin_num, PIN_DIR_MODE_IN);
/* Once all the digital IOs has been made HiZ,
the desired default PAD levels would be held by
the weak-pulls. Input buffers would be alive
(such as auto-SPI or wake-GPIOs) and would not
have Iddq issue since pulls are present. */
}
return;
}
i32 cc_io_park_safe(struct soc_io_park *io_park_choice,
u8 num_pins)
{
i32 loopcnt;
if(NULL == io_park_choice) {
return -1;
}
/* Park the IOs safely as specified by the application */
for(loopcnt = 0; loopcnt < num_pins; loopcnt++) {
switch(io_park_choice[loopcnt].pin_num) {
/* Shared SPI pins for SFLASH */
case PIN_11:
case PIN_12:
case PIN_13:
case PIN_14:
#ifdef DEBUG_MODE
/* JTAG pins */
case PIN_16:
case PIN_17:
case PIN_19:
case PIN_20:
#endif
/* Do not park these pins as they may
have external dependencies */
break;
default:
/* Apply the specified IO parking scheme */
apply_io_park(io_park_choice[loopcnt].pin_num,
io_park_choice[loopcnt].park_val);
}
}
/* parking the SFLASH IOs */
HWREG(0x4402E0E8) &= ~(0x3 << 8);
HWREG(0x4402E0E8) |= (0x2 << 8);
HWREG(0x4402E0EC) &= ~(0x3 << 8);
HWREG(0x4402E0EC) |= (0x2 << 8);
HWREG(0x4402E0F0) &= ~(0x3 << 8);
HWREG(0x4402E0F0) |= (0x2 << 8);
HWREG(0x4402E0F4) &= ~(0x3 << 8);
HWREG(0x4402E0F4) |= (0x1 << 8);
return 0;
}
#define INSTR_READ_STATUS 0x05
#define INSTR_DEEP_POWER_DOWN 0xB9
#define STATUS_BUSY 0x01
//****************************************************************************
//
//! Put SPI flash into Deep Power Down mode
//!
//! Note:SPI flash is a shared resource between MCU and Network processing
//! units. This routine should only be exercised after all the network
//! processing has been stopped. To stop network processing use sl_stop API
//! \param None
//!
//! \return Status, 0:Pass, -1:Fail
//
//****************************************************************************
void SpiFlashDeepPowerDown(void) {
uint32_t status;
// Enable clock for SSPI module
MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK);
// Reset SSPI at PRCM level and wait for reset to complete
MAP_PRCMPeripheralReset(PRCM_SSPI);
while(!MAP_PRCMPeripheralStatusGet(PRCM_SSPI);
// Reset SSPI at module level
MAP_SPIReset(SSPI_BASE);
// Configure SSPI module
MAP_SPIConfigSetExpClk (SSPI_BASE, PRCMPeripheralClockGet(PRCM_SSPI),
20000000, SPI_MODE_MASTER,SPI_SUB_MODE_0,
(SPI_SW_CTRL_CS |
SPI_4PIN_MODE |
SPI_TURBO_OFF |
SPI_CS_ACTIVELOW |
SPI_WL_8));
// Enable SSPI module
MAP_SPIEnable(SSPI_BASE);
// Enable chip select for the spi flash.
MAP_SPICSEnable(SSPI_BASE);
// Wait for the spi flash
do {
// Send the status register read instruction and read back a dummy byte.
MAP_SPIDataPut(SSPI_BASE, INSTR_READ_STATUS);
MAP_SPIDataGet(SSPI_BASE, &status);
// Write a dummy byte then read back the actual status.
MAP_SPIDataPut(SSPI_BASE, 0xFF);
MAP_SPIDataGet(SSPI_BASE, &status);
} while ((status & 0xFF) == STATUS_BUSY);
// Disable chip select for the spi flash.
MAP_SPICSDisable(SSPI_BASE);
// Start another CS enable sequence for Power down command.
MAP_SPICSEnable(SSPI_BASE);
// Send Deep Power Down command to spi flash
MAP_SPIDataPut(SSPI_BASE, INSTR_DEEP_POWER_DOWN);
// Disable chip select for the spi flash.
MAP_SPICSDisable(SSPI_BASE);
}
#define DBG_PRINT Report
#define NUM_NVIC_PEND_REG 6
#define ERR_TIMER_TO_WAKE (-2)
#define MAX_GPIO_WAKESOURCE 6
struct {
u32 vector_table; // Vector Table Offset
u32 aux_ctrl; // Auxiliary control register
u32 int_ctrl_state; // Interrupt Control and State
u32 app_int; // Application Interrupt Reset control
u32 sys_ctrl; // System control
u32 config_ctrl; // Configuration control
u32 sys_pri_1; // System Handler Priority 1
u32 sys_pri_2; // System Handler Priority 2
u32 sys_pri_3; // System Handler Priority 3
u32 sys_hcrs; // System Handler control and state register
u32 systick_ctrl; // SysTick Control Status
u32 systick_reload; // SysTick Reload
u32 systick_calib; // SysTick Calibration
u32 int_en[6]; // Interrupt set enable
u32 int_priority[49]; // Interrupt priority
} nvic_reg_store;
u8 gpio_wake_src[] = {2, 4, 13, 17, 11, 24};
u8 gpio_lpds_inttype[] = {1, 1, 2, 0xFF, 3, 0xFF, 0};
u8 gpio_hib_inttype[] = {2, 2, 0, 0xFF, 3, 0xFF, 1};
u32 nvic_int_mask[] = {NVIC_PEND0_MASK, NVIC_PEND1_MASK, NVIC_PEND2_MASK,
NVIC_PEND3_MASK, NVIC_PEND4_MASK, NVIC_PEND5_MASK};
volatile i32 debug = 0;
/* Network (Host IRQ) based wakeup from S3(LPDS) */
static i32 setup_S3_wakeup_from_nw()
{
#define IS_NWPIC_INTR_SET() (HWREG(NVIC_EN5) & (1 << ((INT_NWPIC - 16) & 31)))
/* Check if the NWP->APPs interrupt is enabled */
if(IS_NWPIC_INTR_SET()) {
/* Set LPDS Wakeup source as NWP request */
MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_HOST_IRQ);
return 0;
} else {
return -1;
}
}
/* GPIO based wakeup from S3(LPDS) */
static i32 check_n_setup_S3_wakeup_from_gpio()
{
i32 retval, indx;
u8 gpio_num[MAX_GPIO_WAKESOURCE];
u8 int_type[MAX_GPIO_WAKESOURCE];
/* Check for any special purpose GPIO usage */
retval = cc_gpio_get_spl_purpose(&gpio_num[0],
&int_type[0],
MAX_GPIO_WAKESOURCE);
if(retval > 0) {
for(indx = 0; indx < sizeof(gpio_wake_src); indx++) {
if(gpio_wake_src[indx] == gpio_num[0]) {
/* Setup the GPIO to be the wake source */
MAP_PRCMLPDSWakeUpGPIOSelect(
indx, gpio_lpds_inttype[int_type[0]]);
MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_GPIO);
/* Save the GPIO number wake from LPDS */
cc_pm_ctrl.spl_gpio_wakefrom_lpds = gpio_num[0];
break;
}
}
} else {
return -1;
}
return 0;
}
/* Timer based wakeup from S3 (LPDS) */
static i32 check_n_setup_S3_wakeup_from_timer()
{
u64 scc_match, scc_curr, scc_remaining;
/* Check if there is an alarm set */
if(cc_rtc_has_alarm()) {
/* Get the time remaining for the RTC timer to expire */
scc_match = MAP_PRCMSlowClkCtrMatchGet();
scc_curr = MAP_PRCMSlowClkCtrGet();
if(scc_match > scc_curr) {
/* Get the time remaining in terms of slow clocks */
scc_remaining = (scc_match - scc_curr);
if(scc_remaining > WAKEUP_TIME_LPDS) {
/* Subtract the time it takes for wakeup
from S3 (LPDS) */
scc_remaining -= WAKEUP_TIME_LPDS;
scc_remaining = (scc_remaining > 0xFFFFFFFF)?
0xFFFFFFFF: scc_remaining;
/* Setup the LPDS wake time */
MAP_PRCMLPDSIntervalSet(
(u32)scc_remaining);
/* Enable the wake source to be timer */
MAP_PRCMLPDSWakeupSourceEnable(
PRCM_LPDS_TIMER);
} else {
/* Cannot enter LPDS */
return ERR_TIMER_TO_WAKE;
}
} else {
return ERR_TIMER_TO_WAKE;
}
} else {
/* Disable timer as the wake source */
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
return -1;
}
return 0;
}
/* Setup the HIBernate wakr source as apecified GPIO */
static void setup_hib_gpio_wake(u32 gpio_num,
u32 gpio_wake_type)
{
MAP_PRCMHibernateWakeUpGPIOSelect(gpio_num, gpio_wake_type);
MAP_PRCMHibernateWakeupSourceEnable(gpio_num);
return;
}
/* GPIO based wakeup from S4 (HIB) */
static i32 check_n_setup_S4_wakeup_from_gpio()
{
i32 retval, indx;
u8 gpio_num[MAX_GPIO_WAKESOURCE];
u8 int_type[MAX_GPIO_WAKESOURCE];
/* Check for any special purpose GPIO usage */
retval = cc_gpio_get_spl_purpose(&gpio_num[0],
&int_type[0],
MAX_GPIO_WAKESOURCE);
if(retval > 0) {
for(indx = 0; indx < retval; indx++) {
switch(gpio_num[indx]) {
case 2:
setup_hib_gpio_wake(PRCM_HIB_GPIO2,
gpio_hib_inttype[int_type[indx]]);
break;
case 4:
setup_hib_gpio_wake(PRCM_HIB_GPIO4,
gpio_hib_inttype[int_type[indx]]);
break;
case 13:
setup_hib_gpio_wake(PRCM_HIB_GPIO13,
gpio_hib_inttype[int_type[indx]]);
break;
case 17:
setup_hib_gpio_wake(PRCM_HIB_GPIO17,
gpio_hib_inttype[int_type[indx]]);
break;
case 11:
setup_hib_gpio_wake(PRCM_HIB_GPIO11,
gpio_hib_inttype[int_type[indx]]);
break;
case 24:
setup_hib_gpio_wake(PRCM_HIB_GPIO24,
gpio_hib_inttype[int_type[indx]]);
break;
default:
break;
}
}
} else {
return -1;
}
return 0;
}
/* Timer based wakeup from S4 (HIB) */
static i32 check_n_setup_S4_wakeup_from_timer()
{
u64 scc_match, scc_curr, scc_remaining;
/* Check if there is an alarm set */
if(cc_rtc_has_alarm()) {
/* Get the time remaining for the RTC timer to expire */
scc_match = MAP_PRCMSlowClkCtrMatchGet();
scc_curr = MAP_PRCMSlowClkCtrGet();
if(scc_match > scc_curr) {
/* Get the time remaining in terms of slow clocks */
scc_remaining = (scc_match - scc_curr);
if(scc_remaining > WAKEUP_TIME_HIB) {
/* Subtract the time it takes for wakeup
from S4 (HIB) */
scc_remaining -= WAKEUP_TIME_HIB;
/* Setup the HIB wake time */
MAP_PRCMHibernateIntervalSet(scc_remaining);
/* Enable the wake source to be RTC */
MAP_PRCMHibernateWakeupSourceEnable(
PRCM_HIB_SLOW_CLK_CTR);
} else {
/* Cannot enter HIB */
return ERR_TIMER_TO_WAKE;
}
} else {
return -1;
}
} else {
/* Disable Timer as wake source */
MAP_PRCMHibernateWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
return -1;
}
return 0;
}
/* Sets up wake-up sources for indicated power mode */
i32 cc_set_up_wkup_srcs(enum soc_pm target)
{
i32 nw_ret = -1, gpio_ret = -1, timer_ret = -1;
switch(target) {
case e_pm_S0:
case e_pm_S1:
case e_pm_S2:
/* These handle the cases of run, sleep, deepsleep.
Wake source is configured outside this scope in
individual peripherals */
break;
case e_pm_S3:
/* Low power deep sleep condition */
/* Network (Host IRQ) based wakeup is always enabled */
nw_ret = setup_S3_wakeup_from_nw();
/* Check and enable GPIO based wakeup */
gpio_ret = check_n_setup_S3_wakeup_from_gpio();
/* Check and enable LRT based wakeup */
timer_ret = check_n_setup_S3_wakeup_from_timer();
break;
case e_pm_S4:
/* Hibernate condition */
/* Check and enable GPIO based wakeup */
gpio_ret = check_n_setup_S4_wakeup_from_gpio();
/* Check and enable LRT based wakeup */
timer_ret = check_n_setup_S4_wakeup_from_timer();
break;
default:
break;
}
if(ERR_TIMER_TO_WAKE == timer_ret) {
return -1;
}
if((nw_ret < 0) && (gpio_ret < 0) && (timer_ret < 0)) {
return -1;
}
else if((gpio_ret < 0) && (timer_ret < 0)) {
/* Setup the LPDS wake time */
MAP_PRCMLPDSIntervalSet(LPDS_WDOG_TIME);
/* Enable the wake source to be timer */
MAP_PRCMLPDSWakeupSourceEnable(
PRCM_LPDS_TIMER);
}
return 0;
}
/* LPDS wake SW interrupt handler */
void wake_interrupt_handler()
{
i32 wake_source;
/* Identify the wakeup source */
wake_source = MAP_PRCMLPDSWakeupCauseGet();
switch(wake_source) {
case PRCM_LPDS_HOST_IRQ:
break;
case PRCM_LPDS_GPIO:
/* Invoke the callback with the last GPIO num
used to enter LPDS (S3) */
gpio_wake_interrupt_handler(
&cc_pm_ctrl.spl_gpio_wakefrom_lpds);
break;
case PRCM_LPDS_TIMER:
break;
}
return;
}
/* Process events that have woken up system from S3 (LPDS) */
i32 cc_handle_S3_wakeup()
{
/* Trigger the SW interrupt */
MAP_IntPendSet(INT_PRCM);
return 0;
}
/* Are there interrupts pending in system? TRUE -> yes else no */
bool cc_are_irqs_pending(void)
{
i32 indx = 0;
u32 *base_reg_addr;
/* Check if there are any interrupts pending */
base_reg_addr = (u32 *)NVIC_PEND0;
for(indx = 0; indx < NUM_NVIC_PEND_REG; indx++) {
if(base_reg_addr[indx] & nvic_int_mask[indx]) {
return true;
}
}
return false;
}
/* Must push system to low power state of S4 (Hibernate) */
i32 cc_enter_S4(void)
{
/* Invoke the driverlib API to enter HIBernate */
MAP_PRCMHibernateEnter();
return 0;
}
/* Must push system to low power state of S3 (LPDS) */
i32 cc_enter_S3(void(*resume_fn)(void), u32 stack_ptr)
{
MAP_PRCMLPDSRestoreInfoSet(stack_ptr, (u32)resume_fn);
/* Enter LPDS */
MAP_PRCMLPDSEnter();
return 0;
}
/* Must push system to low power state of S2 (Deepsleep) */
i32 cc_enter_S2(void)
{
/* Enter deepsleep */
//MAP_PRCMDeepSleepEnter();
return 0;
}
volatile i32 sleep_count = 0;
/* Must push system to low power state of S1 */
i32 cc_enter_S1(void)
{
//MAP_PRCMSleepEnter();
return 0;
}
/* Save the NVIC registers */
void back_up_nvic_regs()
{
i32 indx = 0;
u32 *base_reg_addr;
/* Save the NVIC control registers */
nvic_reg_store.vector_table = HWREG(NVIC_VTABLE);
nvic_reg_store.aux_ctrl = HWREG(NVIC_ACTLR);
nvic_reg_store.int_ctrl_state = HWREG(NVIC_INT_CTRL);
nvic_reg_store.app_int = HWREG(NVIC_APINT);
nvic_reg_store.sys_ctrl = HWREG(NVIC_SYS_CTRL);
nvic_reg_store.config_ctrl = HWREG(NVIC_CFG_CTRL);
nvic_reg_store.sys_pri_1 = HWREG(NVIC_SYS_PRI1);
nvic_reg_store.sys_pri_2 = HWREG(NVIC_SYS_PRI2);
nvic_reg_store.sys_pri_3 = HWREG(NVIC_SYS_PRI3);
nvic_reg_store.sys_hcrs = HWREG(NVIC_SYS_HND_CTRL);
/* Systick registers */
nvic_reg_store.systick_ctrl = HWREG(NVIC_ST_CTRL);
nvic_reg_store.systick_reload = HWREG(NVIC_ST_RELOAD);
nvic_reg_store.systick_calib = HWREG(NVIC_ST_CAL);
/* Save the interrupt enable registers */
base_reg_addr = (u32 *)NVIC_EN0;
for(indx = 0; indx < (sizeof(nvic_reg_store.int_en) / 4); indx++) {
nvic_reg_store.int_en[indx] = base_reg_addr[indx];
}
/* Save the interrupt priority registers */
base_reg_addr = (u32 *)NVIC_PRI0;
for(indx = 0; indx < (sizeof(nvic_reg_store.int_priority) / 4); indx++) {
nvic_reg_store.int_priority[indx] = base_reg_addr[indx];
}
return;
}
/* Reestore the NVIC registers */
void restore_nvic_regs()
{
i32 indx = 0;
u32 *base_reg_addr;
/* Restore the NVIC control registers */
HWREG(NVIC_VTABLE) = nvic_reg_store.vector_table;
HWREG(NVIC_ACTLR) = nvic_reg_store.aux_ctrl;
HWREG(NVIC_APINT) = nvic_reg_store.app_int;
HWREG(NVIC_SYS_CTRL) = nvic_reg_store.sys_ctrl;
HWREG(NVIC_CFG_CTRL) = nvic_reg_store.config_ctrl;
HWREG(NVIC_SYS_PRI1) = nvic_reg_store.sys_pri_1;
HWREG(NVIC_SYS_PRI2) = nvic_reg_store.sys_pri_2;
HWREG(NVIC_SYS_PRI3) = nvic_reg_store.sys_pri_3;
HWREG(NVIC_SYS_HND_CTRL) = nvic_reg_store.sys_hcrs;
/* Systick registers */
HWREG(NVIC_ST_CTRL) = nvic_reg_store.systick_ctrl;
HWREG(NVIC_ST_RELOAD) = nvic_reg_store.systick_reload;
HWREG(NVIC_ST_CAL) = nvic_reg_store.systick_calib;
/* Restore the interrupt priority registers */
base_reg_addr = (u32 *)NVIC_PRI0;
for(indx = 0; indx < (sizeof(nvic_reg_store.int_priority) / 4); indx++) {
base_reg_addr[indx] = nvic_reg_store.int_priority[indx];
}
/* Restore the interrupt enable registers */
base_reg_addr = (u32 *)NVIC_EN0;
for(indx = 0; indx < (sizeof(nvic_reg_store.int_en) / 4); indx++) {
base_reg_addr[indx] = nvic_reg_store.int_en[indx];
}
INTRODUCE_SYNC_BARRIER(); /* Data and instruction sync barriers */
return;
}
/* S3 (LPDS): Back-up system regs & data */
void cc_back_up_soc_data(void) {
/* Enable the RAM retention */
MAP_PRCMSRAMRetentionEnable(PRCM_SRAM_COL_1 | PRCM_SRAM_COL_2 | PRCM_SRAM_COL_3 | PRCM_SRAM_COL_4, PRCM_SRAM_LPDS_RET);
/* Store the NVIC registers */
back_up_nvic_regs();
// Park all IO pins
// Park antenna selection pins
HWREG(0x4402E108) = 0x00000E61;
HWREG(0x4402E10C) = 0x00000E61;
INTRODUCE_SYNC_BARRIER(); /* Data and instruction sync barriers */
BACK_UP_ARM_REGISTERS(); /* Core registers and code is in assembly */
return;
}
/* S3 (LPDS): Restore system regs & data */
void cc_restore_soc_data(void)
{
uint32_t reg;
/* Check if any of the registers/data need to be restored */
/* Take I2C semaphore */
reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register);
reg = (reg & ~0x3) | 0x1;
HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register) = reg;
/* Take GPIO semaphore */
reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_GPIO_properties_register);
reg = (reg & ~0x3FF) | 0x155;
HWREG(COMMON_REG_BASE + COMMON_REG_O_GPIO_properties_register) = reg;
/* Restore the NVIC registers */
restore_nvic_regs();
/* ungates the clk for the shared SPI*/
MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
MAP_PRCMIntEnable (PRCM_INT_SLOW_CLK_CTR);
return;
}
void prcm_interrupt_handler(void *intr_param)
{
int status;
/* Read the interrupt status, also clears the status */
status = MAP_PRCMIntStatus();
if((PRCM_INT_SLOW_CLK_CTR == status) || (sw_simulate_rtc)) {
sw_simulate_rtc = 0;
/* Invoke the RTC interrupt handler */
cc_rtc_isr();
} else if(0 == status) {
/* Invoke the wake from LPDS interrupt handler */
wake_interrupt_handler();
} else {
}
}
/* LPDS wake SW interrupt handler */
void wake_interrupt_handler()
{
i32 wake_source;
/* Identify the wakeup source */
wake_source = MAP_PRCMLPDSWakeupCauseGet();
switch(wake_source) {
case PRCM_LPDS_HOST_IRQ:
break;
case PRCM_LPDS_GPIO:
/* Invoke the callback with the last GPIO num
used to enter LPDS (S3) */
gpio_wake_interrupt_handler(
&cc_pm_ctrl.spl_gpio_wakefrom_lpds);
break;
case PRCM_LPDS_TIMER:
break;
}
return;
}
/* Invoked in interrupt context */
void cc_rtc_isr(void) {
struct u64_time alarm, value;
u32 status;
/* Read the interrupt status, also clears the status */
status = MAP_PRCMIntStatus();
// call the python RTC callback interrupt handler
}
#endif
typedef struct {
mp_obj_t obj;
WakeUpCB_t wakeup;
}pybsleep_obj_t;
STATIC pybsleep_obj_t * pybsleep_find (mp_obj_t obj) {
for (mp_uint_t i = 0; i < MP_STATE_PORT(pybsleep_obj_list).len; i++) {
// search for the object and then remove it
pybsleep_obj_t *sleep_obj = ((pybsleep_obj_t *)MP_STATE_PORT(pybsleep_obj_list).items[i]);
if (sleep_obj->obj == obj) {
return sleep_obj;
}
}
return NULL;
}
void pyblsleep_init0 (void) {
mp_obj_list_init(&MP_STATE_PORT(pybsleep_obj_list), 0);
}
void pybsleep_add (mp_obj_t obj, WakeUpCB_t wakeup) {
pybsleep_obj_t * sleep_obj = m_new_obj(pybsleep_obj_t);
sleep_obj->obj = obj;
sleep_obj->wakeup = wakeup;
// only add objects once
if (!pybsleep_find(sleep_obj)) {
mp_obj_list_append(&MP_STATE_PORT(pybsleep_obj_list), sleep_obj);
}
}
void pybsleep_remove (mp_obj_t obj) {
pybsleep_obj_t *sleep_obj;
if ((sleep_obj = pybsleep_find(obj))) {
mp_obj_list_remove(&MP_STATE_PORT(pybsleep_obj_list), sleep_obj);
}
}
void pybsleep_wakeup (void) {
for (mp_uint_t i = 0; i < MP_STATE_PORT(pybsleep_obj_list).len; i++) {
pybsleep_obj_t *sleep_obj = ((pybsleep_obj_t *)MP_STATE_PORT(pybsleep_obj_list).items[i]);
sleep_obj->wakeup(sleep_obj->obj);
}
}

Wyświetl plik

@ -0,0 +1,37 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2015 Daniel Campora
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef PYBSLEEP_H_
#define PYBSLEEP_H_
typedef void (*WakeUpCB_t)(mp_obj_t self);
void pyblsleep_init0 (void);
void pybsleep_add (mp_obj_t obj, WakeUpCB_t wakeup);
void pybsleep_remove (mp_obj_t obj);
void pybsleep_wakeup (void);
#endif /* PYBSLEEP_H_ */

Wyświetl plik

@ -46,6 +46,7 @@
#include "uart.h"
#include "pybuart.h"
#include "pybioctl.h"
#include "pybsleep.h"
#include "mpexception.h"
#include "py/mpstate.h"
#include "osi.h"
@ -181,6 +182,8 @@ bool uart_init2(pyb_uart_obj_t *self) {
self->enabled = true;
// register it with the sleep module
pybsleep_add (self, (WakeUpCB_t)uart_init2);
return true;
}
@ -512,6 +515,8 @@ STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) {
return mp_const_none;
}
// unregister it with the sleep module
pybsleep_remove (self);
self->enabled = false;
MAP_UARTIntDisable(self->reg, UART_INT_RX | UART_INT_RT);
MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT);

Wyświetl plik

@ -123,6 +123,7 @@ extern const struct _mp_obj_module_t mp_module_network;
mp_obj_list_t pyb_extint_list; \
mp_obj_list_t pyb_uart_list; \
mp_obj_list_t mod_network_nic_list; \
mp_obj_list_t pybsleep_obj_list; \
// type definitions for the specific machine

Wyświetl plik

@ -60,6 +60,7 @@
#include "pybi2c.h"
#include "pybsd.h"
#include "pins.h"
#include "pybsleep.h"
/******************************************************************************
DECLARE PRIVATE CONSTANTS
@ -141,13 +142,14 @@ soft_reset:
mperror_init0();
mpexception_init0();
pyblsleep_init0();
uart_init0();
pin_init0();
// configure stdio uart pins with the correct af
// param 3 ("mode") is DON'T CARE" for AFs others than GPIO
pin_config(&pin_GPIO1, PIN_MODE_3, 0, PIN_TYPE_STD, PIN_STRENGTH_2MA);
pin_config(&pin_GPIO2, PIN_MODE_3, 0, PIN_TYPE_STD, PIN_STRENGTH_2MA);
pin_config ((pin_obj_t *)&pin_GPIO1, PIN_MODE_3, 0, PIN_TYPE_STD, PIN_STRENGTH_2MA);
pin_config ((pin_obj_t *)&pin_GPIO2, PIN_MODE_3, 0, PIN_TYPE_STD, PIN_STRENGTH_2MA);
// Instantiate the stdio uart
mp_obj_t args[2] = {
mp_obj_new_int(MICROPY_STDIO_UART),
@ -157,7 +159,7 @@ soft_reset:
readline_init0();
extint_init0();
mod_network_init();
mod_network_init0();
wlan_init0();
#if MICROPY_HW_ENABLE_RNG
rng_init0();