diff options
34 files changed, 1279 insertions, 1168 deletions
diff --git a/cc3200/FreeRTOS/FreeRTOSConfig.h b/cc3200/FreeRTOS/FreeRTOSConfig.h index e831b10345..2e9a514381 100644 --- a/cc3200/FreeRTOS/FreeRTOSConfig.h +++ b/cc3200/FreeRTOS/FreeRTOSConfig.h @@ -83,7 +83,7 @@ #define configUSE_TICK_HOOK 1 #define configCPU_CLOCK_HZ ( ( unsigned long ) 80000000 ) #define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) -#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 64 ) +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 72 ) #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 16384 ) ) #define configMAX_TASK_NAME_LEN ( 8 ) #define configUSE_TRACE_FACILITY 0 diff --git a/cc3200/application.mk b/cc3200/application.mk index d5b575fa40..c737baaa50 100644 --- a/cc3200/application.mk +++ b/cc3200/application.mk @@ -76,6 +76,7 @@ APP_MISC_SRC_C = $(addprefix misc/,\ FreeRTOSHooks.c \ pin_named_pins.c \ help.c \ + mpcallback.c \ mperror.c \ mpexception.c \ pin_defs_cc3200.c \ @@ -89,8 +90,8 @@ APP_MODS_SRC_C = $(addprefix mods/,\ modutime.c \ modwlan.c \ pybadc.c \ - pybi2c.c \ pybpin.c \ + pybi2c.c \ pybrtc.c \ pybsd.c \ pybsleep.c \ @@ -128,6 +129,7 @@ APP_UTIL_SRC_C = $(addprefix util/,\ APP_UTIL_SRC_S = $(addprefix util/,\ gchelper.s \ + sleeprestore.s \ ) APP_MAIN_SRC_C = \ diff --git a/cc3200/boards/LAUNCHXL/mpconfigboard.h b/cc3200/boards/LAUNCHXL/mpconfigboard.h index 2d12d4f6cb..7044cb003a 100644 --- a/cc3200/boards/LAUNCHXL/mpconfigboard.h +++ b/cc3200/boards/LAUNCHXL/mpconfigboard.h @@ -46,3 +46,5 @@ #define MICROPY_SYS_LED_PORT_PIN GPIO_PIN_1 #define MICROPY_SAFE_BOOT_PORT_PIN GPIO_PIN_6 +#define MICROPY_PORT_SFLASH_BLOCK_COUNT 32 + diff --git a/cc3200/boards/cc3200_prefix.c b/cc3200/boards/cc3200_prefix.c index 2b60134b52..394f8bfa6b 100644 --- a/cc3200/boards/cc3200_prefix.c +++ b/cc3200/boards/cc3200_prefix.c @@ -43,7 +43,7 @@ { \ { &pin_type }, \ .name = MP_QSTR_ ## p_pin_name, \ - .callback = NULL, \ + .callback = mp_const_none, \ .port = PORT_A ## p_port, \ .type = PIN_TYPE_STD, \ .bit = (p_bit), \ diff --git a/cc3200/boards/make-pins.py b/cc3200/boards/make-pins.py index 8d47171337..ebe7e6a33a 100644 --- a/cc3200/boards/make-pins.py +++ b/cc3200/boards/make-pins.py @@ -40,12 +40,11 @@ class Pin(object): self.board_pin = True def print(self): - print('const pin_obj_t pin_{:6s} = PIN({:6s}, {:1d}, {:3d}, {:2d});'.format( + print('pin_obj_t pin_{:6s} = PIN({:6s}, {:1d}, {:3d}, {:2d});'.format( self.name, self.name, self.port, self.gpio_bit, self.pin_num)) def print_header(self, hdr_file): - hdr_file.write('extern const pin_obj_t pin_{:s};\n'. - format(self.name)) + hdr_file.write('extern pin_obj_t pin_{:s};\n'.format(self.name)) class Pins(object): diff --git a/cc3200/bootmgr/main.c b/cc3200/bootmgr/main.c index e718fd9e22..c7c149d217 100644 --- a/cc3200/bootmgr/main.c +++ b/cc3200/bootmgr/main.c @@ -57,7 +57,7 @@ //***************************************************************************** // Local Constants //***************************************************************************** -#define SL_STOP_TIMEOUT 250 +#define SL_STOP_TIMEOUT 35 #define BOOTMGR_HASH_ALGO SHAMD5_ALGO_MD5 #define BOOTMGR_HASH_SIZE 32 #define BOOTMGR_BUFF_SIZE 512 @@ -65,8 +65,8 @@ #define BOOTMGR_WAIT_SAFE_MODE_MS 1600 #define BOOTMGR_WAIT_SAFE_MODE_TOOGLE_MS 200 -#define BOOTMGR_SAFE_MODE_ENTER_MS 700 -#define BOOTMGR_SAFE_MODE_ENTER_TOOGLE_MS 70 +#define BOOTMGR_SAFE_MODE_ENTER_MS 800 +#define BOOTMGR_SAFE_MODE_ENTER_TOOGLE_MS 80 //***************************************************************************** // Exported functions declarations @@ -307,7 +307,7 @@ int main (void) { bootmgr_board_init(); // start simplelink since we need it to access the sflash - sl_Start(NULL, NULL, NULL); + sl_Start(0, 0, 0); // if a boot info file is found, load it, else, create a new one with the default boot info if (!sl_FsOpen((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_READ, NULL, &fhandle)) { diff --git a/cc3200/fatfs/src/drivers/sflash_diskio.h b/cc3200/fatfs/src/drivers/sflash_diskio.h index 26669f5898..de3093439c 100644 --- a/cc3200/fatfs/src/drivers/sflash_diskio.h +++ b/cc3200/fatfs/src/drivers/sflash_diskio.h @@ -2,7 +2,7 @@ #define SFLASH_DISKIO_H_ #define SFLASH_BLOCK_SIZE 2048 -#define SFLASH_BLOCK_COUNT 32 // makes for 64KB of space +#define SFLASH_BLOCK_COUNT MICROPY_PORT_SFLASH_BLOCK_COUNT #define SFLASH_SECTOR_SIZE 512 #define SFLASH_SECTOR_COUNT ((SFLASH_BLOCK_SIZE * SFLASH_BLOCK_COUNT) / SFLASH_SECTOR_SIZE) #define SFLASH_SECTORS_PER_BLOCK (SFLASH_BLOCK_SIZE / SFLASH_SECTOR_SIZE) diff --git a/cc3200/hal/startup_gcc.c b/cc3200/hal/startup_gcc.c index 2d364f87d1..5dff9ffda4 100644 --- a/cc3200/hal/startup_gcc.c +++ b/cc3200/hal/startup_gcc.c @@ -65,7 +65,7 @@ void ResetISR(void); #ifdef DEBUG static void NmiSR(void) __attribute__( ( naked ) ); static void FaultISR( void ) __attribute__( ( naked ) ); -void HardFault_HandlerC(unsigned long *hardfault_args); +void HardFault_HandlerC(uint32_t *pulFaultStackAddress); static void BusFaultHandler(void) __attribute__( ( naked ) ); #endif static void IntDefaultHandler(void) __attribute__( ( naked ) ); diff --git a/cc3200/misc/mpcallback.c b/cc3200/misc/mpcallback.c new file mode 100644 index 0000000000..3a5611f5df --- /dev/null +++ b/cc3200/misc/mpcallback.c @@ -0,0 +1,205 @@ +/* + * 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 "py/mpconfig.h" +#include MICROPY_HAL_H +#include "py/obj.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "inc/hw_types.h" +#include "interrupt.h" +#include "pybsleep.h" +#include "mpcallback.h" +#include "mpexception.h" +#include "mperror.h" + + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC mpcallback_obj_t *mpcallback_find (mp_obj_t parent); + +/****************************************************************************** + DEFINE PUBLIC DATA + ******************************************************************************/ +const mp_arg_t mpcallback_init_args[] = { + { MP_QSTR_intmode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_priority, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_wake, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PYB_PWR_MODE_ACTIVE_IDLE } }, +}; + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +void mpcallback_init0 (void) { + // initialize the callback objects list + mp_obj_list_init(&MP_STATE_PORT(mpcallback_obj_list), 0); +} + +mp_obj_t mpcallback_new (mp_obj_t parent, mp_obj_t handler, const mp_cb_methods_t *methods) { + mpcallback_obj_t *self = m_new_obj(mpcallback_obj_t); + self->base.type = &pyb_callback_type; + self->handler = handler; + self->parent = parent; + self->methods = (mp_cb_methods_t *)methods; + // remove any old callback if present + mpcallback_remove(self->parent); + mp_obj_list_append(&MP_STATE_PORT(mpcallback_obj_list), self); + return self; +} + +void mpcallback_remove (const mp_obj_t parent) { + mpcallback_obj_t *callback_obj; + if ((callback_obj = mpcallback_find(parent))) { + mp_obj_list_remove(&MP_STATE_PORT(mpcallback_obj_list), callback_obj); + } +} + +uint mpcallback_translate_priority (uint priority) { + if (priority < 1 || priority > 7) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + } + + switch (priority) { + case 1: + return INT_PRIORITY_LVL_7; + case 2: + return INT_PRIORITY_LVL_6; + case 3: + return INT_PRIORITY_LVL_5; + case 4: + return INT_PRIORITY_LVL_4; + case 5: + return INT_PRIORITY_LVL_3; + case 6: + return INT_PRIORITY_LVL_2; + case 7: + return INT_PRIORITY_LVL_1; + default: + return INT_PRIORITY_LVL_7; + } +} + +void mpcallback_handler (mp_obj_t self_in) { + mpcallback_obj_t *self = self_in; + if (self->handler != mp_const_none) { + // disable interrupts to avoid nesting + uint primsk = disable_irq(); + // when executing code within a handler we must lock the GC to prevent + // any memory allocations. We must also catch any exceptions. + gc_lock(); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_call_function_1(self->handler, self->parent); + nlr_pop(); + } + else { + // uncaught exception; disable the callback so that it doesn't run again + self->methods->disable (self->parent); + self->handler = mp_const_none; + // printing an exception here will cause a stack overflow that will end up in + // a hard fault, so is better to signal the uncaught (probably non-recoverable) + // exception by blinking the system led instead. + mperror_signal_error(); + } + gc_unlock(); + enable_irq(primsk); + } +} + +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC mpcallback_obj_t *mpcallback_find (mp_obj_t parent) { + for (mp_uint_t i = 0; i < MP_STATE_PORT(mpcallback_obj_list).len; i++) { + // search for the object and then remove it + mpcallback_obj_t *callback_obj = ((mpcallback_obj_t *)(MP_STATE_PORT(mpcallback_obj_list).items[i])); + if (callback_obj->parent == parent) { + return callback_obj; + } + } + return NULL; +} + +/******************************************************************************/ +// Micro Python bindings + +/// \method init() +/// Initializes the interrupt callback. With no parameters passed, everything will default +/// to the values assigned to mpcallback_init_args[]. +STATIC mp_obj_t callback_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mpcallback_obj_t *self = pos_args[0]; + // this is a bit of a hack, but it let us reuse the callback_create method from our parent + ((mp_obj_t *)pos_args)[0] = self->parent; + self->methods->init (n_args, pos_args, kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(callback_init_obj, 1, callback_init); + +/// \method enable() +/// Enables the interrupt callback +STATIC mp_obj_t callback_enable (mp_obj_t self_in) { + mpcallback_obj_t *self = self_in; + self->methods->enable(self->parent); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(callback_enable_obj, callback_enable); + +/// \method disable() +/// Disables the interrupt callback +STATIC mp_obj_t callback_disable (mp_obj_t self_in) { + mpcallback_obj_t *self = self_in; + self->methods->disable(self->parent); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(callback_disable_obj, callback_disable); + +/// \method \call() +/// Triggers the interrupt callback +STATIC mp_obj_t callback_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 0, false); + mpcallback_handler (self_in); + return mp_const_none; +} + +STATIC const mp_map_elem_t callback_locals_dict_table[] = { + // instance methods + { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&callback_init_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&callback_enable_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&callback_disable_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(callback_locals_dict, callback_locals_dict_table); + +const mp_obj_type_t pyb_callback_type = { + { &mp_type_type }, + .name = MP_QSTR_callback, + .call = callback_call, + .locals_dict = (mp_obj_t)&callback_locals_dict, +}; + diff --git a/cc3200/misc/mpcallback.h b/cc3200/misc/mpcallback.h new file mode 100644 index 0000000000..e0a9fc6a92 --- /dev/null +++ b/cc3200/misc/mpcallback.h @@ -0,0 +1,70 @@ +/* + * 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 MPCALLBACK_H_ +#define MPCALLBACK_H_ + +/****************************************************************************** + DEFINE CONSTANTS + ******************************************************************************/ +#define mpcallback_INIT_NUM_ARGS 5 + +/****************************************************************************** + DEFINE TYPES + ******************************************************************************/ +typedef void (*mp_cb_method_t) (mp_obj_t self); +typedef mp_obj_t (*mp_cb_init_t) (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +typedef struct { + mp_cb_init_t init; + mp_cb_method_t enable; + mp_cb_method_t disable; +} mp_cb_methods_t; + +typedef struct { + mp_obj_base_t base; + mp_obj_t parent; + mp_obj_t handler; + mp_cb_methods_t *methods; +} mpcallback_obj_t; + +/****************************************************************************** + DECLARE EXPORTED DATA + ******************************************************************************/ +extern const mp_arg_t mpcallback_init_args[]; +extern const mp_obj_type_t pyb_callback_type; + +/****************************************************************************** + DECLARE PUBLIC FUNCTIONS + ******************************************************************************/ +void mpcallback_init0 (void); +mp_obj_t mpcallback_new (mp_obj_t parent, mp_obj_t handler, const mp_cb_methods_t *methods); +void mpcallback_remove (const mp_obj_t parent); +void mpcallback_handler (mp_obj_t self_in); +uint mpcallback_translate_priority (uint priority); +mp_obj_t mpcallback_new (mp_obj_t parent, mp_obj_t handler, const mp_cb_methods_t *methods); + +#endif /* MPCALLBACK_H_ */ diff --git a/cc3200/misc/mperror.c b/cc3200/misc/mperror.c index 522e76396f..32e04ba00c 100644 --- a/cc3200/misc/mperror.c +++ b/cc3200/misc/mperror.c @@ -51,8 +51,8 @@ /****************************************************************************** DEFINE CONSTANTS ******************************************************************************/ -#define MPERROR_TOOGLE_MS (200) -#define MPERROR_SIGNAL_ERROR_MS (2000) +#define MPERROR_TOOGLE_MS (40) +#define MPERROR_SIGNAL_ERROR_MS (1000) #define MPERROR_HEARTBEAT_ON_MS (80) #define MPERROR_HEARTBEAT_OFF_MS (2920) @@ -113,7 +113,7 @@ void mperror_deinit_sfe_pin (void) { void mperror_signal_error (void) { uint32_t count = 0; - while ((MPERROR_TOOGLE_MS * count++) > MPERROR_SIGNAL_ERROR_MS) { + while ((MPERROR_TOOGLE_MS * count++) < MPERROR_SIGNAL_ERROR_MS) { // toogle the led MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, ~MAP_GPIOPinRead(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN)); UtilsDelay(UTILS_DELAY_US_TO_COUNT(MPERROR_TOOGLE_MS * 1000)); diff --git a/cc3200/misc/pin_defs_cc3200.c b/cc3200/misc/pin_defs_cc3200.c index e585161bc0..a9b9413a12 100644 --- a/cc3200/misc/pin_defs_cc3200.c +++ b/cc3200/misc/pin_defs_cc3200.c @@ -26,6 +26,7 @@ */ #include "py/mpconfig.h" +#include MICROPY_HAL_H #include "py/obj.h" #include "inc/hw_types.h" #include "inc/hw_gpio.h" @@ -35,32 +36,20 @@ #include "gpio.h" #include "pin.h" #include "pybpin.h" -#include MICROPY_HAL_H + // Returns the pin mode. This value returned by this macro should be one of: // GPIO_DIR_MODE_IN or GPIO_DIR_MODE_OUT -uint32_t pin_get_mode(const pin_obj_t *self) { - return MAP_GPIODirModeGet(self->port, self->bit); +uint32_t pin_get_mode (const pin_obj_t *self) { + return self->mode; } -uint32_t pin_get_type(const pin_obj_t *self) { - - uint32_t strenght; - uint32_t type; - - MAP_PinConfigGet(self->pin_num, &strenght, &type); - - return type; +uint32_t pin_get_type (const pin_obj_t *self) { + return self->type; } uint32_t pin_get_strenght (const pin_obj_t *self) { - - uint32_t strenght; - uint32_t type; - - MAP_PinConfigGet(self->pin_num, &strenght, &type); - - return strenght; + return self->strength; } diff --git a/cc3200/misc/pin_named_pins.c b/cc3200/misc/pin_named_pins.c index 67f75c3302..590e013d44 100644 --- a/cc3200/misc/pin_named_pins.c +++ b/cc3200/misc/pin_named_pins.c @@ -49,7 +49,7 @@ const mp_obj_type_t pin_cpu_pins_obj_type = { .locals_dict = (mp_obj_t)&pin_cpu_pins_locals_dict, }; -const pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name) { +pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name) { mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)named_pins); mp_map_elem_t *named_elem = mp_map_lookup(named_map, name, MP_MAP_LOOKUP); if (named_elem != NULL && named_elem->value != NULL) { @@ -58,7 +58,7 @@ const pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t na return NULL; } -const pin_obj_t *pin_find_pin(const mp_obj_dict_t *named_pins, uint pin_num) { +pin_obj_t *pin_find_pin(const mp_obj_dict_t *named_pins, uint pin_num) { mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)named_pins); for (uint i = 0; i < named_map->used; i++) { if (((pin_obj_t *)named_map->table[i].value)->pin_num == pin_num) { @@ -68,7 +68,7 @@ const pin_obj_t *pin_find_pin(const mp_obj_dict_t *named_pins, uint pin_num) { return NULL; } -const pin_obj_t *pin_find_pin_by_port_bit (const mp_obj_dict_t *named_pins, uint port, uint bit) { +pin_obj_t *pin_find_pin_by_port_bit (const mp_obj_dict_t *named_pins, uint port, uint bit) { mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)named_pins); for (uint i = 0; i < named_map->used; i++) { if ((((pin_obj_t *)named_map->table[i].value)->port == port) && diff --git a/cc3200/mods/modpyb.c b/cc3200/mods/modpyb.c index 0caea7b3d5..13c787cc4e 100644 --- a/cc3200/mods/modpyb.c +++ b/cc3200/mods/modpyb.c @@ -30,6 +30,7 @@ #include <stdint.h> #include "py/mpstate.h" +#include "py/runtime.h" #include MICROPY_HAL_H #include "irq.h" #include "inc/hw_types.h" @@ -45,6 +46,7 @@ #include "pybsystick.h" #include "simplelink.h" #include "modwlan.h" +#include "moduos.h" #include "telnet.h" #include "ff.h" #include "diskio.h" @@ -53,11 +55,13 @@ #include "portable.h" #include "task.h" #include "mpexception.h" +#include "mpcallback.h" #include "random.h" #include "pybadc.h" #include "pybi2c.h" #include "pybsd.h" #include "pybwdt.h" +#include "pybsleep.h" #include "utils.h" #include "gccollect.h" #include "mperror.h" @@ -69,6 +73,7 @@ extern OsiTaskHandle svTaskHandle; extern OsiTaskHandle xSimpleLinkSpawnTaskHndl; #endif + /// \module pyb - functions related to the pyboard /// /// The `pyb` module contains specific functions related to the pyboard. @@ -117,15 +122,6 @@ STATIC mp_obj_t pyb_info(uint n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_info_obj, 0, 1, pyb_info); #endif -/// \function unique_id() -/// Returns a string of 6 bytes (48 bits), which is the unique MAC address of the SoC -STATIC mp_obj_t pyb_mac(void) { - uint8_t mac[6]; - wlan_get_mac (mac); - return mp_obj_new_bytes(mac, 6); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_mac_obj, pyb_mac); - /// \function freq() /// Returns the CPU frequency: (F_CPU). STATIC mp_obj_t pyb_freq(void) { @@ -133,14 +129,6 @@ STATIC mp_obj_t pyb_freq(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_freq_obj, pyb_freq); -/// \function sync() -/// Sync all file systems. -STATIC mp_obj_t pyb_sync(void) { - sflash_disk_flush(); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_sync_obj, pyb_sync); - /// \function millis() /// Returns the number of milliseconds since the board was last reset. /// @@ -225,18 +213,6 @@ STATIC mp_obj_t pyb_udelay(mp_obj_t usec_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_udelay_obj, pyb_udelay); -STATIC mp_obj_t pyb_stop(void) { - return mp_const_none; -} - -MP_DEFINE_CONST_FUN_OBJ_0(pyb_stop_obj, pyb_stop); - -STATIC mp_obj_t pyb_standby(void) { - return mp_const_none; -} - -MP_DEFINE_CONST_FUN_OBJ_0(pyb_standby_obj, pyb_standby); - /// \function repl_uart(uart) /// Get or set the UART object that the REPL is repeated on. STATIC mp_obj_t pyb_repl_uart(uint n_args, const mp_obj_t *args) { @@ -275,31 +251,26 @@ MP_DECLARE_CONST_FUN_OBJ(pyb_main_obj); // defined in main.c STATIC const mp_map_elem_t pyb_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_hard_reset), (mp_obj_t)&pyb_hard_reset_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&pyb_hard_reset_obj }, #ifdef DEBUG { MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&pyb_info_obj }, #endif - { MP_OBJ_NEW_QSTR(MP_QSTR_mac), (mp_obj_t)&pyb_mac_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&pyb_freq_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_repl_info), (mp_obj_t)&pyb_set_repl_info_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_repl_uart), (mp_obj_t)&pyb_repl_uart_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_wfi), (mp_obj_t)&pyb_wfi_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_disable_irq), (mp_obj_t)&pyb_disable_irq_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_enable_irq), (mp_obj_t)&pyb_enable_irq_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_stop), (mp_obj_t)&pyb_stop_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_standby), (mp_obj_t)&pyb_standby_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_main), (mp_obj_t)&pyb_main_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_repl_uart), (mp_obj_t)&pyb_repl_uart_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_millis), (mp_obj_t)&pyb_millis_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_elapsed_millis), (mp_obj_t)&pyb_elapsed_millis_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_micros), (mp_obj_t)&pyb_micros_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_elapsed_micros), (mp_obj_t)&pyb_elapsed_micros_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_delay), (mp_obj_t)&pyb_delay_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_udelay), (mp_obj_t)&pyb_udelay_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&pyb_sync_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&os_sync_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_mkdisk), (mp_obj_t)&pyb_mkdisk_obj }, #if MICROPY_HW_ENABLE_RNG @@ -315,6 +286,7 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_I2C), (mp_obj_t)&pyb_i2c_type }, { MP_OBJ_NEW_QSTR(MP_QSTR_UART), (mp_obj_t)&pyb_uart_type }, { MP_OBJ_NEW_QSTR(MP_QSTR_WDT), (mp_obj_t)&pyb_wdt_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_Sleep), (mp_obj_t)&pyb_sleep_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_HeartBeat), (mp_obj_t)&pyb_heartbeat_obj }, #if MICROPY_HW_HAS_SDCARD diff --git a/cc3200/mods/moduos.c b/cc3200/mods/moduos.c index 418f3608a8..b071413d1e 100644 --- a/cc3200/mods/moduos.c +++ b/cc3200/mods/moduos.c @@ -282,11 +282,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_stat_obj, os_stat); /// \function sync() /// Sync all filesystems. -STATIC mp_obj_t os_sync(void) { +mp_obj_t os_sync(void) { sflash_disk_flush(); return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_sync_obj, os_sync); +MP_DEFINE_CONST_FUN_OBJ_0(os_sync_obj, os_sync); #if MICROPY_HW_ENABLE_RNG /// \function urandom(n) diff --git a/cc3200/mods/moduos.h b/cc3200/mods/moduos.h new file mode 100644 index 0000000000..8ce872c4b1 --- /dev/null +++ b/cc3200/mods/moduos.h @@ -0,0 +1,33 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * 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 MODUTIME_H_ +#define MODUTIME_H_ + +MP_DECLARE_CONST_FUN_OBJ(os_sync_obj); + +#endif // MODUTIME_H_ diff --git a/cc3200/mods/modutime.h b/cc3200/mods/modutime.h index 5f1e8ed746..bc2be9cfa2 100644 --- a/cc3200/mods/modutime.h +++ b/cc3200/mods/modutime.h @@ -25,6 +25,9 @@ * THE SOFTWARE. */ +#ifndef MODUOS_H_ +#define MODUOS_H_ + typedef struct { uint16_t tm_year; // i.e. 2014 uint8_t tm_mon; // 1..12 @@ -41,3 +44,5 @@ extern mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp mp_uint_t hour, mp_uint_t minute, mp_uint_t second); extern void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm); + +#endif // MODUOS_H_ diff --git a/cc3200/mods/modwlan.c b/cc3200/mods/modwlan.c index 6cb1ec21d6..c4f9bb31ac 100644 --- a/cc3200/mods/modwlan.c +++ b/cc3200/mods/modwlan.c @@ -41,6 +41,8 @@ #include "serverstask.h" #endif #include "mpexception.h" +#include "mpcallback.h" +#include "pybsleep.h" /****************************************************************************** @@ -77,6 +79,7 @@ typedef enum{ typedef struct _wlan_obj_t { mp_obj_base_t base; + mp_obj_t callback; SlWlanMode_t mode; uint32_t status; @@ -122,7 +125,6 @@ typedef struct _wlan_obj_t { #define ASSERT_ON_ERROR( x ) ASSERT((x) >= 0 ) #define IPV4_ADDR_STR_LEN_MAX (16) -#define SL_STOP_TIMEOUT 250 #define WLAN_MAX_RX_SIZE 16000 #define WLAN_MAX_TX_SIZE 1476 @@ -147,6 +149,7 @@ typedef struct _wlan_obj_t { DECLARE PRIVATE DATA ******************************************************************************/ STATIC wlan_obj_t wlan_obj; +STATIC const mp_cb_methods_t wlan_cb_methods; /****************************************************************************** DECLARE PUBLIC DATA @@ -161,7 +164,8 @@ STATIC void wlan_reenable (SlWlanMode_t mode); STATIC void wlan_get_sl_mac (void); STATIC modwlan_Status_t wlan_do_connect (const char* ssid, uint32_t ssid_len, const char* bssid, uint8_t sec, const char* key, uint32_t key_len); - +STATIC void wlan_callback_enable (mp_obj_t self_in); +STATIC void wlan_callback_disable (mp_obj_t self_in); //***************************************************************************** // @@ -555,10 +559,6 @@ void wlan_get_ip (uint32_t *ip) { } } -void wlan_set_pm_policy (uint8_t policy) { - ASSERT_ON_ERROR(sl_WlanPolicySet(SL_POLICY_PM, policy, NULL, 0)); -} - void wlan_stop_servers (void) { #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) servers_disable(); @@ -657,7 +657,7 @@ STATIC mp_obj_t wlan_init_helper(mp_uint_t n_args, const mp_obj_t *pos_args, mp_ const char *key = mp_obj_str_get_data(args[3].u_obj, &key_len); if (key_len < 8) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, mpexception_value_invalid_arguments)); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); } // Force the channel to be between 1-11 @@ -670,6 +670,13 @@ STATIC mp_obj_t wlan_init_helper(mp_uint_t n_args, const mp_obj_t *pos_args, mp_ return mp_const_none; } +STATIC void wlan_callback_enable (mp_obj_t self_in) { + pybsleep_set_wlan_wake_callback (wlan_obj.callback); +} + +STATIC void wlan_callback_disable (mp_obj_t self_in) { + pybsleep_set_wlan_wake_callback (NULL); +} /******************************************************************************/ // Micro Python bindings; WLAN class @@ -714,7 +721,7 @@ STATIC mp_obj_t wlan_make_new (mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_k STATIC void wlan_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { wlan_obj_t *self = self_in; - print(env, "<WLAN mode=%u", self->mode); + print(env, "<WLAN, mode=%u", self->mode); // only print the bssid if in station mode if (self->mode != ROLE_AP && GET_STATUS_BIT(self->status, STATUS_BIT_CONNECTION)) { @@ -739,16 +746,6 @@ STATIC mp_obj_t wlan_getmode(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_getmode_obj, wlan_getmode); -STATIC mp_obj_t wlan_setpm(mp_obj_t self_in, mp_obj_t pm_mode) { - mp_int_t mode = mp_obj_get_int(pm_mode); - if (mode < SL_NORMAL_POLICY || mode > SL_LONG_SLEEP_INTERVAL_POLICY) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); - } - wlan_set_pm_policy((uint8_t)mode); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(wlan_setpm_obj, wlan_setpm); - /// \method connect(ssid, security=OPEN, key=None, bssid=None) // if security is WPA/WPA2, the key must be a string /// if security is WEP, the key must be binary @@ -947,6 +944,32 @@ STATIC mp_obj_t wlan_scan(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_scan_obj, wlan_scan); +/// \method callback(method, intmode, value, priority, pwrmode) +/// Creates a callback object associated with WLAN +/// min num of arguments is 1 (intmode) +STATIC mp_obj_t wlan_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_arg_val_t args[mpcallback_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args); + + wlan_obj_t *self = pos_args[0]; + // check if any parameters were passed + if (kw_args->used > 0 || self->callback == mp_const_none) { + // check the power mode + if (args[4].u_int != PYB_PWR_MODE_LPDS) { + // throw an exception since WLAN only supports LPDS mode + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + } + + // create the callback + self->callback = mpcallback_new (self, args[1].u_obj, &wlan_cb_methods); + + // enable network wakeup + pybsleep_set_wlan_wake_callback (self->callback); + } + return self->callback; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_callback_obj, 1, wlan_callback); + #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) STATIC mp_obj_t wlan_serversstart(mp_obj_t self_in) { servers_enable(); @@ -977,12 +1000,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_3(wlan_serversuserpass_obj, wlan_serversuserpass) STATIC const mp_map_elem_t wlan_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&wlan_connect_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_getmode), (mp_obj_t)&wlan_getmode_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_setpm), (mp_obj_t)&wlan_setpm_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_scan), (mp_obj_t)&wlan_scan_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_disconnect), (mp_obj_t)&wlan_disconnect_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_isconnected), (mp_obj_t)&wlan_isconnected_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ifconfig), (mp_obj_t)&wlan_ifconfig_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_urn), (mp_obj_t)&wlan_urn_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&wlan_callback_obj }, #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) { MP_OBJ_NEW_QSTR(MP_QSTR_start_servers), (mp_obj_t)&wlan_serversstart_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_stop_servers), (mp_obj_t)&wlan_serversstop_obj }, @@ -1000,14 +1023,14 @@ STATIC const mp_map_elem_t wlan_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_STA), MP_OBJ_NEW_SMALL_INT(ROLE_STA) }, { MP_OBJ_NEW_QSTR(MP_QSTR_AP), MP_OBJ_NEW_SMALL_INT(ROLE_AP) }, { MP_OBJ_NEW_QSTR(MP_QSTR_P2P), MP_OBJ_NEW_SMALL_INT(ROLE_P2P) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_NORMAL_PM), MP_OBJ_NEW_SMALL_INT(SL_NORMAL_POLICY) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_LOW_LATENCY_PM), MP_OBJ_NEW_SMALL_INT(SL_LOW_LATENCY_POLICY) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_LOW_POWER_PM), MP_OBJ_NEW_SMALL_INT(SL_LOW_POWER_POLICY) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ALWAYS_ON_PM), MP_OBJ_NEW_SMALL_INT(SL_ALWAYS_ON_POLICY) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_LONG_SLEEP_PM), MP_OBJ_NEW_SMALL_INT(SL_LONG_SLEEP_INTERVAL_POLICY) }, }; STATIC MP_DEFINE_CONST_DICT(wlan_locals_dict, wlan_locals_dict_table); +STATIC const mp_cb_methods_t wlan_cb_methods = { + .init = wlan_callback, + .enable = wlan_callback_enable, + .disable = wlan_callback_disable, +}; /******************************************************************************/ // Micro Python bindings; WLAN socket diff --git a/cc3200/mods/modwlan.h b/cc3200/mods/modwlan.h index 684708e647..da60d2690f 100644 --- a/cc3200/mods/modwlan.h +++ b/cc3200/mods/modwlan.h @@ -32,6 +32,7 @@ ******************************************************************************/ #define SIMPLELINK_SPAWN_TASK_PRIORITY 3 #define SIMPLELINK_TASK_STACK_SIZE 2048 +#define SL_STOP_TIMEOUT 35 /****************************************************************************** DEFINE TYPES @@ -40,8 +41,7 @@ typedef enum { MODWLAN_OK = 0, MODWLAN_ERROR_INVALID_PARAMS = -1, MODWLAN_ERROR_TIMEOUT = -2, - MODWLAN_ERROR_UNKNOWN = -3 - + MODWLAN_ERROR_UNKNOWN = -3, }modwlan_Status_t; /****************************************************************************** @@ -60,7 +60,6 @@ extern void wlan_start (void); extern SlWlanMode_t wlan_get_mode (void); extern void wlan_get_mac (uint8_t *macAddress); extern void wlan_get_ip (uint32_t *ip); -extern void wlan_set_pm_policy (uint8_t policy); extern void wlan_stop_servers (void); #endif /* MODWLAN_H_ */ diff --git a/cc3200/mods/pybpin.c b/cc3200/mods/pybpin.c index 493446d533..7e561064ce 100644 --- a/cc3200/mods/pybpin.c +++ b/cc3200/mods/pybpin.c @@ -34,6 +34,7 @@ #include "py/obj.h" #include "py/runtime.h" #include "py/gc.h" +#include "py/mpstate.h" #include "inc/hw_types.h" #include "inc/hw_gpio.h" #include "inc/hw_ints.h" @@ -45,6 +46,7 @@ #include "interrupt.h" #include "pybpin.h" #include "pybsleep.h" +#include "mpcallback.h" #include "mpexception.h" #include "mperror.h" @@ -87,10 +89,15 @@ /// /// Example callback: /// -/// def pincb(pin): -/// print(pin.pin()) +/// def pincb(pin): +/// print(pin.pin()) /// -/// extint = pyb.Pin('GPIO10', 0, pyb.Pin.INT_FALLING, pyb.GPIO.STD_PU, pyb.S2MA, callback=pincb) +/// extint = pyb.Pin('GPIO10', 0, pyb.Pin.INT_RISING, pyb.GPIO.STD_PD, pyb.S2MA) +/// extint.callback (intmode=pyb.Pin.INT_RISING, handler=pincb) +/// # the callback can be triggered manually +/// extint.callback()() +/// # to disable the callback +/// extint.callback().disable() /// /// Now every time a falling edge is seen on the gpio pin, the callback will be /// called. Caution: mechanical pushbuttons have "bounce" and pushing or @@ -101,33 +108,34 @@ /// All pin objects go through the pin mapper to come up with one of the /// gpio pins. /// -/// extint = pyb.Pin(pin, af, mode, pull, strength, callback) -/// /// There is also a C API, so that drivers which require Pin interrupts /// can also use this code. See pybextint.h for the available functions. /****************************************************************************** DECLARE PRIVATE FUNCTIONS ******************************************************************************/ -STATIC void ExecuteIntCallback (pin_obj_t *self); STATIC void GPIOA0IntHandler (void); STATIC void GPIOA1IntHandler (void); STATIC void GPIOA2IntHandler (void); STATIC void GPIOA3IntHandler (void); STATIC void EXTI_Handler(uint port); -STATIC mp_obj_t pin_obj_init_helper(pin_obj_t *pin, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); STATIC void pin_obj_configure (const pin_obj_t *self); +STATIC void pin_extint_enable (mp_obj_t self_in); +STATIC void pin_extint_disable (mp_obj_t self_in); +/****************************************************************************** +DECLARE PRIVATE DATA +******************************************************************************/ +STATIC const mp_cb_methods_t pin_cb_methods; /****************************************************************************** DEFINE PUBLIC FUNCTIONS ******************************************************************************/ void pin_init0(void) { - } // C API used to convert a user-supplied pin name into an ordinal pin number. -const pin_obj_t *pin_find(mp_obj_t user_obj) { - const pin_obj_t *pin_obj; +pin_obj_t *pin_find(mp_obj_t user_obj) { + pin_obj_t *pin_obj; // If a pin was provided, then use it if (MP_OBJ_IS_TYPE(user_obj, &pin_type)) { @@ -162,25 +170,21 @@ void pin_verify_af (uint af) { 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; + self->af = af; + self->mode = mode; + self->type = type; + self->strength = strength; pin_obj_configure ((const pin_obj_t *)self); // mark the pin as used - ((pin_obj_t *)self)->used = true; + self->used = true; // register it with the sleep module - pybsleep_add (self, (WakeUpCB_t)pin_obj_configure); + pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)pin_obj_configure); } -void pin_extint_register(pin_obj_t *self, uint32_t intmode, mp_obj_t callback) { +void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t priority) { void *handler; uint32_t intnum; - // we need to update the callback atomically, so we disable the line - // before we update anything. - pin_extint_disable(self); - // configure the interrupt type MAP_GPIOIntTypeSet(self->port, self->bit, intmode); switch (self->port) { @@ -205,24 +209,7 @@ void pin_extint_register(pin_obj_t *self, uint32_t intmode, mp_obj_t callback) { MAP_GPIOIntRegister(self->port, handler); // set the interrupt to the lowest priority, to make sure that // no other ISRs will be preemted by this one - MAP_IntPrioritySet(intnum, INT_PRIORITY_LVL_7); - // set the callback - self->callback = callback; - // enable the interrupt just before leaving - pin_extint_enable(self); -} - -void pin_extint_enable(pin_obj_t *self) { - MAP_GPIOIntClear(self->port, self->bit); - MAP_GPIOIntEnable(self->port, self->bit); -} - -void pin_extint_disable(pin_obj_t *self) { - MAP_GPIOIntDisable(self->port, self->bit); -} - -void pin_extint_swint(pin_obj_t *self) { - ExecuteIntCallback(self); + MAP_IntPrioritySet(intnum, priority); } /****************************************************************************** @@ -261,77 +248,20 @@ STATIC void pin_obj_configure (const pin_obj_t *self) { MAP_PinConfigSet(self->pin_num, self->strength, self->type); } -/// \method print() -/// Return a string describing the pin object. -STATIC void pin_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { +STATIC void pin_extint_enable (mp_obj_t self_in) { pin_obj_t *self = self_in; - uint32_t af = MAP_PinModeGet(self->pin_num); - uint32_t type = pin_get_type(self); - uint32_t strength = pin_get_strenght(self); - - // pin name - print(env, "Pin(Pin.cpu.%s, af=%u", qstr_str(self->name), af); - - if (af == PIN_MODE_0) { - // IO mode - qstr mode_qst; - uint32_t mode = pin_get_mode(self); - if (mode == GPIO_DIR_MODE_IN) { - mode_qst = MP_QSTR_IN; - } else { - mode_qst = MP_QSTR_OUT; - } - print(env, ", mode=Pin.%s", qstr_str(mode_qst)); // safe because mode_qst has no formatting chars - } - - // pin type - qstr type_qst; - if (type == PIN_TYPE_STD) { - type_qst = MP_QSTR_STD; - } else if (type == PIN_TYPE_STD_PU) { - type_qst = MP_QSTR_STD_PU; - } else if (type == PIN_TYPE_STD_PD) { - type_qst = MP_QSTR_STD_PD; - } else if (type == PIN_TYPE_OD) { - type_qst = MP_QSTR_OD; - } else if (type == PIN_TYPE_OD_PU) { - type_qst = MP_QSTR_OD_PU; - } else { - type_qst = MP_QSTR_OD_PD; - } - print(env, ", pull=Pin.%s", qstr_str(type_qst)); - - // Strength - qstr str_qst; - if (strength == PIN_STRENGTH_2MA) { - str_qst = MP_QSTR_S2MA; - } else if (strength == PIN_STRENGTH_4MA) { - str_qst = MP_QSTR_S4MA; - } else { - str_qst = MP_QSTR_S6MA; - } - print(env, ", strength=Pin.%s)", qstr_str(str_qst)); + MAP_GPIOIntClear(self->port, self->bit); + MAP_GPIOIntEnable(self->port, self->bit); } -/// \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`. -STATIC mp_obj_t pin_make_new(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); - - // Run an argument through the mapper and return the result. - pin_obj_t *pin = (pin_obj_t *)pin_find(args[0]); - - if (n_args > 1) { - // pin af given, so configure it - mp_map_t kw_args; - mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); - pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args); - } - - return (mp_obj_t)pin; +STATIC void pin_extint_disable (mp_obj_t self_in) { + pin_obj_t *self = self_in; + MAP_GPIOIntDisable(self->port, self->bit); } +/******************************************************************************/ +// Micro Python bindings + /// \method init(mode, pull=Pin.PULL_NONE, af=-1) /// Initialise the pin: /// @@ -359,7 +289,6 @@ STATIC const mp_arg_t pin_init_args[] = { { MP_QSTR_mode, MP_ARG_INT, {.u_int = GPIO_DIR_MODE_OUT} }, { MP_QSTR_type, MP_ARG_INT, {.u_int = PIN_TYPE_STD} }, { MP_QSTR_str, MP_ARG_INT, {.u_int = PIN_STRENGTH_4MA} }, - { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; #define pin_INIT_NUM_ARGS MP_ARRAY_SIZE(pin_init_args) @@ -375,17 +304,10 @@ STATIC mp_obj_t pin_obj_init_helper(pin_obj_t *self, mp_uint_t n_args, const mp_ } // get the io mode uint mode = args[1].u_int; - uint intmode = 0xFF; // checking the mode only makes sense if af == GPIO if (af == PIN_MODE_0) { if (mode != GPIO_DIR_MODE_IN && mode != GPIO_DIR_MODE_OUT) { - if (mode != GPIO_FALLING_EDGE && mode != GPIO_RISING_EDGE && mode != GPIO_BOTH_EDGES && - mode != GPIO_LOW_LEVEL && mode != GPIO_HIGH_LEVEL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); - } - // select input mode for interrupt triggering - intmode = mode; - mode = GPIO_DIR_MODE_IN; + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); } } // get the type @@ -403,12 +325,78 @@ STATIC mp_obj_t pin_obj_init_helper(pin_obj_t *self, mp_uint_t n_args, const mp_ // configure the pin as requested pin_config (self, af, mode, type, strength); - // register the interrupt if the mode says so - if (intmode != 0xFF) { - pin_extint_register(self, intmode, args[4].u_obj); + return mp_const_none; +} + +/// \method print() +/// Return a string describing the pin object. +STATIC void pin_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { + pin_obj_t *self = self_in; + uint32_t af = MAP_PinModeGet(self->pin_num); + uint32_t type = pin_get_type(self); + uint32_t strength = pin_get_strenght(self); + + // pin name + print(env, "<Pin.cpu.%s, af=%u", qstr_str(self->name), af); + + if (af == PIN_MODE_0) { + // IO mode + qstr mode_qst; + uint32_t mode = pin_get_mode(self); + if (mode == GPIO_DIR_MODE_IN) { + mode_qst = MP_QSTR_IN; + } else { + mode_qst = MP_QSTR_OUT; + } + print(env, ", mode=Pin.%s", qstr_str(mode_qst)); // safe because mode_qst has no formatting chars } - return mp_const_none; + // pin type + qstr type_qst; + if (type == PIN_TYPE_STD) { + type_qst = MP_QSTR_STD; + } else if (type == PIN_TYPE_STD_PU) { + type_qst = MP_QSTR_STD_PU; + } else if (type == PIN_TYPE_STD_PD) { + type_qst = MP_QSTR_STD_PD; + } else if (type == PIN_TYPE_OD) { + type_qst = MP_QSTR_OD; + } else if (type == PIN_TYPE_OD_PU) { + type_qst = MP_QSTR_OD_PU; + } else { + type_qst = MP_QSTR_OD_PD; + } + print(env, ", pull=Pin.%s", qstr_str(type_qst)); + + // Strength + qstr str_qst; + if (strength == PIN_STRENGTH_2MA) { + str_qst = MP_QSTR_S2MA; + } else if (strength == PIN_STRENGTH_4MA) { + str_qst = MP_QSTR_S4MA; + } else { + str_qst = MP_QSTR_S6MA; + } + print(env, ", strength=Pin.%s>", qstr_str(str_qst)); +} + +/// \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`. +STATIC mp_obj_t pin_make_new(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // Run an argument through the mapper and return the result. + pin_obj_t *pin = (pin_obj_t *)pin_find(args[0]); + + if (n_args > 1 || n_kw > 0) { + // pin af given, so configure it + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args); + } + + return (mp_obj_t)pin; } STATIC mp_obj_t pin_obj_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { @@ -419,7 +407,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(pin_init_obj, 1, pin_obj_init); /// \method value([value]) /// Get or set the digital logic level of the pin: /// -/// - With no argument, return 0 or 1 depending on the logic level of the pin. +/// - With no arguments, return 0 or 1 depending on the logic level of the pin. /// - With `value` given, set the logic level of the pin. `value` can be /// anything that converts to a boolean. If it converts to `True`, the pin /// is set high, otherwise it is set low. @@ -527,51 +515,142 @@ STATIC mp_obj_t pin_af(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_obj, pin_af); -/// \method int_enable() -/// Enable a disabled interrupt. -STATIC mp_obj_t pin_int_enable(mp_obj_t self_in) { - pin_obj_t *self = self_in; - pin_extint_enable(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_int_enable_obj, pin_int_enable); +/// \method callback(method, intmode, value, priority, pwrmode) +/// Creates a callback object associated to a pin +/// min num of arguments is 1 (intmode) +STATIC mp_obj_t pin_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_arg_val_t args[mpcallback_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args); + + pin_obj_t *self = pos_args[0]; + // check if any parameters were passed + if (kw_args->used > 0 || self->callback == mp_const_none) { + // convert the priority to the correct value + uint priority = mpcallback_translate_priority (args[2].u_int); + // verify the interrupt mode + uint intmode = args[0].u_int; + if (intmode != GPIO_FALLING_EDGE && intmode != GPIO_RISING_EDGE && intmode != GPIO_BOTH_EDGES && + intmode != GPIO_LOW_LEVEL && intmode != GPIO_HIGH_LEVEL) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + } -/// \method int_disable() -/// Disable the interrupt associated with the Pin object. -/// This could be useful for debouncing. -STATIC mp_obj_t pin_int_disable(mp_obj_t self_in) { - pin_obj_t *self = self_in; - pin_extint_disable(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_int_disable_obj, pin_int_disable); + if (args[4].u_int & PYB_PWR_MODE_LPDS) { + uint wake_pin; + uint wake_mode; + // pin_num is actually : (package_pin - 1) + switch (self->pin_num) { + case 56: // GPIO2 + wake_pin = PRCM_LPDS_GPIO2; + break; + case 58: // GPIO4 + wake_pin = PRCM_LPDS_GPIO4; + break; + case 3: // GPIO13 + wake_pin = PRCM_LPDS_GPIO13; + break; + case 7: // GPIO17 + wake_pin = PRCM_LPDS_GPIO17; + break; + case 1: // GPIO11 + wake_pin = PRCM_LPDS_GPIO11; + break; + case 16: // GPIO24 + wake_pin = PRCM_LPDS_GPIO24; + break; + default: + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + break; + } -/// \method intmode([mode]) -/// Get or set the interrupt mode of the pin: -/// -/// - With no argument, returns the configured interrupt mode -/// - With `mode` given, sets the interrupt mode of the pin -STATIC mp_obj_t pin_intmode(mp_uint_t n_args, const mp_obj_t *args) { - pin_obj_t *self = args[0]; - if (n_args == 1) { - // get the interrupt mode - return MP_OBJ_NEW_SMALL_INT(MAP_GPIOIntTypeGet(self->port, self->bit)); - } else { - // set the interrupt mode - MAP_GPIOIntTypeSet(self->port, self->bit, mp_obj_get_int(args[1])); - return mp_const_none; - } -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_intmode_obj, 1, 2, pin_intmode); + // intmodes are different in LDPS + switch (intmode) { + case GPIO_FALLING_EDGE: + wake_mode = PRCM_LPDS_FALL_EDGE; + break; + case GPIO_RISING_EDGE: + wake_mode = PRCM_LPDS_RISE_EDGE; + break; + case GPIO_LOW_LEVEL: + wake_mode = PRCM_LPDS_LOW_LEVEL; + break; + case GPIO_HIGH_LEVEL: + wake_mode = PRCM_LPDS_HIGH_LEVEL; + break; + default: + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + break; + } -/// \method swint() -/// Trigger the interrupt callback from software. -STATIC mp_obj_t pin_swint(mp_obj_t self_in) { - pin_obj_t *self = self_in; - pin_extint_swint(self); - return mp_const_none; + // enable GPIO as a wake source during LPDS + MAP_PRCMLPDSWakeUpGPIOSelect(wake_pin, wake_mode); + MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_GPIO); + } + + if (args[4].u_int & PYB_PWR_MODE_HIBERNATE) { + uint wake_pin; + uint wake_mode; + // pin_num is actually : (package_pin - 1) + switch (self->pin_num) { + case 56: // GPIO2 + wake_pin = PRCM_HIB_GPIO2; + break; + case 58: // GPIO4 + wake_pin = PRCM_HIB_GPIO4; + break; + case 3: // GPIO13 + wake_pin = PRCM_HIB_GPIO13; + break; + case 7: // GPIO17 + wake_pin = PRCM_HIB_GPIO17; + break; + case 1: // GPIO11 + wake_pin = PRCM_HIB_GPIO11; + break; + case 16: // GPIO24 + wake_pin = PRCM_HIB_GPIO24; + break; + default: + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + break; + } + + // intmodes are bit different in hibernate + switch (intmode) { + case GPIO_FALLING_EDGE: + wake_mode = PRCM_HIB_FALL_EDGE; + break; + case GPIO_RISING_EDGE: + wake_mode = PRCM_HIB_RISE_EDGE; + break; + case GPIO_LOW_LEVEL: + wake_mode = PRCM_HIB_LOW_LEVEL; + break; + case GPIO_HIGH_LEVEL: + wake_mode = PRCM_HIB_HIGH_LEVEL; + break; + default: + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + break; + } + + // enable GPIO as a wake source during hibernate + MAP_PRCMHibernateWakeUpGPIOSelect(wake_pin, wake_mode); + MAP_PRCMHibernateWakeupSourceEnable(wake_pin); + } + + // we need to update the callback atomically, so we disable the + // interrupt before we update anything. + pin_extint_disable(self); + // register the interrupt + pin_extint_register((pin_obj_t *)self, intmode, priority); + // create the callback + self->callback = mpcallback_new (self, args[1].u_obj, &pin_cb_methods); + // enable the interrupt just before leaving + pin_extint_enable(self); + } + return self->callback; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_swint_obj, pin_swint); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_callback_obj, 1, pin_callback); STATIC const mp_map_elem_t pin_locals_dict_table[] = { // instance methods @@ -587,10 +666,7 @@ STATIC const mp_map_elem_t pin_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_type), (mp_obj_t)&pin_type_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_strength), (mp_obj_t)&pin_strenght_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_af), (mp_obj_t)&pin_af_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_intenable), (mp_obj_t)&pin_int_enable_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_intdisable), (mp_obj_t)&pin_int_disable_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_intmode), (mp_obj_t)&pin_intmode_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_swint), (mp_obj_t)&pin_swint_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pin_callback_obj }, // class attributes { MP_OBJ_NEW_QSTR(MP_QSTR_cpu), (mp_obj_t)&pin_cpu_pins_obj_type }, @@ -641,30 +717,11 @@ const mp_obj_type_t pin_type = { .locals_dict = (mp_obj_t)&pin_locals_dict, }; -STATIC void ExecuteIntCallback (pin_obj_t *self) { - if (self->callback != mp_const_none) { - // disable interrupts to avoid nesting - uint primsk = disable_irq(); - // when executing code within a handler we must lock the GC to prevent - // any memory allocations. We must also catch any exceptions. - gc_lock(); - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_call_function_1(self->callback, self); - nlr_pop(); - } else { - // uncaught exception; disable the callback so that it doesn't run again - self->callback = mp_const_none; - pin_extint_disable(self); - // printing an exception here will cause a stack overflow that ends up in a - // hard fault so, is better to signal the uncaught (probably non-recoverable) - // exception by blinkg the system led - mperror_signal_error(); - } - gc_unlock(); - enable_irq(primsk); - } -} +STATIC const mp_cb_methods_t pin_cb_methods = { + .init = pin_callback, + .enable = pin_extint_enable, + .disable = pin_extint_disable, +}; STATIC void GPIOA0IntHandler (void) { EXTI_Handler(GPIOA0_BASE); @@ -689,6 +746,7 @@ STATIC void EXTI_Handler(uint port) { MAP_GPIOIntClear(port, bit); if (NULL != (self = (pin_obj_t *)pin_find_pin_by_port_bit(&pin_cpu_pins_locals_dict, port, bit))) { - ExecuteIntCallback(self); + mpcallback_handler(self->callback); } } + diff --git a/cc3200/mods/pybpin.h b/cc3200/mods/pybpin.h index 6228fa2ec3..9cc0243d1a 100644 --- a/cc3200/mods/pybpin.h +++ b/cc3200/mods/pybpin.h @@ -33,24 +33,24 @@ #define PYBPIN_ANALOG_TYPE 0xFF typedef struct { - mp_obj_base_t base; - qstr name; - mp_obj_t callback; - uint32_t port; - uint16_t type; - uint8_t bit; - uint8_t pin_num; - uint8_t af; - uint8_t strength; - uint8_t mode; - bool used; + const mp_obj_base_t base; + const qstr name; + mp_obj_t callback; + const uint32_t port; + uint16_t type; + const uint8_t bit; + const 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; typedef struct { - const char *name; - const pin_obj_t *pin; + const char *name; + const pin_obj_t *pin; } pin_named_pin_t; typedef struct { @@ -62,19 +62,14 @@ typedef struct { extern const mp_obj_type_t pin_cpu_pins_obj_type; extern const mp_obj_dict_t pin_cpu_pins_locals_dict; -MP_DECLARE_CONST_FUN_OBJ(pin_init_obj); - void pin_init0(void); void pin_verify_af (uint af); void pin_config(pin_obj_t *self, uint af, uint mode, uint type, uint strength); -void pin_extint_register(pin_obj_t *self, uint32_t intmode, mp_obj_t callback); -void pin_extint_enable(pin_obj_t *self); -void pin_extint_disable(pin_obj_t *self); -void pin_extint_swint(pin_obj_t *self); -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); -const pin_obj_t *pin_find_pin_by_port_bit (const mp_obj_dict_t *named_pins, uint port, uint bit); +void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t priority); +pin_obj_t *pin_find(mp_obj_t user_obj); +pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name); +pin_obj_t *pin_find_pin(const mp_obj_dict_t *named_pins, uint pin_num); +pin_obj_t *pin_find_pin_by_port_bit (const mp_obj_dict_t *named_pins, uint port, uint bit); uint32_t pin_get_mode(const pin_obj_t *self); uint32_t pin_get_type(const pin_obj_t *self); uint32_t pin_get_strenght(const pin_obj_t *self); diff --git a/cc3200/mods/pybrtc.c b/cc3200/mods/pybrtc.c index 1844a6d7f3..5744662018 100644 --- a/cc3200/mods/pybrtc.c +++ b/cc3200/mods/pybrtc.c @@ -53,16 +53,16 @@ __attribute__ ((section (".boot"))) void pybrtc_init(void) { - // if RTC was previously set leave it alone + // if the RTC was previously set, leave it alone if (MAP_PRCMSysResetCauseGet() == PRCM_POWER_ON) { - // fresh reset; configure RTC Calendar + // fresh reset; configure the RTC Calendar // set the date to 1st Jan 2015 // set the time to 00:00:00 uint32_t seconds = mod_time_seconds_since_2000(2015, 1, 1, 0, 0, 0); MAP_PRCMRTCSet(seconds, 0); - // Mark that the RTC is in use + // Mark the RTC in use MAP_PRCMRTCInUseSet(); } } @@ -90,7 +90,7 @@ STATIC mp_obj_t pyb_rtc_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n /// Get or set the date and time of the RTC. /// /// With no arguments, this method returns an 8-tuple with the current -/// date and time. With 1 argument (being an 8-tuple) it sets the date +/// date and time. With 1 argument (being an 8-tuple) it sets the date /// and time. /// /// The 8-tuple has the following format: diff --git a/cc3200/mods/pybsleep.c b/cc3200/mods/pybsleep.c index 8e94100a91..833c5882f1 100644 --- a/cc3200/mods/pybsleep.c +++ b/cc3200/mods/pybsleep.c @@ -30,13 +30,41 @@ #include "py/mpstate.h" #include MICROPY_HAL_H -#include "hw_types.h" +#include "py/runtime.h" +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_nvic.h" +#include "inc/hw_common_reg.h" +#include "inc/hw_memmap.h" +#include "cc3200_asm.h" +#include "rom_map.h" +#include "interrupt.h" +#include "systick.h" +#include "prcm.h" +#include "spi.h" +#include "pin.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. -*/ - +#include "pybpin.h" +#include "simplelink.h" +#include "modwlan.h" +#include "osi.h" +#include "debug.h" +#include "mpexception.h" +#include "mpcallback.h" +#include "mperror.h" +#include "sleeprestore.h" + +/****************************************************************************** + DECLARE PRIVATE CONSTANTS + ******************************************************************************/ +#define SPIFLASH_INSTR_READ_STATUS (0x05) +#define SPIFLASH_INSTR_DEEP_POWER_DOWN (0xB9) +#define SPIFLASH_STATUS_BUSY (0x01) + +/****************************************************************************** + DECLARE PRIVATE TYPES + ******************************************************************************/ +// storage memory for Cortex M4 registers typedef struct { uint32_t msp; uint32_t psp; @@ -45,189 +73,132 @@ typedef struct { 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"); \ -} +} arm_cm4_core_regs_t; -#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"); \ -} +// storage memory for the NVIC registers +typedef struct { + uint32_t vector_table; // Vector Table Offset + uint32_t aux_ctrl; // Auxiliary control register + uint32_t int_ctrl_state; // Interrupt Control and State + uint32_t app_int; // Application Interrupt Reset control + uint32_t sys_ctrl; // System control + uint32_t config_ctrl; // Configuration control + uint32_t sys_pri_1; // System Handler Priority 1 + uint32_t sys_pri_2; // System Handler Priority 2 + uint32_t sys_pri_3; // System Handler Priority 3 + uint32_t sys_hcrs; // System Handler control and state register + uint32_t systick_ctrl; // SysTick Control Status + uint32_t systick_reload; // SysTick Reload + uint32_t systick_calib; // SysTick Calibration + uint32_t int_en[6]; // Interrupt set enable + uint32_t int_priority[49]; // Interrupt priority +} nvic_reg_store_t; -#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 */ +typedef struct { + mp_obj_base_t base; + mp_obj_t obj; + WakeUpCB_t wakeup; +} pybsleep_obj_t; - RESTORE_ARM_REGISTERS(); /* Core registers and code is in assembly */ +typedef struct { + mp_obj_t wlan_wake_cb; + mp_obj_t timer_wake_cb; + mp_obj_t gpio_wake_cb; +} pybsleep_wake_cb_t; + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +STATIC const mp_obj_type_t pybsleep_type; +STATIC nvic_reg_store_t *nvic_reg_store; +STATIC pybsleep_wake_cb_t pybsleep_wake_cb; +volatile arm_cm4_core_regs_t vault_arm_registers; + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC pybsleep_obj_t *pybsleep_find (mp_obj_t obj); +STATIC void pybsleep_flash_powerdown (void); +STATIC NORETURN void pybsleep_suspend_enter (void); +void pybsleep_suspend_exit (void); +STATIC void pybsleep_obj_wakeup (void); +STATIC void PRCMInterruptHandler (void); +STATIC void pybsleep_iopark (void); + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +void pyblsleep_init0 (void) { + // initialize the sleep objects list + mp_obj_list_init(&MP_STATE_PORT(pybsleep_obj_list), 0); - INTRODUCE_SYNC_BARRIER(); /* Data and instruction sync barriers */ + // allocate memory for nvic registers vault + ASSERT ((nvic_reg_store = mem_Malloc(sizeof(nvic_reg_store_t))) != NULL); - 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; + // enable and register the PRCM interrupt + osi_InterruptRegister(INT_PRCM, (P_OSI_INTR_ENTRY)PRCMInterruptHandler, INT_PRIORITY_LVL_1); + MAP_IntPendClear(INT_PRCM); + MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR); } -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"); +void pybsleep_add (const mp_obj_t obj, WakeUpCB_t wakeup) { + pybsleep_obj_t * sleep_obj = m_new_obj(pybsleep_obj_t); + sleep_obj->base.type = &pybsleep_type; + 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); + } } -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; +void pybsleep_remove (const 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); + } } -i32 cc_io_park_safe(struct soc_io_park *io_park_choice, - u8 num_pins) -{ - i32 loopcnt; - - if(NULL == io_park_choice) { - return -1; - } +void pybsleep_set_wlan_wake_callback (mp_obj_t cb_obj) { + if (cb_obj) { + MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ); + } + else { + MAP_PRCMLPDSWakeupSourceDisable (PRCM_LPDS_HOST_IRQ); + } + pybsleep_wake_cb.wlan_wake_cb = cb_obj; +} - /* 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); +void pybsleep_set_gpio_wake_callback (mp_obj_t cb_obj) { + pybsleep_wake_cb.gpio_wake_cb = cb_obj; +} - } +void pybsleep_set_timer_wake_callback (mp_obj_t cb_obj) { + pybsleep_wake_cb.timer_wake_cb = cb_obj; +} +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ +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; } - - /* 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; + } + return NULL; } - - -#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) { +STATIC void pybsleep_flash_powerdown (void) { uint32_t status; // Enable clock for SSPI module - MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK); + MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); // Reset SSPI at PRCM level and wait for reset to complete MAP_PRCMPeripheralReset(PRCM_SSPI); - while(!MAP_PRCMPeripheralStatusGet(PRCM_SSPI); + while(!MAP_PRCMPeripheralStatusGet(PRCM_SSPI)); // Reset SSPI at module level MAP_SPIReset(SSPI_BASE); @@ -247,599 +218,272 @@ void SpiFlashDeepPowerDown(void) { // 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_SPIDataPut(SSPI_BASE, SPIFLASH_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); + } while ((status & 0xFF) == SPIFLASH_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); + MAP_SPIDataPut(SSPI_BASE, SPIFLASH_INSTR_DEEP_POWER_DOWN); // Disable chip select for the spi flash. MAP_SPICSDisable(SSPI_BASE); } +STATIC NORETURN void pybsleep_suspend_enter (void) { + // enable full RAM retention + MAP_PRCMSRAMRetentionEnable(PRCM_SRAM_COL_1 | PRCM_SRAM_COL_2 | PRCM_SRAM_COL_3 | PRCM_SRAM_COL_4, PRCM_SRAM_LPDS_RET); + + // 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); + + // save the 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 + uint32_t *base_reg_addr = (uint32_t *)NVIC_EN0; + for(int32_t i = 0; i < (sizeof(nvic_reg_store->int_en) / 4); i++) { + nvic_reg_store->int_en[i] = base_reg_addr[i]; + } -#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; - } + // save the interrupt priority registers + base_reg_addr = (uint32_t *)NVIC_PRI0; + for(int32_t i = 0; i < (sizeof(nvic_reg_store->int_priority) / 4); i++) { + nvic_reg_store->int_priority[i] = base_reg_addr[i]; + } - return 0; -} + // park the io pins + pybsleep_iopark(); + + sleep_store(); + + // save the restore info and enter LPDS + MAP_PRCMLPDSRestoreInfoSet(vault_arm_registers.psp, (uint32_t)sleep_restore); + MAP_PRCMLPDSEnter(); + + // let the cpu fade away... + for ( ; ; ); +} + +void pybsleep_suspend_exit (void) { + // take the I2C semaphore + uint32_t 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 the 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 de NVIC control registers + HWREG(NVIC_VTABLE) = nvic_reg_store->vector_table; + HWREG(NVIC_ACTLR) = nvic_reg_store->aux_ctrl; + HWREG(NVIC_INT_CTRL) = nvic_reg_store->int_ctrl_state; + 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; + + // restore the systick register + 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 + uint32_t *base_reg_addr = (uint32_t *)NVIC_PRI0; + for (uint32_t i = 0; i < (sizeof(nvic_reg_store->int_priority) / 4); i++) { + base_reg_addr[i] = nvic_reg_store->int_priority[i]; + } -/* 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; - } + // restore the interrupt enable registers + base_reg_addr = (uint32_t *)NVIC_EN0; + for(uint32_t i = 0; i < (sizeof(nvic_reg_store->int_en) / 4); i++) { + base_reg_addr[i] = nvic_reg_store->int_en[i]; + } - return 0; -} + HAL_INTRODUCE_SYNC_BARRIER(); -/* 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); + // ungate the clock to the shared spi bus + MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + MAP_PRCMIntEnable (PRCM_INT_SLOW_CLK_CTR); - return; -} + // reinitialize simplelink's bus + sl_IfOpen (NULL, 0); -/* 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; - } + // initialize the system led + mperror_init0(); - return 0; -} + // restore the configuration of all active peripherals + pybsleep_obj_wakeup(); -/* 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; - } + // trigger a sw interrupt + MAP_IntPendSet(INT_PRCM); - return 0; + // force an exception to go back to the point where suspend mode was entered + nlr_raise(mp_obj_new_exception(&mp_type_SystemExit)); } -/* 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; +STATIC void PRCMInterruptHandler (void) { + // reading the interrupt status automatically clears the interrupt + if (PRCM_INT_SLOW_CLK_CTR == MAP_PRCMIntStatus()) { + if (pybsleep_wake_cb.timer_wake_cb) { + mpcallback_handler(pybsleep_wake_cb.timer_wake_cb); } - 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) { + } + else { + switch (MAP_PRCMLPDSWakeupCauseGet()) { case PRCM_LPDS_HOST_IRQ: - break; + if (pybsleep_wake_cb.wlan_wake_cb) { + mpcallback_handler(pybsleep_wake_cb.wlan_wake_cb); + } + 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; + if (pybsleep_wake_cb.gpio_wake_cb) { + mpcallback_handler(pybsleep_wake_cb.gpio_wake_cb); + } + 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; - } + if (pybsleep_wake_cb.timer_wake_cb) { + mpcallback_handler(pybsleep_wake_cb.timer_wake_cb); + } + break; + default: + break; } - - 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 { - } +STATIC void pybsleep_obj_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); + } } -/* 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; +STATIC void pybsleep_iopark (void) { + mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)&pin_cpu_pins_locals_dict); + for (uint i = 0; i < named_map->used; i++) { + pin_obj_t * pin = (pin_obj_t *)named_map->table[i].value; + // skip the sflash pins since these are shared with the network processor + switch (pin->pin_num) { + case PIN_11: + case PIN_12: + case PIN_13: + case PIN_14: +#ifdef DEBUG + // also skip the JTAG pins + case PIN_16: + case PIN_17: + case PIN_19: + case PIN_20: +#endif + break; + default: + if (!pin->used) { + // enable the pull-down in unused pins + MAP_PinConfigSet(pin->pin_num, pin->strength, PIN_TYPE_STD_PD); + } + // make the pin an input + MAP_PinDirModeSet(pin->pin_num, PIN_DIR_MODE_IN); + 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(); + // park the sflash pins + 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); + + // park the antenna selection pins + HWREG(0x4402E108) = 0x00000E61; + HWREG(0x4402E10C) = 0x00000E61; +} + +/******************************************************************************/ +// Micro Python bindings; Sleep class + +/// \function idle() +/// Gates the processor clock until an interrupt is triggered +STATIC mp_obj_t pyb_sleep_idle (mp_obj_t self_in) { + __WFI(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_idle_obj, pyb_sleep_idle); + +/// \function suspend() +/// Enters suspended mode. Wake up sources should have been enable prior to +// calling this method. +STATIC mp_obj_t pyb_sleep_suspend (mp_obj_t self_in) { + nlr_buf_t nlr; + + // entering and exiting suspend mode must be an atomic operation + // therefore interrupts must be disabled + uint primsk = disable_irq(); + if (nlr_push(&nlr) == 0) { + pybsleep_suspend_enter(); + nlr_pop(); + } + // an exception is always raised when exiting suspend mode + enable_irq(primsk); - // call the python RTC callback interrupt handler + return mp_const_none; } -#endif - - -typedef struct { - mp_obj_t obj; - WakeUpCB_t wakeup; -}pybsleep_obj_t; +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_suspend_obj, pyb_sleep_suspend); - -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; +/// \function hibernate() +/// Enters hibernate mode. Wake up sources should have been enable prior to +// calling this method. +STATIC mp_obj_t pyb_sleep_hibernate (mp_obj_t self_in) { + wlan_stop(); + pybsleep_flash_powerdown(); + MAP_PRCMHibernateEnter(); + return mp_const_none; } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_hibernate_obj, pyb_sleep_hibernate); -void pyblsleep_init0 (void) { - mp_obj_list_init(&MP_STATE_PORT(pybsleep_obj_list), 0); -} +STATIC const mp_map_elem_t pybsleep_locals_dict_table[] = { + // instance methods + { MP_OBJ_NEW_QSTR(MP_QSTR_idle), (mp_obj_t)&pyb_sleep_idle_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_suspend), (mp_obj_t)&pyb_sleep_suspend_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_hibernate), (mp_obj_t)&pyb_sleep_hibernate_obj }, -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); - } -} + // class constants + { MP_OBJ_NEW_QSTR(MP_QSTR_SUSPENDED), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_LPDS) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_HIBERNATING), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_HIBERNATE) }, +}; -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); - } -} +STATIC MP_DEFINE_CONST_DICT(pybsleep_locals_dict, pybsleep_locals_dict_table); -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); - } -} +STATIC const mp_obj_type_t pybsleep_type = { + { &mp_type_type }, + .name = MP_QSTR_sleep, + .locals_dict = (mp_obj_t)&pybsleep_locals_dict, +}; +const mp_obj_base_t pyb_sleep_obj = {&pybsleep_type}; diff --git a/cc3200/mods/pybsleep.h b/cc3200/mods/pybsleep.h index d91437ffa2..97997080d8 100644 --- a/cc3200/mods/pybsleep.h +++ b/cc3200/mods/pybsleep.h @@ -27,11 +27,31 @@ #ifndef PYBSLEEP_H_ #define PYBSLEEP_H_ -typedef void (*WakeUpCB_t)(mp_obj_t self); +/****************************************************************************** + DEFINE CONSTANTS + ******************************************************************************/ +#define PYB_PWR_MODE_ACTIVE_IDLE (0x00) +#define PYB_PWR_MODE_LPDS (0x01) +#define PYB_PWR_MODE_HIBERNATE (0x02) +/****************************************************************************** + DEFINE TYPES + ******************************************************************************/ +typedef void (*WakeUpCB_t)(const mp_obj_t self); + +/****************************************************************************** + DECLARE EXPORTED VARIABLES + ******************************************************************************/ +extern const mp_obj_base_t pyb_sleep_obj; + +/****************************************************************************** + DECLARE FUNCTIONS + ******************************************************************************/ 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); +void pybsleep_add (const mp_obj_t obj, WakeUpCB_t wakeup); +void pybsleep_remove (const mp_obj_t obj); +void pybsleep_set_wlan_wake_callback (mp_obj_t cb_obj); +void pybsleep_set_gpio_wake_callback (mp_obj_t cb_obj); +void pybsleep_set_timer_wake_callback (mp_obj_t cb_obj); #endif /* PYBSLEEP_H_ */ diff --git a/cc3200/mods/pybuart.c b/cc3200/mods/pybuart.c index 8d054bb088..ccaf3a31e0 100644 --- a/cc3200/mods/pybuart.c +++ b/cc3200/mods/pybuart.c @@ -93,6 +93,8 @@ /****************************************************************************** DECLARE PRIVATE FUNCTIONS ******************************************************************************/ +STATIC void uart_init (pyb_uart_obj_t *self); +STATIC bool uart_rx_wait (pyb_uart_obj_t *self, uint32_t timeout); STATIC pyb_uart_obj_t* pyb_uart_add (pyb_uart_id_t uart_id); STATIC pyb_uart_obj_t* pyb_uart_find (pyb_uart_id_t uart_id); STATIC void UARTGenericIntHandler(uint32_t uart_id); @@ -137,8 +139,57 @@ void uart_deinit(void) { } } +bool uart_rx_any(pyb_uart_obj_t *self) { + return (self->read_buf_tail != self->read_buf_head || MAP_UARTCharsAvail(self->reg)); +} + +int uart_rx_char(pyb_uart_obj_t *self) { + if (self->read_buf_tail != self->read_buf_head) { + // buffering via IRQ + int data = self->read_buf[self->read_buf_tail]; + self->read_buf_tail = (self->read_buf_tail + 1) % self->read_buf_len; + return data; + } else { + // no buffering + return MAP_UARTCharGetNonBlocking(self->reg); + } +} + +bool uart_tx_char(pyb_uart_obj_t *self, int c) { + uint32_t timeout = 0; + + while (!MAP_UARTCharPutNonBlocking(self->reg, c)) { + if (timeout++ > (PYBUART_TX_MAX_TIMEOUT_MS / PYBUART_TX_WAIT_MS)) { + return false; + } + HAL_Delay (PYBUART_TX_WAIT_MS); + } + return true; +} + +bool uart_tx_strn(pyb_uart_obj_t *self, const char *str, uint len) { + for (const char *top = str + len; str < top; str++) { + if (!uart_tx_char(self, *str)) { + return false; + } + } + return true; +} + +void uart_tx_strn_cooked(pyb_uart_obj_t *self, const char *str, uint len) { + for (const char *top = str + len; str < top; str++) { + if (*str == '\n') { + uart_tx_char(self, '\r'); + } + uart_tx_char(self, *str); + } +} + +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ // assumes init parameters have been set up correctly -bool uart_init2(pyb_uart_obj_t *self) { +STATIC void uart_init (pyb_uart_obj_t *self) { uint uartPerh; switch (self->uart_id) { @@ -155,7 +206,7 @@ bool uart_init2(pyb_uart_obj_t *self) { MAP_IntPrioritySet(INT_UARTA1, INT_PRIORITY_LVL_3); break; default: - return false; + return; } // Enable the peripheral clock @@ -173,35 +224,23 @@ bool uart_init2(pyb_uart_obj_t *self) { // Configure the FIFO interrupt levels MAP_UARTFIFOLevelSet(self->reg, UART_FIFO_TX4_8, UART_FIFO_RX4_8); - + // Configure the flow control mode UARTFlowControlSet(self->reg, self->flowcontrol); - // Enable the RX and RX timeout interrupts - MAP_UARTIntEnable(self->reg, UART_INT_RX | UART_INT_RT); - - self->enabled = true; - - // register it with the sleep module - pybsleep_add (self, (WakeUpCB_t)uart_init2); - return true; -} - -bool uart_init(pyb_uart_obj_t *self, uint baudrate) { - self->baudrate = baudrate; - self->config = UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE; - self->flowcontrol = UART_FLOWCONTROL_NONE; - return uart_init2(self); -} - -bool uart_rx_any(pyb_uart_obj_t *self) { - return (self->read_buf_tail != self->read_buf_head || MAP_UARTCharsAvail(self->reg)); + // Setup the RX interrupts + if (self->read_buf != NULL) { + MAP_UARTIntEnable(self->reg, UART_INT_RX | UART_INT_RT); + } + else { + MAP_UARTIntDisable(self->reg, UART_INT_RX | UART_INT_RT); + } } // Waits at most timeout milliseconds for at least 1 char to become ready for // reading (from buf or for direct reading). // Returns true if something available, false if not. -STATIC bool uart_rx_wait(pyb_uart_obj_t *self, uint32_t timeout) { +STATIC bool uart_rx_wait (pyb_uart_obj_t *self, uint32_t timeout) { for (;;) { if (uart_rx_any(self)) { return true; // have at least 1 char ready for reading @@ -216,51 +255,6 @@ STATIC bool uart_rx_wait(pyb_uart_obj_t *self, uint32_t timeout) { } } -int uart_rx_char(pyb_uart_obj_t *self) { - if (self->read_buf_tail != self->read_buf_head) { - // buffering via IRQ - int data = self->read_buf[self->read_buf_tail]; - self->read_buf_tail = (self->read_buf_tail + 1) % self->read_buf_len; - return data; - } else { - // no buffering - return MAP_UARTCharGetNonBlocking(self->reg); - } -} - -bool uart_tx_char(pyb_uart_obj_t *self, int c) { - uint32_t timeout = 0; - - while (!MAP_UARTCharPutNonBlocking(self->reg, c)) { - if (timeout++ > (PYBUART_TX_MAX_TIMEOUT_MS / PYBUART_TX_WAIT_MS)) { - return false; - } - HAL_Delay (PYBUART_TX_WAIT_MS); - } - return true; -} - -bool uart_tx_strn(pyb_uart_obj_t *self, const char *str, uint len) { - for (const char *top = str + len; str < top; str++) { - if (!uart_tx_char(self, *str)) { - return false; - } - } - return true; -} - -void uart_tx_strn_cooked(pyb_uart_obj_t *self, const char *str, uint len) { - for (const char *top = str + len; str < top; str++) { - if (*str == '\n') { - uart_tx_char(self, '\r'); - } - uart_tx_char(self, *str); - } -} - -/****************************************************************************** - DEFINE PRIVATE FUNCTIONS - ******************************************************************************/ STATIC pyb_uart_obj_t* pyb_uart_add (pyb_uart_id_t uart_id) { // create a new uart object pyb_uart_obj_t *self = m_new_obj(pyb_uart_obj_t); @@ -327,7 +321,7 @@ STATIC void pyb_uart_print(void (*print)(void *env, const char *fmt, ...), void if (!self->enabled) { print(env, "<UART%u>", self->uart_id); } else { - print(env, "<UART%u baudrate=%u, bits=", self->uart_id, self->baudrate); + print(env, "<UART%u, baudrate=%u, bits=", self->uart_id, self->baudrate); switch (self->config & UART_CONFIG_WLEN_MASK) { case UART_CONFIG_WLEN_5: print(env, "5"); @@ -380,15 +374,35 @@ STATIC const mp_arg_t pyb_uart_init_args[] = { }; STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - bool success; - // parse args mp_arg_val_t args[MP_ARRAY_SIZE(pyb_uart_init_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(pyb_uart_init_args), pyb_uart_init_args, args); + // set timeouts + self->timeout = args[5].u_int; + self->timeout_char = args[6].u_int; + + // setup the read buffer + m_del(byte, self->read_buf, self->read_buf_len); + self->read_buf_head = 0; + self->read_buf_tail = 0; + + if (args[7].u_int <= 0) { + // no read buffer + self->read_buf_len = 0; + self->read_buf = NULL; + } + else { + // read buffer using interrupts + self->read_buf_len = args[7].u_int; + self->read_buf = m_new(byte, args[7].u_int); + } + + // get the baudrate + self->baudrate = args[0].u_int; + // set the UART configuration values if (n_args > 1) { - self->baudrate = args[0].u_int; switch (args[1].u_int) { case 5: self->config = UART_CONFIG_WLEN_5; @@ -417,36 +431,17 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, mp_uint_t n_args, con // Flow control self->flowcontrol = args[4].u_int; - success = uart_init2(self); - } else { - success = uart_init(self, args[0].u_int); } - - // init UART (if it fails, something weird happened) - if (!success) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + else { + self->config = UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE; + self->flowcontrol = UART_FLOWCONTROL_NONE; } + // initialize and enable the uart + uart_init (self); + self->enabled = true; + // register it with the sleep module + pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)uart_init); - // set timeouts - self->timeout = args[5].u_int; - self->timeout_char = args[6].u_int; - - // setup the read buffer - m_del(byte, self->read_buf, self->read_buf_len); - self->read_buf_head = 0; - self->read_buf_tail = 0; - - if (args[7].u_int <= 0) { - // no read buffer - self->read_buf_len = 0; - self->read_buf = NULL; - MAP_UARTIntDisable(self->reg, UART_INT_RX | UART_INT_RT); - } else { - // read buffer using interrupts - self->read_buf_len = args[7].u_int; - self->read_buf = m_new(byte, args[7].u_int); - } - return mp_const_none; } diff --git a/cc3200/mods/pybuart.h b/cc3200/mods/pybuart.h index e648225843..e628b2903b 100644 --- a/cc3200/mods/pybuart.h +++ b/cc3200/mods/pybuart.h @@ -36,7 +36,6 @@ typedef struct _pyb_uart_obj_t pyb_uart_obj_t; extern const mp_obj_type_t pyb_uart_type; void uart_init0(void); -bool uart_init(pyb_uart_obj_t *uart_obj, uint baudrate); void uart_deinit (void); bool uart_rx_any(pyb_uart_obj_t *uart_obj); int uart_rx_char(pyb_uart_obj_t *uart_obj); diff --git a/cc3200/mods/pybwdt.c b/cc3200/mods/pybwdt.c index 97d284d066..68213de6e6 100644 --- a/cc3200/mods/pybwdt.c +++ b/cc3200/mods/pybwdt.c @@ -47,7 +47,7 @@ DECLARE CONSTANTS ******************************************************************************/ #define PYBWDT_MILLISECONDS_TO_TICKS(ms) ((80000000 / 1000) * (ms)) -#define PYBWDT_MIN_TIMEOUT_MS (500) +#define PYBWDT_MIN_TIMEOUT_MS (1000) /****************************************************************************** DECLARE TYPES diff --git a/cc3200/mpconfigport.h b/cc3200/mpconfigport.h index 344e8249c9..52bbf530dd 100644 --- a/cc3200/mpconfigport.h +++ b/cc3200/mpconfigport.h @@ -123,6 +123,7 @@ extern const struct _mp_obj_module_t mp_module_network; mp_obj_list_t pyb_uart_list; \ mp_obj_list_t mod_network_nic_list; \ mp_obj_list_t pybsleep_obj_list; \ + mp_obj_list_t mpcallback_obj_list; \ // type definitions for the specific machine diff --git a/cc3200/mptask.c b/cc3200/mptask.c index 3e51199fb2..6f0a3a0540 100644 --- a/cc3200/mptask.c +++ b/cc3200/mptask.c @@ -59,6 +59,7 @@ #include "pybsd.h" #include "pins.h" #include "pybsleep.h" +#include "mpcallback.h" /****************************************************************************** DECLARE PRIVATE CONSTANTS @@ -118,11 +119,19 @@ soft_reset: mp_obj_list_init(mp_sys_argv, 0); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) + // execute all basic initializations mperror_init0(); mpexception_init0(); + mpcallback_init0(); pyblsleep_init0(); uart_init0(); pin_init0(); + readline_init0(); + mod_network_init0(); + wlan_init0(); +#if MICROPY_HW_ENABLE_RNG + rng_init0(); +#endif // configure stdio uart pins with the correct af // param 3 ("mode") is DON'T CARE" for AFs others than GPIO @@ -135,13 +144,6 @@ soft_reset: }; pyb_stdio_uart = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, MP_ARRAY_SIZE(args), 0, args); - readline_init0(); - mod_network_init0(); - wlan_init0(); -#if MICROPY_HW_ENABLE_RNG - rng_init0(); -#endif - mperror_enable_heartbeat(); mptask_enter_ap_mode(); @@ -328,7 +330,6 @@ STATIC void mptask_enter_ap_mode (void) { // Enable simplelink in low power mode wlan_sl_enable (ROLE_AP, SERVERS_DEF_AP_SSID, strlen(SERVERS_DEF_AP_SSID), SERVERS_DEF_AP_SECURITY, SERVERS_DEF_AP_KEY, strlen(SERVERS_DEF_AP_KEY), SERVERS_DEF_AP_CHANNEL); - wlan_set_pm_policy (SL_NORMAL_POLICY); } STATIC void mptask_create_main_py (void) { diff --git a/cc3200/qstrdefsport.h b/cc3200/qstrdefsport.h index 1ae4b0b172..3c6c2b253c 100644 --- a/cc3200/qstrdefsport.h +++ b/cc3200/qstrdefsport.h @@ -3,9 +3,7 @@ Q(__name__) Q(help) Q(pyb) Q(info) -Q(hard_reset) -Q(stop) -Q(standby) +Q(reset) Q(main) Q(sync) Q(gc) @@ -22,10 +20,8 @@ Q(readall) Q(readline) Q(input) Q(os) -Q(mac) Q(freq) Q(repl_info) -Q(wfi) Q(disable_irq) Q(enable_irq) Q(millis) @@ -85,7 +81,6 @@ Q(pull) Q(index) Q(strength) Q(af) -Q(callback) Q(intenable) Q(intdisable) Q(intmode) @@ -220,7 +215,6 @@ Q(getmode) Q(channel) Q(ifconfig) Q(urn) -Q(setpm) Q(start_servers) Q(stop_servers) Q(servers_enabled) @@ -234,11 +228,6 @@ Q(WPA_WPA2) Q(WPA_ENT) Q(WPS_PBC) Q(WPS_PIN) -Q(NORMAL_PM) -Q(LOW_LATENCY_PM) -Q(LOW_POWER_PM) -Q(ALWAYS_ON_PM) -Q(LONG_SLEEP_PM) // for WDT class Q(WDT) @@ -247,3 +236,21 @@ Q(kick) // for HeartBeat class Q(HeartBeat) +// for callback class +Q(init) +Q(enable) +Q(disable) +Q(callback) +Q(handler) +Q(intmode) +Q(value) +Q(priority) +Q(wake) + +// for Sleep class +Q(Sleep) +Q(idle) +Q(suspend) +Q(hibernate) +Q(SUSPENDED) +Q(HIBERNATING) diff --git a/cc3200/simplelink/oslib/osi.h b/cc3200/simplelink/oslib/osi.h index cf2574b1ec..11fe61bb63 100644 --- a/cc3200/simplelink/oslib/osi.h +++ b/cc3200/simplelink/oslib/osi.h @@ -538,26 +538,26 @@ void osi_Sleep(unsigned int MilliSecs); /*! \brief This function used to disable the tasks \param - void - \return - Key with the suspended tasks + \return - void \note \warning */ -unsigned long osi_TaskDisable(void); +void osi_TaskDisable(void); /*! \brief This function used to enable all tasks - \param unsigned long + \param - void \return - void \note \warning */ -void osi_TaskEnable(unsigned long); +void osi_TaskEnable(void); + /*! \brief structure definition for simple link spawn message \note On each porting or platform the type could be whatever is needed - integer, pointer to structure etc. */ - typedef struct { P_OSI_SPAWN_ENTRY pEntry; diff --git a/cc3200/simplelink/oslib/osi_freertos.c b/cc3200/simplelink/oslib/osi_freertos.c index 2f00ab2689..196672de70 100644 --- a/cc3200/simplelink/oslib/osi_freertos.c +++ b/cc3200/simplelink/oslib/osi_freertos.c @@ -693,11 +693,9 @@ void osi_Sleep(unsigned int MilliSecs) \note \warning */ -unsigned long osi_TaskDisable(void) +void osi_TaskDisable(void) { vTaskSuspendAll(); - - return OSI_OK; } @@ -708,7 +706,7 @@ unsigned long osi_TaskDisable(void) \note \warning */ -void osi_TaskEnable(unsigned long key) +void osi_TaskEnable(void) { xTaskResumeAll(); } diff --git a/cc3200/util/sleeprestore.h b/cc3200/util/sleeprestore.h new file mode 100644 index 0000000000..51416f0fce --- /dev/null +++ b/cc3200/util/sleeprestore.h @@ -0,0 +1,33 @@ +/* + * 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 SLEEPRESTORE_H_ +#define SLEEPRESTORE_H_ + +extern void sleep_store(void); +extern void sleep_restore(void); + +#endif /* SLEEPRESTORE_H_ */ diff --git a/cc3200/util/sleeprestore.s b/cc3200/util/sleeprestore.s new file mode 100644 index 0000000000..decc6994ec --- /dev/null +++ b/cc3200/util/sleeprestore.s @@ -0,0 +1,61 @@ + .syntax unified + .cpu cortex-m4 + .thumb + .text + .align 2 + +@ global variable with the backup registers + .extern vault_arm_registers +@ global function that performs the wake up actions + .extern pybsleep_suspend_exit + +@ uint sleep_store(void) + .global sleep_store + .thumb + .thumb_func + .type sleep_store, %function +sleep_store: + dsb + isb + push {r0-r12, lr} + ldr r1, =vault_arm_registers + mrs r0, msp + str r0, [r1] + mrs r0, psp + str r0, [r1, #4] + mrs r0, primask + str r0, [r1, #12] + mrs r0, faultmask + str r0, [r1, #16] + mrs r0, basepri + str r0, [r1, #20] + mrs r0, control + str r0, [r1, #24] + dsb + isb + bx lr + +@ uint sleep_restore(void) + .global sleep_restore + .thumb + .thumb_func + .type sleep_restore, %function +sleep_restore: + dsb + isb + mrs r0, msp + msr psp, r0 + ldr r1, =vault_arm_registers + ldr r0, [r1, #24] + msr control, r0 + ldr r0, [r1] + msr msp, r0 + ldr r0, [r1, #12] + msr primask, r0 + ldr r0, [r1, #16] + msr faultmask, r0 + ldr r0, [r1, #20] + msr basepri, r0 + dsb + isb + bl pybsleep_suspend_exit |