From 8e611e841476d98eb829978a7e73ce92ff822ca8 Mon Sep 17 00:00:00 2001 From: Daniel Campora Date: Sat, 9 May 2015 17:46:16 +0200 Subject: [PATCH] cc3200: Add Timer module. Supports free running, PWM and capture modes. --- cc3200/application.lds | 1 - cc3200/application.mk | 2 + cc3200/misc/mpcallback.c | 1 - cc3200/mods/modnetwork.c | 6 +- cc3200/mods/modpyb.c | 2 + cc3200/mods/modwlan.c | 1 + cc3200/mods/pybpin.c | 1 + cc3200/mods/pybrtc.c | 24 +- cc3200/mods/pybrtc.h | 1 + cc3200/mods/pybtimer.c | 834 +++++++++++++++++++++++++++++++++++++++ cc3200/mods/pybtimer.h | 38 ++ cc3200/mods/pybuart.c | 24 +- cc3200/mods/pybuart.h | 2 +- cc3200/mpconfigport.h | 1 + cc3200/mptask.c | 12 +- cc3200/qstrdefsport.h | 27 +- 16 files changed, 946 insertions(+), 31 deletions(-) create mode 100644 cc3200/mods/pybtimer.c create mode 100644 cc3200/mods/pybtimer.h diff --git a/cc3200/application.lds b/cc3200/application.lds index 4ffcd03c35..22ad1968d5 100644 --- a/cc3200/application.lds +++ b/cc3200/application.lds @@ -26,7 +26,6 @@ __stack_size__ = 2K; /* interrupts are handled within this stack */ __min_heap_size__ = 8K; -__rtos_heap_size = 16K; MEMORY { diff --git a/cc3200/application.mk b/cc3200/application.mk index 29be228bd1..6ae8b51ab1 100644 --- a/cc3200/application.mk +++ b/cc3200/application.mk @@ -98,6 +98,7 @@ APP_MODS_SRC_C = $(addprefix mods/,\ pybsd.c \ pybsleep.c \ pybspi.c \ + pybtimer.c \ pybuart.c \ pybwdt.c \ ) @@ -192,6 +193,7 @@ $(BUILD)/FreeRTOS/Source/%.o: CFLAGS += -Os $(BUILD)/ftp/%.o: CFLAGS += -Os $(BUILD)/hal/%.o: CFLAGS += -Os $(BUILD)/misc/%.o: CFLAGS += -Os +$(BUILD)/mods/%.o: CFLAGS += -Os $(BUILD)/py/%.o: CFLAGS += -Os $(BUILD)/simplelink/%.o: CFLAGS += -Os $(BUILD)/drivers/cc3100/%.o: CFLAGS += -Os diff --git a/cc3200/misc/mpcallback.c b/cc3200/misc/mpcallback.c index 87969f7276..6ca4f49d20 100644 --- a/cc3200/misc/mpcallback.c +++ b/cc3200/misc/mpcallback.c @@ -71,7 +71,6 @@ mp_obj_t mpcallback_new (mp_obj_t parent, mp_obj_t handler, const mp_cb_methods_ mpcallback_obj_t *mpcallback_find (mp_obj_t parent) { for (mp_uint_t i = 0; i < MP_STATE_PORT(mpcallback_obj_list).len; i++) { - // search for the object and then remove it mpcallback_obj_t *callback_obj = ((mpcallback_obj_t *)(MP_STATE_PORT(mpcallback_obj_list).items[i])); if (callback_obj->parent == parent) { return callback_obj; diff --git a/cc3200/mods/modnetwork.c b/cc3200/mods/modnetwork.c index f9536ccb5e..f7dfd139f8 100644 --- a/cc3200/mods/modnetwork.c +++ b/cc3200/mods/modnetwork.c @@ -80,10 +80,10 @@ STATIC mp_obj_t network_server_stop(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(network_server_stop_obj, network_server_stop); -STATIC mp_obj_t network_server_enabled(void) { +STATIC mp_obj_t network_server_running(void) { return MP_BOOL(servers_are_enabled()); } -STATIC MP_DEFINE_CONST_FUN_OBJ_0(network_server_enabled_obj, network_server_enabled); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(network_server_running_obj, network_server_running); STATIC mp_obj_t network_server_login(mp_obj_t user, mp_obj_t pass) { const char *_user = mp_obj_str_get_str(user); @@ -102,7 +102,7 @@ STATIC const mp_map_elem_t mp_module_network_globals_table[] = { #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) { MP_OBJ_NEW_QSTR(MP_QSTR_start_server), (mp_obj_t)&network_server_start_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_stop_server), (mp_obj_t)&network_server_stop_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_server_enabled), (mp_obj_t)&network_server_enabled_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_server_running), (mp_obj_t)&network_server_running_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_server_login), (mp_obj_t)&network_server_login_obj }, #endif }; diff --git a/cc3200/mods/modpyb.c b/cc3200/mods/modpyb.c index a261c8b0d8..5dc9a35c23 100644 --- a/cc3200/mods/modpyb.c +++ b/cc3200/mods/modpyb.c @@ -62,6 +62,7 @@ #include "pybwdt.h" #include "pybsleep.h" #include "pybspi.h" +#include "pybtimer.h" #include "utils.h" #include "gccollect.h" #include "mperror.h" @@ -271,6 +272,7 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_I2C), (mp_obj_t)&pyb_i2c_type }, { MP_OBJ_NEW_QSTR(MP_QSTR_SPI), (mp_obj_t)&pyb_spi_type }, { MP_OBJ_NEW_QSTR(MP_QSTR_UART), (mp_obj_t)&pyb_uart_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_Timer), (mp_obj_t)&pyb_timer_type }, { MP_OBJ_NEW_QSTR(MP_QSTR_WDT), (mp_obj_t)&pyb_wdt_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_Sleep), (mp_obj_t)&pyb_sleep_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_HeartBeat), (mp_obj_t)&pyb_heartbeat_obj }, diff --git a/cc3200/mods/modwlan.c b/cc3200/mods/modwlan.c index e2fbdf5031..c00145ec3e 100644 --- a/cc3200/mods/modwlan.c +++ b/cc3200/mods/modwlan.c @@ -787,6 +787,7 @@ STATIC mp_obj_t wlan_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ // connect to the requested access point modwlan_Status_t status; status = wlan_do_connect (ssid, ssid_len, bssid, sec, key, key_len); + // TODO: make the timeout a parameter so that is configurable if (status == MODWLAN_ERROR_TIMEOUT) { nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); } diff --git a/cc3200/mods/pybpin.c b/cc3200/mods/pybpin.c index e1e7e4871b..c9454de337 100644 --- a/cc3200/mods/pybpin.c +++ b/cc3200/mods/pybpin.c @@ -755,6 +755,7 @@ STATIC void EXTI_Handler(uint port) { uint32_t bit = MAP_GPIOIntStatus(port, true); MAP_GPIOIntClear(port, bit); + // TODO: loop through all the active bits before exiting pin_obj_t *self = (pin_obj_t *)pin_find_pin_by_port_bit(&pin_cpu_pins_locals_dict, port, bit); mp_obj_t _callback = mpcallback_find(self); mpcallback_handler(_callback); diff --git a/cc3200/mods/pybrtc.c b/cc3200/mods/pybrtc.c index a9cc995d57..603f9930c8 100644 --- a/cc3200/mods/pybrtc.c +++ b/cc3200/mods/pybrtc.c @@ -92,6 +92,18 @@ void pybrtc_init(void) { } } +void pyb_rtc_callback_disable (mp_obj_t self_in) { + // check the wake from param + if (pybrtc_data.prwmode & PYB_PWR_MODE_ACTIVE) { + // disable the slow clock interrupt + 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(); +} + /****************************************************************************** DECLARE PRIVATE FUNCTIONS ******************************************************************************/ @@ -108,18 +120,6 @@ STATIC void pyb_rtc_callback_enable (mp_obj_t self_in) { pybsleep_configure_timer_wakeup (pybrtc_data.prwmode); } -STATIC void pyb_rtc_callback_disable (mp_obj_t self_in) { - // check the wake from param - if (pybrtc_data.prwmode & PYB_PWR_MODE_ACTIVE) { - // disable the slow clock interrupt - 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(); -} - /******************************************************************************/ // Micro Python bindings diff --git a/cc3200/mods/pybrtc.h b/cc3200/mods/pybrtc.h index a41cff772e..0c7a6f859a 100644 --- a/cc3200/mods/pybrtc.h +++ b/cc3200/mods/pybrtc.h @@ -34,5 +34,6 @@ extern const mp_obj_base_t pyb_rtc_obj; void pybrtc_init(void); +void pyb_rtc_callback_disable (mp_obj_t self_in); #endif // PYBRTC_H_ diff --git a/cc3200/mods/pybtimer.c b/cc3200/mods/pybtimer.c new file mode 100644 index 0000000000..c52b506110 --- /dev/null +++ b/cc3200/mods/pybtimer.c @@ -0,0 +1,834 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/mpconfig.h" +#include MICROPY_HAL_H +#include "py/obj.h" +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "inc/hw_timer.h" +#include "rom_map.h" +#include "interrupt.h" +#include "prcm.h" +#include "timer.h" +#include "pybtimer.h" +#include "pybsleep.h" +#include "mpcallback.h" +#include "mpexception.h" + + +/// \moduleref pyb +/// \class Timer - generate periodic events, count events, and create PWM signals. +/// +/// Each timer consists of a counter that counts up at a certain rate. The rate +/// at which it counts is the peripheral clock frequency (in Hz) divided by the +/// timer prescaler. When the counter reaches the timer period it triggers an +/// event, and the counter resets back to zero. By using the callback method, +/// the timer event can call a Python function. +/// +/// Example usage to toggle an LED at a fixed frequency: +/// +/// tim = pyb.Timer(3) # create a timer object using timer 4 +/// tim.init(mode=Timer.PERIODIC) # initialize it in periodic mode +/// tim_ch = tim.channel(Timer.A, freq=2) # configure channel A at a frequency of 2Hz +/// tim_ch.callback(handler=lambda t:led.toggle()) # toggle a led on every cycle of the timer +/// +/// Further examples: +/// +/// tim1 = pyb.Timer(2, mode=Timer.EVENT_COUNT) # initialize it capture mode +/// tim2 = pyb.Timer(0, mode=Timer.PWM) # initialize it in PWM mode +/// tim_ch = tim1.channel(Timer.A, freq=1, polarity=Timer.POSITIVE) # start the PWM on channel B with a 50% duty cycle +/// tim_ch = tim2.channel(Timer.B, freq=10000, duty_cycle=50) # start the event counter with a frequency of 1Hz and triggered by positive edges +/// tim_ch.time() # get the current time in usec (can also be set) +/// tim_ch.freq(20) # set the frequency (can also get) +/// tim_ch.duty_cycle(30) # set the duty cycle to 30% (can also get) +/// tim_ch.duty_cycle(30, Timer.NEGATIVE) # set the duty cycle to 30% and change the polarity to negative +/// tim_ch.event_count() # get the number of captured events +/// tim_ch.event_time() # get the the time of the last captured event +/// + +/****************************************************************************** + DECLARE PRIVATE CONSTANTS + ******************************************************************************/ +#define PYBTIMER_NUM_TIMERS (4) +#define PYBTIMER_POLARITY_POS (0x01) +#define PYBTIMER_POLARITY_NEG (0x02) + +#define PYBTIMER_SRC_FREQ_HZ HAL_FCPU_HZ + +/****************************************************************************** + DEFINE PRIVATE TYPES + ******************************************************************************/ +typedef struct _pyb_timer_obj_t { + mp_obj_base_t base; + uint32_t timer; + uint32_t config; + uint16_t intflags; + uint8_t peripheral; + uint8_t id; +} pyb_timer_obj_t; + +typedef struct _pyb_timer_channel_obj_t { + mp_obj_base_t base; + struct _pyb_timer_obj_t *timer; + uint32_t frequency; + uint16_t channel; + uint8_t polarity; + uint8_t duty_cycle; +} pyb_timer_channel_obj_t; + +/****************************************************************************** + DEFINE PRIVATE DATA + ******************************************************************************/ +STATIC const mp_cb_methods_t pyb_timer_channel_cb_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}, + {.timer = TIMERA3_BASE, .peripheral = PRCM_TIMERA3}}; +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 void timer_disable (pyb_timer_obj_t *tim); +STATIC void TIMER0AIntHandler(void); +STATIC void TIMER0BIntHandler(void); +STATIC void TIMER1AIntHandler(void); +STATIC void TIMER1BIntHandler(void); +STATIC void TIMER2AIntHandler(void); +STATIC void TIMER2BIntHandler(void); +STATIC void TIMER3AIntHandler(void); +STATIC void TIMER3BIntHandler(void); + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +void timer_init0 (void) { + mp_obj_list_init(&MP_STATE_PORT(pyb_timer_channel_obj_list), 0); +} + +void timer_disable_all (void) { + pyb_timer_obj_t timer = { + .timer = TIMERA0_BASE, + .intflags = TIMER_CAPB_EVENT | TIMER_CAPB_MATCH | + TIMER_TIMB_TIMEOUT | TIMER_CAPA_EVENT | + TIMER_CAPA_MATCH | TIMER_TIMA_TIMEOUT, + .peripheral = PRCM_TIMERA0 + }; + + for (uint32_t i = 0; i < PYBTIMER_NUM_TIMERS; i++) { + // in case it's not clocked + MAP_PRCMPeripheralClkEnable(timer.peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + timer_disable(&timer); + // timer base offset according to hw_memmap.h + timer.timer += 0x1000; + // peripheral offset according to prcm.h + timer.peripheral++; + } +} + +void pyb_timer_channel_callback_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); +} + +void pyb_timer_channel_callback_disable (mp_obj_t self_in) { + pyb_timer_channel_obj_t *self = self_in; + MAP_TimerIntDisable(self->timer->timer, self->timer->intflags & self->channel); +} + +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 + if (ch->timer->timer == timer && ((ch->channel & TIMER_A) == channel_n || (ch->channel & TIMER_B) == channel_n)) { + return ch; + } + } + return MP_OBJ_NULL; +} + +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) { + // 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); +} + +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_PRCMPeripheralClkDisable(tim->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + memset(&pyb_timer_obj[tim->id], 0, sizeof(pyb_timer_obj_t)); +} + +// computes prescaler period and match value so timer triggers at freq-Hz +STATIC uint32_t compute_prescaler_period_and_match_value(pyb_timer_channel_obj_t *ch, uint32_t *period_out, uint32_t *match_out) { + uint32_t maxcount = (ch->channel == (TIMER_A | TIMER_B)) ? 0xFFFFFFFF : 0xFFFF; + uint32_t prescaler; + uint32_t period = PYBTIMER_SRC_FREQ_HZ / ch->frequency; + + period = MAX(1, period) - 1; + prescaler = period >> 16; + *period_out = period; + if (prescaler > 0xFF && maxcount == 0xFFFF) { + goto error; + } + // check limit values for the duty cycle + if (ch->duty_cycle == 0) { + *match_out = period - 1; + } + else { + *match_out = period - ((period * ch->duty_cycle) / 100); + } + if ((ch->timer->config & 0x0F) == TIMER_CFG_A_PWM && (*match_out > 0xFFFF)) { + goto error; + } + return prescaler; + +error: + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); +} + +STATIC void timer_init (pyb_timer_obj_t *tim) { + MAP_PRCMPeripheralClkEnable(tim->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + MAP_PRCMPeripheralReset(tim->peripheral); + MAP_TimerConfigure(tim->timer, tim->config); +} + +STATIC void timer_channel_init (pyb_timer_channel_obj_t *ch) { + // calculate the period, the prescaler and the match value + uint32_t period; + uint32_t match; + uint32_t prescaler = compute_prescaler_period_and_match_value(ch, &period, &match); + + // set the prescaler + MAP_TimerPrescaleSet(ch->timer->timer, ch->channel, (prescaler < 0xFF) ? prescaler : 0); + + // set the load value + MAP_TimerLoadSet(ch->timer->timer, ch->channel, period); + + // configure the pwm if we are in such mode + if ((ch->timer->config & 0x0F) == TIMER_CFG_A_PWM) { + // invert the timer output if required + MAP_TimerControlLevel(ch->timer->timer, ch->channel, (ch->polarity == PYBTIMER_POLARITY_NEG) ? true : false); + // set the match value (which is simply the duty cycle translated to ticks) + MAP_TimerMatchSet(ch->timer->timer, ch->channel, match); + } + // configure the event edge type if we are in such mode + else if ((ch->timer->config & 0x0F) == TIMER_CFG_A_CAP_COUNT || (ch->timer->config & 0x0F) == TIMER_CFG_A_CAP_TIME) { + uint32_t polarity = TIMER_EVENT_BOTH_EDGES; + if (ch->polarity == PYBTIMER_POLARITY_POS) { + polarity = TIMER_EVENT_POS_EDGE; + } + else if (ch->polarity == PYBTIMER_POLARITY_NEG) { + polarity = TIMER_EVENT_NEG_EDGE; + } + MAP_TimerControlEvent(ch->timer->timer, ch->channel, polarity); + } + +#ifdef DEBUG + // stall the timer when the processor is halted while debugging + MAP_TimerControlStall(ch->timer->timer, ch->channel, true); +#endif + + // now enable the timer channel + MAP_TimerEnable(ch->timer->timer, ch->channel); +} + +/******************************************************************************/ +/* Micro Python bindings */ + +STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_timer_obj_t *tim = self_in; + uint32_t mode = tim->config & 0xFF; + + // timer mode + qstr mode_qst = MP_QSTR_PWM; + switch(mode) { + case TIMER_CFG_A_ONE_SHOT: + mode_qst = MP_QSTR_ONE_SHOT; + break; + case TIMER_CFG_A_PERIODIC: + mode_qst = MP_QSTR_PERIODIC; + break; + case TIMER_CFG_A_CAP_COUNT: + mode_qst = MP_QSTR_EDGE_COUNT; + break; + case TIMER_CFG_A_CAP_TIME: + mode_qst = MP_QSTR_EDGE_TIME; + break; + default: + break; + } + mp_printf(print, "", tim->id, mode_qst); +} + +/// \method init(mode, *, width) +/// Initialise the timer. Initialisation must give the desired mode +/// and an optional timer width +/// +/// tim.init(mode=Timer.PERIODIC) # configure in free running periodic mode +/// tim.init(mode=Timer.ONE_SHOT, width=16) # one shot mode splitted into two 16-bit independent timers +/// +/// Keyword arguments: +/// +/// - `width` - specifies the width of the timer. Default is 32 bit mode. When in 16 bit mode +/// the timer is splitted into 2 independent channels. +/// +STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *tim, 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_mode, MP_ARG_REQUIRED | MP_ARG_INT, }, + { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // check the mode + uint32_t _mode = args[0].u_int; + if (_mode != TIMER_CFG_A_ONE_SHOT && _mode != TIMER_CFG_A_PERIODIC && _mode != TIMER_CFG_A_CAP_COUNT && + _mode != TIMER_CFG_A_CAP_TIME && _mode != TIMER_CFG_A_PWM) { + goto error; + } + + // check the width + if (args[1].u_int != 16 && args[1].u_int != 32) { + goto error; + } + bool is16bit = (args[1].u_int == 16); + + if (!is16bit && (_mode != TIMER_CFG_A_ONE_SHOT && _mode != TIMER_CFG_A_PERIODIC)) { + // 32-bit mode is only available when in free running modes + goto error; + } + tim->config = is16bit ? ((_mode | (_mode << 8)) | TIMER_CFG_SPLIT_PAIR) : _mode; + + timer_init(tim); + // register it with the sleep module + pybsleep_add ((const mp_obj_t)tim, (WakeUpCB_t)timer_channel_init); + + return mp_const_none; + +error: + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); +} + +/// \classmethod \constructor(id, ...) +/// Construct a new timer object of the given id. If additional +/// arguments are given, then the timer is initialised by `init(...)`. +/// `id` can be 0 to 3 +STATIC mp_obj_t pyb_timer_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // create a new Timer object + uint32_t timer_idx = mp_obj_get_int(args[0]); + if (timer_idx < 0 || timer_idx > (PYBTIMER_NUM_TIMERS - 1)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + } + + pyb_timer_obj_t *tim = &pyb_timer_obj[timer_idx]; + tim->base.type = &pyb_timer_type; + tim->id = timer_idx; + + if (n_args > 1 || n_kw > 0) { + // start the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_timer_init_helper(tim, n_args - 1, args + 1, &kw_args); + } + return (mp_obj_t)tim; +} + +// \method init() +/// initializes the timer +STATIC mp_obj_t pyb_timer_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pyb_timer_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_init_obj, 1, pyb_timer_init); + +// \method deinit() +/// disables the timer +STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) { + pyb_timer_obj_t *self = self_in; + timer_disable(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit); + +/// \method channel(channel, *, freq, polarity, duty_cycle) +/// Initialise the timer channel. Initialization requires at least a frequency param. With no +/// extra params given besides the channel id, the channel is returned with the previous configuration +/// os 'None', if it hasn't been initialized before. +/// +/// tim1.channel(Timer.A, freq=1000) # set channel A frequency to 1KHz +/// tim2.channel(Timer.AB, freq=10) # both channels (because it's a 32 bit timer) combined to create a 10Hz timer +/// +/// when initialiazing the channel of a 32-bit timer, channel ID MUST be = Timer.AB +/// +/// Keyword arguments: +/// +/// - `freq` - specifies the frequency in Hz +/// +/// - `polarity` - in PWM specifies the polarity of the pulse. In capture mode specifies the edge to capture. +/// in order to capture on both negative and positive edges, make it = Timer.POSITIVE | Timer.NEGATIVE. +/// +STATIC mp_obj_t pyb_timer_channel(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_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PYBTIMER_POLARITY_POS} }, + { MP_QSTR_duty_cycle, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + + pyb_timer_obj_t *tim = pos_args[0]; + mp_int_t channel_n = mp_obj_get_int(pos_args[1]); + + // verify that the timer has been already initialized + if (!tim->config) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + } + + if (channel_n != TIMER_A && channel_n != TIMER_B && channel_n != (TIMER_A | TIMER_B)) { + // invalid channel + goto error; + } + if (channel_n == (TIMER_A | TIMER_B) && (tim->config & TIMER_CFG_SPLIT_PAIR)) { + // 32-bit channel selected when the timer is in 16-bit mode + goto error; + } + + // if only the channel number is given return the previously + // allocated channel (or None if no previous channel) + if (n_args == 2 && kw_args->used == 0) { + pyb_timer_channel_obj_t *ch; + if ((ch = pyb_timer_channel_find(tim->timer, channel_n))) { + return ch; + } + return mp_const_none; + } + + // parse the arguments + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // check the frequency + if (args[0].u_int <= 0) { + goto error; + } + // check that the polarity is not both in pwm mode + if ((tim->config & TIMER_A) == TIMER_CFG_A_PWM && args[1].u_int == (PYBTIMER_POLARITY_POS | PYBTIMER_POLARITY_NEG)) { + goto error; + } + // check the range of the duty cycle + if (args[2].u_int < 0 || args[2].u_int > 100) { + goto error; + } + + // allocate a new timer channel + pyb_timer_channel_obj_t *ch = m_new_obj(pyb_timer_channel_obj_t); + ch->base.type = &pyb_timer_channel_type; + ch->timer = tim; + ch->channel = channel_n; + + // get the frequency the polarity and the duty cycle + ch->frequency = args[0].u_int; + ch->polarity = args[1].u_int; + ch->duty_cycle = args[2].u_int; + + timer_channel_init(ch); + + // add the timer to the list + pyb_timer_channel_add(ch); + + return ch; + +error: + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_obj, 2, pyb_timer_channel); + +STATIC const mp_map_elem_t pyb_timer_locals_dict_table[] = { + // instance methods + { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_timer_init_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_timer_deinit_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_channel), (mp_obj_t)&pyb_timer_channel_obj }, + + // class constants + { MP_OBJ_NEW_QSTR(MP_QSTR_A), MP_OBJ_NEW_SMALL_INT(TIMER_A) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_B), MP_OBJ_NEW_SMALL_INT(TIMER_B) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_AB), MP_OBJ_NEW_SMALL_INT(TIMER_A | TIMER_B) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ONE_SHOT), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_ONE_SHOT) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_PERIODIC), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_PERIODIC) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_EDGE_COUNT), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_CAP_COUNT) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_EDGE_TIME), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_CAP_TIME) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_PWM), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_PWM) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_POSITIVE), MP_OBJ_NEW_SMALL_INT(PYBTIMER_POLARITY_POS) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_NEGATIVE), MP_OBJ_NEW_SMALL_INT(PYBTIMER_POLARITY_NEG) }, +}; +STATIC MP_DEFINE_CONST_DICT(pyb_timer_locals_dict, pyb_timer_locals_dict_table); + +const mp_obj_type_t pyb_timer_type = { + { &mp_type_type }, + .name = MP_QSTR_Timer, + .print = pyb_timer_print, + .make_new = pyb_timer_make_new, + .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 void TIMERGenericIntHandler(uint32_t timer, uint16_t channel) { + pyb_timer_channel_obj_t *self; + uint32_t status; + + 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); + } +} + +STATIC void TIMER0AIntHandler(void) { + TIMERGenericIntHandler(TIMERA0_BASE, TIMER_A); +} + +STATIC void TIMER0BIntHandler(void) { + TIMERGenericIntHandler(TIMERA0_BASE, TIMER_B); +} + +STATIC void TIMER1AIntHandler(void) { + TIMERGenericIntHandler(TIMERA1_BASE, TIMER_A); +} + +STATIC void TIMER1BIntHandler(void) { + TIMERGenericIntHandler(TIMERA1_BASE, TIMER_B); +} + +STATIC void TIMER2AIntHandler(void) { + TIMERGenericIntHandler(TIMERA2_BASE, TIMER_A); +} + +STATIC void TIMER2BIntHandler(void) { + TIMERGenericIntHandler(TIMERA2_BASE, TIMER_B); +} + +STATIC void TIMER3AIntHandler(void) { + TIMERGenericIntHandler(TIMERA3_BASE, TIMER_A); +} + +STATIC void TIMER3BIntHandler(void) { + TIMERGenericIntHandler(TIMERA3_BASE, TIMER_B); +} + +STATIC void pyb_timer_channel_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_timer_channel_obj_t *ch = self_in; + char *ch_id = "AB"; + // timer channel + if (ch->channel == TIMER_A) { + ch_id = "A"; + } + else if (ch->channel == TIMER_B) { + ch_id = "B"; + } + + mp_printf(print, "<%q %s, timer=%u, %q=%u", MP_QSTR_TimerChannel, + ch_id, ch->timer->id, MP_QSTR_freq, ch->frequency); + + uint32_t mode = ch->timer->config & 0xFF; + if (mode == TIMER_CFG_A_CAP_COUNT || mode == TIMER_CFG_A_CAP_TIME || mode == TIMER_CFG_A_PWM) { + mp_printf(print, ", %q=Timer.", MP_QSTR_polarity); + switch (ch->polarity) { + case PYBTIMER_POLARITY_POS: + mp_printf(print, "POSITIVE"); + break; + case PYBTIMER_POLARITY_NEG: + mp_printf(print, "NEGATIVE"); + break; + default: + mp_printf(print, "BOTH"); + break; + } + if (mode == TIMER_CFG_A_PWM) { + mp_printf(print, ", %q=%u", MP_QSTR_duty_cycle, ch->duty_cycle); + } + } + mp_printf(print, ">"); +} + +/// \method freq([value]) +/// get or set the frequency of the timer channel +STATIC mp_obj_t pyb_timer_channel_freq(mp_uint_t n_args, const mp_obj_t *args) { + pyb_timer_channel_obj_t *ch = args[0]; + if (n_args == 1) { + // get + return mp_obj_new_int(ch->frequency); + } else { + // set + ch->frequency = mp_obj_get_int(args[1]); + timer_channel_init(ch); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_freq_obj, 1, 2, pyb_timer_channel_freq); + +/// \method time([value]) +/// get or set the value of the timer channel in microseconds +STATIC mp_obj_t pyb_timer_channel_time(mp_uint_t n_args, const mp_obj_t *args) { + pyb_timer_channel_obj_t *ch = args[0]; + uint32_t value; + // calculate the period, the prescaler and the match value + uint32_t period; + uint32_t match; + (void)compute_prescaler_period_and_match_value(ch, &period, &match); + if (n_args == 1) { + // get + value = (ch->channel == TIMER_B) ? HWREG(ch->timer->timer + TIMER_O_TBV) : HWREG(ch->timer->timer + TIMER_O_TAV); + // return the current timer value in microseconds + // substract value to period since we are always operating in count-down mode + uint32_t time_t = (1000 * (period - value)) / period; + return mp_obj_new_int((time_t * 1000) / ch->frequency); + } + else { + // set + value = (mp_obj_get_int(args[1]) * ((ch->frequency * period) / 1000)) / 1000; + if ((value > 0xFFFF) && (ch->timer->config & TIMER_CFG_SPLIT_PAIR)) { + // this exceeds the maximum value of a 16-bit timer + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + } + // write period minus value since we are always operating in count-down mode + TimerValueSet (ch->timer->timer, ch->channel, (period - value)); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_time_obj, 1, 2, pyb_timer_channel_time); + +/// \method event_count() +/// get the number of events triggered by the configured edge +STATIC mp_obj_t pyb_timer_channel_event_count(mp_obj_t self_in) { + pyb_timer_channel_obj_t *ch = self_in; + return mp_obj_new_int(MAP_TimerValueGet(ch->timer->timer, ch->channel == (TIMER_A | TIMER_B) ? TIMER_A : ch->channel)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_channel_event_count_obj, pyb_timer_channel_event_count); + +/// \method event_time() +/// get the time at which the last event was triggered +STATIC mp_obj_t pyb_timer_channel_event_time(mp_obj_t self_in) { + pyb_timer_channel_obj_t *ch = self_in; + // calculate the period, the prescaler and the match value + uint32_t period; + uint32_t match; + (void)compute_prescaler_period_and_match_value(ch, &period, &match); + uint32_t value = MAP_TimerValueGet(ch->timer->timer, ch->channel == (TIMER_A | TIMER_B) ? TIMER_A : ch->channel); + // substract value to period since we are always operating in count-down mode + uint32_t time_t = (1000 * (period - value)) / period; + return mp_obj_new_int((time_t * 1000) / ch->frequency); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_channel_event_time_obj, pyb_timer_channel_event_time); + +/// \method duty_cycle() +/// get or set the duty cycle when in PWM mode +STATIC mp_obj_t pyb_timer_channel_duty_cycle(mp_uint_t n_args, const mp_obj_t *args) { + pyb_timer_channel_obj_t *ch = args[0]; + if (n_args == 1) { + // get + return mp_obj_new_int(ch->duty_cycle); + } + else { + // duty cycle must be converted from percentage to ticks + // calculate the period, the prescaler and the match value + uint32_t period; + uint32_t match; + ch->duty_cycle = mp_obj_get_int(args[1]); + compute_prescaler_period_and_match_value(ch, &period, &match); + if (n_args == 3) { + // set the new polarity if requested + ch->polarity = mp_obj_get_int(args[2]); + MAP_TimerControlLevel(ch->timer->timer, ch->channel, (ch->polarity == PYBTIMER_POLARITY_NEG) ? true : false); + } + MAP_TimerMatchSet(ch->timer->timer, ch->channel, match); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_duty_cycle_obj, 1, 3, pyb_timer_channel_duty_cycle); + +/// \method callback(handler, value, priority) +/// 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); + + pyb_timer_channel_obj_t *ch = pos_args[0]; + mp_obj_t _callback = mpcallback_find(ch); + if (kw_args->used > 0 || !_callback) { + // 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; + } + + // disable the callback first + pyb_timer_channel_callback_disable(ch); + + uint32_t _config = (ch->channel == TIMER_B) ? ((ch->timer->config & TIMER_B) >> 8) : (ch->timer->config & TIMER_A); + 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; + break; + case TIMER_CFG_A_CAP_TIME: + ch->timer->intflags |= TIMER_CAPA_EVENT << shift; + break; + case TIMER_CFG_A_PWM: + // special case for the match interrupt + ch->timer->intflags |= ((ch->channel & TIMER_A) == TIMER_A) ? TIMER_TIMA_MATCH : TIMER_TIMB_MATCH; + break; + default: + break; + } + if (ch->channel == (TIMER_A | TIMER_B)) { + // again a special case for the match interrupt + if (_config == TIMER_CFG_A_PWM) { + ch->timer->intflags |= TIMER_TIMB_MATCH; + } else { + 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); + + // reload the timer + uint32_t period; + uint32_t match; + compute_prescaler_period_and_match_value(ch, &period, &match); + MAP_TimerLoadSet(ch->timer->timer, ch->channel, period); + + // enable the callback before returning + pyb_timer_channel_callback_enable(ch); + } + return _callback; + +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 const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = { + // instance methods + { MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&pyb_timer_channel_freq_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&pyb_timer_channel_time_obj }, + { 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 }, +}; +STATIC MP_DEFINE_CONST_DICT(pyb_timer_channel_locals_dict, pyb_timer_channel_locals_dict_table); + +STATIC const mp_obj_type_t pyb_timer_channel_type = { + { &mp_type_type }, + .name = MP_QSTR_TimerChannel, + .print = pyb_timer_channel_print, + .locals_dict = (mp_obj_t)&pyb_timer_channel_locals_dict, +}; + diff --git a/cc3200/mods/pybtimer.h b/cc3200/mods/pybtimer.h new file mode 100644 index 0000000000..849e41ed74 --- /dev/null +++ b/cc3200/mods/pybtimer.h @@ -0,0 +1,38 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/****************************************************************************** + DECLARE EXPORTED DATA + ******************************************************************************/ +extern const mp_obj_type_t pyb_timer_type; + +/****************************************************************************** + DECLARE PUBLIC FUNCTIONS + ******************************************************************************/ +void timer_init0 (void); +void timer_disable_all (void); + diff --git a/cc3200/mods/pybuart.c b/cc3200/mods/pybuart.c index 8d1f79b03f..87b8b15e7c 100644 --- a/cc3200/mods/pybuart.c +++ b/cc3200/mods/pybuart.c @@ -101,6 +101,7 @@ 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); /****************************************************************************** DEFINE PRIVATE TYPES @@ -124,7 +125,8 @@ struct _pyb_uart_obj_t { /****************************************************************************** DECLARE PRIVATE DATA ******************************************************************************/ -STATIC pyb_uart_obj_t pyb_uart_obj[PYB_NUM_UARTS]; +STATIC pyb_uart_obj_t pyb_uart_obj[PYB_NUM_UARTS] = {{.reg = UARTA0_BASE, .peripheral = PRCM_UARTA0}, + {.reg = UARTA1_BASE, .peripheral = PRCM_UARTA1}}; STATIC const mp_cb_methods_t uart_cb_methods; /****************************************************************************** @@ -208,20 +210,19 @@ mp_obj_t uart_callback_new (pyb_uart_obj_t *self, mp_obj_t handler, uint rxbuffe return _callback; } +void uart_disable_all (void) { + for (int i = 0; i < PYB_NUM_UARTS; i++) { + // in case it's not clocked + MAP_PRCMPeripheralClkEnable(pyb_uart_obj[i].peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + pyb_uart_deinit(&pyb_uart_obj[i]); + } +} + /****************************************************************************** DEFINE PRIVATE FUNCTIONS ******************************************************************************/ // assumes init parameters have been set up correctly STATIC void uart_init (pyb_uart_obj_t *self) { - if (self->uart_id == PYB_UART_0) { - self->reg = UARTA0_BASE; - self->peripheral = PRCM_UARTA0; - } - else { - self->reg = UARTA1_BASE; - self->peripheral = PRCM_UARTA1; - } - // Enable the peripheral clock MAP_PRCMPeripheralClkEnable(self->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); @@ -457,6 +458,7 @@ STATIC mp_obj_t pyb_uart_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t pyb_uart_obj_t *self = &pyb_uart_obj[uart_id]; self->base.type = &pyb_uart_type; self->uart_id = uart_id; + if (n_args > 1 || n_kw > 0) { // start the peripheral mp_map_t kw_args; @@ -474,7 +476,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_init_obj, 1, pyb_uart_init); /// \method deinit() /// Turn off the UART bus. -mp_obj_t pyb_uart_deinit(mp_obj_t self_in) { +STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) { pyb_uart_obj_t *self = self_in; // unregister it with the sleep module diff --git a/cc3200/mods/pybuart.h b/cc3200/mods/pybuart.h index 2441c1b9dc..66812a8834 100644 --- a/cc3200/mods/pybuart.h +++ b/cc3200/mods/pybuart.h @@ -38,12 +38,12 @@ typedef struct _pyb_uart_obj_t pyb_uart_obj_t; extern const mp_obj_type_t pyb_uart_type; void uart_init0(void); -mp_obj_t pyb_uart_deinit(mp_obj_t self_in); bool uart_rx_any(pyb_uart_obj_t *uart_obj); 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, uint rxbuffer_size, mp_int_t priority); +void uart_disable_all (void); #endif // PYBUART_H_ diff --git a/cc3200/mpconfigport.h b/cc3200/mpconfigport.h index dfdce7f8bd..c585b3e382 100644 --- a/cc3200/mpconfigport.h +++ b/cc3200/mpconfigport.h @@ -139,6 +139,7 @@ extern const struct _mp_obj_module_t mp_module_network; mp_obj_list_t mod_network_nic_list; \ mp_obj_list_t pybsleep_obj_list; \ mp_obj_list_t mpcallback_obj_list; \ + mp_obj_list_t pyb_timer_channel_obj_list; \ // type definitions for the specific machine diff --git a/cc3200/mptask.c b/cc3200/mptask.c index 4c077107f7..28dde5185c 100644 --- a/cc3200/mptask.c +++ b/cc3200/mptask.c @@ -63,6 +63,7 @@ #include "pybsd.h" #include "pins.h" #include "pybsleep.h" +#include "pybtimer.h" #include "mpcallback.h" /****************************************************************************** @@ -124,6 +125,7 @@ soft_reset: mperror_init0(); uart_init0(); pin_init0(); + timer_init0(); readline_init0(); mod_network_init0(); #if MICROPY_HW_ENABLE_RNG @@ -242,15 +244,23 @@ soft_reset_exit: // soft reset pybsleep_signal_soft_reset(); - mp_printf(&mp_plat_print, "PYB: soft reboot\n"); + // disable all peripherals that could trigger a callback + pyb_rtc_callback_disable(NULL); + timer_disable_all(); + uart_disable_all(); + + // flush the serial flash buffer sflash_disk_flush(); #if MICROPY_HW_HAS_SDCARD pybsd_deinit(); #endif + // wait for pending transactions to complete + HAL_Delay(20); + goto soft_reset; } diff --git a/cc3200/qstrdefsport.h b/cc3200/qstrdefsport.h index b14925d196..3a8fb55dea 100644 --- a/cc3200/qstrdefsport.h +++ b/cc3200/qstrdefsport.h @@ -235,7 +235,7 @@ Q(network) Q(route) Q(start_server) Q(stop_server) -Q(server_enabled) +Q(server_running) Q(server_login) // for WLAN class @@ -325,3 +325,28 @@ Q(send_recv) Q(ACTIVE_LOW) Q(ACTIVE_HIGH) +// for Timer class +Q(Timer) +Q(TimerChannel) +Q(init) +Q(deinit) +Q(freq) +Q(mode) +Q(width) +Q(channel) +Q(polarity) +Q(duty_cycle) +Q(time) +Q(event_count) +Q(event_time) +Q(A) +Q(B) +Q(AB) +Q(ONE_SHOT) +Q(PERIODIC) +Q(EDGE_COUNT) +Q(EDGE_TIME) +Q(PWM) +Q(POSITIVE) +Q(NEGATIVE) +