Skip to content

Commit

Permalink
stm32/timer: Make pyb.Timer() instances persistent.
Browse files Browse the repository at this point in the history
Prior to this patch calling pyb.Timer(id) would always create a new timer
instance, even if there was an existing one.  This patch fixes this
behaviour to match other peripherals, like UART, such that constructing a
timer with just the id will retrieve any existing instances.

The patch also refactors the way timers are validated on construction to
simplify and reduce code size.
  • Loading branch information
dpgeorge committed Sep 13, 2017
1 parent da8c4c2 commit d7cd1d2
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 67 deletions.
6 changes: 4 additions & 2 deletions ports/stm32/mpconfigport.h
Expand Up @@ -232,9 +232,11 @@ extern const struct _mp_obj_module_t mp_module_onewire;

#if defined(MCU_SERIES_F7)
#define PYB_EXTI_NUM_VECTORS (24)
#define MICROPY_HW_MAX_TIMER (17)
#define MICROPY_HW_MAX_UART (8)
#else
#define PYB_EXTI_NUM_VECTORS (23)
#define MICROPY_HW_MAX_TIMER (14)
#define MICROPY_HW_MAX_UART (6)
#endif

Expand All @@ -254,8 +256,8 @@ extern const struct _mp_obj_module_t mp_module_onewire;
\
mp_obj_t pyb_extint_callback[PYB_EXTI_NUM_VECTORS]; \
\
/* Used to do callbacks to Python code on interrupt */ \
struct _pyb_timer_obj_t *pyb_timer_obj_all[14]; \
/* pointers to all Timer objects (if they have been created) */ \
struct _pyb_timer_obj_t *pyb_timer_obj_all[MICROPY_HW_MAX_TIMER]; \
\
/* stdio is repeated on this UART object if it's not null */ \
struct _pyb_uart_obj_t *pyb_stdio_uart; \
Expand Down
142 changes: 77 additions & 65 deletions ports/stm32/timer.c
Expand Up @@ -629,6 +629,62 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons
return mp_const_none;
}

// This table encodes the timer instance and irq number.
// It assumes that timer instance pointer has the lower 8 bits cleared.
#define TIM_ENTRY(id, irq) [id - 1] = (uint32_t)TIM##id | irq
STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
TIM_ENTRY(1, TIM1_UP_TIM10_IRQn),
#elif defined(MCU_SERIES_L4)
TIM_ENTRY(1, TIM1_UP_TIM16_IRQn),
#endif
TIM_ENTRY(2, TIM2_IRQn),
TIM_ENTRY(3, TIM3_IRQn),
TIM_ENTRY(4, TIM4_IRQn),
TIM_ENTRY(5, TIM5_IRQn),
#if defined(TIM6)
TIM_ENTRY(6, TIM6_DAC_IRQn),
#endif
#if defined(TIM7)
TIM_ENTRY(7, TIM7_IRQn),
#endif
#if defined(TIM8)
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
TIM_ENTRY(8, TIM8_UP_TIM13_IRQn),
#elif defined(MCU_SERIES_L4)
TIM_ENTRY(8, TIM8_UP_IRQn),
#endif
#endif
#if defined(TIM9)
TIM_ENTRY(9, TIM1_BRK_TIM9_IRQn),
#endif
#if defined(TIM10)
TIM_ENTRY(10, TIM1_UP_TIM10_IRQn),
#endif
#if defined(TIM11)
TIM_ENTRY(11, TIM1_TRG_COM_TIM11_IRQn),
#endif
#if defined(TIM12)
TIM_ENTRY(12, TIM8_BRK_TIM12_IRQn),
#endif
#if defined(TIM13)
TIM_ENTRY(13, TIM8_UP_TIM13_IRQn),
#endif
#if defined(TIM14)
TIM_ENTRY(14, TIM8_TRG_COM_TIM14_IRQn),
#endif
#if defined(TIM15)
TIM_ENTRY(15, TIM1_BRK_TIM15_IRQn),
#endif
#if defined(TIM16)
TIM_ENTRY(16, TIM1_UP_TIM16_IRQn),
#endif
#if defined(TIM17)
TIM_ENTRY(17, TIM1_TRG_COM_TIM17_IRQn),
#endif
};
#undef TIM_ENTRY

/// \classmethod \constructor(id, ...)
/// Construct a new timer object of the given id. If additional
/// arguments are given, then the timer is initialised by `init(...)`.
Expand All @@ -637,74 +693,30 @@ STATIC mp_obj_t pyb_timer_make_new(const mp_obj_type_t *type, size_t n_args, siz
// check arguments
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);

// create new Timer object
pyb_timer_obj_t *tim = m_new_obj(pyb_timer_obj_t);
memset(tim, 0, sizeof(*tim));

