cc3200: New irq API, affects all classes that provide the irq method.
This commit is contained in:
parent
81d64ab939
commit
dbdcb58d64
@ -78,7 +78,7 @@ APP_MISC_SRC_C = $(addprefix misc/,\
|
||||
antenna.c \
|
||||
FreeRTOSHooks.c \
|
||||
help.c \
|
||||
mpcallback.c \
|
||||
mpirq.c \
|
||||
mperror.c \
|
||||
mpexception.c \
|
||||
mpsystick.c \
|
||||
|
@ -52,16 +52,18 @@
|
||||
#define PIN(p_pin_name, p_port, p_bit, p_pin_num, p_af_list, p_num_afs) \
|
||||
{ \
|
||||
{ &pin_type }, \
|
||||
.name = MP_QSTR_ ## p_pin_name, \
|
||||
.port = PORT_A ## p_port, \
|
||||
.af_list = (p_af_list), \
|
||||
.pull = PIN_TYPE_STD, \
|
||||
.bit = (p_bit), \
|
||||
.pin_num = (p_pin_num), \
|
||||
.af = PIN_MODE_0, \
|
||||
.strength = PIN_STRENGTH_4MA, \
|
||||
.mode = GPIO_DIR_MODE_IN, \
|
||||
.num_afs = (p_num_afs), \
|
||||
.value = 0, \
|
||||
.used = false, \
|
||||
.name = MP_QSTR_ ## p_pin_name, \
|
||||
.port = PORT_A ## p_port, \
|
||||
.af_list = (p_af_list), \
|
||||
.pull = PIN_TYPE_STD, \
|
||||
.bit = (p_bit), \
|
||||
.pin_num = (p_pin_num), \
|
||||
.af = PIN_MODE_0, \
|
||||
.strength = PIN_STRENGTH_4MA, \
|
||||
.mode = GPIO_DIR_MODE_IN, \
|
||||
.num_afs = (p_num_afs), \
|
||||
.value = 0, \
|
||||
.used = false, \
|
||||
.irq_trigger = 0, \
|
||||
.irq_flags = 0, \
|
||||
}
|
||||
|
@ -112,17 +112,17 @@
|
||||
// following wrapper can be used to convert the value from cycles to
|
||||
// millisecond:
|
||||
//
|
||||
// CYCLES_U16MS(cycles) ((cycles *1000)/ 1024),
|
||||
// CYCLES_U16MS(cycles) ((cycles * 1000) / 1024),
|
||||
//
|
||||
// Similarly, before setting the value, it must be first converted (from ms to
|
||||
// cycles).
|
||||
//
|
||||
// U16MS_CYCLES(msec) ((msec *1024)/1000)
|
||||
// U16MS_CYCLES(msec) ((msec * 1024) / 1000)
|
||||
//
|
||||
// Note: There is a precision loss of 1 ms with the above scheme.
|
||||
//
|
||||
//
|
||||
#define SCC_U64MSEC_GET() (MAP_PRCMSlowClkCtrGet() >> 5)
|
||||
#define SCC_U64MSEC_GET() (RTCFastDomainCounterGet() >> 5)
|
||||
#define SCC_U64MSEC_MATCH_SET(u64Msec) (MAP_PRCMSlowClkCtrMatchSet(u64Msec << 5))
|
||||
#define SCC_U64MSEC_MATCH_GET() (MAP_PRCMSlowClkCtrMatchGet() >> 5)
|
||||
|
||||
@ -208,6 +208,39 @@ static void RTCU32SecRegWrite(unsigned long u32Msec)
|
||||
MAP_PRCMHIBRegWrite(RTC_SECS_U32_REG_ADDR, u32Msec);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// Fast function to get the most accurate RTC counter value
|
||||
//*****************************************************************************
|
||||
static unsigned long long RTCFastDomainCounterGet (void) {
|
||||
|
||||
#define BRK_IF_RTC_CTRS_ALIGN(c2, c1) if (c2 - c1 <= 1) { \
|
||||
itr++; \
|
||||
break; \
|
||||
}
|
||||
|
||||
unsigned long long rtc_count1, rtc_count2, rtc_count3;
|
||||
unsigned int itr;
|
||||
|
||||
do {
|
||||
rtc_count1 = PRCMSlowClkCtrFastGet();
|
||||
rtc_count2 = PRCMSlowClkCtrFastGet();
|
||||
rtc_count3 = PRCMSlowClkCtrFastGet();
|
||||
itr = 0;
|
||||
|
||||
BRK_IF_RTC_CTRS_ALIGN(rtc_count2, rtc_count1);
|
||||
BRK_IF_RTC_CTRS_ALIGN(rtc_count3, rtc_count2);
|
||||
BRK_IF_RTC_CTRS_ALIGN(rtc_count3, rtc_count1);
|
||||
|
||||
// Consistent values in two consecutive reads implies a correct
|
||||
// value of the counter. Do note, the counter does not give the
|
||||
// calendar time but a hardware that ticks upwards continuously.
|
||||
// The 48-bit counter operates at 32,768 HZ.
|
||||
|
||||
} while (true);
|
||||
|
||||
return (1 == itr) ? rtc_count2 : rtc_count3;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// Macros
|
||||
//*****************************************************************************
|
||||
@ -1245,6 +1278,35 @@ unsigned long long PRCMSlowClkCtrGet(void)
|
||||
return ullRTCVal;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! Gets the current value of the internal slow clock counter
|
||||
//!
|
||||
//! This function is similar to \sa PRCMSlowClkCtrGet() but reads the counter
|
||||
//! value from a relatively faster interface using an auto-latch mechainsm.
|
||||
//!
|
||||
//! \note Due to the nature of implemetation of auto latching, when using this
|
||||
//! API, the recommendation is to read the value thrice and identify the right
|
||||
//! value (as 2 out the 3 read values will always be correct and with a max. of
|
||||
//! 1 LSB change)
|
||||
//!
|
||||
//! \return 64-bit current counter vlaue.
|
||||
//
|
||||
//*****************************************************************************
|
||||
unsigned long long PRCMSlowClkCtrFastGet(void)
|
||||
{
|
||||
unsigned long long ullRTCVal;
|
||||
|
||||
//
|
||||
// Read as 2 32-bit values
|
||||
//
|
||||
ullRTCVal = HWREG(HIB1P2_BASE + HIB1P2_O_HIB_RTC_TIMER_MSW_1P2);
|
||||
ullRTCVal = ullRTCVal << 32;
|
||||
ullRTCVal |= HWREG(HIB1P2_BASE + HIB1P2_O_HIB_RTC_TIMER_LSW_1P2);
|
||||
|
||||
return ullRTCVal;
|
||||
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
|
@ -247,6 +247,7 @@ extern void PRCMHibernateWakeupSourceDisable(unsigned long ulHIBWakupSrc);
|
||||
extern void PRCMHibernateIntervalSet(unsigned long long ullTicks);
|
||||
|
||||
extern unsigned long long PRCMSlowClkCtrGet(void);
|
||||
extern unsigned long long PRCMSlowClkCtrFastGet(void);
|
||||
extern void PRCMSlowClkCtrMatchSet(unsigned long long ullTicks);
|
||||
extern unsigned long long PRCMSlowClkCtrMatchGet(void);
|
||||
|
||||
|
@ -34,46 +34,51 @@
|
||||
#include "inc/hw_types.h"
|
||||
#include "interrupt.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpcallback.h"
|
||||
#include "mpexception.h"
|
||||
#include "mperror.h"
|
||||
#include "mpirq.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC DATA
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
const mp_arg_t mpcallback_init_args[] = {
|
||||
{ MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
const mp_arg_t mp_irq_init_args[] = {
|
||||
{ MP_QSTR_trigger, 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} }, // the lowest priority
|
||||
{ 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_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_wake_from, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PYB_PWR_MODE_ACTIVE} },
|
||||
{ MP_QSTR_wake, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC uint8_t mp_irq_priorities[] = { INT_PRIORITY_LVL_7, INT_PRIORITY_LVL_6, INT_PRIORITY_LVL_5, INT_PRIORITY_LVL_4,
|
||||
INT_PRIORITY_LVL_3, INT_PRIORITY_LVL_2, INT_PRIORITY_LVL_1 };
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void mpcallback_init0 (void) {
|
||||
void mp_irq_init0 (void) {
|
||||
// initialize the callback objects list
|
||||
mp_obj_list_init(&MP_STATE_PORT(mpcallback_obj_list), 0);
|
||||
mp_obj_list_init(&MP_STATE_PORT(mp_irq_obj_list), 0);
|
||||
}
|
||||
|
||||
mp_obj_t mpcallback_new (mp_obj_t parent, mp_obj_t handler, const mp_cb_methods_t *methods, bool enable) {
|
||||
mpcallback_obj_t *self = m_new_obj(mpcallback_obj_t);
|
||||
self->base.type = &pyb_callback_type;
|
||||
mp_obj_t mp_irq_new (mp_obj_t parent, mp_obj_t handler, const mp_irq_methods_t *methods) {
|
||||
mp_irq_obj_t *self = m_new_obj(mp_irq_obj_t);
|
||||
self->base.type = &mp_irq_type;
|
||||
self->handler = handler;
|
||||
self->parent = parent;
|
||||
self->methods = (mp_cb_methods_t *)methods;
|
||||
self->isenabled = enable;
|
||||
self->methods = (mp_irq_methods_t *)methods;
|
||||
self->isenabled = true;
|
||||
// remove it in case it was already registered
|
||||
mpcallback_remove(parent);
|
||||
mp_obj_list_append(&MP_STATE_PORT(mpcallback_obj_list), self);
|
||||
mp_irq_remove(parent);
|
||||
mp_obj_list_append(&MP_STATE_PORT(mp_irq_obj_list), self);
|
||||
return self;
|
||||
}
|
||||
|
||||
mpcallback_obj_t *mpcallback_find (mp_obj_t parent) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mpcallback_obj_list).len; i++) {
|
||||
mpcallback_obj_t *callback_obj = ((mpcallback_obj_t *)(MP_STATE_PORT(mpcallback_obj_list).items[i]));
|
||||
mp_irq_obj_t *mp_irq_find (mp_obj_t parent) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) {
|
||||
mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i]));
|
||||
if (callback_obj->parent == parent) {
|
||||
return callback_obj;
|
||||
}
|
||||
@ -81,58 +86,40 @@ mpcallback_obj_t *mpcallback_find (mp_obj_t parent) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void mpcallback_wake_all (void) {
|
||||
void mp_irq_wake_all (void) {
|
||||
// re-enable all active callback objects one by one
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mpcallback_obj_list).len; i++) {
|
||||
mpcallback_obj_t *callback_obj = ((mpcallback_obj_t *)(MP_STATE_PORT(mpcallback_obj_list).items[i]));
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) {
|
||||
mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i]));
|
||||
if (callback_obj->isenabled) {
|
||||
callback_obj->methods->enable(callback_obj->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mpcallback_disable_all (void) {
|
||||
void mp_irq_disable_all (void) {
|
||||
// re-enable all active callback objects one by one
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mpcallback_obj_list).len; i++) {
|
||||
mpcallback_obj_t *callback_obj = ((mpcallback_obj_t *)(MP_STATE_PORT(mpcallback_obj_list).items[i]));
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) {
|
||||
mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i]));
|
||||
callback_obj->methods->disable(callback_obj->parent);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
void mp_irq_remove (const mp_obj_t parent) {
|
||||
mp_irq_obj_t *callback_obj;
|
||||
if ((callback_obj = mp_irq_find(parent))) {
|
||||
mp_obj_list_remove(&MP_STATE_PORT(mp_irq_obj_list), callback_obj);
|
||||
}
|
||||
}
|
||||
|
||||
uint mpcallback_translate_priority (uint priority) {
|
||||
if (priority < 1 || priority > 7) {
|
||||
uint mp_irq_translate_priority (uint priority) {
|
||||
if (priority < 1 || priority > MP_ARRAY_SIZE(mp_irq_priorities)) {
|
||||
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;
|
||||
}
|
||||
return mp_irq_priorities[priority - 1];
|
||||
}
|
||||
|
||||
void mpcallback_handler (mp_obj_t self_in) {
|
||||
mpcallback_obj_t *self = self_in;
|
||||
void mp_irq_handler (mp_obj_t self_in) {
|
||||
mp_irq_obj_t *self = self_in;
|
||||
if (self && self->handler != mp_const_none) {
|
||||
// when executing code within a handler we must lock the GC to prevent
|
||||
// any memory allocations.
|
||||
@ -159,59 +146,57 @@ void mpcallback_handler (mp_obj_t self_in) {
|
||||
/******************************************************************************/
|
||||
// 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];
|
||||
STATIC mp_obj_t mp_irq_init (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_irq_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);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_irq_init_obj, 1, mp_irq_init);
|
||||
|
||||
/// \method enable()
|
||||
/// Enables the interrupt callback
|
||||
STATIC mp_obj_t callback_enable (mp_obj_t self_in) {
|
||||
mpcallback_obj_t *self = self_in;
|
||||
STATIC mp_obj_t mp_irq_enable (mp_obj_t self_in) {
|
||||
mp_irq_obj_t *self = self_in;
|
||||
self->methods->enable(self->parent);
|
||||
self->isenabled = true;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(callback_enable_obj, callback_enable);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_enable_obj, mp_irq_enable);
|
||||
|
||||
/// \method disable()
|
||||
/// Disables the interrupt callback
|
||||
STATIC mp_obj_t callback_disable (mp_obj_t self_in) {
|
||||
mpcallback_obj_t *self = self_in;
|
||||
STATIC mp_obj_t mp_irq_disable (mp_obj_t self_in) {
|
||||
mp_irq_obj_t *self = self_in;
|
||||
self->methods->disable(self->parent);
|
||||
self->isenabled = false;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(callback_disable_obj, callback_disable);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_disable_obj, mp_irq_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) {
|
||||
STATIC mp_obj_t mp_irq_flags (mp_obj_t self_in) {
|
||||
mp_irq_obj_t *self = self_in;
|
||||
return mp_obj_new_int(self->methods->flags(self->parent));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_flags_obj, mp_irq_flags);
|
||||
|
||||
STATIC mp_obj_t mp_irq_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);
|
||||
mp_irq_handler (self_in);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC const mp_map_elem_t callback_locals_dict_table[] = {
|
||||
STATIC const mp_map_elem_t mp_irq_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 },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&mp_irq_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&mp_irq_enable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&mp_irq_disable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_flags), (mp_obj_t)&mp_irq_flags_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(callback_locals_dict, callback_locals_dict_table);
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_irq_locals_dict, mp_irq_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_callback_type = {
|
||||
const mp_obj_type_t mp_irq_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_callback,
|
||||
.call = callback_call,
|
||||
.locals_dict = (mp_obj_t)&callback_locals_dict,
|
||||
.name = MP_QSTR_irq,
|
||||
.call = mp_irq_call,
|
||||
.locals_dict = (mp_obj_t)&mp_irq_locals_dict,
|
||||
};
|
||||
|
@ -24,50 +24,52 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MPCALLBACK_H_
|
||||
#define MPCALLBACK_H_
|
||||
#ifndef MPIRQ_H_
|
||||
#define MPIRQ_H_
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define mpcallback_INIT_NUM_ARGS 5
|
||||
#define mp_irq_INIT_NUM_ARGS 4
|
||||
|
||||
/******************************************************************************
|
||||
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 mp_obj_t (*mp_irq_init_t) (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
typedef void (*mp_irq_void_method_t) (mp_obj_t self);
|
||||
typedef int (*mp_irq_int_method_t) (mp_obj_t self);
|
||||
|
||||
typedef struct {
|
||||
mp_cb_init_t init;
|
||||
mp_cb_method_t enable;
|
||||
mp_cb_method_t disable;
|
||||
} mp_cb_methods_t;
|
||||
mp_irq_init_t init;
|
||||
mp_irq_void_method_t enable;
|
||||
mp_irq_void_method_t disable;
|
||||
mp_irq_int_method_t flags;
|
||||
} mp_irq_methods_t;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t parent;
|
||||
mp_obj_t handler;
|
||||
mp_cb_methods_t *methods;
|
||||
mp_irq_methods_t *methods;
|
||||
bool isenabled;
|
||||
} mpcallback_obj_t;
|
||||
} mp_irq_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE EXPORTED DATA
|
||||
******************************************************************************/
|
||||
extern const mp_arg_t mpcallback_init_args[];
|
||||
extern const mp_obj_type_t pyb_callback_type;
|
||||
extern const mp_arg_t mp_irq_init_args[];
|
||||
extern const mp_obj_type_t mp_irq_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, bool enable);
|
||||
mpcallback_obj_t *mpcallback_find (mp_obj_t parent);
|
||||
void mpcallback_wake_all (void);
|
||||
void mpcallback_disable_all (void);
|
||||
void mpcallback_remove (const mp_obj_t parent);
|
||||
void mpcallback_handler (mp_obj_t self_in);
|
||||
uint mpcallback_translate_priority (uint priority);
|
||||
void mp_irq_init0 (void);
|
||||
mp_obj_t mp_irq_new (mp_obj_t parent, mp_obj_t handler, const mp_irq_methods_t *methods);
|
||||
mp_irq_obj_t *mp_irq_find (mp_obj_t parent);
|
||||
void mp_irq_wake_all (void);
|
||||
void mp_irq_disable_all (void);
|
||||
void mp_irq_remove (const mp_obj_t parent);
|
||||
void mp_irq_handler (mp_obj_t self_in);
|
||||
uint mp_irq_translate_priority (uint priority);
|
||||
|
||||
#endif /* MPCALLBACK_H_ */
|
||||
#endif /* MPIRQ_H_ */
|
@ -56,7 +56,7 @@
|
||||
/// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which
|
||||
/// contains: (year, month, mday, hour, minute, second, weekday, yearday)
|
||||
/// If secs is not provided or None, then the current time from the RTC is used.
|
||||
/// year includes the century (for example 2014)
|
||||
/// year includes the century (for example 2015)
|
||||
/// month is 1-12
|
||||
/// mday is 1-31
|
||||
/// hour is 0-23
|
||||
@ -67,14 +67,9 @@
|
||||
STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0 || args[0] == mp_const_none) {
|
||||
timeutils_struct_time_t tm;
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
|
||||
// get the seconds and the milliseconds from the RTC
|
||||
MAP_PRCMRTCGet(&seconds, &mseconds);
|
||||
mseconds = RTC_CYCLES_U16MS(mseconds);
|
||||
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
|
||||
|
||||
// get the seconds from the RTC
|
||||
timeutils_seconds_since_2000_to_struct_time(pyb_rtc_get_seconds(), &tm);
|
||||
mp_obj_t tuple[8] = {
|
||||
mp_obj_new_int(tm.tm_year),
|
||||
mp_obj_new_int(tm.tm_mon),
|
||||
|
@ -51,7 +51,7 @@
|
||||
#include "serverstask.h"
|
||||
#endif
|
||||
#include "mpexception.h"
|
||||
#include "mpcallback.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybsleep.h"
|
||||
#include "antenna.h"
|
||||
|
||||
@ -88,31 +88,6 @@ typedef enum{
|
||||
// the ping operation
|
||||
} e_StatusBits;
|
||||
|
||||
typedef struct _wlan_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint32_t status;
|
||||
|
||||
uint32_t ip;
|
||||
|
||||
int8_t mode;
|
||||
uint8_t security;
|
||||
uint8_t channel;
|
||||
uint8_t antenna;
|
||||
|
||||
// my own ssid, key and mac
|
||||
uint8_t ssid[33];
|
||||
uint8_t key[65];
|
||||
uint8_t mac[SL_MAC_ADDR_LEN];
|
||||
|
||||
// the sssid (or name) and mac of the other device
|
||||
uint8_t ssid_o[33];
|
||||
uint8_t bssid[6];
|
||||
|
||||
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
|
||||
bool servers_enabled;
|
||||
#endif
|
||||
} wlan_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
@ -181,7 +156,7 @@ STATIC wlan_obj_t wlan_obj = {
|
||||
#endif
|
||||
};
|
||||
|
||||
STATIC const mp_cb_methods_t wlan_cb_methods;
|
||||
STATIC const mp_irq_methods_t wlan_irq_methods;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
@ -199,8 +174,8 @@ STATIC void wlan_get_sl_mac (void);
|
||||
STATIC void wlan_wep_key_unhexlify(const char *key, char *key_out);
|
||||
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, uint32_t timeout);
|
||||
STATIC void wlan_lpds_callback_enable (mp_obj_t self_in);
|
||||
STATIC void wlan_lpds_callback_disable (mp_obj_t self_in);
|
||||
STATIC void wlan_lpds_irq_enable (mp_obj_t self_in);
|
||||
STATIC void wlan_lpds_irq_disable (mp_obj_t self_in);
|
||||
STATIC bool wlan_scan_result_is_unique (const mp_obj_list_t *nets, _u8 *bssid);
|
||||
|
||||
//*****************************************************************************
|
||||
@ -793,13 +768,19 @@ arg_error:
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_iwconfig_obj, 1, wlan_iwconfig);
|
||||
|
||||
STATIC void wlan_lpds_callback_enable (mp_obj_t self_in) {
|
||||
mp_obj_t _callback = mpcallback_find(self_in);
|
||||
pybsleep_set_wlan_lpds_callback (_callback);
|
||||
STATIC void wlan_lpds_irq_enable (mp_obj_t self_in) {
|
||||
wlan_obj_t *self = self_in;
|
||||
self->irq_enabled = true;
|
||||
}
|
||||
|
||||
STATIC void wlan_lpds_callback_disable (mp_obj_t self_in) {
|
||||
pybsleep_set_wlan_lpds_callback (NULL);
|
||||
STATIC void wlan_lpds_irq_disable (mp_obj_t self_in) {
|
||||
wlan_obj_t *self = self_in;
|
||||
self->irq_enabled = false;
|
||||
}
|
||||
|
||||
STATIC int wlan_irq_flags (mp_obj_t self_in) {
|
||||
wlan_obj_t *self = self_in;
|
||||
return self->irq_flags;
|
||||
}
|
||||
|
||||
STATIC bool wlan_scan_result_is_unique (const mp_obj_list_t *nets, _u8 *bssid) {
|
||||
@ -829,6 +810,7 @@ STATIC mp_obj_t wlan_make_new (mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_k
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args);
|
||||
wlan_iwconfig(n_args + 1, (const mp_obj_t *)&wlan_obj, &kw_args);
|
||||
}
|
||||
pybsleep_set_wlan_obj(&wlan_obj);
|
||||
return &wlan_obj;
|
||||
}
|
||||
|
||||
@ -1086,34 +1068,34 @@ 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(handler, pwrmode)
|
||||
/// Create a callback object associated with the WLAN subsystem
|
||||
/// Only takes one argument (wake_from)
|
||||
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);
|
||||
/// \method irq(trigger, priority, handler, wake)
|
||||
STATIC mp_obj_t wlan_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
|
||||
wlan_obj_t *self = pos_args[0];
|
||||
mp_obj_t _callback = mpcallback_find(self);
|
||||
// check if any parameters were passed
|
||||
if (kw_args->used > 0) {
|
||||
// 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
|
||||
_callback = mpcallback_new (self, args[1].u_obj, &wlan_cb_methods, true);
|
||||
|
||||
// enable network wakeup
|
||||
pybsleep_set_wlan_lpds_callback (_callback);
|
||||
} else if (!_callback) {
|
||||
_callback = mpcallback_new (self, mp_const_none, &wlan_cb_methods, false);
|
||||
// check the trigger, only one type is supported
|
||||
if (mp_obj_get_int(args[0].u_obj) != MODWLAN_WIFI_EVENT_ANY) {
|
||||
goto invalid_args;
|
||||
}
|
||||
return _callback;
|
||||
|
||||
// check the power mode
|
||||
if (mp_obj_get_int(args[3].u_obj) != PYB_PWR_MODE_LPDS) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// create the callback
|
||||
mp_obj_t _irq = mp_irq_new (self, args[2].u_obj, &wlan_irq_methods);
|
||||
self->irq_obj = _irq;
|
||||
|
||||
return _irq;
|
||||
|
||||
invalid_args:
|
||||
// throw an exception since WLAN only supports LPDS mode
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_callback_obj, 1, wlan_callback);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq);
|
||||
|
||||
/// \method mac()
|
||||
/// returns the MAC address
|
||||
@ -1150,7 +1132,7 @@ STATIC const mp_map_elem_t wlan_locals_dict_table[] = {
|
||||
#if MICROPY_PORT_WLAN_URN
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_urn), (mp_obj_t)&wlan_urn_obj },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&wlan_callback_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&wlan_irq_obj },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_STA), MP_OBJ_NEW_SMALL_INT(ROLE_STA) },
|
||||
@ -1161,6 +1143,7 @@ STATIC const mp_map_elem_t wlan_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WPA2), MP_OBJ_NEW_SMALL_INT(SL_SEC_TYPE_WPA_WPA2) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_INTERNAL), MP_OBJ_NEW_SMALL_INT(ANTENNA_TYPE_INTERNAL) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_EXTERNAL), MP_OBJ_NEW_SMALL_INT(ANTENNA_TYPE_EXTERNAL) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ANY_EVENT), MP_OBJ_NEW_SMALL_INT(MODWLAN_WIFI_EVENT_ANY) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(wlan_locals_dict, wlan_locals_dict_table);
|
||||
|
||||
@ -1173,10 +1156,11 @@ const mod_network_nic_type_t mod_network_nic_type_wlan = {
|
||||
},
|
||||
};
|
||||
|
||||
STATIC const mp_cb_methods_t wlan_cb_methods = {
|
||||
.init = wlan_callback,
|
||||
.enable = wlan_lpds_callback_enable,
|
||||
.disable = wlan_lpds_callback_disable,
|
||||
STATIC const mp_irq_methods_t wlan_irq_methods = {
|
||||
.init = wlan_irq,
|
||||
.enable = wlan_lpds_irq_enable,
|
||||
.disable = wlan_lpds_irq_disable,
|
||||
.flags = wlan_irq_flags,
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
@ -1373,7 +1357,7 @@ int wlan_socket_ioctl (mod_network_socket_obj_t *s, mp_uint_t request, mp_uint_t
|
||||
tv.tv_usec = 1;
|
||||
int32_t nfds = sl_Select(sd + 1, &rfds, &wfds, &xfds, &tv);
|
||||
|
||||
// check for error
|
||||
// check for errors
|
||||
if (nfds == -1) {
|
||||
*_errno = nfds;
|
||||
return -1;
|
||||
|
@ -35,6 +35,8 @@
|
||||
#define SL_STOP_TIMEOUT 35
|
||||
#define SL_STOP_TIMEOUT_LONG 575
|
||||
|
||||
#define MODWLAN_WIFI_EVENT_ANY 0x01
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
@ -45,6 +47,34 @@ typedef enum {
|
||||
MODWLAN_ERROR_UNKNOWN = -3,
|
||||
} modwlan_Status_t;
|
||||
|
||||
typedef struct _wlan_obj_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t irq_obj;
|
||||
uint32_t status;
|
||||
|
||||
uint32_t ip;
|
||||
|
||||
int8_t mode;
|
||||
uint8_t security;
|
||||
uint8_t channel;
|
||||
uint8_t antenna;
|
||||
|
||||
// my own ssid, key and mac
|
||||
uint8_t ssid[33];
|
||||
uint8_t key[65];
|
||||
uint8_t mac[SL_MAC_ADDR_LEN];
|
||||
|
||||
// the sssid (or name) and mac of the other device
|
||||
uint8_t ssid_o[33];
|
||||
uint8_t bssid[6];
|
||||
uint8_t irq_flags;
|
||||
bool irq_enabled;
|
||||
|
||||
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
|
||||
bool servers_enabled;
|
||||
#endif
|
||||
} wlan_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
|
@ -45,9 +45,9 @@
|
||||
#include "gpio.h"
|
||||
#include "interrupt.h"
|
||||
#include "pybpin.h"
|
||||
#include "mpirq.h"
|
||||
#include "pins.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpcallback.h"
|
||||
#include "mpexception.h"
|
||||
#include "mperror.h"
|
||||
|
||||
@ -66,8 +66,8 @@ STATIC void pin_free_af_from_pins (uint8_t fn, uint8_t unit, uint8_t type);
|
||||
STATIC void pin_deassign (pin_obj_t* pin);
|
||||
STATIC void pin_obj_configure (const pin_obj_t *self);
|
||||
STATIC void pin_get_hibernate_pin_and_idx (const pin_obj_t *self, uint *wake_pin, uint *idx);
|
||||
STATIC void pin_extint_enable (mp_obj_t self_in);
|
||||
STATIC void pin_extint_disable (mp_obj_t self_in);
|
||||
STATIC void pin_irq_enable (mp_obj_t self_in);
|
||||
STATIC void pin_irq_disable (mp_obj_t self_in);
|
||||
STATIC void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t priority);
|
||||
STATIC void pin_validate_mode (uint mode);
|
||||
STATIC void pin_validate_pull (uint pull);
|
||||
@ -88,6 +88,11 @@ DEFINE CONSTANTS
|
||||
#define GPIO_DIR_MODE_ALT 0x00000002 // Pin is NOT controlled by the PGIO module
|
||||
#define GPIO_DIR_MODE_ALT_OD 0x00000003 // Pin is NOT controlled by the PGIO module and is in open drain mode
|
||||
|
||||
#define PYB_PIN_FALLING_EDGE 0x01
|
||||
#define PYB_PIN_RISING_EDGE 0x02
|
||||
#define PYB_PIN_LOW_LEVEL 0x04
|
||||
#define PYB_PIN_HIGH_LEVEL 0x08
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
@ -100,7 +105,7 @@ typedef struct {
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_cb_methods_t pin_cb_methods;
|
||||
STATIC const mp_irq_methods_t pin_irq_methods;
|
||||
STATIC pybpin_wake_pin_t pybpin_wake_pin[PYBPIN_NUM_WAKE_PINS] =
|
||||
{ {.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT},
|
||||
{.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT},
|
||||
@ -334,7 +339,7 @@ STATIC void pin_get_hibernate_pin_and_idx (const pin_obj_t *self, uint *hib_pin,
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pin_extint_enable (mp_obj_t self_in) {
|
||||
STATIC void pin_irq_enable (mp_obj_t self_in) {
|
||||
const pin_obj_t *self = self_in;
|
||||
uint hib_pin, idx;
|
||||
|
||||
@ -366,7 +371,7 @@ STATIC void pin_extint_enable (mp_obj_t self_in) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pin_extint_disable (mp_obj_t self_in) {
|
||||
STATIC void pin_irq_disable (mp_obj_t self_in) {
|
||||
const pin_obj_t *self = self_in;
|
||||
uint hib_pin, idx;
|
||||
|
||||
@ -385,6 +390,11 @@ STATIC void pin_extint_disable (mp_obj_t self_in) {
|
||||
MAP_GPIOIntDisable(self->port, self->bit);
|
||||
}
|
||||
|
||||
STATIC int pin_irq_flags (mp_obj_t self_in) {
|
||||
const pin_obj_t *self = self_in;
|
||||
return self->irq_flags;
|
||||
}
|
||||
|
||||
STATIC void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t priority) {
|
||||
void *handler;
|
||||
uint32_t intnum;
|
||||
@ -467,14 +477,22 @@ STATIC void EXTI_Handler(uint port) {
|
||||
uint32_t bits = MAP_GPIOIntStatus(port, true);
|
||||
MAP_GPIOIntClear(port, bits);
|
||||
|
||||
// might be that we have more than one Pin interrupt pending
|
||||
// might be that we have more than one pin interrupt pending
|
||||
// therefore we must loop through all of the 8 possible bits
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint32_t bit = (1 << i);
|
||||
if (bit & bits) {
|
||||
pin_obj_t *self = (pin_obj_t *)pin_find_pin_by_port_bit(&pin_board_pins_locals_dict, port, bit);
|
||||
mp_obj_t _callback = mpcallback_find(self);
|
||||
mpcallback_handler(_callback);
|
||||
if (self->irq_trigger == (PYB_PIN_FALLING_EDGE | PYB_PIN_RISING_EDGE)) {
|
||||
// read the pin value (hoping that the pin level has remained stable)
|
||||
self->irq_flags = MAP_GPIOPinRead(self->port, self->bit) ? PYB_PIN_RISING_EDGE : PYB_PIN_FALLING_EDGE;
|
||||
} else {
|
||||
// same as the triggers
|
||||
self->irq_flags = self->irq_trigger;
|
||||
}
|
||||
mp_irq_handler(mp_irq_find(self));
|
||||
// always clear the flags after leaving the user handler
|
||||
self->irq_flags = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -484,7 +502,7 @@ STATIC void EXTI_Handler(uint port) {
|
||||
// Micro Python bindings
|
||||
|
||||
STATIC const mp_arg_t pin_init_args[] = {
|
||||
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_drive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PIN_STRENGTH_4MA} },
|
||||
@ -498,8 +516,14 @@ STATIC mp_obj_t pin_obj_init_helper(pin_obj_t *self, mp_uint_t n_args, const mp_
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, pin_INIT_NUM_ARGS, pin_init_args, args);
|
||||
|
||||
// get the io mode
|
||||
uint mode = args[0].u_int;
|
||||
pin_validate_mode(mode);
|
||||
uint mode;
|
||||
// default is input
|
||||
if (args[0].u_obj == MP_OBJ_NULL) {
|
||||
mode = GPIO_DIR_MODE_IN;
|
||||
} else {
|
||||
mode = mp_obj_get_int(args[0].u_obj);
|
||||
pin_validate_mode (mode);
|
||||
}
|
||||
|
||||
// get the pull type
|
||||
uint pull;
|
||||
@ -609,12 +633,9 @@ STATIC mp_obj_t pin_make_new(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw,
|
||||
// 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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
@ -726,136 +747,147 @@ STATIC mp_obj_t pin_alt_list(mp_obj_t self_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_alt_list_obj, pin_alt_list);
|
||||
|
||||
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);
|
||||
|
||||
/// \method irq(trigger, priority, handler, wake)
|
||||
STATIC mp_obj_t pin_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
pin_obj_t *self = pos_args[0];
|
||||
// check if any parameters were passed
|
||||
mp_obj_t _callback = mpcallback_find(self);
|
||||
if (kw_args->used > 0) {
|
||||
// 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 | GPIO_RISING_EDGE)) {
|
||||
intmode = GPIO_BOTH_EDGES;
|
||||
}
|
||||
else if (intmode != GPIO_FALLING_EDGE && intmode != GPIO_RISING_EDGE &&
|
||||
intmode != GPIO_LOW_LEVEL && intmode != GPIO_HIGH_LEVEL) {
|
||||
|
||||
// convert the priority to the correct value
|
||||
uint priority = mp_irq_translate_priority (args[1].u_int);
|
||||
|
||||
// verify and translate the interrupt mode
|
||||
uint mp_trigger = mp_obj_get_int(args[0].u_obj);
|
||||
uint trigger;
|
||||
if (mp_trigger == (PYB_PIN_FALLING_EDGE | PYB_PIN_RISING_EDGE)) {
|
||||
trigger = GPIO_BOTH_EDGES;
|
||||
} else {
|
||||
switch (mp_trigger) {
|
||||
case PYB_PIN_FALLING_EDGE:
|
||||
trigger = GPIO_FALLING_EDGE;
|
||||
break;
|
||||
case PYB_PIN_RISING_EDGE:
|
||||
trigger = GPIO_RISING_EDGE;
|
||||
break;
|
||||
case PYB_PIN_LOW_LEVEL:
|
||||
trigger = GPIO_LOW_LEVEL;
|
||||
break;
|
||||
case PYB_PIN_HIGH_LEVEL:
|
||||
trigger = GPIO_HIGH_LEVEL;
|
||||
break;
|
||||
default:
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
uint pwrmode = args[4].u_int;
|
||||
if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// get the wake info from this pin
|
||||
uint hib_pin, idx;
|
||||
pin_get_hibernate_pin_and_idx ((const pin_obj_t *)self, &hib_pin, &idx);
|
||||
if (pwrmode & PYB_PWR_MODE_LPDS) {
|
||||
if (idx >= PYBPIN_NUM_WAKE_PINS) {
|
||||
goto invalid_args;
|
||||
}
|
||||
// wake modes are different in LDPS
|
||||
uint wake_mode;
|
||||
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:
|
||||
goto invalid_args;
|
||||
break;
|
||||
}
|
||||
|
||||
// first clear the lpds value from all wake-able pins
|
||||
for (uint i = 0; i < PYBPIN_NUM_WAKE_PINS; i++) {
|
||||
pybpin_wake_pin[i].lpds = PYBPIN_WAKES_NOT;
|
||||
}
|
||||
|
||||
// enable this pin as a wake-up source during LPDS
|
||||
pybpin_wake_pin[idx].lpds = wake_mode;
|
||||
}
|
||||
else {
|
||||
// this pin was the previous LPDS wake source, so disable it completely
|
||||
if (pybpin_wake_pin[idx].lpds != PYBPIN_WAKES_NOT) {
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO);
|
||||
}
|
||||
pybpin_wake_pin[idx].lpds = PYBPIN_WAKES_NOT;
|
||||
}
|
||||
|
||||
if (pwrmode & PYB_PWR_MODE_HIBERNATE) {
|
||||
if (idx >= PYBPIN_NUM_WAKE_PINS) {
|
||||
goto invalid_args;
|
||||
}
|
||||
// wake modes are different in hibernate
|
||||
uint wake_mode;
|
||||
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:
|
||||
goto invalid_args;
|
||||
break;
|
||||
}
|
||||
|
||||
// enable this pin as wake-up source during hibernate
|
||||
pybpin_wake_pin[idx].hib = wake_mode;
|
||||
}
|
||||
else {
|
||||
pybpin_wake_pin[idx].hib = PYBPIN_WAKES_NOT;
|
||||
}
|
||||
|
||||
// we need to update the callback atomically, so we disable the
|
||||
// interrupt before we update anything.
|
||||
pin_extint_disable(self);
|
||||
if (pwrmode & PYB_PWR_MODE_ACTIVE) {
|
||||
// register the interrupt
|
||||
pin_extint_register((pin_obj_t *)self, intmode, priority);
|
||||
if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
pybpin_wake_pin[idx].active = true;
|
||||
}
|
||||
}
|
||||
else if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
pybpin_wake_pin[idx].active = false;
|
||||
}
|
||||
|
||||
// all checks have passed, now we can create the callback
|
||||
_callback = mpcallback_new (self, args[1].u_obj, &pin_cb_methods, true);
|
||||
if (pwrmode & PYB_PWR_MODE_LPDS) {
|
||||
pybsleep_set_gpio_lpds_callback (_callback);
|
||||
}
|
||||
|
||||
// enable the interrupt just before leaving
|
||||
pin_extint_enable(self);
|
||||
} else if (!_callback) {
|
||||
_callback = mpcallback_new (self, mp_const_none, &pin_cb_methods, false);
|
||||
}
|
||||
return _callback;
|
||||
|
||||
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
|
||||
if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// get the wake info from this pin
|
||||
uint hib_pin, idx;
|
||||
pin_get_hibernate_pin_and_idx ((const pin_obj_t *)self, &hib_pin, &idx);
|
||||
if (pwrmode & PYB_PWR_MODE_LPDS) {
|
||||
if (idx >= PYBPIN_NUM_WAKE_PINS) {
|
||||
goto invalid_args;
|
||||
}
|
||||
// wake modes are different in LDPS
|
||||
uint wake_mode;
|
||||
switch (trigger) {
|
||||
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:
|
||||
goto invalid_args;
|
||||
break;
|
||||
}
|
||||
|
||||
// first clear the lpds value from all wake-able pins
|
||||
for (uint i = 0; i < PYBPIN_NUM_WAKE_PINS; i++) {
|
||||
pybpin_wake_pin[i].lpds = PYBPIN_WAKES_NOT;
|
||||
}
|
||||
|
||||
// enable this pin as a wake-up source during LPDS
|
||||
pybpin_wake_pin[idx].lpds = wake_mode;
|
||||
} else if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
// this pin was the previous LPDS wake source, so disable it completely
|
||||
if (pybpin_wake_pin[idx].lpds != PYBPIN_WAKES_NOT) {
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO);
|
||||
}
|
||||
pybpin_wake_pin[idx].lpds = PYBPIN_WAKES_NOT;
|
||||
}
|
||||
|
||||
if (pwrmode & PYB_PWR_MODE_HIBERNATE) {
|
||||
if (idx >= PYBPIN_NUM_WAKE_PINS) {
|
||||
goto invalid_args;
|
||||
}
|
||||
// wake modes are different in hibernate
|
||||
uint wake_mode;
|
||||
switch (trigger) {
|
||||
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:
|
||||
goto invalid_args;
|
||||
break;
|
||||
}
|
||||
|
||||
// enable this pin as wake-up source during hibernate
|
||||
pybpin_wake_pin[idx].hib = wake_mode;
|
||||
} else if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
pybpin_wake_pin[idx].hib = PYBPIN_WAKES_NOT;
|
||||
}
|
||||
|
||||
// we need to update the callback atomically, so we disable the
|
||||
// interrupt before we update anything.
|
||||
pin_irq_disable(self);
|
||||
if (pwrmode & PYB_PWR_MODE_ACTIVE) {
|
||||
// register the interrupt
|
||||
pin_extint_register((pin_obj_t *)self, trigger, priority);
|
||||
if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
pybpin_wake_pin[idx].active = true;
|
||||
}
|
||||
} else if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
pybpin_wake_pin[idx].active = false;
|
||||
}
|
||||
|
||||
// all checks have passed, we can create the irq object
|
||||
mp_obj_t _irq = mp_irq_new (self, args[2].u_obj, &pin_irq_methods);
|
||||
if (pwrmode & PYB_PWR_MODE_LPDS) {
|
||||
pybsleep_set_gpio_lpds_callback (_irq);
|
||||
}
|
||||
|
||||
// save the mp_trigge for later
|
||||
self->irq_trigger = mp_trigger;
|
||||
|
||||
// enable the interrupt just before leaving
|
||||
pin_irq_enable(self);
|
||||
|
||||
return _irq;
|
||||
|
||||
invalid_args:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_callback_obj, 1, pin_callback);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_irq_obj, 1, pin_irq);
|
||||
|
||||
STATIC const mp_map_elem_t pin_locals_dict_table[] = {
|
||||
// instance methods
|
||||
@ -867,7 +899,7 @@ STATIC const mp_map_elem_t pin_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pull), (mp_obj_t)&pin_pull_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_drive), (mp_obj_t)&pin_drive_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alt_list), (mp_obj_t)&pin_alt_list_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pin_callback_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pin_irq_obj },
|
||||
|
||||
// class attributes
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_board), (mp_obj_t)&pin_board_pins_obj_type },
|
||||
@ -883,10 +915,10 @@ STATIC const mp_map_elem_t pin_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_LOW_POWER), MP_OBJ_NEW_SMALL_INT(PIN_STRENGTH_2MA) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_MED_POWER), MP_OBJ_NEW_SMALL_INT(PIN_STRENGTH_4MA) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_HIGH_POWER), MP_OBJ_NEW_SMALL_INT(PIN_STRENGTH_6MA) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_FALLING), MP_OBJ_NEW_SMALL_INT(GPIO_FALLING_EDGE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING), MP_OBJ_NEW_SMALL_INT(GPIO_RISING_EDGE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_LOW_LEVEL), MP_OBJ_NEW_SMALL_INT(GPIO_LOW_LEVEL) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_HIGH_LEVEL), MP_OBJ_NEW_SMALL_INT(GPIO_HIGH_LEVEL) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_FALLING), MP_OBJ_NEW_SMALL_INT(PYB_PIN_FALLING_EDGE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING), MP_OBJ_NEW_SMALL_INT(PYB_PIN_RISING_EDGE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_LOW_LEVEL), MP_OBJ_NEW_SMALL_INT(PYB_PIN_LOW_LEVEL) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_HIGH_LEVEL), MP_OBJ_NEW_SMALL_INT(PYB_PIN_HIGH_LEVEL) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pin_locals_dict, pin_locals_dict_table);
|
||||
@ -900,10 +932,11 @@ const mp_obj_type_t pin_type = {
|
||||
.locals_dict = (mp_obj_t)&pin_locals_dict,
|
||||
};
|
||||
|
||||
STATIC const mp_cb_methods_t pin_cb_methods = {
|
||||
.init = pin_callback,
|
||||
.enable = pin_extint_enable,
|
||||
.disable = pin_extint_disable,
|
||||
STATIC const mp_irq_methods_t pin_irq_methods = {
|
||||
.init = pin_irq,
|
||||
.enable = pin_irq_enable,
|
||||
.disable = pin_irq_disable,
|
||||
.flags = pin_irq_flags,
|
||||
};
|
||||
|
||||
STATIC void pin_named_pins_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
|
@ -110,9 +110,11 @@ typedef struct {
|
||||
int8_t af;
|
||||
uint8_t strength;
|
||||
uint8_t mode; // this is now a combination of type and mode
|
||||
uint8_t num_afs: 6; // up to 63 AFs
|
||||
uint8_t value : 1;
|
||||
uint8_t used : 1;
|
||||
const uint8_t num_afs; // 255 AFs
|
||||
uint8_t value;
|
||||
uint8_t used;
|
||||
uint8_t irq_trigger;
|
||||
uint8_t irq_flags;
|
||||
} pin_obj_t;
|
||||
|
||||
extern const mp_obj_type_t pin_type;
|
||||
|
@ -37,8 +37,8 @@
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "pybrtc.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpcallback.h"
|
||||
#include "timeutils.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
@ -48,88 +48,148 @@
|
||||
/// \moduleref pyb
|
||||
/// \class RTC - real time clock
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct _pyb_rtc_obj_t {
|
||||
mp_obj_base_t base;
|
||||
byte prwmode;
|
||||
bool alarmset;
|
||||
bool repeat;
|
||||
} pyb_rtc_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_cb_methods_t pybrtc_cb_methods;
|
||||
STATIC pyb_rtc_obj_t pyb_rtc_obj = {.prwmode = 0, .alarmset = false, .repeat = false};
|
||||
STATIC const mp_irq_methods_t pyb_rtc_irq_methods;
|
||||
STATIC pyb_rtc_obj_t pyb_rtc_obj;
|
||||
|
||||
/******************************************************************************
|
||||
FUNCTION-LIKE MACROS
|
||||
******************************************************************************/
|
||||
#define RTC_U16MS_CYCLES(msec) ((msec * 1024) / 1000)
|
||||
#define RTC_CYCLES_U16MS(cycles) ((cycles * 1000) / 1024)
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC uint32_t pyb_rtc_reset (mp_obj_t self_in);
|
||||
STATIC void pyb_rtc_callback_enable (mp_obj_t self_in);
|
||||
STATIC void pyb_rtc_callback_disable (mp_obj_t self_in);
|
||||
STATIC void pyb_rtc_set_time (uint32_t secs, uint16_t msecs);
|
||||
STATIC uint32_t pyb_rtc_reset (void);
|
||||
STATIC void pyb_rtc_disable_interupt (void);
|
||||
STATIC void pyb_rtc_irq_enable (mp_obj_t self_in);
|
||||
STATIC void pyb_rtc_irq_disable (mp_obj_t self_in);
|
||||
STATIC int pyb_rtc_irq_flags (mp_obj_t self_in);
|
||||
STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds);
|
||||
STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self, const mp_obj_t datetime);
|
||||
STATIC void pyb_rtc_set_alarm (pyb_rtc_obj_t *self, uint32_t seconds, uint16_t mseconds);
|
||||
STATIC void rtc_msec_add(uint16_t msecs_1, uint32_t *secs, uint16_t *msecs_2);
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
__attribute__ ((section (".boot")))
|
||||
void pyb_rtc_pre_init(void) {
|
||||
// if the RTC was previously set, leave it alone
|
||||
// only if comming out of a power-on reset
|
||||
if (MAP_PRCMSysResetCauseGet() == PRCM_POWER_ON) {
|
||||
// Mark the RTC in use first
|
||||
MAP_PRCMRTCInUseSet();
|
||||
// reset the time and date
|
||||
pyb_rtc_reset((mp_obj_t)&pyb_rtc_obj);
|
||||
pyb_rtc_reset();
|
||||
}
|
||||
}
|
||||
|
||||
void pyb_rtc_get_time (uint32_t *secs, uint16_t *msecs) {
|
||||
uint16_t cycles;
|
||||
MAP_PRCMRTCGet (secs, &cycles);
|
||||
*msecs = RTC_CYCLES_U16MS(cycles);
|
||||
}
|
||||
|
||||
uint32_t pyb_rtc_get_seconds (void) {
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
MAP_PRCMRTCGet(&seconds, &mseconds);
|
||||
pyb_rtc_get_time(&seconds, &mseconds);
|
||||
return seconds;
|
||||
}
|
||||
|
||||
void pyb_rtc_calc_future_time (uint32_t a_mseconds, uint32_t *f_seconds, uint16_t *f_mseconds) {
|
||||
uint32_t c_seconds;
|
||||
uint16_t c_mseconds;
|
||||
// get the current time
|
||||
pyb_rtc_get_time(&c_seconds, &c_mseconds);
|
||||
// calculate the future seconds
|
||||
*f_seconds = c_seconds + (a_mseconds / 1000);
|
||||
// calculate the "remaining" future mseconds
|
||||
*f_mseconds = a_mseconds % 1000;
|
||||
// add the current milliseconds
|
||||
rtc_msec_add (c_mseconds, f_seconds, f_mseconds);
|
||||
}
|
||||
|
||||
void pyb_rtc_repeat_alarm (pyb_rtc_obj_t *self) {
|
||||
if (self->repeat) {
|
||||
uint32_t f_seconds, c_seconds;
|
||||
uint16_t f_mseconds, c_mseconds;
|
||||
|
||||
pyb_rtc_get_time(&c_seconds, &c_mseconds);
|
||||
|
||||
// substract the time elapsed between waking up and setting up the alarm again
|
||||
int32_t wake_ms = ((c_seconds * 1000) + c_mseconds) - ((self->alarm_time_s * 1000) + self->alarm_time_ms);
|
||||
int32_t next_alarm = self->alarm_ms - wake_ms;
|
||||
next_alarm = next_alarm > 0 ? next_alarm : PYB_RTC_MIN_ALARM_TIME_MS;
|
||||
pyb_rtc_calc_future_time (next_alarm, &f_seconds, &f_mseconds);
|
||||
|
||||
// now configure the alarm
|
||||
pyb_rtc_set_alarm (self, f_seconds, f_mseconds);
|
||||
}
|
||||
}
|
||||
|
||||
void pyb_rtc_disable_alarm (void) {
|
||||
pyb_rtc_obj.alarmset = false;
|
||||
pyb_rtc_disable_interupt();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC uint32_t pyb_rtc_reset (mp_obj_t self_in) {
|
||||
STATIC void pyb_rtc_set_time (uint32_t secs, uint16_t msecs) {
|
||||
// add the RTC access time
|
||||
rtc_msec_add(RTC_ACCESS_TIME_MSEC, &secs, &msecs);
|
||||
// convert from mseconds to cycles
|
||||
msecs = RTC_U16MS_CYCLES(msecs);
|
||||
// now set the time
|
||||
MAP_PRCMRTCSet(secs, msecs);
|
||||
}
|
||||
|
||||
STATIC uint32_t pyb_rtc_reset (void) {
|
||||
// fresh reset; configure the RTC Calendar
|
||||
// set the date to 1st Jan 2015
|
||||
// set the time to 00:00:00
|
||||
uint32_t seconds = timeutils_seconds_since_2000(2015, 1, 1, 0, 0, 0);
|
||||
// Now set the RTC calendar seconds
|
||||
MAP_PRCMRTCSet(seconds, 0);
|
||||
// disable any running alarm
|
||||
pyb_rtc_disable_alarm();
|
||||
// Now set the RTC calendar time
|
||||
pyb_rtc_set_time(seconds, 0);
|
||||
return seconds;
|
||||
}
|
||||
|
||||
STATIC void pyb_rtc_callback_enable (mp_obj_t self_in) {
|
||||
pyb_rtc_obj_t *self = self_in;
|
||||
// check the wake from param
|
||||
if (self->prwmode & PYB_PWR_MODE_ACTIVE) {
|
||||
// enable the slow clock interrupt
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
} else {
|
||||
// just in case it was already enabled before
|
||||
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
|
||||
}
|
||||
pybsleep_configure_timer_wakeup (self->prwmode);
|
||||
STATIC void pyb_rtc_disable_interupt (void) {
|
||||
uint primsk = disable_irq();
|
||||
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
|
||||
(void)MAP_PRCMIntStatus();
|
||||
enable_irq(primsk);
|
||||
}
|
||||
|
||||
STATIC void pyb_rtc_callback_disable (mp_obj_t self_in) {
|
||||
STATIC void pyb_rtc_irq_enable (mp_obj_t self_in) {
|
||||
pyb_rtc_obj_t *self = self_in;
|
||||
// check the wake from param
|
||||
if (self->prwmode & PYB_PWR_MODE_ACTIVE) {
|
||||
// disable the slow clock interrupt
|
||||
// we always need interrupts if repeat is enabled
|
||||
if ((self->pwrmode & PYB_PWR_MODE_ACTIVE) || self->repeat) {
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
} else { // just in case it was already enabled before
|
||||
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
|
||||
}
|
||||
// disable wake from ldps and hibernate
|
||||
pybsleep_configure_timer_wakeup (PYB_PWR_MODE_ACTIVE);
|
||||
// read the interrupt status to clear any pending interrupt
|
||||
(void)MAP_PRCMIntStatus();
|
||||
self->irq_enabled = true;
|
||||
}
|
||||
|
||||
STATIC void pyb_rtc_irq_disable (mp_obj_t self_in) {
|
||||
pyb_rtc_obj_t *self = self_in;
|
||||
self->irq_enabled = false;
|
||||
if (!self->repeat) { // we always need interrupts if repeat is enabled
|
||||
pyb_rtc_disable_interupt();
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int pyb_rtc_irq_flags (mp_obj_t self_in) {
|
||||
pyb_rtc_obj_t *self = self_in;
|
||||
return self->irq_flags;
|
||||
}
|
||||
|
||||
STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds) {
|
||||
@ -177,15 +237,15 @@ STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds) {
|
||||
///
|
||||
/// (year, month, day, hours, minutes, seconds, milliseconds, tzinfo=None)
|
||||
///
|
||||
STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self, const mp_obj_t datetime) {
|
||||
STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self_in, const mp_obj_t datetime) {
|
||||
uint32_t seconds;
|
||||
uint32_t useconds;
|
||||
|
||||
if (datetime != MP_OBJ_NULL) {
|
||||
useconds = pyb_rtc_datetime_s_us(datetime, &seconds);
|
||||
MAP_PRCMRTCSet(seconds, RTC_U16MS_CYCLES(useconds / 1000));
|
||||
pyb_rtc_set_time (seconds, useconds / 1000);
|
||||
} else {
|
||||
seconds = pyb_rtc_reset(self);
|
||||
seconds = pyb_rtc_reset();
|
||||
}
|
||||
|
||||
// set WLAN time and date, this is needed to verify certificates
|
||||
@ -193,6 +253,32 @@ STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self, const mp_obj_t datetime) {
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC void pyb_rtc_set_alarm (pyb_rtc_obj_t *self, uint32_t seconds, uint16_t mseconds) {
|
||||
// disable the interrupt before updating anything
|
||||
if (self->irq_enabled) {
|
||||
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
|
||||
}
|
||||
// set the match value
|
||||
MAP_PRCMRTCMatchSet(seconds, RTC_U16MS_CYCLES(mseconds));
|
||||
self->alarmset = true;
|
||||
self->alarm_time_s = seconds;
|
||||
self->alarm_time_ms = mseconds;
|
||||
// enabled the interrupts again if applicable
|
||||
if (self->irq_enabled || self->repeat) {
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void rtc_msec_add (uint16_t msecs_1, uint32_t *secs, uint16_t *msecs_2) {
|
||||
if (msecs_1 + *msecs_2 >= 1000) { // larger than one second
|
||||
*msecs_2 = (msecs_1 + *msecs_2) - 1000;
|
||||
*secs += 1; // carry flag
|
||||
} else {
|
||||
// simply add the mseconds
|
||||
*msecs_2 = msecs_1 + *msecs_2;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings
|
||||
|
||||
@ -219,6 +305,9 @@ STATIC mp_obj_t pyb_rtc_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n
|
||||
// set the time and date
|
||||
pyb_rtc_datetime((mp_obj_t)&pyb_rtc_obj, args[1].u_obj);
|
||||
|
||||
// pass it to the sleep module
|
||||
pybsleep_set_rtc_obj (self);
|
||||
|
||||
// return constant object
|
||||
return (mp_obj_t)&pyb_rtc_obj;
|
||||
}
|
||||
@ -236,9 +325,8 @@ STATIC mp_obj_t pyb_rtc_now (mp_obj_t self_in) {
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
|
||||
// get the seconds and the milliseconds from the RTC
|
||||
MAP_PRCMRTCGet(&seconds, &mseconds);
|
||||
mseconds = RTC_CYCLES_U16MS(mseconds);
|
||||
// get the time from the RTC
|
||||
pyb_rtc_get_time(&seconds, &mseconds);
|
||||
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
|
||||
|
||||
mp_obj_t tuple[8] = {
|
||||
@ -256,7 +344,7 @@ STATIC mp_obj_t pyb_rtc_now (mp_obj_t self_in) {
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_now_obj, pyb_rtc_now);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_deinit (mp_obj_t self_in) {
|
||||
pyb_rtc_reset (self_in);
|
||||
pyb_rtc_reset();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_deinit_obj, pyb_rtc_deinit);
|
||||
@ -264,7 +352,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_deinit_obj, pyb_rtc_deinit);
|
||||
STATIC mp_obj_t pyb_rtc_alarm (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_time, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_time, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_repeat, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
||||
};
|
||||
|
||||
@ -278,114 +366,97 @@ STATIC mp_obj_t pyb_rtc_alarm (mp_uint_t n_args, const mp_obj_t *pos_args, mp_ma
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
|
||||
uint32_t a_seconds;
|
||||
uint16_t a_mseconds;
|
||||
uint32_t f_seconds;
|
||||
uint16_t f_mseconds;
|
||||
bool repeat = args[2].u_bool;
|
||||
if (MP_OBJ_IS_TYPE(args[1].u_obj, &mp_type_tuple)) { // datetime tuple given
|
||||
a_mseconds = pyb_rtc_datetime_s_us (args[1].u_obj, &a_seconds) / 1000;
|
||||
} else { // then it must be an integer or MP_OBJ_NULL
|
||||
uint32_t c_seconds;
|
||||
uint16_t c_mseconds;
|
||||
if (MP_OBJ_IS_INT(args[1].u_obj)) {
|
||||
a_seconds = 0, a_mseconds = mp_obj_get_int(args[1].u_obj);
|
||||
} else {
|
||||
a_seconds = 1, a_mseconds = 0;
|
||||
// repeat cannot be used with a datetime tuple
|
||||
if (repeat) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
// get the seconds and the milliseconds from the RTC
|
||||
MAP_PRCMRTCGet(&c_seconds, &c_mseconds);
|
||||
a_mseconds += RTC_CYCLES_U16MS(c_mseconds);
|
||||
// calculate the future time
|
||||
a_seconds += c_seconds + (a_mseconds / 1000);
|
||||
a_mseconds -= ((a_mseconds / 1000) * 1000);
|
||||
f_mseconds = pyb_rtc_datetime_s_us (args[1].u_obj, &f_seconds) / 1000;
|
||||
} else { // then it must be an integer
|
||||
self->alarm_ms = mp_obj_get_int(args[1].u_obj);
|
||||
pyb_rtc_calc_future_time (self->alarm_ms, &f_seconds, &f_mseconds);
|
||||
}
|
||||
|
||||
// disable the interrupt before updating anything
|
||||
pyb_rtc_callback_disable((mp_obj_t)self);
|
||||
// store the repepat flag
|
||||
self->repeat = repeat;
|
||||
|
||||
// set the match value
|
||||
MAP_PRCMRTCMatchSet(a_seconds, a_mseconds);
|
||||
|
||||
// enabled it again (according to the power mode)
|
||||
pyb_rtc_callback_enable((mp_obj_t)self);
|
||||
|
||||
// set the alarmset flag and store the repeat one
|
||||
self->alarmset = true;
|
||||
self->repeat = args[2].u_bool;
|
||||
// now configure the alarm
|
||||
pyb_rtc_set_alarm (self, f_seconds, f_mseconds);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_alarm_obj, 1, pyb_rtc_alarm);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_alarm_left (mp_obj_t self_in) {
|
||||
pyb_rtc_obj_t *self = self_in;
|
||||
uint32_t a_seconds, c_seconds;
|
||||
uint16_t a_mseconds, c_mseconds;
|
||||
STATIC mp_obj_t pyb_rtc_alarm_left (mp_uint_t n_args, const mp_obj_t *args) {
|
||||
pyb_rtc_obj_t *self = args[0];
|
||||
int32_t ms_left;
|
||||
uint32_t c_seconds;
|
||||
uint16_t c_mseconds;
|
||||
|
||||
// only alarm id 0 is available
|
||||
if (n_args > 1 && mp_obj_get_int(args[1]) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
|
||||
// get the alarm time
|
||||
MAP_PRCMRTCMatchGet(&a_seconds, &a_mseconds);
|
||||
a_mseconds = RTC_CYCLES_U16MS(a_mseconds);
|
||||
// get the current time
|
||||
MAP_PRCMRTCGet(&c_seconds, &c_mseconds);
|
||||
c_mseconds = RTC_CYCLES_U16MS(c_mseconds);
|
||||
pyb_rtc_get_time(&c_seconds, &c_mseconds);
|
||||
|
||||
// calculate the ms left
|
||||
ms_left = ((a_seconds * 1000) + a_mseconds) - ((c_seconds * 1000) + c_mseconds);
|
||||
ms_left = ((self->alarm_time_s * 1000) + self->alarm_time_ms) - ((c_seconds * 1000) + c_mseconds);
|
||||
if (!self->alarmset || ms_left < 0) {
|
||||
ms_left = 0;
|
||||
}
|
||||
return mp_obj_new_int(ms_left);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_alarm_left_obj, pyb_rtc_alarm_left);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_left_obj, 1, 2, pyb_rtc_alarm_left);
|
||||
|
||||
/// \method callback(handler, value, pwrmode)
|
||||
/// Creates a callback object associated with the real time clock
|
||||
/// min num of arguments is 1 (value). The value is the alarm time
|
||||
/// in the future, in msec
|
||||
/// FIXME
|
||||
STATIC mp_obj_t pyb_rtc_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);
|
||||
STATIC mp_obj_t pyb_rtc_alarm_cancel (mp_uint_t n_args, const mp_obj_t *args) {
|
||||
// only alarm id 0 is available
|
||||
if (n_args > 1 && mp_obj_get_int(args[1]) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
// disable the alarm
|
||||
pyb_rtc_disable_alarm();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_cancel_obj, 1, 2, pyb_rtc_alarm_cancel);
|
||||
|
||||
/// \method irq(trigger, priority, handler, wake)
|
||||
STATIC mp_obj_t pyb_rtc_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
pyb_rtc_obj_t *self = pos_args[0];
|
||||
|
||||
// check if any parameters were passed
|
||||
mp_obj_t _callback = mpcallback_find((mp_obj_t)&pyb_rtc_obj);
|
||||
if (kw_args->used > 0) {
|
||||
uint32_t f_mseconds = MAX(1, mp_obj_get_int(args[3].u_obj));
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
// get the seconds and the milliseconds from the RTC
|
||||
MAP_PRCMRTCGet(&seconds, &mseconds);
|
||||
mseconds = RTC_CYCLES_U16MS(mseconds);
|
||||
|
||||
// configure the rtc alarm accordingly
|
||||
seconds += f_mseconds / 1000;
|
||||
mseconds += f_mseconds - ((f_mseconds / 1000) * 1000);
|
||||
|
||||
// disable the interrupt before updating anything
|
||||
pyb_rtc_callback_disable((mp_obj_t)&pyb_rtc_obj);
|
||||
|
||||
// set the match value
|
||||
MAP_PRCMRTCMatchSet(seconds, mseconds);
|
||||
|
||||
// save the power mode data for later
|
||||
self->prwmode = args[4].u_int;
|
||||
|
||||
// create the callback
|
||||
_callback = mpcallback_new ((mp_obj_t)&pyb_rtc_obj, args[1].u_obj, &pybrtc_cb_methods, true);
|
||||
|
||||
// set the lpds callback
|
||||
pybsleep_set_timer_lpds_callback(_callback);
|
||||
|
||||
// the interrupt priority is ignored since it's already set to to highest level by the sleep module
|
||||
// to make sure that the wakeup callbacks are always called first when resuming from sleep
|
||||
|
||||
// enable the interrupt
|
||||
pyb_rtc_callback_enable((mp_obj_t)&pyb_rtc_obj);
|
||||
} else if (!_callback) {
|
||||
_callback = mpcallback_new ((mp_obj_t)&pyb_rtc_obj, mp_const_none, &pybrtc_cb_methods, false);
|
||||
// save the power mode data for later
|
||||
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
|
||||
if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) {
|
||||
goto invalid_args;
|
||||
}
|
||||
return _callback;
|
||||
|
||||
// check the trigger
|
||||
if (mp_obj_get_int(args[0].u_obj) == PYB_RTC_ALARM0) {
|
||||
self->pwrmode = pwrmode;
|
||||
pyb_rtc_irq_enable((mp_obj_t)self);
|
||||
} else {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// the interrupt priority is ignored since it's already set to to highest level by the sleep module
|
||||
// to make sure that the wakeup irqs are always called first when resuming from sleep
|
||||
|
||||
// create the callback
|
||||
mp_obj_t _irq = mp_irq_new ((mp_obj_t)self, args[2].u_obj, &pyb_rtc_irq_methods);
|
||||
self->irq_obj = _irq;
|
||||
|
||||
return _irq;
|
||||
|
||||
invalid_args:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_callback_obj, 1, pyb_rtc_callback);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_irq_obj, 1, pyb_rtc_irq);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_rtc_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_rtc_init_obj },
|
||||
@ -393,7 +464,11 @@ STATIC const mp_map_elem_t pyb_rtc_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_now), (mp_obj_t)&pyb_rtc_now_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm), (mp_obj_t)&pyb_rtc_alarm_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm_left), (mp_obj_t)&pyb_rtc_alarm_left_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_rtc_callback_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm_cancel), (mp_obj_t)&pyb_rtc_alarm_cancel_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_rtc_irq_obj },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ALARM0), MP_OBJ_NEW_SMALL_INT(PYB_RTC_ALARM0) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_rtc_locals_dict, pyb_rtc_locals_dict_table);
|
||||
|
||||
@ -404,8 +479,9 @@ const mp_obj_type_t pyb_rtc_type = {
|
||||
.locals_dict = (mp_obj_t)&pyb_rtc_locals_dict,
|
||||
};
|
||||
|
||||
STATIC const mp_cb_methods_t pybrtc_cb_methods = {
|
||||
.init = pyb_rtc_callback,
|
||||
.enable = pyb_rtc_callback_enable,
|
||||
.disable = pyb_rtc_callback_disable,
|
||||
STATIC const mp_irq_methods_t pyb_rtc_irq_methods = {
|
||||
.init = pyb_rtc_irq,
|
||||
.enable = pyb_rtc_irq_enable,
|
||||
.disable = pyb_rtc_irq_disable,
|
||||
.flags = pyb_rtc_irq_flags
|
||||
};
|
||||
|
@ -28,12 +28,32 @@
|
||||
#ifndef PYBRTC_H_
|
||||
#define PYBRTC_H_
|
||||
|
||||
#define RTC_U16MS_CYCLES(msec) ((msec * 1024) / 1000)
|
||||
#define RTC_CYCLES_U16MS(cycles) ((cycles * 1000) / 1024)
|
||||
// RTC triggers
|
||||
#define PYB_RTC_ALARM0 (0x01)
|
||||
|
||||
#define RTC_ACCESS_TIME_MSEC (5)
|
||||
#define PYB_RTC_MIN_ALARM_TIME_MS (RTC_ACCESS_TIME_MSEC * 2)
|
||||
|
||||
typedef struct _pyb_rtc_obj_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t irq_obj;
|
||||
uint32_t irq_flags;
|
||||
uint32_t alarm_ms;
|
||||
uint32_t alarm_time_s;
|
||||
uint16_t alarm_time_ms;
|
||||
byte pwrmode;
|
||||
bool alarmset;
|
||||
bool repeat;
|
||||
bool irq_enabled;
|
||||
} pyb_rtc_obj_t;
|
||||
|
||||
extern const mp_obj_type_t pyb_rtc_type;
|
||||
|
||||
extern void pyb_rtc_pre_init(void);
|
||||
extern void pyb_rtc_get_time (uint32_t *secs, uint16_t *msecs);
|
||||
extern uint32_t pyb_rtc_get_seconds (void);
|
||||
extern void pyb_rtc_calc_future_time (uint32_t a_mseconds, uint32_t *f_seconds, uint16_t *f_mseconds);
|
||||
extern void pyb_rtc_repeat_alarm (pyb_rtc_obj_t *self);
|
||||
extern void pyb_rtc_disable_alarm (void);
|
||||
|
||||
#endif // PYBRTC_H_
|
||||
|
@ -54,7 +54,7 @@
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
pybsd_obj_t pybsd_obj = {.pin_clk = MP_OBJ_NULL, .enabled = false};
|
||||
pybsd_obj_t pybsd_obj;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "spi.h"
|
||||
#include "pin.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybpin.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
@ -50,12 +51,12 @@
|
||||
#include "osi.h"
|
||||
#include "debug.h"
|
||||
#include "mpexception.h"
|
||||
#include "mpcallback.h"
|
||||
#include "mperror.h"
|
||||
#include "sleeprestore.h"
|
||||
#include "serverstask.h"
|
||||
#include "antenna.h"
|
||||
#include "cryptohash.h"
|
||||
#include "pybrtc.h"
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE CONSTANTS
|
||||
@ -70,8 +71,8 @@
|
||||
#define WAKEUP_TIME_LPDS (LPDS_UP_TIME + LPDS_DOWN_TIME + USER_OFFSET) // 20 msec
|
||||
#define WAKEUP_TIME_HIB (32768) // 1 s
|
||||
|
||||
#define FORCED_TIMER_INTERRUPT_MS (1)
|
||||
#define FAILED_SLEEP_DELAY_MS (FORCED_TIMER_INTERRUPT_MS * 3)
|
||||
#define FORCED_TIMER_INTERRUPT_MS (PYB_RTC_MIN_ALARM_TIME_MS)
|
||||
#define FAILED_SLEEP_DELAY_MS (FORCED_TIMER_INTERRUPT_MS * 2)
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE TYPES
|
||||
@ -113,10 +114,9 @@ typedef struct {
|
||||
} pybsleep_obj_t;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_t wlan_lpds_wake_cb;
|
||||
mp_obj_t timer_lpds_wake_cb;
|
||||
mp_obj_t gpio_lpds_wake_cb;
|
||||
uint timer_wake_pwrmode;
|
||||
mp_obj_t gpio_lpds_wake_cb;
|
||||
wlan_obj_t *wlan_obj;
|
||||
pyb_rtc_obj_t *rtc_obj;
|
||||
} pybsleep_data_t;
|
||||
|
||||
/******************************************************************************
|
||||
@ -124,7 +124,7 @@ typedef struct {
|
||||
******************************************************************************/
|
||||
STATIC const mp_obj_type_t pybsleep_type;
|
||||
STATIC nvic_reg_store_t *nvic_reg_store;
|
||||
STATIC pybsleep_data_t pybsleep_data = {NULL, NULL, NULL, 0};
|
||||
STATIC pybsleep_data_t pybsleep_data = {NULL, NULL, NULL};
|
||||
volatile arm_cm4_core_regs_t vault_arm_registers;
|
||||
STATIC pybsleep_reset_cause_t pybsleep_reset_cause = PYB_SLP_PWRON_RESET;
|
||||
STATIC pybsleep_wake_reason_t pybsleep_wake_reason = PYB_SLP_WAKED_PWRON;
|
||||
@ -224,20 +224,16 @@ void pybsleep_remove (const mp_obj_t obj) {
|
||||
}
|
||||
}
|
||||
|
||||
void pybsleep_set_wlan_lpds_callback (mp_obj_t cb_obj) {
|
||||
pybsleep_data.wlan_lpds_wake_cb = cb_obj;
|
||||
}
|
||||
|
||||
void pybsleep_set_gpio_lpds_callback (mp_obj_t cb_obj) {
|
||||
pybsleep_data.gpio_lpds_wake_cb = cb_obj;
|
||||
}
|
||||
|
||||
void pybsleep_set_timer_lpds_callback (mp_obj_t cb_obj) {
|
||||
pybsleep_data.timer_lpds_wake_cb = cb_obj;
|
||||
void pybsleep_set_wlan_obj (mp_obj_t wlan_obj) {
|
||||
pybsleep_data.wlan_obj = (wlan_obj_t *)wlan_obj;
|
||||
}
|
||||
|
||||
void pybsleep_configure_timer_wakeup (uint pwrmode) {
|
||||
pybsleep_data.timer_wake_pwrmode = pwrmode;
|
||||
void pybsleep_set_rtc_obj (mp_obj_t rtc_obj) {
|
||||
pybsleep_data.rtc_obj = (pyb_rtc_obj_t *)rtc_obj;
|
||||
}
|
||||
|
||||
pybsleep_reset_cause_t pybsleep_get_reset_cause (void) {
|
||||
@ -410,7 +406,7 @@ void pybsleep_suspend_exit (void) {
|
||||
pybsleep_obj_wakeup();
|
||||
|
||||
// reconfigure all the previously enabled interrupts
|
||||
mpcallback_wake_all();
|
||||
mp_irq_wake_all();
|
||||
|
||||
// we need to init the crypto hash engine again
|
||||
CRYPTOHASH_Init();
|
||||
@ -425,25 +421,35 @@ void pybsleep_suspend_exit (void) {
|
||||
STATIC void PRCMInterruptHandler (void) {
|
||||
// reading the interrupt status automatically clears the interrupt
|
||||
if (PRCM_INT_SLOW_CLK_CTR == MAP_PRCMIntStatus()) {
|
||||
// this interrupt is triggered during active mode
|
||||
mpcallback_handler(pybsleep_data.timer_lpds_wake_cb);
|
||||
}
|
||||
else {
|
||||
// reconfigure it again (if repeat is true)
|
||||
pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj);
|
||||
pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0;
|
||||
// need to check if irq's are enabled from the user point of view
|
||||
if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_ACTIVE)) {
|
||||
mp_irq_handler(pybsleep_data.rtc_obj->irq_obj);
|
||||
}
|
||||
pybsleep_data.rtc_obj->irq_flags = 0;
|
||||
} else {
|
||||
// interrupt has been triggered while waking up from LPDS
|
||||
switch (MAP_PRCMLPDSWakeupCauseGet()) {
|
||||
case PRCM_LPDS_HOST_IRQ:
|
||||
mpcallback_handler(pybsleep_data.wlan_lpds_wake_cb);
|
||||
pybsleep_data.wlan_obj->irq_flags = MODWLAN_WIFI_EVENT_ANY;
|
||||
mp_irq_handler(pybsleep_data.wlan_obj->irq_obj);
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_WLAN;
|
||||
pybsleep_data.wlan_obj->irq_flags = 0;
|
||||
break;
|
||||
case PRCM_LPDS_GPIO:
|
||||
mpcallback_handler(pybsleep_data.gpio_lpds_wake_cb);
|
||||
mp_irq_handler(pybsleep_data.gpio_lpds_wake_cb);
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_GPIO;
|
||||
break;
|
||||
case PRCM_LPDS_TIMER:
|
||||
// disable the timer as wake-up source
|
||||
pybsleep_data.timer_wake_pwrmode &= ~PYB_PWR_MODE_LPDS;
|
||||
// reconfigure it again if repeat is true
|
||||
pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj);
|
||||
pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0;
|
||||
// next one clears the wake cause flag
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
|
||||
mpcallback_handler(pybsleep_data.timer_lpds_wake_cb);
|
||||
mp_irq_handler(pybsleep_data.rtc_obj->irq_obj);
|
||||
pybsleep_data.rtc_obj->irq_flags = 0;
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_RTC;
|
||||
break;
|
||||
default:
|
||||
@ -473,9 +479,9 @@ STATIC void pybsleep_iopark (bool hibernate) {
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
// enable a weak pull-down if the pin is unused
|
||||
// enable a weak pull-up if the pin is unused
|
||||
if (!pin->used) {
|
||||
MAP_PinConfigSet(pin->pin_num, pin->strength, PIN_TYPE_STD_PD);
|
||||
MAP_PinConfigSet(pin->pin_num, pin->strength, PIN_TYPE_STD_PU);
|
||||
}
|
||||
if (hibernate) {
|
||||
// make it an input
|
||||
@ -517,71 +523,70 @@ STATIC void pybsleep_iopark (bool hibernate) {
|
||||
}
|
||||
|
||||
STATIC bool setup_timer_lpds_wake (void) {
|
||||
uint64_t t_match, t_curr, t_remaining;
|
||||
uint64_t t_match, t_curr;
|
||||
int64_t t_remaining;
|
||||
|
||||
// get the time remaining for the RTC timer to expire
|
||||
t_match = MAP_PRCMSlowClkCtrMatchGet();
|
||||
t_curr = MAP_PRCMSlowClkCtrGet();
|
||||
|
||||
if (t_match > t_curr) {
|
||||
// get the time remaining in terms of slow clocks
|
||||
t_remaining = (t_match - t_curr);
|
||||
if (t_remaining > WAKEUP_TIME_LPDS) {
|
||||
// subtract the time it takes for wakeup from lpds
|
||||
t_remaining -= WAKEUP_TIME_LPDS;
|
||||
t_remaining = (t_remaining > 0xFFFFFFFF) ? 0xFFFFFFFF: t_remaining;
|
||||
// setup the LPDS wake time
|
||||
MAP_PRCMLPDSIntervalSet((uint32_t)t_remaining);
|
||||
// enable the wake source
|
||||
MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// setup a timer interrupt immediately
|
||||
MAP_PRCMRTCMatchSet(0, FORCED_TIMER_INTERRUPT_MS);
|
||||
// get the time remaining in terms of slow clocks
|
||||
t_remaining = (t_match - t_curr);
|
||||
if (t_remaining > WAKEUP_TIME_LPDS) {
|
||||
// subtract the time it takes to wakeup from lpds
|
||||
t_remaining -= WAKEUP_TIME_LPDS;
|
||||
t_remaining = (t_remaining > 0xFFFFFFFF) ? 0xFFFFFFFF: t_remaining;
|
||||
// setup the LPDS wake time
|
||||
MAP_PRCMLPDSIntervalSet((uint32_t)t_remaining);
|
||||
// enable the wake source
|
||||
MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER);
|
||||
return true;
|
||||
}
|
||||
|
||||
// disable the timer as wake source
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
|
||||
|
||||
// LPDS wake by timer was not possible, force
|
||||
// an interrupt in active mode instead
|
||||
uint32_t f_seconds;
|
||||
uint16_t f_mseconds;
|
||||
// setup a timer interrupt immediately
|
||||
pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds);
|
||||
MAP_PRCMRTCMatchSet(f_seconds, f_mseconds);
|
||||
// LPDS wake by timer was not possible, force an interrupt in active mode instead
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
STATIC bool setup_timer_hibernate_wake (void) {
|
||||
uint64_t t_match, t_curr, t_remaining;
|
||||
uint64_t t_match, t_curr;
|
||||
int64_t t_remaining;
|
||||
|
||||
// get the time remaining for the RTC timer to expire
|
||||
t_match = MAP_PRCMSlowClkCtrMatchGet();
|
||||
t_curr = MAP_PRCMSlowClkCtrGet();
|
||||
|
||||
if (t_match > t_curr) {
|
||||
// get the time remaining in terms of slow clocks
|
||||
t_remaining = (t_match - t_curr);
|
||||
if (t_remaining > WAKEUP_TIME_HIB) {
|
||||
// subtract the time it takes for wakeup from hibernate
|
||||
t_remaining -= WAKEUP_TIME_HIB;
|
||||
// setup the LPDS wake time
|
||||
MAP_PRCMHibernateIntervalSet((uint32_t)t_remaining);
|
||||
// enable the wake source
|
||||
MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// setup a timer interrupt immediately
|
||||
MAP_PRCMRTCMatchSet(0, FORCED_TIMER_INTERRUPT_MS);
|
||||
// get the time remaining in terms of slow clocks
|
||||
t_remaining = (t_match - t_curr);
|
||||
if (t_remaining > WAKEUP_TIME_HIB) {
|
||||
// subtract the time it takes for wakeup from hibernate
|
||||
t_remaining -= WAKEUP_TIME_HIB;
|
||||
// setup the LPDS wake time
|
||||
MAP_PRCMHibernateIntervalSet((uint32_t)t_remaining);
|
||||
// enable the wake source
|
||||
MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// disable the timer as wake source
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
|
||||
|
||||
// hibernate wake by timer was not possible, force
|
||||
// an interrupt in active mode instead
|
||||
uint32_t f_seconds;
|
||||
uint16_t f_mseconds;
|
||||
// setup a timer interrupt immediately
|
||||
pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds);
|
||||
MAP_PRCMRTCMatchSet(f_seconds, f_mseconds);
|
||||
// LPDS wake by timer was not possible, force an interrupt in active mode instead
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
|
||||
return false;
|
||||
@ -605,21 +610,22 @@ STATIC mp_obj_t pyb_sleep_suspend (mp_obj_t self_in) {
|
||||
nlr_buf_t nlr;
|
||||
|
||||
// check if we should enable timer wake-up
|
||||
if (pybsleep_data.timer_wake_pwrmode & PYB_PWR_MODE_LPDS) {
|
||||
if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_LPDS)) {
|
||||
if (!setup_timer_lpds_wake()) {
|
||||
// lpds entering is not possible, wait for the forced interrupt and return
|
||||
pybsleep_data.timer_wake_pwrmode &= ~PYB_PWR_MODE_LPDS;
|
||||
HAL_Delay (FAILED_SLEEP_DELAY_MS);
|
||||
return mp_const_none;
|
||||
}
|
||||
} else {
|
||||
// disable the timer as wake source
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
|
||||
}
|
||||
|
||||
// do we need network wake-up?
|
||||
if (pybsleep_data.wlan_lpds_wake_cb) {
|
||||
if (pybsleep_data.wlan_obj->irq_enabled) {
|
||||
MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ);
|
||||
server_sleep_sockets();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
MAP_PRCMLPDSWakeupSourceDisable (PRCM_LPDS_HOST_IRQ);
|
||||
}
|
||||
|
||||
@ -643,14 +649,17 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_suspend_obj, pyb_sleep_suspend);
|
||||
/// calling this method.
|
||||
STATIC mp_obj_t pyb_sleep_hibernate (mp_obj_t self_in) {
|
||||
// check if we should enable timer wake-up
|
||||
if (pybsleep_data.timer_wake_pwrmode & PYB_PWR_MODE_HIBERNATE) {
|
||||
if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_HIBERNATE)) {
|
||||
if (!setup_timer_hibernate_wake()) {
|
||||
// hibernating is not possible, wait for the forced interrupt and return
|
||||
pybsleep_data.timer_wake_pwrmode &= ~PYB_PWR_MODE_HIBERNATE;
|
||||
HAL_Delay (FAILED_SLEEP_DELAY_MS);
|
||||
return mp_const_none;
|
||||
}
|
||||
} else {
|
||||
// disable the timer as hibernate wake source
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
|
||||
}
|
||||
|
||||
wlan_stop(SL_STOP_TIMEOUT);
|
||||
pybsleep_flash_powerdown();
|
||||
// must be done just before entering hibernate mode
|
||||
|
@ -67,10 +67,9 @@ void pybsleep_init0 (void);
|
||||
void pybsleep_signal_soft_reset (void);
|
||||
void pybsleep_add (const mp_obj_t obj, WakeUpCB_t wakeup);
|
||||
void pybsleep_remove (const mp_obj_t obj);
|
||||
void pybsleep_set_wlan_lpds_callback (mp_obj_t cb_obj);
|
||||
void pybsleep_set_gpio_lpds_callback (mp_obj_t cb_obj);
|
||||
void pybsleep_set_timer_lpds_callback (mp_obj_t cb_obj);
|
||||
void pybsleep_configure_timer_wakeup (uint pwrmode);
|
||||
void pybsleep_set_wlan_obj (mp_obj_t wlan_obj);
|
||||
void pybsleep_set_rtc_obj (mp_obj_t rtc_obj);
|
||||
pybsleep_reset_cause_t pybsleep_get_reset_cause (void);
|
||||
|
||||
#endif /* PYBSLEEP_H_ */
|
||||
|
@ -44,8 +44,8 @@
|
||||
#include "prcm.h"
|
||||
#include "timer.h"
|
||||
#include "pybtimer.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpcallback.h"
|
||||
#include "mpexception.h"
|
||||
|
||||
|
||||
@ -96,7 +96,8 @@ typedef struct _pyb_timer_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint32_t timer;
|
||||
uint32_t config;
|
||||
uint16_t intflags;
|
||||
uint16_t irq_trigger;
|
||||
uint16_t irq_flags;
|
||||
uint8_t peripheral;
|
||||
uint8_t id;
|
||||
} pyb_timer_obj_t;
|
||||
@ -114,7 +115,7 @@ typedef struct _pyb_timer_channel_obj_t {
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_cb_methods_t pyb_timer_channel_cb_methods;
|
||||
STATIC const mp_irq_methods_t pyb_timer_channel_irq_methods;
|
||||
STATIC pyb_timer_obj_t pyb_timer_obj[PYBTIMER_NUM_TIMERS] = {{.timer = TIMERA0_BASE, .peripheral = PRCM_TIMERA0},
|
||||
{.timer = TIMERA1_BASE, .peripheral = PRCM_TIMERA1},
|
||||
{.timer = TIMERA2_BASE, .peripheral = PRCM_TIMERA2},
|
||||
@ -124,7 +125,7 @@ STATIC const mp_obj_type_t pyb_timer_channel_type;
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC mp_obj_t pyb_timer_channel_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
STATIC void timer_disable (pyb_timer_obj_t *tim);
|
||||
STATIC void TIMER0AIntHandler(void);
|
||||
STATIC void TIMER0BIntHandler(void);
|
||||
@ -142,18 +143,26 @@ void timer_init0 (void) {
|
||||
mp_obj_list_init(&MP_STATE_PORT(pyb_timer_channel_obj_list), 0);
|
||||
}
|
||||
|
||||
void pyb_timer_channel_callback_enable (mp_obj_t self_in) {
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void pyb_timer_channel_irq_enable (mp_obj_t self_in) {
|
||||
pyb_timer_channel_obj_t *self = self_in;
|
||||
MAP_TimerIntClear(self->timer->timer, self->timer->intflags & self->channel);
|
||||
MAP_TimerIntEnable(self->timer->timer, self->timer->intflags & self->channel);
|
||||
MAP_TimerIntClear(self->timer->timer, self->timer->irq_trigger & self->channel);
|
||||
MAP_TimerIntEnable(self->timer->timer, self->timer->irq_trigger & self->channel);
|
||||
}
|
||||
|
||||
void pyb_timer_channel_callback_disable (mp_obj_t self_in) {
|
||||
STATIC void pyb_timer_channel_irq_disable (mp_obj_t self_in) {
|
||||
pyb_timer_channel_obj_t *self = self_in;
|
||||
MAP_TimerIntDisable(self->timer->timer, self->timer->intflags & self->channel);
|
||||
MAP_TimerIntDisable(self->timer->timer, self->timer->irq_trigger & self->channel);
|
||||
}
|
||||
|
||||
pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channel_n) {
|
||||
STATIC int pyb_timer_channel_irq_flags (mp_obj_t self_in) {
|
||||
pyb_timer_channel_obj_t *self = self_in;
|
||||
return self->timer->irq_flags;
|
||||
}
|
||||
|
||||
STATIC pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channel_n) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_timer_channel_obj_list).len; i++) {
|
||||
pyb_timer_channel_obj_t *ch = ((pyb_timer_channel_obj_t *)(MP_STATE_PORT(pyb_timer_channel_obj_list).items[i]));
|
||||
// any 32-bit timer must be matched by any of its 16-bit versions
|
||||
@ -164,14 +173,14 @@ pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channe
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
void pyb_timer_channel_remove (pyb_timer_channel_obj_t *ch) {
|
||||
STATIC void pyb_timer_channel_remove (pyb_timer_channel_obj_t *ch) {
|
||||
pyb_timer_channel_obj_t *channel;
|
||||
if ((channel = pyb_timer_channel_find(ch->timer->timer, ch->channel))) {
|
||||
mp_obj_list_remove(&MP_STATE_PORT(pyb_timer_channel_obj_list), channel);
|
||||
}
|
||||
}
|
||||
|
||||
void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) {
|
||||
STATIC void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) {
|
||||
// remove it in case it already exists
|
||||
pyb_timer_channel_remove(ch);
|
||||
mp_obj_list_append(&MP_STATE_PORT(pyb_timer_channel_obj_list), ch);
|
||||
@ -180,8 +189,8 @@ void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) {
|
||||
STATIC void timer_disable (pyb_timer_obj_t *tim) {
|
||||
// disable all timers and it's interrupts
|
||||
MAP_TimerDisable(tim->timer, TIMER_A | TIMER_B);
|
||||
MAP_TimerIntDisable(tim->timer, tim->intflags);
|
||||
MAP_TimerIntClear(tim->timer, tim->intflags);
|
||||
MAP_TimerIntDisable(tim->timer, tim->irq_trigger);
|
||||
MAP_TimerIntClear(tim->timer, tim->irq_trigger);
|
||||
MAP_PRCMPeripheralClkDisable(tim->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
memset(&pyb_timer_obj[tim->id], 0, sizeof(pyb_timer_obj_t));
|
||||
}
|
||||
@ -509,10 +518,11 @@ const mp_obj_type_t pyb_timer_type = {
|
||||
.locals_dict = (mp_obj_t)&pyb_timer_locals_dict,
|
||||
};
|
||||
|
||||
STATIC const mp_cb_methods_t pyb_timer_channel_cb_methods = {
|
||||
.init = pyb_timer_channel_callback,
|
||||
.enable = pyb_timer_channel_callback_enable,
|
||||
.disable = pyb_timer_channel_callback_disable,
|
||||
STATIC const mp_irq_methods_t pyb_timer_channel_irq_methods = {
|
||||
.init = pyb_timer_channel_irq,
|
||||
.enable = pyb_timer_channel_irq_enable,
|
||||
.disable = pyb_timer_channel_irq_disable,
|
||||
.flags = pyb_timer_channel_irq_flags,
|
||||
};
|
||||
|
||||
STATIC void TIMERGenericIntHandler(uint32_t timer, uint16_t channel) {
|
||||
@ -522,8 +532,7 @@ STATIC void TIMERGenericIntHandler(uint32_t timer, uint16_t channel) {
|
||||
if ((self = pyb_timer_channel_find(timer, channel))) {
|
||||
status = MAP_TimerIntStatus(self->timer->timer, true) & self->channel;
|
||||
MAP_TimerIntClear(self->timer->timer, status);
|
||||
mp_obj_t _callback = mpcallback_find(self);
|
||||
mpcallback_handler(_callback);
|
||||
mp_irq_handler(mp_irq_find(self));
|
||||
}
|
||||
}
|
||||
|
||||
@ -716,130 +725,107 @@ STATIC mp_obj_t pyb_timer_channel_duty_cycle(mp_uint_t n_args, const mp_obj_t *a
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_duty_cycle_obj, 1, 3, pyb_timer_channel_duty_cycle);
|
||||
|
||||
/// \method callback(handler, priority, value)
|
||||
/// create a callback object associated with the timer channel
|
||||
STATIC mp_obj_t pyb_timer_channel_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);
|
||||
|
||||
/// \method irq(trigger, priority, handler, wake)
|
||||
/// FIXME triggers!!
|
||||
STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
pyb_timer_channel_obj_t *ch = pos_args[0];
|
||||
mp_obj_t _callback = mpcallback_find(ch);
|
||||
if (kw_args->used > 0) {
|
||||
// convert the priority to the correct value
|
||||
uint priority = mpcallback_translate_priority (args[2].u_int);
|
||||
|
||||
// validate the power mode
|
||||
uint pwrmode = args[4].u_int;
|
||||
if (pwrmode != PYB_PWR_MODE_ACTIVE) {
|
||||
goto invalid_args;
|
||||
}
|
||||
// convert the priority to the correct value
|
||||
uint priority = mp_irq_translate_priority (args[1].u_int);
|
||||
|
||||
uint32_t _config = (ch->channel == TIMER_B) ? ((ch->timer->config & TIMER_B) >> 8) : (ch->timer->config & TIMER_A);
|
||||
uint32_t c_value = mp_obj_get_int(args[3].u_obj);
|
||||
|
||||
// validate and set the value if we are in edge count mode
|
||||
if (_config == TIMER_CFG_A_CAP_COUNT) {
|
||||
if (!c_value || c_value > 0xFFFF) {
|
||||
// zero or exceeds the maximum value of a 16-bit timer
|
||||
goto invalid_args;
|
||||
}
|
||||
MAP_TimerMatchSet(ch->timer->timer, ch->channel, c_value);
|
||||
}
|
||||
|
||||
// disable the callback first
|
||||
pyb_timer_channel_callback_disable(ch);
|
||||
|
||||
uint8_t shift = (ch->channel == TIMER_B) ? 8 : 0;
|
||||
switch (_config) {
|
||||
case TIMER_CFG_A_ONE_SHOT:
|
||||
case TIMER_CFG_A_PERIODIC:
|
||||
ch->timer->intflags |= TIMER_TIMA_TIMEOUT << shift;
|
||||
break;
|
||||
case TIMER_CFG_A_CAP_COUNT:
|
||||
ch->timer->intflags |= TIMER_CAPA_MATCH << shift;
|
||||
// set the match value and make 1 the minimum
|
||||
MAP_TimerMatchSet(ch->timer->timer, ch->channel, MAX(1, c_value));
|
||||
break;
|
||||
case TIMER_CFG_A_CAP_TIME:
|
||||
ch->timer->intflags |= TIMER_CAPA_EVENT << shift;
|
||||
break;
|
||||
case TIMER_CFG_A_PWM:
|
||||
// special case for the PWM match interrupt
|
||||
ch->timer->intflags |= ((ch->channel & TIMER_A) == TIMER_A) ? TIMER_TIMA_MATCH : TIMER_TIMB_MATCH;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// special case for a 32-bit timer
|
||||
if (ch->channel == (TIMER_A | TIMER_B)) {
|
||||
ch->timer->intflags |= (ch->timer->intflags << 8);
|
||||
}
|
||||
|
||||
void (*pfnHandler)(void);
|
||||
uint32_t intregister;
|
||||
switch (ch->timer->timer) {
|
||||
case TIMERA0_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER0BIntHandler;
|
||||
intregister = INT_TIMERA0B;
|
||||
} else {
|
||||
pfnHandler = &TIMER0AIntHandler;
|
||||
intregister = INT_TIMERA0A;
|
||||
}
|
||||
break;
|
||||
case TIMERA1_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER1BIntHandler;
|
||||
intregister = INT_TIMERA1B;
|
||||
} else {
|
||||
pfnHandler = &TIMER1AIntHandler;
|
||||
intregister = INT_TIMERA1A;
|
||||
}
|
||||
break;
|
||||
case TIMERA2_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER2BIntHandler;
|
||||
intregister = INT_TIMERA2B;
|
||||
} else {
|
||||
pfnHandler = &TIMER2AIntHandler;
|
||||
intregister = INT_TIMERA2A;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER3BIntHandler;
|
||||
intregister = INT_TIMERA3B;
|
||||
} else {
|
||||
pfnHandler = &TIMER3AIntHandler;
|
||||
intregister = INT_TIMERA3A;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// register the interrupt and configure the priority
|
||||
MAP_IntPrioritySet(intregister, priority);
|
||||
MAP_TimerIntRegister(ch->timer->timer, ch->channel, pfnHandler);
|
||||
|
||||
// create the callback
|
||||
_callback = mpcallback_new (ch, args[1].u_obj, &pyb_timer_channel_cb_methods, true);
|
||||
|
||||
// reload the timer
|
||||
uint32_t period_c;
|
||||
uint32_t match;
|
||||
compute_prescaler_period_and_match_value(ch, &period_c, &match);
|
||||
MAP_TimerLoadSet(ch->timer->timer, ch->channel, period_c);
|
||||
|
||||
// enable the callback before returning
|
||||
pyb_timer_channel_callback_enable(ch);
|
||||
} else if (!_callback) {
|
||||
_callback = mpcallback_new (ch, mp_const_none, &pyb_timer_channel_cb_methods, false);
|
||||
// validate the power mode
|
||||
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
|
||||
if (pwrmode != PYB_PWR_MODE_ACTIVE) {
|
||||
goto invalid_args;
|
||||
}
|
||||
return _callback;
|
||||
|
||||
// disable the callback first
|
||||
pyb_timer_channel_irq_disable(ch);
|
||||
|
||||
uint8_t shift = (ch->channel == TIMER_B) ? 8 : 0;
|
||||
uint32_t _config = (ch->channel == TIMER_B) ? ((ch->timer->config & TIMER_B) >> 8) : (ch->timer->config & TIMER_A);
|
||||
switch (_config) {
|
||||
case TIMER_CFG_A_ONE_SHOT:
|
||||
case TIMER_CFG_A_PERIODIC:
|
||||
ch->timer->irq_trigger |= TIMER_TIMA_TIMEOUT << shift;
|
||||
break;
|
||||
case TIMER_CFG_A_CAP_COUNT:
|
||||
ch->timer->irq_trigger |= TIMER_CAPA_MATCH << shift;
|
||||
break;
|
||||
case TIMER_CFG_A_CAP_TIME:
|
||||
ch->timer->irq_trigger |= TIMER_CAPA_EVENT << shift;
|
||||
break;
|
||||
case TIMER_CFG_A_PWM:
|
||||
// special case for the PWM match interrupt
|
||||
ch->timer->irq_trigger |= ((ch->channel & TIMER_A) == TIMER_A) ? TIMER_TIMA_MATCH : TIMER_TIMB_MATCH;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// special case for a 32-bit timer
|
||||
if (ch->channel == (TIMER_A | TIMER_B)) {
|
||||
ch->timer->irq_trigger |= (ch->timer->irq_trigger << 8);
|
||||
}
|
||||
|
||||
void (*pfnHandler)(void);
|
||||
uint32_t intregister;
|
||||
switch (ch->timer->timer) {
|
||||
case TIMERA0_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER0BIntHandler;
|
||||
intregister = INT_TIMERA0B;
|
||||
} else {
|
||||
pfnHandler = &TIMER0AIntHandler;
|
||||
intregister = INT_TIMERA0A;
|
||||
}
|
||||
break;
|
||||
case TIMERA1_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER1BIntHandler;
|
||||
intregister = INT_TIMERA1B;
|
||||
} else {
|
||||
pfnHandler = &TIMER1AIntHandler;
|
||||
intregister = INT_TIMERA1A;
|
||||
}
|
||||
break;
|
||||
case TIMERA2_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER2BIntHandler;
|
||||
intregister = INT_TIMERA2B;
|
||||
} else {
|
||||
pfnHandler = &TIMER2AIntHandler;
|
||||
intregister = INT_TIMERA2A;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER3BIntHandler;
|
||||
intregister = INT_TIMERA3B;
|
||||
} else {
|
||||
pfnHandler = &TIMER3AIntHandler;
|
||||
intregister = INT_TIMERA3A;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// register the interrupt and configure the priority
|
||||
MAP_IntPrioritySet(intregister, priority);
|
||||
MAP_TimerIntRegister(ch->timer->timer, ch->channel, pfnHandler);
|
||||
|
||||
// create the callback
|
||||
mp_obj_t _irq = mp_irq_new (ch, args[2].u_obj, &pyb_timer_channel_irq_methods);
|
||||
|
||||
// enable the callback before returning
|
||||
pyb_timer_channel_irq_enable(ch);
|
||||
|
||||
return _irq;
|
||||
|
||||
invalid_args:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_callback_obj, 1, pyb_timer_channel_callback);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_irq_obj, 1, pyb_timer_channel_irq);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = {
|
||||
// instance methods
|
||||
@ -849,7 +835,7 @@ STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_event_count), (mp_obj_t)&pyb_timer_channel_event_count_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_event_time), (mp_obj_t)&pyb_timer_channel_event_time_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_duty_cycle), (mp_obj_t)&pyb_timer_channel_duty_cycle_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_timer_channel_callback_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_timer_channel_irq_obj },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_timer_channel_locals_dict, pyb_timer_channel_locals_dict_table);
|
||||
|
||||
|
@ -45,9 +45,9 @@
|
||||
#include "prcm.h"
|
||||
#include "uart.h"
|
||||
#include "pybuart.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybioctl.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpcallback.h"
|
||||
#include "mpexception.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "osi.h"
|
||||
@ -69,13 +69,13 @@
|
||||
#define PYBUART_TX_WAIT_US(baud) ((PYBUART_FRAME_TIME_US(baud)) + 1)
|
||||
#define PYBUART_TX_MAX_TIMEOUT_MS (5)
|
||||
|
||||
#define PYBUART_RX_BUFFER_LEN (128)
|
||||
#define PYBUART_RX_BUFFER_LEN (256)
|
||||
|
||||
// interrupt triggers
|
||||
#define E_UART_TRIGGER_RX_ANY (0x01)
|
||||
#define E_UART_TRIGGER_RX_HALF (0x02)
|
||||
#define E_UART_TRIGGER_RX_FULL (0x04)
|
||||
#define E_UART_TRIGGER_TX_DONE (0x08)
|
||||
#define UART_TRIGGER_RX_ANY (0x01)
|
||||
#define UART_TRIGGER_RX_HALF (0x02)
|
||||
#define UART_TRIGGER_RX_FULL (0x04)
|
||||
#define UART_TRIGGER_TX_DONE (0x08)
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
@ -83,12 +83,12 @@
|
||||
STATIC void uart_init (pyb_uart_obj_t *self);
|
||||
STATIC bool uart_rx_wait (pyb_uart_obj_t *self);
|
||||
STATIC void uart_check_init(pyb_uart_obj_t *self);
|
||||
STATIC mp_obj_t uart_irq_new (pyb_uart_obj_t *self, byte trigger, mp_int_t priority, mp_obj_t handler);
|
||||
STATIC void UARTGenericIntHandler(uint32_t uart_id);
|
||||
STATIC void UART0IntHandler(void);
|
||||
STATIC void UART1IntHandler(void);
|
||||
STATIC void uart_callback_enable (mp_obj_t self_in);
|
||||
STATIC void uart_callback_disable (mp_obj_t self_in);
|
||||
STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in);
|
||||
STATIC void uart_irq_enable (mp_obj_t self_in);
|
||||
STATIC void uart_irq_disable (mp_obj_t self_in);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE TYPES
|
||||
@ -105,7 +105,8 @@ struct _pyb_uart_obj_t {
|
||||
uint16_t read_buf_tail; // indexes first full slot (not full if equals head)
|
||||
byte peripheral;
|
||||
byte irq_trigger;
|
||||
bool callback_enabled;
|
||||
bool irq_enabled;
|
||||
byte irq_flags;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
@ -113,7 +114,7 @@ struct _pyb_uart_obj_t {
|
||||
******************************************************************************/
|
||||
STATIC pyb_uart_obj_t pyb_uart_obj[PYB_NUM_UARTS] = { {.reg = UARTA0_BASE, .baudrate = 0, .read_buf = NULL, .peripheral = PRCM_UARTA0},
|
||||
{.reg = UARTA1_BASE, .baudrate = 0, .read_buf = NULL, .peripheral = PRCM_UARTA1} };
|
||||
STATIC const mp_cb_methods_t uart_cb_methods;
|
||||
STATIC const mp_irq_methods_t uart_irq_methods;
|
||||
|
||||
STATIC const mp_obj_t pyb_uart_def_pin[PYB_NUM_UARTS][2] = { {&pin_GP1, &pin_GP2}, {&pin_GP3, &pin_GP4} };
|
||||
|
||||
@ -176,28 +177,6 @@ void uart_tx_strn_cooked(pyb_uart_obj_t *self, const char *str, uint len) {
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t uart_callback_new (pyb_uart_obj_t *self, mp_obj_t handler, mp_int_t priority, byte trigger) {
|
||||
// disable the uart interrupts before updating anything
|
||||
uart_callback_disable (self);
|
||||
|
||||
if (self->uart_id == PYB_UART_0) {
|
||||
MAP_IntPrioritySet(INT_UARTA0, priority);
|
||||
MAP_UARTIntRegister(self->reg, UART0IntHandler);
|
||||
} else {
|
||||
MAP_IntPrioritySet(INT_UARTA1, priority);
|
||||
MAP_UARTIntRegister(self->reg, UART1IntHandler);
|
||||
}
|
||||
|
||||
// create the callback
|
||||
mp_obj_t _callback = mpcallback_new ((mp_obj_t)self, handler, &uart_cb_methods, true);
|
||||
|
||||
// enable the interrupts now
|
||||
self->irq_trigger = trigger;
|
||||
uart_callback_enable (self);
|
||||
|
||||
return _callback;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
@ -248,15 +227,37 @@ STATIC bool uart_rx_wait (pyb_uart_obj_t *self) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uart_irq_new (pyb_uart_obj_t *self, byte trigger, mp_int_t priority, mp_obj_t handler) {
|
||||
// disable the uart interrupts before updating anything
|
||||
uart_irq_disable (self);
|
||||
|
||||
if (self->uart_id == PYB_UART_0) {
|
||||
MAP_IntPrioritySet(INT_UARTA0, priority);
|
||||
MAP_UARTIntRegister(self->reg, UART0IntHandler);
|
||||
} else {
|
||||
MAP_IntPrioritySet(INT_UARTA1, priority);
|
||||
MAP_UARTIntRegister(self->reg, UART1IntHandler);
|
||||
}
|
||||
|
||||
// create the callback
|
||||
mp_obj_t _irq = mp_irq_new ((mp_obj_t)self, handler, &uart_irq_methods);
|
||||
|
||||
// enable the interrupts now
|
||||
self->irq_trigger = trigger;
|
||||
uart_irq_enable (self);
|
||||
return _irq;
|
||||
}
|
||||
|
||||
STATIC void UARTGenericIntHandler(uint32_t uart_id) {
|
||||
pyb_uart_obj_t *self;
|
||||
uint32_t status;
|
||||
bool exec_callback = false;
|
||||
|
||||
self = &pyb_uart_obj[uart_id];
|
||||
status = MAP_UARTIntStatus(self->reg, true);
|
||||
// receive interrupt
|
||||
if (status & (UART_INT_RX | UART_INT_RT)) {
|
||||
// set the flags
|
||||
self->irq_flags = UART_TRIGGER_RX_ANY;
|
||||
MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
while (UARTCharsAvail(self->reg)) {
|
||||
int data = MAP_UARTCharGetNonBlocking(self->reg);
|
||||
@ -274,17 +275,16 @@ STATIC void UARTGenericIntHandler(uint32_t uart_id) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (self->irq_trigger & E_UART_TRIGGER_RX_ANY) {
|
||||
exec_callback = true;
|
||||
}
|
||||
|
||||
if (exec_callback && self->callback_enabled) {
|
||||
// call the user defined handler
|
||||
mp_obj_t _callback = mpcallback_find(self);
|
||||
mpcallback_handler(_callback);
|
||||
}
|
||||
}
|
||||
|
||||
// check the flags to see if the user handler should be called
|
||||
if ((self->irq_trigger & self->irq_flags) && self->irq_enabled) {
|
||||
// call the user defined handler
|
||||
mp_irq_handler(mp_irq_find(self));
|
||||
}
|
||||
|
||||
// clear the flags
|
||||
self->irq_flags = 0;
|
||||
}
|
||||
|
||||
STATIC void uart_check_init(pyb_uart_obj_t *self) {
|
||||
@ -302,19 +302,24 @@ STATIC void UART1IntHandler(void) {
|
||||
UARTGenericIntHandler(1);
|
||||
}
|
||||
|
||||
STATIC void uart_callback_enable (mp_obj_t self_in) {
|
||||
STATIC void uart_irq_enable (mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
// check for any of the rx interrupt types
|
||||
if (self->irq_trigger & (E_UART_TRIGGER_RX_ANY | E_UART_TRIGGER_RX_HALF | E_UART_TRIGGER_RX_FULL)) {
|
||||
if (self->irq_trigger & (UART_TRIGGER_RX_ANY | UART_TRIGGER_RX_HALF | UART_TRIGGER_RX_FULL)) {
|
||||
MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
MAP_UARTIntEnable(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
}
|
||||
self->callback_enabled = true;
|
||||
self->irq_enabled = true;
|
||||
}
|
||||
|
||||
STATIC void uart_callback_disable (mp_obj_t self_in) {
|
||||
STATIC void uart_irq_disable (mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
self->callback_enabled = false;
|
||||
self->irq_enabled = false;
|
||||
}
|
||||
|
||||
STATIC int uart_irq_flags (mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
return self->irq_flags;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@ -430,7 +435,9 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, const mp_arg_val_t *a
|
||||
// register it with the sleep module
|
||||
pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)uart_init);
|
||||
// enable the callback
|
||||
uart_callback_new (self, mp_const_none, INT_PRIORITY_LVL_3, E_UART_TRIGGER_RX_ANY);
|
||||
uart_irq_new (self, UART_TRIGGER_RX_ANY, INT_PRIORITY_LVL_3, mp_const_none);
|
||||
// disable the irq (from the user point of view)
|
||||
uart_irq_disable(self);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
@ -531,33 +538,37 @@ STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_sendbreak_obj, pyb_uart_sendbreak);
|
||||
|
||||
STATIC mp_obj_t pyb_uart_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);
|
||||
/// \method irq(trigger, priority, handler, wake)
|
||||
STATIC mp_obj_t pyb_uart_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
|
||||
// check if any parameters were passed
|
||||
pyb_uart_obj_t *self = pos_args[0];
|
||||
uart_check_init(self);
|
||||
mp_obj_t _callback = mpcallback_find((mp_obj_t)self);
|
||||
if (kw_args->used > 0) {
|
||||
|
||||
// convert the priority to the correct value
|
||||
uint priority = mpcallback_translate_priority (args[2].u_int);
|
||||
// convert the priority to the correct value
|
||||
uint priority = mp_irq_translate_priority (args[1].u_int);
|
||||
|
||||
// check the power mode
|
||||
if (PYB_PWR_MODE_ACTIVE != args[4].u_int) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
|
||||
// register a new callback
|
||||
// FIXME triggers!!
|
||||
return uart_callback_new (self, args[1].u_obj, mp_obj_get_int(args[3].u_obj), priority);
|
||||
} else if (!_callback) {
|
||||
_callback = mpcallback_new (self, mp_const_none, &uart_cb_methods, false);
|
||||
// check the power mode
|
||||
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
|
||||
if (PYB_PWR_MODE_ACTIVE != pwrmode) {
|
||||
goto invalid_args;
|
||||
}
|
||||
return _callback;
|
||||
|
||||
// check the trigger
|
||||
uint trigger = mp_obj_get_int(args[0].u_obj);
|
||||
if (!trigger || trigger > (UART_TRIGGER_RX_ANY | UART_TRIGGER_RX_HALF | UART_TRIGGER_RX_FULL | UART_TRIGGER_TX_DONE)) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// register a new callback
|
||||
return uart_irq_new (self, trigger, priority, args[2].u_obj);
|
||||
|
||||
invalid_args:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_callback_obj, 1, pyb_uart_callback);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_callback_obj, 1, pyb_uart_irq);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
|
||||
// instance methods
|
||||
@ -565,7 +576,7 @@ STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_uart_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&pyb_uart_any_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sendbreak), (mp_obj_t)&pyb_uart_sendbreak_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_uart_callback_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_uart_callback_obj },
|
||||
|
||||
/// \method read([nbytes])
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
|
||||
@ -581,7 +592,7 @@ STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_EVEN), MP_OBJ_NEW_SMALL_INT(UART_CONFIG_PAR_EVEN) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ODD), MP_OBJ_NEW_SMALL_INT(UART_CONFIG_PAR_ODD) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RX_ANY), MP_OBJ_NEW_SMALL_INT(E_UART_TRIGGER_RX_ANY) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RX_ANY), MP_OBJ_NEW_SMALL_INT(UART_TRIGGER_RX_ANY) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table);
|
||||
@ -654,10 +665,11 @@ STATIC const mp_stream_p_t uart_stream_p = {
|
||||
.is_text = false,
|
||||
};
|
||||
|
||||
STATIC const mp_cb_methods_t uart_cb_methods = {
|
||||
.init = pyb_uart_callback,
|
||||
.enable = uart_callback_enable,
|
||||
.disable = uart_callback_disable,
|
||||
STATIC const mp_irq_methods_t uart_irq_methods = {
|
||||
.init = pyb_uart_irq,
|
||||
.enable = uart_irq_enable,
|
||||
.disable = uart_irq_disable,
|
||||
.flags = uart_irq_flags
|
||||
};
|
||||
|
||||
const mp_obj_type_t pyb_uart_type = {
|
||||
|
@ -43,6 +43,5 @@ int uart_rx_char(pyb_uart_obj_t *uart_obj);
|
||||
bool uart_tx_char(pyb_uart_obj_t *self, int c);
|
||||
bool uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len);
|
||||
void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len);
|
||||
mp_obj_t uart_callback_new (pyb_uart_obj_t *self, mp_obj_t handler, mp_int_t priority, byte trigger);
|
||||
|
||||
#endif // PYBUART_H_
|
||||
|
@ -160,7 +160,7 @@ extern const struct _mp_obj_module_t mp_module_ussl;
|
||||
mp_obj_t mp_const_user_interrupt; \
|
||||
mp_obj_t pyb_config_main; \
|
||||
mp_obj_list_t pybsleep_obj_list; \
|
||||
mp_obj_list_t mpcallback_obj_list; \
|
||||
mp_obj_list_t mp_irq_obj_list; \
|
||||
mp_obj_list_t pyb_timer_channel_obj_list; \
|
||||
mp_obj_list_t mount_obj_list; \
|
||||
struct _pyb_uart_obj_t *pyb_uart_objs[2]; \
|
||||
|
@ -64,8 +64,8 @@
|
||||
#include "pins.h"
|
||||
#include "pybsleep.h"
|
||||
#include "pybtimer.h"
|
||||
#include "mpcallback.h"
|
||||
#include "cryptohash.h"
|
||||
#include "mpirq.h"
|
||||
#include "updater.h"
|
||||
#include "moduos.h"
|
||||
|
||||
@ -126,7 +126,7 @@ soft_reset:
|
||||
|
||||
// execute all basic initializations
|
||||
mpexception_init0();
|
||||
mpcallback_init0();
|
||||
mp_irq_init0();
|
||||
pybsleep_init0();
|
||||
pin_init0();
|
||||
mperror_init0();
|
||||
@ -234,7 +234,10 @@ soft_reset_exit:
|
||||
|
||||
// disable all callbacks to avoid undefined behaviour
|
||||
// when coming out of a soft reset
|
||||
mpcallback_disable_all();
|
||||
mp_irq_disable_all();
|
||||
|
||||
// cancel the RTC alarm which might be running independent of the irq state
|
||||
pyb_rtc_disable_alarm();
|
||||
|
||||
// flush the serial flash buffer
|
||||
sflash_disk_flush();
|
||||
|
@ -179,10 +179,12 @@ Q(RTC)
|
||||
Q(init)
|
||||
Q(alarm)
|
||||
Q(alarm_left)
|
||||
Q(alarm_cancel)
|
||||
Q(now)
|
||||
Q(deinit)
|
||||
Q(datetime)
|
||||
Q(repeat)
|
||||
Q(ALARM0)
|
||||
|
||||
// for time class
|
||||
Q(time)
|
||||
@ -292,6 +294,7 @@ Q(WPA)
|
||||
Q(WPA2)
|
||||
Q(INTERNAL)
|
||||
Q(EXTERNAL)
|
||||
Q(ANY_EVENT)
|
||||
|
||||
// for WDT class
|
||||
Q(WDT)
|
||||
@ -303,16 +306,16 @@ Q(HeartBeat)
|
||||
Q(enable)
|
||||
Q(disable)
|
||||
|
||||
// for callback class
|
||||
// for irq class
|
||||
Q(irq)
|
||||
Q(init)
|
||||
Q(enable)
|
||||
Q(disable)
|
||||
Q(callback)
|
||||
Q(flags)
|
||||
Q(trigger)
|
||||
Q(handler)
|
||||
Q(mode)
|
||||
Q(value)
|
||||
Q(priority)
|
||||
Q(wake_from)
|
||||
Q(wake)
|
||||
|
||||
// for Sleep class
|
||||
Q(Sleep)
|
||||
|
@ -32,14 +32,13 @@
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "pybrtc.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modwlan.h"
|
||||
#include "random.h"
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* LOCAL TYPES
|
||||
******************************************************************************/
|
||||
@ -57,16 +56,19 @@ static uint32_t s_seed;
|
||||
/******************************************************************************
|
||||
* LOCAL FUNCTION DECLARATIONS
|
||||
******************************************************************************/
|
||||
static uint32_t lfsr (uint32_t input);
|
||||
STATIC uint32_t lfsr (uint32_t input);
|
||||
|
||||
/******************************************************************************
|
||||
* PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
static uint32_t lfsr (uint32_t input) {
|
||||
STATIC uint32_t lfsr (uint32_t input) {
|
||||
assert( input != 0 );
|
||||
return (input >> 1) ^ (-(input & 0x01) & 0x00E10000);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings;
|
||||
|
||||
STATIC mp_obj_t pyb_rng_get(void) {
|
||||
return mp_obj_new_int(rng_get());
|
||||
}
|
||||
@ -81,7 +83,7 @@ void rng_init0 (void) {
|
||||
uint16_t mseconds;
|
||||
|
||||
// get the seconds and the milliseconds from the RTC
|
||||
MAP_PRCMRTCGet(&seconds, &mseconds);
|
||||
pyb_rtc_get_time(&seconds, &mseconds);
|
||||
|
||||
wlan_get_mac (juggler.id8);
|
||||
|
||||
|
116
tests/wipy/pin_irq.py
Normal file
116
tests/wipy/pin_irq.py
Normal file
@ -0,0 +1,116 @@
|
||||
'''
|
||||
Pin IRQ test for the CC3200 based boards.
|
||||
'''
|
||||
|
||||
from pyb import Pin
|
||||
from pyb import Sleep
|
||||
import os
|
||||
import time
|
||||
|
||||
machine = os.uname().machine
|
||||
if 'LaunchPad' in machine:
|
||||
pins = ['GP16', 'GP13']
|
||||
elif 'WiPy' in machine:
|
||||
pins = ['GP16', 'GP13']
|
||||
else:
|
||||
raise Exception('Board not supported!')
|
||||
|
||||
pin0 = Pin(pins[0], mode=Pin.OUT, value=1)
|
||||
pin1 = Pin(pins[1], mode=Pin.IN, pull=Pin.PULL_UP)
|
||||
|
||||
def pin_handler (pin_o):
|
||||
global pin_irq_count_trigger
|
||||
global pin_irq_count_total
|
||||
global _trigger
|
||||
if _trigger & pin1_irq.flags():
|
||||
pin_irq_count_trigger += 1
|
||||
pin_irq_count_total += 1
|
||||
|
||||
pin_irq_count_trigger = 0
|
||||
pin_irq_count_total = 0
|
||||
_trigger = Pin.IRQ_FALLING
|
||||
pin1_irq = pin1.irq(trigger=_trigger, handler=pin_handler)
|
||||
for i in range (0, 10):
|
||||
pin0.toggle()
|
||||
time.sleep_ms(5)
|
||||
print(pin_irq_count_trigger == 5)
|
||||
print(pin_irq_count_total == 5)
|
||||
|
||||
pin_irq_count_trigger = 0
|
||||
pin_irq_count_total = 0
|
||||
_trigger = Pin.IRQ_RISING
|
||||
pin1_irq = pin1.irq(trigger=_trigger, handler=pin_handler)
|
||||
for i in range (0, 200):
|
||||
pin0.toggle()
|
||||
time.sleep_ms(5)
|
||||
print(pin_irq_count_trigger == 100)
|
||||
print(pin_irq_count_total == 100)
|
||||
|
||||
pin1_irq.disable()
|
||||
pin0(1)
|
||||
pin_irq_count_trigger = 0
|
||||
pin_irq_count_total = 0
|
||||
_trigger = Pin.IRQ_FALLING
|
||||
pin1_irq.init(trigger=_trigger, handler=pin_handler)
|
||||
pin0(0)
|
||||
time.sleep_us(50)
|
||||
print(pin_irq_count_trigger == 1)
|
||||
print(pin_irq_count_total == 1)
|
||||
pin0(1)
|
||||
time.sleep_us(50)
|
||||
print(pin_irq_count_trigger == 1)
|
||||
print(pin_irq_count_total == 1)
|
||||
|
||||
# check the call method
|
||||
pin1_irq()
|
||||
print(pin_irq_count_trigger == 1) # no flags since the irq was manually triggered
|
||||
print(pin_irq_count_total == 2)
|
||||
|
||||
pin1_irq.disable()
|
||||
pin_irq_count_trigger = 0
|
||||
pin_irq_count_total = 0
|
||||
for i in range (0, 10):
|
||||
pin0.toggle()
|
||||
time.sleep_ms(5)
|
||||
print(pin_irq_count_trigger == 0)
|
||||
print(pin_irq_count_total == 0)
|
||||
|
||||
# test waking up from suspended mode on low level
|
||||
pin0(0)
|
||||
t0 = time.ticks_ms()
|
||||
pin1_irq.init(trigger=Pin.IRQ_LOW_LEVEL, wake=Sleep.SUSPENDED)
|
||||
Sleep.suspend()
|
||||
print(time.ticks_ms() - t0 < 10)
|
||||
print('Awake')
|
||||
|
||||
# test waking up from suspended mode on high level
|
||||
pin0(1)
|
||||
t0 = time.ticks_ms()
|
||||
pin1_irq.init(trigger=Pin.IRQ_HIGH_LEVEL, wake=Sleep.SUSPENDED)
|
||||
Sleep.suspend()
|
||||
print(time.ticks_ms() - t0 < 10)
|
||||
print('Awake')
|
||||
|
||||
# check for memory leaks
|
||||
for i in range(0, 1000):
|
||||
pin0_irq = pin0.irq(trigger=_trigger, handler=pin_handler)
|
||||
pin1_irq = pin1.irq(trigger=_trigger, handler=pin_handler)
|
||||
|
||||
# next ones must raise
|
||||
try:
|
||||
pin1_irq.init(trigger=123456, handler=pin_handler)
|
||||
except:
|
||||
print('Exception')
|
||||
|
||||
try:
|
||||
pin1_irq.init(trigger=Pin.IRQ_LOW_LEVEL, wake=1789456)
|
||||
except:
|
||||
print('Exception')
|
||||
|
||||
try:
|
||||
pin0_irq = pin0.irq(trigger=Pin.IRQ_RISING, wake=Sleep.SUSPENDED) # GP16 can't wake up from DEEPSLEEP
|
||||
except:
|
||||
print('Exception')
|
||||
|
||||
pin0_irq.disable()
|
||||
pin1_irq.disable()
|
19
tests/wipy/pin_irq.py.exp
Normal file
19
tests/wipy/pin_irq.py.exp
Normal file
@ -0,0 +1,19 @@
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
Awake
|
||||
True
|
||||
Awake
|
||||
Exception
|
||||
Exception
|
||||
Exception
|
@ -66,17 +66,22 @@ rtc.alarm(0, 5000)
|
||||
rtc.alarm(time=2000)
|
||||
time.sleep_ms(1000)
|
||||
left = rtc.alarm_left()
|
||||
print(abs(left-1000) < 20)
|
||||
print(abs(left-1000) <= 10)
|
||||
time.sleep_ms(1000)
|
||||
print(rtc.alarm_left() == 0)
|
||||
time.sleep_ms(100)
|
||||
print(rtc.alarm_left() == 0)
|
||||
print(rtc.alarm_left(0) == 0)
|
||||
|
||||
rtc.alarm(time=1000, repeat=True)
|
||||
time.sleep_ms(1500)
|
||||
left = rtc.alarm_left()
|
||||
print(abs(left-500) <= 15)
|
||||
|
||||
rtc.init((2015, 8, 29, 9, 0, 0, 0, None))
|
||||
rtc.alarm(time=(2015, 8, 29, 9, 0, 45))
|
||||
time.sleep_ms(1000)
|
||||
left = rtc.alarm_left()
|
||||
print(abs(left-44000) < 100)
|
||||
print(abs(left-44000) <= 90)
|
||||
|
||||
# next ones must raise
|
||||
try:
|
||||
@ -84,6 +89,16 @@ try:
|
||||
except:
|
||||
print('Exception')
|
||||
|
||||
try:
|
||||
rtc.alarm_left(1)
|
||||
except:
|
||||
print('Exception')
|
||||
|
||||
try:
|
||||
rtc.alarm_cancel(1)
|
||||
except:
|
||||
print('Exception')
|
||||
|
||||
try:
|
||||
rtc.alarm(5000)
|
||||
except:
|
||||
|
@ -28,6 +28,9 @@ True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
Exception
|
||||
Exception
|
||||
Exception
|
||||
Exception
|
||||
Exception
|
||||
|
89
tests/wipy/rtc_irq.py
Normal file
89
tests/wipy/rtc_irq.py
Normal file
@ -0,0 +1,89 @@
|
||||
'''
|
||||
RTC IRQ test for the CC3200 based boards.
|
||||
'''
|
||||
|
||||
from pyb import RTC
|
||||
from pyb import Sleep
|
||||
import os
|
||||
import time
|
||||
|
||||
machine = os.uname().machine
|
||||
if not 'LaunchPad' in machine and not 'WiPy' in machine:
|
||||
raise Exception('Board not supported!')
|
||||
|
||||
def rtc_ticks_ms(rtc):
|
||||
timedate = rtc.now()
|
||||
return (timedate[5] * 1000) + (timedate[6] // 1000)
|
||||
|
||||
rtc_irq_count = 0
|
||||
|
||||
def alarm_handler (rtc_o):
|
||||
global rtc_irq
|
||||
global rtc_irq_count
|
||||
if rtc_irq.flags() & RTC.ALARM0:
|
||||
rtc_irq_count += 1
|
||||
|
||||
rtc = RTC()
|
||||
rtc.alarm(time=500, repeat=True)
|
||||
rtc_irq = rtc.irq(trigger=RTC.ALARM0, handler=alarm_handler)
|
||||
|
||||
# active mode
|
||||
time.sleep_ms(1000)
|
||||
rtc.alarm_cancel()
|
||||
print(rtc_irq_count == 2)
|
||||
rtc_irq_count = 0
|
||||
rtc.alarm(time=200, repeat=True)
|
||||
time.sleep_ms(1000)
|
||||
rtc.alarm_cancel()
|
||||
print(rtc_irq_count == 5)
|
||||
|
||||
rtc_irq_count = 0
|
||||
rtc.alarm(time=100, repeat=True)
|
||||
time.sleep_ms(1000)
|
||||
rtc.alarm_cancel()
|
||||
print(rtc_irq_count == 10)
|
||||
|
||||
# deep sleep mode
|
||||
rtc.alarm_cancel()
|
||||
rtc_irq_count = 0
|
||||
rtc.alarm(time=50, repeat=True)
|
||||
rtc_irq.init(trigger=RTC.ALARM0, handler=alarm_handler, wake=Sleep.SUSPENDED | Sleep.ACTIVE)
|
||||
while rtc_irq_count < 3:
|
||||
Sleep.suspend()
|
||||
print(rtc_irq_count == 3)
|
||||
|
||||
# no repetition
|
||||
rtc.alarm_cancel()
|
||||
rtc_irq_count = 0
|
||||
rtc.alarm(time=100, repeat=False)
|
||||
time.sleep_ms(250)
|
||||
print(rtc_irq_count == 1)
|
||||
|
||||
rtc.alarm_cancel()
|
||||
t0 = rtc_ticks_ms(rtc)
|
||||
rtc.alarm(time=500, repeat=False)
|
||||
Sleep.suspend()
|
||||
t1 = rtc_ticks_ms(rtc)
|
||||
print(abs(t1 - t0 - 500) < 20)
|
||||
|
||||
# deep sleep repeated mode
|
||||
rtc.alarm_cancel()
|
||||
rtc_irq_count = 0
|
||||
rtc.alarm(time=250, repeat=True)
|
||||
t0 = rtc_ticks_ms(rtc)
|
||||
rtc_irq = rtc.irq(trigger=RTC.ALARM0, handler=alarm_handler, wake=Sleep.SUSPENDED)
|
||||
while rtc_irq_count < 10:
|
||||
Sleep.suspend()
|
||||
t1 = rtc_ticks_ms(rtc)
|
||||
print(abs(t1 - t0 - (250 * rtc_irq_count)) < 25)
|
||||
|
||||
# next ones must raise
|
||||
try:
|
||||
rtc_irq = rtc.irq(trigger=10, handler=alarm_handler)
|
||||
except:
|
||||
print('Exception')
|
||||
|
||||
try:
|
||||
rtc_irq = rtc.irq(trigger=RTC.ALARM0, wake=1789456)
|
||||
except:
|
||||
print('Exception')
|
18
tests/wipy/rtc_irq.py.exp
Normal file
18
tests/wipy/rtc_irq.py.exp
Normal file
@ -0,0 +1,18 @@
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
Exception
|
||||
Exception
|
149
tests/wipy/uart_irq.py
Normal file
149
tests/wipy/uart_irq.py
Normal file
@ -0,0 +1,149 @@
|
||||
'''
|
||||
UART IRQ test for the CC3200 based boards.
|
||||
'''
|
||||
|
||||
from pyb import UART
|
||||
import os
|
||||
import pyb
|
||||
import time
|
||||
|
||||
machine = os.uname().machine
|
||||
if 'LaunchPad' in machine:
|
||||
uart_pins = [[('GP12', 'GP13'), ('GP12', 'GP13', 'GP7', 'GP6')], [('GP16', 'GP17'), ('GP16', 'GP17', 'GP7', 'GP6')]]
|
||||
elif 'WiPy' in machine:
|
||||
uart_pins = [[('GP12', 'GP13'), ('GP12', 'GP13', 'GP7', 'GP6')], [('GP16', 'GP17'), ('GP16', 'GP17', 'GP7', 'GP6')]]
|
||||
else:
|
||||
raise Exception('Board not supported!')
|
||||
|
||||
# just in case we have stdio duplicated on any of the uarts
|
||||
pyb.repl_uart(None)
|
||||
|
||||
uart0 = UART(0, 1000000, pins=uart_pins[0][0])
|
||||
uart1 = UART(1, 1000000, pins=uart_pins[1][0])
|
||||
|
||||
uart0_int_count = 0
|
||||
uart1_int_count = 0
|
||||
|
||||
def uart0_handler (uart_o):
|
||||
global uart0_irq
|
||||
global uart0_int_count
|
||||
if (uart0_irq.flags() & UART.RX_ANY):
|
||||
uart0_int_count += 1
|
||||
|
||||
def uart1_handler (uart_o):
|
||||
global uart1_irq
|
||||
global uart1_int_count
|
||||
if (uart1_irq.flags() & UART.RX_ANY):
|
||||
uart1_int_count += 1
|
||||
|
||||
uart0_irq = uart0.irq(trigger=UART.RX_ANY, handler=uart0_handler)
|
||||
uart1_irq = uart1.irq(trigger=UART.RX_ANY, handler=uart1_handler)
|
||||
|
||||
uart0.write(b'123')
|
||||
# wait for the characters to be received
|
||||
while not uart1.any():
|
||||
pass
|
||||
|
||||
time.sleep_us(100)
|
||||
print(uart1.any() == 3)
|
||||
print(uart1_int_count > 0)
|
||||
print(uart1_irq.flags() == 0)
|
||||
print(uart0_irq.flags() == 0)
|
||||
print(uart1.read() == b'123')
|
||||
|
||||
uart1.write(b'12345')
|
||||
# wait for the characters to be received
|
||||
while not uart0.any():
|
||||
pass
|
||||
|
||||
time.sleep_us(100)
|
||||
print(uart0.any() == 5)
|
||||
print(uart0_int_count > 0)
|
||||
print(uart0_irq.flags() == 0)
|
||||
print(uart1_irq.flags() == 0)
|
||||
print(uart0.read() == b'12345')
|
||||
|
||||
# do it again
|
||||
uart1_int_count = 0
|
||||
uart0.write(b'123')
|
||||
# wait for the characters to be received
|
||||
while not uart1.any():
|
||||
pass
|
||||
|
||||
time.sleep_us(100)
|
||||
print(uart1.any() == 3)
|
||||
print(uart1_int_count > 0)
|
||||
print(uart1_irq.flags() == 0)
|
||||
print(uart0_irq.flags() == 0)
|
||||
print(uart1.read() == b'123')
|
||||
|
||||
# disable the interrupt
|
||||
uart1_irq.disable()
|
||||
# do it again
|
||||
uart1_int_count = 0
|
||||
uart0.write(b'123')
|
||||
# wait for the characters to be received
|
||||
while not uart1.any():
|
||||
pass
|
||||
|
||||
time.sleep_us(100)
|
||||
print(uart1.any() == 3)
|
||||
print(uart1_int_count == 0) # no interrupt triggered this time
|
||||
print(uart1_irq.flags() == 0)
|
||||
print(uart0_irq.flags() == 0)
|
||||
print(uart1.read() == b'123')
|
||||
|
||||
# enable the interrupt
|
||||
uart1_irq.enable()
|
||||
# do it again
|
||||
uart1_int_count = 0
|
||||
uart0.write(b'123')
|
||||
# wait for the characters to be received
|
||||
while not uart1.any():
|
||||
pass
|
||||
|
||||
time.sleep_us(100)
|
||||
print(uart1.any() == 3)
|
||||
print(uart1_int_count > 0)
|
||||
print(uart1_irq.flags() == 0)
|
||||
print(uart0_irq.flags() == 0)
|
||||
print(uart1.read() == b'123')
|
||||
|
||||
uart1_irq.init(trigger=UART.RX_ANY, handler=None) # No handler
|
||||
# do it again
|
||||
uart1_int_count = 0
|
||||
uart0.write(b'123')
|
||||
# wait for the characters to be received
|
||||
while not uart1.any():
|
||||
pass
|
||||
|
||||
time.sleep_us(100)
|
||||
print(uart1.any() == 3)
|
||||
print(uart1_int_count == 0) # no interrupt handler called
|
||||
print(uart1_irq.flags() == 0)
|
||||
print(uart0_irq.flags() == 0)
|
||||
print(uart1.read() == b'123')
|
||||
|
||||
# check for memory leaks
|
||||
for i in range(0, 1000):
|
||||
uart0_irq = uart0.irq(trigger=UART.RX_ANY, handler=uart0_handler)
|
||||
uart1_irq = uart1.irq(trigger=UART.RX_ANY, handler=uart1_handler)
|
||||
|
||||
# next ones must raise
|
||||
try:
|
||||
uart0_irq = uart0.irq(trigger=100, handler=uart0_handler)
|
||||
except:
|
||||
print('Exception')
|
||||
|
||||
try:
|
||||
uart0_irq = uart0.irq(trigger=0)
|
||||
except:
|
||||
print('Exception')
|
||||
|
||||
try:
|
||||
uart0_irq = uart0.irq(trigger=UART.RX_ANY, wake=Sleep.SUSPENDED)
|
||||
except:
|
||||
print('Exception')
|
||||
|
||||
uart0_irq.disable()
|
||||
uart1_irq.disable()
|
33
tests/wipy/uart_irq.py.exp
Normal file
33
tests/wipy/uart_irq.py.exp
Normal file
@ -0,0 +1,33 @@
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
True
|
||||
Exception
|
||||
Exception
|
||||
Exception
|
Loading…
x
Reference in New Issue
Block a user