Merge pull request #868 from dhylands/fix-teensy-float
Add pulse_width_percent to teensy.
This commit is contained in:
commit
3fafe730d3
@ -175,7 +175,7 @@ Q(BOTH)
|
|||||||
// for TimerChannel class
|
// for TimerChannel class
|
||||||
Q(TimerChannel)
|
Q(TimerChannel)
|
||||||
Q(pulse_width)
|
Q(pulse_width)
|
||||||
Q(pulse_width_ratio)
|
Q(pulse_width_percent)
|
||||||
Q(compare)
|
Q(compare)
|
||||||
Q(capture)
|
Q(capture)
|
||||||
Q(polarity)
|
Q(polarity)
|
||||||
|
@ -276,8 +276,8 @@ STATIC void pyb_timer_print(void (*print)(void *env, const char *fmt, ...), void
|
|||||||
} else {
|
} else {
|
||||||
print(env, "Timer(%u, prescaler=%u, period=%u, mode=%s, div=%u)",
|
print(env, "Timer(%u, prescaler=%u, period=%u, mode=%s, div=%u)",
|
||||||
self->tim_id,
|
self->tim_id,
|
||||||
self->tim.Init.Prescaler,
|
self->tim.Instance->PSC & 0xffff,
|
||||||
self->tim.Init.Period,
|
__HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self),
|
||||||
self->tim.Init.CounterMode == TIM_COUNTERMODE_UP ? "UP" :
|
self->tim.Init.CounterMode == TIM_COUNTERMODE_UP ? "UP" :
|
||||||
self->tim.Init.CounterMode == TIM_COUNTERMODE_DOWN ? "DOWN" : "CENTER",
|
self->tim.Init.CounterMode == TIM_COUNTERMODE_DOWN ? "DOWN" : "CENTER",
|
||||||
self->tim.Init.ClockDivision == TIM_CLOCKDIVISION_DIV4 ? 4 :
|
self->tim.Init.ClockDivision == TIM_CLOCKDIVISION_DIV4 ? 4 :
|
||||||
@ -543,7 +543,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
|
|||||||
/// Keyword arguments for Timer.PWM modes:
|
/// Keyword arguments for Timer.PWM modes:
|
||||||
///
|
///
|
||||||
/// - `pulse_width` - determines the initial pulse width value to use.
|
/// - `pulse_width` - determines the initial pulse width value to use.
|
||||||
/// - `pulse_width_ratio` - determines the initial pulse width ratio to use.
|
/// - `pulse_width_percent` - determines the initial pulse width percentage to use.
|
||||||
///
|
///
|
||||||
/// Keyword arguments for Timer.OC modes:
|
/// Keyword arguments for Timer.OC modes:
|
||||||
///
|
///
|
||||||
@ -569,7 +569,7 @@ STATIC const mp_arg_t pyb_timer_channel_args[] = {
|
|||||||
{ MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
{ MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||||
{ MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
{ MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||||
{ MP_QSTR_pulse_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
|
{ MP_QSTR_pulse_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
|
||||||
{ MP_QSTR_pulse_width_ratio, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
{ MP_QSTR_pulse_width_percent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||||
{ MP_QSTR_compare, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
{ MP_QSTR_compare, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||||
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
|
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
|
||||||
};
|
};
|
||||||
@ -667,9 +667,17 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *args, mp_map
|
|||||||
// absolute pulse width value given
|
// absolute pulse width value given
|
||||||
oc_config.Pulse = vals[2].u_int;
|
oc_config.Pulse = vals[2].u_int;
|
||||||
} else if (vals[3].u_obj != mp_const_none) {
|
} else if (vals[3].u_obj != mp_const_none) {
|
||||||
// pulse width ratio given
|
// pulse width percent given
|
||||||
uint32_t period = (__HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self)) + 1;
|
uint32_t period = (__HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self)) + 1;
|
||||||
uint32_t cmp = mp_obj_get_float(vals[3].u_obj) * period;
|
uint32_t cmp;
|
||||||
|
#if MICROPY_PY_BUILTINS_FLOAT
|
||||||
|
if (MP_OBJ_IS_TYPE(vals[3].u_obj, &mp_type_float)) {
|
||||||
|
cmp = mp_obj_get_float(vals[3].u_obj) * period / 100.0;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
cmp = mp_obj_get_int(vals[3].u_obj) * period / 100;
|
||||||
|
}
|
||||||
if (cmp < 0) {
|
if (cmp < 0) {
|
||||||
cmp = 0;
|
cmp = 0;
|
||||||
} else if (cmp > period) {
|
} else if (cmp > period) {
|
||||||
@ -891,9 +899,6 @@ STATIC void pyb_timer_channel_print(void (*print)(void *env, const char *fmt, ..
|
|||||||
/// pulse_width is the logical name to use when the channel is in PWM mode.
|
/// pulse_width is the logical name to use when the channel is in PWM mode.
|
||||||
STATIC mp_obj_t pyb_timer_channel_capture_compare(mp_uint_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t pyb_timer_channel_capture_compare(mp_uint_t n_args, const mp_obj_t *args) {
|
||||||
pyb_timer_channel_obj_t *self = args[0];
|
pyb_timer_channel_obj_t *self = args[0];
|
||||||
if (self->channel == 0) {
|
|
||||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Timer %d no channel specified", self->timer->tim_id));
|
|
||||||
}
|
|
||||||
if (n_args == 1) {
|
if (n_args == 1) {
|
||||||
// get
|
// get
|
||||||
return mp_obj_new_int(__HAL_TIM_GetCompare(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer));
|
return mp_obj_new_int(__HAL_TIM_GetCompare(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer));
|
||||||
@ -910,19 +915,28 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_capture_compare_obj
|
|||||||
/// a floating-point number between 0.0 and 1.0, and is relative to the period
|
/// a floating-point number between 0.0 and 1.0, and is relative to the period
|
||||||
/// of the timer associated with this channel. For example, a ratio of 0.5
|
/// of the timer associated with this channel. For example, a ratio of 0.5
|
||||||
/// would be a 50% duty cycle.
|
/// would be a 50% duty cycle.
|
||||||
STATIC mp_obj_t pyb_timer_channel_pulse_width_ratio(mp_uint_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t pyb_timer_channel_pulse_width_percent(mp_uint_t n_args, const mp_obj_t *args) {
|
||||||
pyb_timer_channel_obj_t *self = args[0];
|
pyb_timer_channel_obj_t *self = args[0];
|
||||||
if (self->channel == 0) {
|
|
||||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Timer %d no channel specified", self->timer->tim_id));
|
|
||||||
}
|
|
||||||
uint32_t period = (__HAL_TIM_GetAutoreload(&self->timer->tim) & TIMER_CNT_MASK(self->timer)) + 1;
|
uint32_t period = (__HAL_TIM_GetAutoreload(&self->timer->tim) & TIMER_CNT_MASK(self->timer)) + 1;
|
||||||
if (n_args == 1) {
|
if (n_args == 1) {
|
||||||
// get
|
// get
|
||||||
uint32_t cmp = __HAL_TIM_GetCompare(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer);
|
uint32_t cmp = __HAL_TIM_GetCompare(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer);
|
||||||
return mp_obj_new_float((float)cmp / (float)period);
|
#if MICROPY_PY_BUILTINS_FLOAT
|
||||||
|
return mp_obj_new_float((float)cmp * 100.0 / (float)period);
|
||||||
|
#else
|
||||||
|
return mp_obj_new_int(cmp * 100 / period);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
// set
|
// set
|
||||||
uint32_t cmp = mp_obj_get_float(args[1]) * period;
|
uint32_t cmp;
|
||||||
|
#if MICROPY_PY_BUILTINS_FLOAT
|
||||||
|
if (MP_OBJ_IS_TYPE(args[1], &mp_type_float)) {
|
||||||
|
cmp = mp_obj_get_float(args[1]) * period / 100.0;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
cmp = mp_obj_get_int(args[1]) * period / 100;
|
||||||
|
}
|
||||||
if (cmp < 0) {
|
if (cmp < 0) {
|
||||||
cmp = 0;
|
cmp = 0;
|
||||||
} else if (cmp > period) {
|
} else if (cmp > period) {
|
||||||
@ -932,7 +946,7 @@ STATIC mp_obj_t pyb_timer_channel_pulse_width_ratio(mp_uint_t n_args, const mp_o
|
|||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_pulse_width_ratio_obj, 1, 2, pyb_timer_channel_pulse_width_ratio);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_pulse_width_percent_obj, 1, 2, pyb_timer_channel_pulse_width_percent);
|
||||||
|
|
||||||
/// \method callback(fun)
|
/// \method callback(fun)
|
||||||
/// Set the function to be called when the timer channel triggers.
|
/// Set the function to be called when the timer channel triggers.
|
||||||
@ -976,7 +990,7 @@ STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = {
|
|||||||
// instance methods
|
// instance methods
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_timer_channel_callback_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_timer_channel_callback_obj },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pulse_width), (mp_obj_t)&pyb_timer_channel_capture_compare_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_pulse_width), (mp_obj_t)&pyb_timer_channel_capture_compare_obj },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pulse_width_ratio), (mp_obj_t)&pyb_timer_channel_pulse_width_ratio_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_pulse_width_percent), (mp_obj_t)&pyb_timer_channel_pulse_width_percent_obj },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_capture), (mp_obj_t)&pyb_timer_channel_capture_compare_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_capture), (mp_obj_t)&pyb_timer_channel_capture_compare_obj },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_compare), (mp_obj_t)&pyb_timer_channel_capture_compare_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_compare), (mp_obj_t)&pyb_timer_channel_capture_compare_obj },
|
||||||
};
|
};
|
||||||
|
@ -6,10 +6,28 @@ QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h
|
|||||||
# include py core make definitions
|
# include py core make definitions
|
||||||
include ../py/py.mk
|
include ../py/py.mk
|
||||||
|
|
||||||
|
# If you set USE_ARDUINO_TOOLCHAIN=1 then this makefile will attempt to use
|
||||||
|
# the toolchain that comes with Teensyduino
|
||||||
|
ifeq ($(USE_ARDUINO_TOOLCHAIN),)
|
||||||
|
USE_ARDUINO_TOOLCHAIN = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(USE_ARDUINO_TOOLCHAIN),1)
|
||||||
|
ifeq ($(ARDUINO),)
|
||||||
|
$(error USE_ARDUINO_TOOLCHAIN requires that ARDUINO be set)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(USE_ARDUINO_TOOLCHAIN),1)
|
||||||
|
$(info Using ARDUINO toolchain)
|
||||||
|
CROSS_COMPILE = $(ARDUINO)/hardware/tools/arm-none-eabi/bin/arm-none-eabi-
|
||||||
|
else
|
||||||
|
$(info Using toolchain from PATH)
|
||||||
CROSS_COMPILE = arm-none-eabi-
|
CROSS_COMPILE = arm-none-eabi-
|
||||||
|
endif
|
||||||
|
|
||||||
CFLAGS_TEENSY = -DF_CPU=96000000 -DUSB_SERIAL -D__MK20DX256__
|
CFLAGS_TEENSY = -DF_CPU=96000000 -DUSB_SERIAL -D__MK20DX256__
|
||||||
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mcpu=cortex-m4 -fsingle-precision-constant -Wdouble-promotion $(CFLAGS_TEENSY)
|
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mcpu=cortex-m4 -msoft-float -mfloat-abi=soft -fsingle-precision-constant -Wdouble-promotion $(CFLAGS_TEENSY)
|
||||||
|
|
||||||
INC = -I.
|
INC = -I.
|
||||||
INC += -I$(PY_SRC)
|
INC += -I$(PY_SRC)
|
||||||
@ -18,11 +36,21 @@ INC += -I$(BUILD)
|
|||||||
INC += -Icore
|
INC += -Icore
|
||||||
|
|
||||||
CFLAGS = $(INC) -Wall -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4)
|
CFLAGS = $(INC) -Wall -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4)
|
||||||
LDFLAGS = -nostdlib -T mk20dx256.ld
|
LDFLAGS = -nostdlib -T mk20dx256.ld -msoft-float -mfloat-abi=soft
|
||||||
|
|
||||||
LIBGCC_FILE_NAME = $(shell $(CC) -print-libgcc-file-name)
|
ifeq ($(USE_ARDUINO_TOOLCHAIN),1)
|
||||||
LIBM_FILE_NAME = $(shell $(CC) -print-file-name=libm.a)
|
|
||||||
LIBC_FILE_NAME = $(shell $(CC) -print-file-name=libc.a)
|
LIBGCC_FILE_NAME = $(ARDUINO)/hardware/tools/arm-none-eabi/lib/gcc/arm-none-eabi/4.7.2/thumb2/libgcc.a
|
||||||
|
LIBM_FILE_NAME = $(ARDUINO)/hardware/tools/arm-none-eabi/arm-none-eabi/lib/thumb2/libm.a
|
||||||
|
LIBC_FILE_NAME = $(ARDUINO)/hardware/tools/arm-none-eabi/arm-none-eabi/lib/thumb2/libc.a
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
|
||||||
|
LIBM_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-file-name=libm.a)
|
||||||
|
LIBC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-file-name=libc.a)
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
#$(info %%%%% LIBGCC_FILE_NAME = $(LIBGCC_FILE_NAME))
|
#$(info %%%%% LIBGCC_FILE_NAME = $(LIBGCC_FILE_NAME))
|
||||||
#$(info %%%%% LIBM_FILE_NAME = $(LIBM_FILE_NAME))
|
#$(info %%%%% LIBM_FILE_NAME = $(LIBM_FILE_NAME))
|
||||||
|
@ -119,6 +119,7 @@ Q(BOTH)
|
|||||||
// for TimerChannel class
|
// for TimerChannel class
|
||||||
Q(TimerChannel)
|
Q(TimerChannel)
|
||||||
Q(pulse_width)
|
Q(pulse_width)
|
||||||
|
Q(pulse_width_percent)
|
||||||
Q(compare)
|
Q(compare)
|
||||||
Q(capture)
|
Q(capture)
|
||||||
Q(polarity)
|
Q(polarity)
|
||||||
|
135
teensy/timer.c
135
teensy/timer.c
@ -42,7 +42,6 @@
|
|||||||
|
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CHANNEL_MODE_PWM_NORMAL,
|
CHANNEL_MODE_PWM_NORMAL,
|
||||||
CHANNEL_MODE_PWM_INVERTED,
|
CHANNEL_MODE_PWM_INVERTED,
|
||||||
@ -58,7 +57,7 @@ typedef enum {
|
|||||||
STATIC const struct {
|
STATIC const struct {
|
||||||
qstr name;
|
qstr name;
|
||||||
uint32_t oc_mode;
|
uint32_t oc_mode;
|
||||||
} gChannelMode[] = {
|
} channel_mode_info[] = {
|
||||||
{ MP_QSTR_PWM, FTM_OCMODE_PWM1 },
|
{ MP_QSTR_PWM, FTM_OCMODE_PWM1 },
|
||||||
{ MP_QSTR_PWM_INVERTED, FTM_OCMODE_PWM2 },
|
{ MP_QSTR_PWM_INVERTED, FTM_OCMODE_PWM2 },
|
||||||
{ MP_QSTR_OC_TIMING, FTM_OCMODE_TIMING },
|
{ MP_QSTR_OC_TIMING, FTM_OCMODE_TIMING },
|
||||||
@ -127,6 +126,8 @@ mp_uint_t get_prescaler_shift(mp_int_t prescaler) {
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* Micro Python bindings */
|
/* Micro Python bindings */
|
||||||
|
|
||||||
|
STATIC const mp_obj_type_t pyb_timer_channel_type;
|
||||||
|
|
||||||
STATIC void pyb_timer_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
STATIC void pyb_timer_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||||
pyb_timer_obj_t *self = self_in;
|
pyb_timer_obj_t *self = self_in;
|
||||||
|
|
||||||
@ -135,8 +136,8 @@ STATIC void pyb_timer_print(void (*print)(void *env, const char *fmt, ...), void
|
|||||||
} else {
|
} else {
|
||||||
print(env, "Timer(%u, prescaler=%u, period=%u, mode=%s)",
|
print(env, "Timer(%u, prescaler=%u, period=%u, mode=%s)",
|
||||||
self->tim_id,
|
self->tim_id,
|
||||||
1 << self->ftm.Init.PrescalerShift,
|
1 << (self->ftm.Instance->SC & 7),
|
||||||
self->ftm.Init.Period,
|
self->ftm.Instance->MOD & 0xffff,
|
||||||
self->ftm.Init.CounterMode == FTM_COUNTERMODE_UP ? "tUP" : "CENTER");
|
self->ftm.Init.CounterMode == FTM_COUNTERMODE_UP ? "tUP" : "CENTER");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -243,7 +244,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, uint n_args, const
|
|||||||
/// Construct a new timer object of the given id. If additional
|
/// Construct a new timer object of the given id. If additional
|
||||||
/// arguments are given, then the timer is initialised by `init(...)`.
|
/// arguments are given, then the timer is initialised by `init(...)`.
|
||||||
/// `id` can be 1 to 14, excluding 3.
|
/// `id` can be 1 to 14, excluding 3.
|
||||||
STATIC mp_obj_t pyb_timer_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
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
|
// check arguments
|
||||||
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
|
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
|
||||||
|
|
||||||
@ -280,7 +281,7 @@ STATIC mp_obj_t pyb_timer_make_new(mp_obj_t type_in, uint n_args, uint n_kw, con
|
|||||||
return (mp_obj_t)tim;
|
return (mp_obj_t)tim;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC mp_obj_t pyb_timer_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
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);
|
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);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_init_obj, 1, pyb_timer_init);
|
||||||
@ -289,11 +290,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_init_obj, 1, pyb_timer_init);
|
|||||||
/// Deinitialises the timer.
|
/// Deinitialises the timer.
|
||||||
///
|
///
|
||||||
/// Disables the callback (and the associated irq).
|
/// Disables the callback (and the associated irq).
|
||||||
|
/// Disables any channel callbacks (and the associated irq).
|
||||||
/// Stops the timer, and disables the timer peripheral.
|
/// Stops the timer, and disables the timer peripheral.
|
||||||
STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) {
|
STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) {
|
||||||
pyb_timer_obj_t *self = self_in;
|
pyb_timer_obj_t *self = self_in;
|
||||||
|
|
||||||
// Disable the interrupt
|
// Disable the base interrupt
|
||||||
pyb_timer_callback(self_in, mp_const_none);
|
pyb_timer_callback(self_in, mp_const_none);
|
||||||
|
|
||||||
pyb_timer_channel_obj_t *chan = self->channel;
|
pyb_timer_channel_obj_t *chan = self->channel;
|
||||||
@ -312,10 +314,10 @@ STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) {
|
|||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
|
||||||
|
|
||||||
/// \method channel(channel, ...)
|
/// \method channel(channel, mode, ...)
|
||||||
///
|
///
|
||||||
/// If only a channel nunber is passed, then a previously initialized channel
|
/// If only a channel number is passed, then a previously initialized channel
|
||||||
/// object is returned.
|
/// object is returned (or `None` if there is no previous channel).
|
||||||
///
|
///
|
||||||
/// Othwerwise, a TimerChannel object is initialized and returned.
|
/// Othwerwise, a TimerChannel object is initialized and returned.
|
||||||
///
|
///
|
||||||
@ -345,7 +347,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
|
|||||||
///
|
///
|
||||||
/// Keyword arguments for Timer.PWM modes:
|
/// Keyword arguments for Timer.PWM modes:
|
||||||
///
|
///
|
||||||
/// - 'pulse_width' - determines the initial pulse width to use.
|
/// - `pulse_width` - determines the initial pulse width value to use.
|
||||||
|
/// - `pulse_width_percent` - determines the initial pulse width percentage to use.
|
||||||
///
|
///
|
||||||
/// Keyword arguments for Timer.OC modes:
|
/// Keyword arguments for Timer.OC modes:
|
||||||
///
|
///
|
||||||
@ -370,15 +373,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
|
|||||||
STATIC const mp_arg_t pyb_timer_channel_args[] = {
|
STATIC const mp_arg_t pyb_timer_channel_args[] = {
|
||||||
{ MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
{ MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||||
{ MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
{ MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||||
{ MP_QSTR_pulse_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
{ MP_QSTR_pulse_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
|
||||||
|
{ MP_QSTR_pulse_width_percent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||||
{ MP_QSTR_compare, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
{ MP_QSTR_compare, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||||
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
|
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
|
||||||
};
|
};
|
||||||
#define PYB_TIMER_CHANNEL_NUM_ARGS MP_ARRAY_SIZE(pyb_timer_channel_args)
|
#define PYB_TIMER_CHANNEL_NUM_ARGS MP_ARRAY_SIZE(pyb_timer_channel_args)
|
||||||
|
|
||||||
STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||||
mp_arg_check_num(n_args, n_args - 2, 2, MP_OBJ_FUN_ARGS_MAX, true);
|
|
||||||
|
|
||||||
pyb_timer_obj_t *self = args[0];
|
pyb_timer_obj_t *self = args[0];
|
||||||
mp_int_t channel = mp_obj_get_int(args[1]);
|
mp_int_t channel = mp_obj_get_int(args[1]);
|
||||||
|
|
||||||
@ -396,8 +398,10 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *args, mp_map
|
|||||||
prev_chan = chan;
|
prev_chan = chan;
|
||||||
chan = chan->next;
|
chan = chan->next;
|
||||||
}
|
}
|
||||||
if (kw_args->used == 0) {
|
|
||||||
// Return the previously allocated channel
|
// If only the channel number is given return the previously allocated
|
||||||
|
// channel (or None if no previous channel).
|
||||||
|
if (n_args == 2) {
|
||||||
if (chan) {
|
if (chan) {
|
||||||
return chan;
|
return chan;
|
||||||
}
|
}
|
||||||
@ -463,8 +467,32 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *args, mp_map
|
|||||||
case CHANNEL_MODE_PWM_NORMAL:
|
case CHANNEL_MODE_PWM_NORMAL:
|
||||||
case CHANNEL_MODE_PWM_INVERTED: {
|
case CHANNEL_MODE_PWM_INVERTED: {
|
||||||
FTM_OC_InitTypeDef oc_config;
|
FTM_OC_InitTypeDef oc_config;
|
||||||
oc_config.OCMode = gChannelMode[chan->mode].oc_mode;
|
oc_config.OCMode = channel_mode_info[chan->mode].oc_mode;
|
||||||
|
if (vals[2].u_int != 0xffffffff) {
|
||||||
|
// absolute pulse width value given
|
||||||
oc_config.Pulse = vals[2].u_int;
|
oc_config.Pulse = vals[2].u_int;
|
||||||
|
} else if (vals[3].u_obj != mp_const_none) {
|
||||||
|
// pulse width ratio given
|
||||||
|
uint32_t period = (self->ftm.Instance->MOD & 0xffff) + 1;
|
||||||
|
uint32_t cmp;
|
||||||
|
#if MICROPY_PY_BUILTINS_FLOAT
|
||||||
|
if (MP_OBJ_IS_TYPE(vals[3].u_obj, &mp_type_float)) {
|
||||||
|
cmp = mp_obj_get_float(vals[3].u_obj) * period / 100.0;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
cmp = mp_obj_get_int(vals[3].u_obj) * period / 100;
|
||||||
|
}
|
||||||
|
if (cmp < 0) {
|
||||||
|
cmp = 0;
|
||||||
|
} else if (cmp > period) {
|
||||||
|
cmp = period;
|
||||||
|
}
|
||||||
|
oc_config.Pulse = cmp;
|
||||||
|
} else {
|
||||||
|
// nothing given, default to pulse width of 0
|
||||||
|
oc_config.Pulse = 0;
|
||||||
|
}
|
||||||
oc_config.OCPolarity = FTM_OCPOLARITY_HIGH;
|
oc_config.OCPolarity = FTM_OCPOLARITY_HIGH;
|
||||||
|
|
||||||
HAL_FTM_PWM_ConfigChannel(&self->ftm, &oc_config, channel);
|
HAL_FTM_PWM_ConfigChannel(&self->ftm, &oc_config, channel);
|
||||||
@ -481,9 +509,9 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *args, mp_map
|
|||||||
case CHANNEL_MODE_OC_INACTIVE:
|
case CHANNEL_MODE_OC_INACTIVE:
|
||||||
case CHANNEL_MODE_OC_TOGGLE: {
|
case CHANNEL_MODE_OC_TOGGLE: {
|
||||||
FTM_OC_InitTypeDef oc_config;
|
FTM_OC_InitTypeDef oc_config;
|
||||||
oc_config.OCMode = gChannelMode[chan->mode].oc_mode;
|
oc_config.OCMode = channel_mode_info[chan->mode].oc_mode;
|
||||||
oc_config.Pulse = vals[3].u_int;
|
oc_config.Pulse = vals[4].u_int;
|
||||||
oc_config.OCPolarity = vals[4].u_int;
|
oc_config.OCPolarity = vals[5].u_int;
|
||||||
if (oc_config.OCPolarity == 0xffffffff) {
|
if (oc_config.OCPolarity == 0xffffffff) {
|
||||||
oc_config.OCPolarity = FTM_OCPOLARITY_HIGH;
|
oc_config.OCPolarity = FTM_OCPOLARITY_HIGH;
|
||||||
}
|
}
|
||||||
@ -503,7 +531,7 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *args, mp_map
|
|||||||
case CHANNEL_MODE_IC: {
|
case CHANNEL_MODE_IC: {
|
||||||
FTM_IC_InitTypeDef ic_config;
|
FTM_IC_InitTypeDef ic_config;
|
||||||
|
|
||||||
ic_config.ICPolarity = vals[4].u_int;
|
ic_config.ICPolarity = vals[5].u_int;
|
||||||
if (ic_config.ICPolarity == 0xffffffff) {
|
if (ic_config.ICPolarity == 0xffffffff) {
|
||||||
ic_config.ICPolarity = FTM_ICPOLARITY_RISING;
|
ic_config.ICPolarity = FTM_ICPOLARITY_RISING;
|
||||||
}
|
}
|
||||||
@ -523,13 +551,14 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *args, mp_map
|
|||||||
default:
|
default:
|
||||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid mode (%d)", chan->mode));
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid mode (%d)", chan->mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
return chan;
|
return chan;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_obj, 3, pyb_timer_channel);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_obj, 2, pyb_timer_channel);
|
||||||
|
|
||||||
/// \method counter([value])
|
/// \method counter([value])
|
||||||
/// Get or set the timer counter.
|
/// Get or set the timer counter.
|
||||||
mp_obj_t pyb_timer_counter(uint n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t pyb_timer_counter(mp_uint_t n_args, const mp_obj_t *args) {
|
||||||
pyb_timer_obj_t *self = args[0];
|
pyb_timer_obj_t *self = args[0];
|
||||||
if (n_args == 1) {
|
if (n_args == 1) {
|
||||||
// get
|
// get
|
||||||
@ -544,7 +573,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_counter_obj, 1, 2, pyb_time
|
|||||||
|
|
||||||
/// \method prescaler([value])
|
/// \method prescaler([value])
|
||||||
/// Get or set the prescaler for the timer.
|
/// Get or set the prescaler for the timer.
|
||||||
mp_obj_t pyb_timer_prescaler(uint n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t pyb_timer_prescaler(mp_uint_t n_args, const mp_obj_t *args) {
|
||||||
pyb_timer_obj_t *self = args[0];
|
pyb_timer_obj_t *self = args[0];
|
||||||
if (n_args == 1) {
|
if (n_args == 1) {
|
||||||
// get
|
// get
|
||||||
@ -565,7 +594,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_prescaler_obj, 1, 2, pyb_ti
|
|||||||
|
|
||||||
/// \method period([value])
|
/// \method period([value])
|
||||||
/// Get or set the period of the timer.
|
/// Get or set the period of the timer.
|
||||||
mp_obj_t pyb_timer_period(uint n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t pyb_timer_period(mp_uint_t n_args, const mp_obj_t *args) {
|
||||||
pyb_timer_obj_t *self = args[0];
|
pyb_timer_obj_t *self = args[0];
|
||||||
if (n_args == 1) {
|
if (n_args == 1) {
|
||||||
// get
|
// get
|
||||||
@ -663,7 +692,6 @@ STATIC const mp_map_elem_t pyb_timer_locals_dict_table[] = {
|
|||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_FALLING), MP_OBJ_NEW_SMALL_INT(FTM_ICPOLARITY_FALLING) },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_FALLING), MP_OBJ_NEW_SMALL_INT(FTM_ICPOLARITY_FALLING) },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BOTH), MP_OBJ_NEW_SMALL_INT(FTM_ICPOLARITY_BOTH) },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_BOTH), MP_OBJ_NEW_SMALL_INT(FTM_ICPOLARITY_BOTH) },
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC MP_DEFINE_CONST_DICT(pyb_timer_locals_dict, pyb_timer_locals_dict_table);
|
STATIC MP_DEFINE_CONST_DICT(pyb_timer_locals_dict, pyb_timer_locals_dict_table);
|
||||||
|
|
||||||
const mp_obj_type_t pyb_timer_type = {
|
const mp_obj_type_t pyb_timer_type = {
|
||||||
@ -683,10 +711,10 @@ const mp_obj_type_t pyb_timer_type = {
|
|||||||
STATIC void pyb_timer_channel_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
STATIC void pyb_timer_channel_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||||
pyb_timer_channel_obj_t *self = self_in;
|
pyb_timer_channel_obj_t *self = self_in;
|
||||||
|
|
||||||
print(env, "TimerChannel(timer=%u, channel=%u mode=%s)",
|
print(env, "TimerChannel(timer=%u, channel=%u, mode=%s)",
|
||||||
self->timer->tim_id,
|
self->timer->tim_id,
|
||||||
self->channel,
|
self->channel,
|
||||||
qstr_str(gChannelMode[self->mode].name));
|
qstr_str(channel_mode_info[self->mode].name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \method capture([value])
|
/// \method capture([value])
|
||||||
@ -703,25 +731,61 @@ STATIC void pyb_timer_channel_print(void (*print)(void *env, const char *fmt, ..
|
|||||||
/// Get or set the pulse width value associated with a channel.
|
/// Get or set the pulse width value associated with a channel.
|
||||||
/// capture, compare, and pulse_width are all aliases for the same function.
|
/// capture, compare, and pulse_width are all aliases for the same function.
|
||||||
/// pulse_width is the logical name to use when the channel is in PWM mode.
|
/// pulse_width is the logical name to use when the channel is in PWM mode.
|
||||||
STATIC mp_obj_t pyb_timer_channel_capture_compare(uint n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t pyb_timer_channel_capture_compare(mp_uint_t n_args, const mp_obj_t *args) {
|
||||||
pyb_timer_channel_obj_t *self = args[0];
|
pyb_timer_channel_obj_t *self = args[0];
|
||||||
if (self->channel == 0xffffffff) {
|
|
||||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Timer %d no channel specified", self->timer->tim_id));
|
|
||||||
}
|
|
||||||
FTM_TypeDef *FTMx = self->timer->ftm.Instance;
|
FTM_TypeDef *FTMx = self->timer->ftm.Instance;
|
||||||
if (n_args == 1) {
|
if (n_args == 1) {
|
||||||
// get
|
// get
|
||||||
return mp_obj_new_int(FTMx->channel[self->channel].CV);
|
return mp_obj_new_int(FTMx->channel[self->channel].CV & 0xffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_int_t pw = mp_obj_get_int(args[1]);
|
mp_int_t pw = mp_obj_get_int(args[1]);
|
||||||
|
|
||||||
// set
|
// set
|
||||||
FTMx->channel[self->channel].CV = pw;
|
FTMx->channel[self->channel].CV = pw & 0xffff;
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_capture_compare_obj, 1, 2, pyb_timer_channel_capture_compare);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_capture_compare_obj, 1, 2, pyb_timer_channel_capture_compare);
|
||||||
|
|
||||||
|
/// \method pulse_width_percent([value])
|
||||||
|
/// Get or set the pulse width ratio associated with a channel. The value is
|
||||||
|
/// a floating-point number between 0.0 and 1.0, and is relative to the period
|
||||||
|
/// of the timer associated with this channel. For example, a ratio of 0.5
|
||||||
|
/// would be a 50% duty cycle.
|
||||||
|
STATIC mp_obj_t pyb_timer_channel_pulse_width_percent(mp_uint_t n_args, const mp_obj_t *args) {
|
||||||
|
pyb_timer_channel_obj_t *self = args[0];
|
||||||
|
FTM_TypeDef *FTMx = self->timer->ftm.Instance;
|
||||||
|
uint32_t period = (FTMx->MOD & 0xffff) + 1;
|
||||||
|
if (n_args == 1) {
|
||||||
|
// get
|
||||||
|
uint32_t cmp = FTMx->channel[self->channel].CV & 0xffff;
|
||||||
|
#if MICROPY_PY_BUILTINS_FLOAT
|
||||||
|
return mp_obj_new_float((float)cmp * 100.0 / (float)period);
|
||||||
|
#else
|
||||||
|
return mp_obj_new_int(cmp * 100 / period);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
// set
|
||||||
|
uint32_t cmp;
|
||||||
|
#if MICROPY_PY_BUILTINS_FLOAT
|
||||||
|
if (MP_OBJ_IS_TYPE(args[1], &mp_type_float)) {
|
||||||
|
cmp = mp_obj_get_float(args[1]) * period / 100.0;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
cmp = mp_obj_get_int(args[1]) * period / 100;
|
||||||
|
}
|
||||||
|
if (cmp < 0) {
|
||||||
|
cmp = 0;
|
||||||
|
} else if (cmp > period) {
|
||||||
|
cmp = period;
|
||||||
|
}
|
||||||
|
FTMx->channel[self->channel].CV = cmp & 0xffff;
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_pulse_width_percent_obj, 1, 2, pyb_timer_channel_pulse_width_percent);
|
||||||
|
|
||||||
/// \method callback(fun)
|
/// \method callback(fun)
|
||||||
/// Set the function to be called when the timer channel triggers.
|
/// Set the function to be called when the timer channel triggers.
|
||||||
/// `fun` is passed 1 argument, the timer object.
|
/// `fun` is passed 1 argument, the timer object.
|
||||||
@ -777,6 +841,7 @@ STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = {
|
|||||||
// instance methods
|
// instance methods
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_timer_channel_callback_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_timer_channel_callback_obj },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pulse_width), (mp_obj_t)&pyb_timer_channel_capture_compare_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_pulse_width), (mp_obj_t)&pyb_timer_channel_capture_compare_obj },
|
||||||
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_pulse_width_percent), (mp_obj_t)&pyb_timer_channel_pulse_width_percent_obj },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_capture), (mp_obj_t)&pyb_timer_channel_capture_compare_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_capture), (mp_obj_t)&pyb_timer_channel_capture_compare_obj },
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_compare), (mp_obj_t)&pyb_timer_channel_capture_compare_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_compare), (mp_obj_t)&pyb_timer_channel_capture_compare_obj },
|
||||||
#if MICROPY_TIMER_REG
|
#if MICROPY_TIMER_REG
|
||||||
@ -785,7 +850,7 @@ STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = {
|
|||||||
};
|
};
|
||||||
STATIC MP_DEFINE_CONST_DICT(pyb_timer_channel_locals_dict, pyb_timer_channel_locals_dict_table);
|
STATIC MP_DEFINE_CONST_DICT(pyb_timer_channel_locals_dict, pyb_timer_channel_locals_dict_table);
|
||||||
|
|
||||||
const mp_obj_type_t pyb_timer_channel_type = {
|
STATIC const mp_obj_type_t pyb_timer_channel_type = {
|
||||||
{ &mp_type_type },
|
{ &mp_type_type },
|
||||||
.name = MP_QSTR_TimerChannel,
|
.name = MP_QSTR_TimerChannel,
|
||||||
.print = pyb_timer_channel_print,
|
.print = pyb_timer_channel_print,
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
extern const mp_obj_type_t pyb_timer_type;
|
extern const mp_obj_type_t pyb_timer_type;
|
||||||
extern const mp_obj_type_t pyb_timer_channel_type;
|
|
||||||
|
|
||||||
void timer_init0(void);
|
void timer_init0(void);
|
||||||
void timer_deinit(void);
|
void timer_deinit(void);
|
||||||
|
Loading…
Reference in New Issue
Block a user