tim->base.type = &pyb_timer_type;
tim->callback = mp_const_none;
tim->channel = NULL;

// get TIM number
tim->tim_id = mp_obj_get_int(args[0]);
tim->is_32bit = false;
// get the timer id
mp_int_t tim_id = mp_obj_get_int(args[0]);

switch (tim->tim_id) {
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
case 1: tim->tim.Instance = TIM1; tim->irqn = TIM1_UP_TIM10_IRQn; break;
#elif defined(MCU_SERIES_L4)
case 1: tim->tim.Instance = TIM1; tim->irqn = TIM1_UP_TIM16_IRQn; break;
#endif
case 2: tim->tim.Instance = TIM2; tim->irqn = TIM2_IRQn; tim->is_32bit = true; break;
case 3: tim->tim.Instance = TIM3; tim->irqn = TIM3_IRQn; break;
case 4: tim->tim.Instance = TIM4; tim->irqn = TIM4_IRQn; break;
case 5: tim->tim.Instance = TIM5; tim->irqn = TIM5_IRQn; tim->is_32bit = true; break;
#if defined(TIM6)
case 6: tim->tim.Instance = TIM6; tim->irqn = TIM6_DAC_IRQn; break;
#endif
#if defined(TIM7)
case 7: tim->tim.Instance = TIM7; tim->irqn = TIM7_IRQn; break;
#endif
#if defined(TIM8)
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
case 8: tim->tim.Instance = TIM8; tim->irqn = TIM8_UP_TIM13_IRQn; break;
#elif defined(MCU_SERIES_L4)
case 8: tim->tim.Instance = TIM8; tim->irqn = TIM8_UP_IRQn; break;
#endif
#endif
#if defined(TIM9)
case 9: tim->tim.Instance = TIM9; tim->irqn = TIM1_BRK_TIM9_IRQn; break;
#endif
#if defined(TIM10)
case 10: tim->tim.Instance = TIM10; tim->irqn = TIM1_UP_TIM10_IRQn; break;
#endif
#if defined(TIM11)
case 11: tim->tim.Instance = TIM11; tim->irqn = TIM1_TRG_COM_TIM11_IRQn; break;
#endif
#if defined(TIM12)
case 12: tim->tim.Instance = TIM12; tim->irqn = TIM8_BRK_TIM12_IRQn; break;
#endif
#if defined(TIM13)
case 13: tim->tim.Instance = TIM13; tim->irqn = TIM8_UP_TIM13_IRQn; break;
#endif
#if defined(TIM14)
case 14: tim->tim.Instance = TIM14; tim->irqn = TIM8_TRG_COM_TIM14_IRQn; break;
#endif
#if defined(TIM15)
case 15: tim->tim.Instance = TIM15; tim->irqn = TIM1_BRK_TIM15_IRQn; break;
#endif
#if defined(TIM16)
case 16: tim->tim.Instance = TIM16; tim->irqn = TIM1_UP_TIM16_IRQn; break;
#endif
#if defined(TIM17)
case 17: tim->tim.Instance = TIM17; tim->irqn = TIM1_TRG_COM_TIM17_IRQn; break;
#endif
default: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Timer(%d) doesn't exist", tim->tim_id));
// check if the timer exists
if (tim_id <= 0 || tim_id > MICROPY_HW_MAX_TIMER || tim_instance_table[tim_id - 1] == 0) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Timer(%d) doesn't exist", tim_id));
}

// set the global variable for interrupt callbacks
if (tim->tim_id - 1 < PYB_TIMER_OBJ_ALL_NUM) {
MP_STATE_PORT(pyb_timer_obj_all)[tim->tim_id - 1] = tim;
pyb_timer_obj_t *tim;
if (MP_STATE_PORT(pyb_timer_obj_all)[tim_id - 1] == NULL) {
// create new Timer object
tim = m_new_obj(pyb_timer_obj_t);
memset(tim, 0, sizeof(*tim));
tim->base.type = &pyb_timer_type;
tim->tim_id = tim_id;
tim->is_32bit = tim_id == 2 || tim_id == 5;
tim->callback = mp_const_none;
uint32_t ti = tim_instance_table[tim_id - 1];
tim->tim.Instance = (TIM_TypeDef*)(ti & 0xffffff00);
tim->irqn = ti & 0xff;
MP_STATE_PORT(pyb_timer_obj_all)[tim_id - 1] = tim;
} else {
// reference existing Timer object
tim = MP_STATE_PORT(pyb_timer_obj_all)[tim_id - 1];
}

if (n_args > 1 || n_kw > 0) {
Expand Down

0 comments on commit d7cd1d2

Please sign in to comment.