micropython/cc3200/mods/pybsleep.c

846 lines
30 KiB
C

/*
* 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);
}
}