Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
TASTE
uPython-mirror
Commits
becbc87f
Commit
becbc87f
authored
Aug 20, 2014
by
Dave Hylands
Browse files
Add Timer support (PWM, OC, IC) for stmhal and teensy
parent
2842945e
Changes
23
Hide whitespace changes
Inline
Side-by-side
stmhal/pin.c
View file @
becbc87f
...
...
@@ -413,7 +413,7 @@ STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *self, mp_uint_t n_args, con
STATIC
mp_obj_t
pin_obj_init
(
mp_uint_t
n_args
,
const
mp_obj_t
*
args
,
mp_map_t
*
kw_args
)
{
return
pin_obj_init_helper
(
args
[
0
],
n_args
-
1
,
args
+
1
,
kw_args
);
}
STATIC
MP_DEFINE_CONST_FUN_OBJ_KW
(
pin_init_obj
,
1
,
pin_obj_init
);
MP_DEFINE_CONST_FUN_OBJ_KW
(
pin_init_obj
,
1
,
pin_obj_init
);
/// \method value([value])
/// Get or set the digital logic level of the pin:
...
...
stmhal/pin.h
View file @
becbc87f
...
...
@@ -82,12 +82,14 @@ extern const mp_obj_type_t pin_cpu_pins_obj_type;
extern
const
mp_obj_dict_t
pin_cpu_pins_locals_dict
;
extern
const
mp_obj_dict_t
pin_board_pins_locals_dict
;
MP_DECLARE_CONST_FUN_OBJ
(
pin_init_obj
);
void
pin_init0
(
void
);
uint32_t
pin_get_mode
(
const
pin_obj_t
*
pin
);
uint32_t
pin_get_pull
(
const
pin_obj_t
*
pin
);
uint32_t
pin_get_af
(
const
pin_obj_t
*
pin
);
const
pin_obj_t
*
pin_find
(
mp_obj_t
user_obj
);
const
pin_obj_t
*
pin_find_named_pin
(
const
mp_obj_dict_t
*
named_pins
,
mp_obj_t
name
);
const
pin_af_obj_t
*
pin_find_af
(
const
pin_obj_t
*
pin
,
uint8_t
fn
,
uint8_t
unit
,
uint8_t
pin_type
);
const
pin_af_obj_t
*
pin_find_af
(
const
pin_obj_t
*
pin
,
uint8_t
fn
,
uint8_t
unit
);
const
pin_af_obj_t
*
pin_find_af_by_index
(
const
pin_obj_t
*
pin
,
mp_uint_t
af_idx
);
const
pin_af_obj_t
*
pin_find_af_by_name
(
const
pin_obj_t
*
pin
,
const
char
*
name
);
stmhal/pin_named_pins.c
View file @
becbc87f
...
...
@@ -64,17 +64,15 @@ const pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t na
return
NULL
;
}
/* unused
const pin_af_obj_t *pin_find_af(const pin_obj_t *pin, uint8_t fn, uint8_t unit, uint8_t type) {
const
pin_af_obj_t
*
pin_find_af
(
const
pin_obj_t
*
pin
,
uint8_t
fn
,
uint8_t
unit
)
{
const
pin_af_obj_t
*
af
=
pin
->
af
;
for
(
mp_uint_t
i
=
0
;
i
<
pin
->
num_af
;
i
++
,
af
++
)
{
if (af->fn == fn && af->unit == unit
&& af->type == type
) {
if
(
af
->
fn
==
fn
&&
af
->
unit
==
unit
)
{
return
af
;
}
}
return
NULL
;
}
*/
const
pin_af_obj_t
*
pin_find_af_by_index
(
const
pin_obj_t
*
pin
,
mp_uint_t
af_idx
)
{
const
pin_af_obj_t
*
af
=
pin
->
af
;
...
...
stmhal/qstrdefsport.h
View file @
becbc87f
...
...
@@ -144,6 +144,9 @@ Q(recv)
// for Timer class
Q
(
Timer
)
Q
(
init
)
Q
(
deinit
)
Q
(
channel
)
Q
(
counter
)
Q
(
prescaler
)
Q
(
period
)
...
...
@@ -151,6 +154,30 @@ Q(callback)
Q
(
freq
)
Q
(
mode
)
Q
(
div
)
Q
(
UP
)
Q
(
DOWN
)
Q
(
CENTER
)
Q
(
IC
)
Q
(
PWM
)
Q
(
PWM_INVERTED
)
Q
(
OC_TIMING
)
Q
(
OC_ACTIVE
)
Q
(
OC_INACTIVE
)
Q
(
OC_TOGGLE
)
Q
(
OC_FORCED_ACTIVE
)
Q
(
OC_FORCED_INACTIVE
)
Q
(
HIGH
)
Q
(
LOW
)
Q
(
RISING
)
Q
(
FALLING
)
Q
(
BOTH
)
// for TimerChannel class
Q
(
TimerChannel
)
Q
(
pulse_width
)
Q
(
compare
)
Q
(
capture
)
Q
(
polarity
)
// for ExtInt class
Q
(
ExtInt
)
...
...
stmhal/timer.c
View file @
becbc87f
...
...
@@ -41,6 +41,7 @@
#include
"runtime.h"
#include
"timer.h"
#include
"servo.h"
#include
"pin.h"
/// \moduleref pyb
/// \class Timer - periodically call a function
...
...
@@ -63,10 +64,10 @@
/// Further examples:
///
/// tim = pyb.Timer(4, freq=100) # freq in Hz
/// tim = pyb.Timer(4, prescaler=
1
, period=
100
)
/// tim = pyb.Timer(4, prescaler=
0
, period=
99
)
/// tim.counter() # get counter (can also set)
/// tim.prescaler(2) # set prescaler (can also get)
/// tim.period(
200
) # set period (can also get)
/// tim.period(
199
) # set period (can also get)
/// tim.callback(lambda t: ...) # set callback for update interrupt (t=tim instance)
/// tim.callback(None) # clear callback
///
...
...
@@ -88,14 +89,59 @@
// TIM6:
// - ADC, DAC for read_timed and write_timed
typedef
enum
{
CHANNEL_MODE_PWM_NORMAL
,
CHANNEL_MODE_PWM_INVERTED
,
CHANNEL_MODE_OC_TIMING
,
CHANNEL_MODE_OC_ACTIVE
,
CHANNEL_MODE_OC_INACTIVE
,
CHANNEL_MODE_OC_TOGGLE
,
CHANNEL_MODE_OC_FORCED_ACTIVE
,
CHANNEL_MODE_OC_FORCED_INACTIVE
,
CHANNEL_MODE_IC
,
}
pyb_channel_mode
;
STATIC
const
struct
{
qstr
name
;
uint32_t
oc_mode
;
}
gChannelMode
[]
=
{
{
MP_QSTR_PWM
,
TIM_OCMODE_PWM1
},
{
MP_QSTR_PWM_INVERTED
,
TIM_OCMODE_PWM2
},
{
MP_QSTR_OC_TIMING
,
TIM_OCMODE_TIMING
},
{
MP_QSTR_OC_ACTIVE
,
TIM_OCMODE_ACTIVE
},
{
MP_QSTR_OC_INACTIVE
,
TIM_OCMODE_INACTIVE
},
{
MP_QSTR_OC_TOGGLE
,
TIM_OCMODE_TOGGLE
},
{
MP_QSTR_OC_FORCED_ACTIVE
,
TIM_OCMODE_FORCED_ACTIVE
},
{
MP_QSTR_OC_FORCED_INACTIVE
,
TIM_OCMODE_FORCED_INACTIVE
},
{
MP_QSTR_IC
,
0
},
};
typedef
struct
_pyb_timer_channel_obj_t
{
mp_obj_base_t
base
;
struct
_pyb_timer_obj_t
*
timer
;
uint8_t
channel
;
uint8_t
mode
;
mp_obj_t
callback
;
struct
_pyb_timer_channel_obj_t
*
next
;
}
pyb_timer_channel_obj_t
;
typedef
struct
_pyb_timer_obj_t
{
mp_obj_base_t
base
;
mp_uint_t
tim_id
;
uint8_t
tim_id
;
uint8_t
is_32bit
;
mp_obj_t
callback
;
TIM_HandleTypeDef
tim
;
IRQn_Type
irqn
;
pyb_timer_channel_obj_t
*
channel
;
}
pyb_timer_obj_t
;
// The following yields TIM_IT_UPDATE when channel is zero and
// TIM_IT_CC1..TIM_IT_CC4 when channel is 1..4
#define TIMER_IRQ_MASK(channel) (1 << (channel))
#define TIMER_CNT_MASK(self) ((self)->is_32bit ? 0x3fffffff : 0xffff)
#define TIMER_CHANNEL(self) ((((self)->channel) - 1) << 2)
TIM_HandleTypeDef
TIM3_Handle
;
TIM_HandleTypeDef
TIM5_Handle
;
TIM_HandleTypeDef
TIM6_Handle
;
...
...
@@ -109,6 +155,7 @@ STATIC pyb_timer_obj_t *pyb_timer_obj_all[14];
STATIC
mp_obj_t
pyb_timer_deinit
(
mp_obj_t
self_in
);
STATIC
mp_obj_t
pyb_timer_callback
(
mp_obj_t
self_in
,
mp_obj_t
callback
);
STATIC
mp_obj_t
pyb_timer_channel_callback
(
mp_obj_t
self_in
,
mp_obj_t
callback
);
void
timer_init0
(
void
)
{
tim3_counter
=
0
;
...
...
@@ -135,7 +182,7 @@ void timer_tim3_init(void) {
TIM3_Handle
.
Instance
=
TIM3
;
TIM3_Handle
.
Init
.
Period
=
(
USBD_CDC_POLLING_INTERVAL
*
1000
)
-
1
;
// TIM3 fires every USBD_CDC_POLLING_INTERVAL ms
TIM3_Handle
.
Init
.
Prescaler
=
84
-
1
;
// for System clock at 168MHz, TIM3 runs at 1MHz
TIM3_Handle
.
Init
.
ClockDivision
=
0
;
TIM3_Handle
.
Init
.
ClockDivision
=
TIM_CLOCKDIVISION_DIV1
;
TIM3_Handle
.
Init
.
CounterMode
=
TIM_COUNTERMODE_UP
;
HAL_TIM_Base_Init
(
&
TIM3_Handle
);
...
...
@@ -167,10 +214,11 @@ void timer_tim5_init(void) {
// PWM clock configuration
TIM5_Handle
.
Instance
=
TIM5
;
TIM5_Handle
.
Init
.
Period
=
2000
;
// timer cycles at 50Hz
TIM5_Handle
.
Init
.
Period
=
2000
-
1
;
// timer cycles at 50Hz
TIM5_Handle
.
Init
.
Prescaler
=
((
SystemCoreClock
/
2
)
/
100000
)
-
1
;
// timer runs at 100kHz
TIM5_Handle
.
Init
.
ClockDivision
=
0
;
TIM5_Handle
.
Init
.
ClockDivision
=
TIM_CLOCKDIVISION_DIV1
;
TIM5_Handle
.
Init
.
CounterMode
=
TIM_COUNTERMODE_UP
;
HAL_TIM_PWM_Init
(
&
TIM5_Handle
);
}
...
...
@@ -194,7 +242,7 @@ void timer_tim6_init(uint freq) {
TIM6_Handle
.
Instance
=
TIM6
;
TIM6_Handle
.
Init
.
Period
=
period
-
1
;
TIM6_Handle
.
Init
.
Prescaler
=
prescaler
-
1
;
TIM6_Handle
.
Init
.
ClockDivision
=
0
;
// unused for TIM6
TIM6_Handle
.
Init
.
ClockDivision
=
TIM_CLOCKDIVISION_DIV1
;
// unused for TIM6
TIM6_Handle
.
Init
.
CounterMode
=
TIM_COUNTERMODE_UP
;
// unused for TIM6
HAL_TIM_Base_Init
(
&
TIM6_Handle
);
}
...
...
@@ -224,13 +272,14 @@ STATIC void pyb_timer_print(void (*print)(void *env, const char *fmt, ...), void
if
(
self
->
tim
.
State
==
HAL_TIM_STATE_RESET
)
{
print
(
env
,
"Timer(%u)"
,
self
->
tim_id
);
}
else
{
print
(
env
,
"Timer(%u, prescaler=%u, period=%u, mode=%
u
, div=%u)"
,
print
(
env
,
"Timer(%u, prescaler=%u, period=%u, mode=%
s
, div=%u)"
,
self
->
tim_id
,
self
->
tim
.
Init
.
Prescaler
,
self
->
tim
.
Init
.
Period
,
self
->
tim
.
Init
.
CounterMode
,
self
->
tim
.
Init
.
ClockDivision
);
self
->
tim
.
Init
.
CounterMode
==
TIM_COUNTERMODE_UP
?
"UP"
:
self
->
tim
.
Init
.
CounterMode
==
TIM_COUNTERMODE_DOWN
?
"DOWN"
:
"CENTER"
,
self
->
tim
.
Init
.
ClockDivision
==
TIM_CLOCKDIVISION_DIV4
?
4
:
self
->
tim
.
Init
.
ClockDivision
==
TIM_CLOCKDIVISION_DIV2
?
2
:
1
);
}
}
...
...
@@ -239,13 +288,45 @@ STATIC void pyb_timer_print(void (*print)(void *env, const char *fmt, ...), void
/// or by prescaler and period:
///
/// tim.init(freq=100) # set the timer to trigger at 100Hz
/// tim.init(prescaler=100, period=300) # set the prescaler and period directly
STATIC
const
mp_arg_t
pyb_timer_init_args
[]
=
{
{
MP_QSTR_freq
,
MP_ARG_KW_ONLY
|
MP_ARG_INT
,
{.
u_int
=
0xffffffff
}
},
{
MP_QSTR_prescaler
,
MP_ARG_KW_ONLY
|
MP_ARG_INT
,
{.
u_int
=
0xffffffff
}
},
{
MP_QSTR_period
,
MP_ARG_KW_ONLY
|
MP_ARG_INT
,
{.
u_int
=
0xffffffff
}
},
{
MP_QSTR_mode
,
MP_ARG_KW_ONLY
|
MP_ARG_INT
,
{.
u_int
=
TIM_COUNTERMODE_UP
}
},
{
MP_QSTR_div
,
MP_ARG_KW_ONLY
|
MP_ARG_INT
,
{.
u_int
=
TIM_CLOCKDIVISION_DIV1
}
},
/// tim.init(prescaler=83, period=999) # set the prescaler and period directly
///
/// Keyword arguments:
///
/// - `freq` - specifies the periodic frequency of the timer. You migh also
/// view this as the frequency with which the timer goes through
/// one complete cycle.
///
/// - `prescaler` [0-0xffff] - specifies the value to be loaded into the
/// timer's Prescaler Register (PSC). The timer clock source is divided by
/// (`prescaler + 1`) to arrive at the timer clock. Timers 2-7 and 12-14
/// have a clock source of 84 MHz (pyb.freq()[2] * 2), and Timers 1, and 8-11
/// have a clock source of 168 MHz (pyb.freq()[3] * 2).
///
/// - `period` [0-0xffff] for timers 1, 3, 4, and 6-15. [0-0x3fffffff] for timers 2 & 5.
/// Specifies the value to be loaded into the timer's AutoReload
/// Register (ARR). This determines the period of the timer (i.e. when the
/// counter cycles). The timer counter will roll-over after `period + 1`
/// timer clock cycles.
///
/// - `mode` can be one of:
/// - `Timer.UP` - configures the timer to count from 0 to ARR (default)
/// - `Timer.DOWN` - configures the timer to count from ARR down to 0.
/// - `Timer.CENTER` - confgures the timer to count from 0 to ARR and
/// then back down to 0.
///
/// - `div` can be one of 1, 2, or 4. Divides the timer clock to determine
/// the sampling clock used by the digital filters.
///
/// - `callback` - as per Timer.callback()
///
/// You must either specify freq or both of period and prescaler.
STATIC
const
mp_arg_t
pyb_timer_init_args
[]
=
{
{
MP_QSTR_freq
,
MP_ARG_KW_ONLY
|
MP_ARG_INT
,
{.
u_int
=
0xffffffff
}
},
{
MP_QSTR_prescaler
,
MP_ARG_KW_ONLY
|
MP_ARG_INT
,
{.
u_int
=
0xffffffff
}
},
{
MP_QSTR_period
,
MP_ARG_KW_ONLY
|
MP_ARG_INT
,
{.
u_int
=
0xffffffff
}
},
{
MP_QSTR_mode
,
MP_ARG_KW_ONLY
|
MP_ARG_INT
,
{.
u_int
=
TIM_COUNTERMODE_UP
}
},
{
MP_QSTR_div
,
MP_ARG_KW_ONLY
|
MP_ARG_INT
,
{.
u_int
=
1
}
},
{
MP_QSTR_callback
,
MP_ARG_KW_ONLY
|
MP_ARG_OBJ
,
{.
u_obj
=
mp_const_none
}
},
};
#define PYB_TIMER_INIT_NUM_ARGS MP_ARRAY_SIZE(pyb_timer_init_args)
...
...
@@ -281,7 +362,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, mp_uint_t n_args, c
// respective APB clock. See DM00031020 Rev 4, page 115.
uint32_t
period
=
MAX
(
1
,
2
*
tim_clock
/
vals
[
0
].
u_int
);
uint32_t
prescaler
=
1
;
while
(
period
>
0xffff
)
{
while
(
period
>
TIMER_CNT_MASK
(
self
)
)
{
period
>>=
1
;
prescaler
<<=
1
;
}
...
...
@@ -296,9 +377,16 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, mp_uint_t n_args, c
}
init
->
CounterMode
=
vals
[
3
].
u_int
;
init
->
ClockDivision
=
vals
[
4
].
u_int
;
init
->
ClockDivision
=
vals
[
4
].
u_int
==
2
?
TIM_CLOCKDIVISION_DIV2
:
vals
[
4
].
u_int
==
4
?
TIM_CLOCKDIVISION_DIV4
:
TIM_CLOCKDIVISION_DIV1
;
init
->
RepetitionCounter
=
0
;
if
(
!
IS_TIM_COUNTER_MODE
(
init
->
CounterMode
))
{
nlr_raise
(
mp_obj_new_exception_msg_varg
(
&
mp_type_ValueError
,
"Invalid counter_mode (%d)"
,
init
->
CounterMode
));
}
// init the TIM peripheral
switch
(
self
->
tim_id
)
{
case
1
:
__TIM1_CLK_ENABLE
();
break
;
...
...
@@ -316,14 +404,18 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, mp_uint_t n_args, c
case
13
:
__TIM13_CLK_ENABLE
();
break
;
case
14
:
__TIM14_CLK_ENABLE
();
break
;
}
HAL_TIM_Base_Init
(
&
self
->
tim
);
HAL_TIM_Base_Start
(
&
self
->
tim
);
// set the priority (if not a special timer)
if
(
self
->
tim_id
!=
3
&&
self
->
tim_id
!=
5
)
{
HAL_NVIC_SetPriority
(
self
->
irqn
,
0xe
,
0xe
);
// next-to lowest priority
}
HAL_TIM_Base_Init
(
&
self
->
tim
);
if
(
vals
[
5
].
u_obj
==
mp_const_none
)
{
HAL_TIM_Base_Start
(
&
self
->
tim
);
}
else
{
pyb_timer_callback
(
self
,
vals
[
5
].
u_obj
);
}
return
mp_const_none
;
}
...
...
@@ -337,19 +429,22 @@ STATIC mp_obj_t pyb_timer_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t
// 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
;
memset
(
&
tim
->
tim
,
0
,
sizeof
(
tim
->
tim
))
;
tim
->
channel
=
NULL
;
// get TIM number
tim
->
tim_id
=
mp_obj_get_int
(
args
[
0
]);
tim
->
is_32bit
=
false
;
switch
(
tim
->
tim_id
)
{
case
1
:
tim
->
tim
.
Instance
=
TIM1
;
tim
->
irqn
=
TIM1_UP_TIM10_IRQn
;
break
;
case
2
:
tim
->
tim
.
Instance
=
TIM2
;
tim
->
irqn
=
TIM2_IRQn
;
break
;
case
2
:
tim
->
tim
.
Instance
=
TIM2
;
tim
->
irqn
=
TIM2_IRQn
;
tim
->
is_32bit
=
true
;
break
;
case
3
:
nlr_raise
(
mp_obj_new_exception_msg
(
&
mp_type_ValueError
,
"Timer 3 is for internal use only"
));
// TIM3 used for low-level stuff; go via regs if necessary
case
4
:
tim
->
tim
.
Instance
=
TIM4
;
tim
->
irqn
=
TIM4_IRQn
;
break
;
case
5
:
tim
->
tim
.
Instance
=
TIM5
;
tim
->
irqn
=
TIM5_IRQn
;
break
;
case
5
:
tim
->
tim
.
Instance
=
TIM5
;
tim
->
irqn
=
TIM5_IRQn
;
tim
->
is_32bit
=
true
;
break
;
case
6
:
tim
->
tim
.
Instance
=
TIM6
;
tim
->
irqn
=
TIM6_DAC_IRQn
;
break
;
case
7
:
tim
->
tim
.
Instance
=
TIM7
;
tim
->
irqn
=
TIM7_IRQn
;
break
;
case
8
:
tim
->
tim
.
Instance
=
TIM8
;
tim
->
irqn
=
TIM8_UP_TIM13_IRQn
;
break
;
...
...
@@ -386,18 +481,261 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_init_obj, 1, pyb_timer_init);
/// Deinitialises the timer.
///
/// Disables the callback (and the associated irq).
/// Disables any channel callbacks (and the associated irq).
/// Stops the timer, and disables the timer peripheral.
STATIC
mp_obj_t
pyb_timer_deinit
(
mp_obj_t
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_channel_obj_t
*
chan
=
self
->
channel
;
self
->
channel
=
NULL
;
// Disable the channel interrupts
while
(
chan
!=
NULL
)
{
pyb_timer_channel_callback
(
chan
,
mp_const_none
);
pyb_timer_channel_obj_t
*
prev_chan
=
chan
;
chan
=
chan
->
next
;
prev_chan
->
next
=
NULL
;
}
HAL_TIM_Base_DeInit
(
&
self
->
tim
);
return
mp_const_none
;
}
STATIC
MP_DEFINE_CONST_FUN_OBJ_1
(
pyb_timer_deinit_obj
,
pyb_timer_deinit
);
/// \method channel(channel, mode, ...)
///
/// If only a channel nunber is passed, then a previously initialized channel
/// object is returned.
///
/// Othwerwise, a TimerChannel object is initialized and returned.
///
/// Each channel can be configured to perform pwm, output compare, or
/// input capture. All channels share the same underlying timer, which means
/// that they share the same timer clock.
///
/// Keyword arguments:
///
/// - `mode` can be one of:
/// - `Timer.PWM` - configure the timer in PWM mode (active high).
/// - `Timer.PWM_INVERTED` - configure the timer in PWM mode (active low).
/// - `Timer.OC_TIMING` - indicates that no pin is driven.
/// - `Timer.OC_ACTIVE` - the pin will be made active when a compare
/// match occurs (active is determined by polarity)
/// - `Timer.OC_INACTIVE` - the pin will be made inactive when a compare
/// match occurs.
/// - `Timer.OC_TOGGLE` - the pin will be toggled when an compare match occurs.
/// - `Timer.OC_FORCED_ACTIVE` - the pin is forced active (compare match is ignored).
/// - `Timer.OC_FORCED_INACTIVE` - the pin is forced inactive (compare match is ignored).
/// - `Timer.IC` - configure the timer in Input Capture mode.
///
/// - `callback` - as per TimerChannel.callback()
///
/// - `pin` None (the default) or a Pin object. If specified (and not None)
/// this will cause the alternate function of the the indicated pin
/// to be configured for this timer channel. An error will be raised if
/// the pin doesn't support any alternate functions for this timer channel.
///
/// Keyword arguments for Timer.PWM modes:
///
/// - 'pulse_width' - determines the initial pulse width to use.
///
/// Keyword arguments for Timer.OC modes:
///
/// - `compare` - determines the initial value of the compare register.
///
/// - `polarity` can be one of:
/// - `Timer.HIGH` - output is active high
/// - `Timer.LOW` - output is acive low
///
/// Optional keyword arguments for Timer.IC modes:
///
/// - `polarity` can be one of:
/// - `Timer.RISING` - captures on rising edge.
/// - `Timer.FALLING` - captures on falling edge.
/// - `Timer.BOTH` - captures on both edges.
///
/// PWM Example:
///
/// timer = pyb.Timer(2, freq=1000)
/// ch2 = timer.channel(2, pyb.Timer.PWM, pin=pyb.Pin.board.X2, pulse_width=210000)
/// ch3 = timer.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width=420000)
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_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_compare
,
MP_ARG_KW_ONLY
|
MP_ARG_INT
,
{.
u_int
=
0
}
},
{
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)
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
-
3
,
3
,
MP_OBJ_FUN_ARGS_MAX
,
true
);
pyb_timer_obj_t
*
self
=
args
[
0
];
mp_int_t
channel
=
mp_obj_get_int
(
args
[
1
]);
if
(
channel
<
1
||
channel
>
4
)
{
nlr_raise
(
mp_obj_new_exception_msg_varg
(
&
mp_type_ValueError
,
"Invalid channel (%d)"
,
channel
));
}
pyb_timer_channel_obj_t
*
chan
=
self
->
channel
;
pyb_timer_channel_obj_t
*
prev_chan
=
NULL
;
while
(
chan
!=
NULL
)
{
if
(
chan
->
channel
==
channel
)
{
break
;
}
prev_chan
=
chan
;
chan
=
chan
->
next
;
}
if
(
kw_args
->
used
==
0
)
{
// Return the previously allocated channel
if
(
chan
)
{
return
chan
;
}
return
mp_const_none
;
}
// If there was already a channel, then remove it from the list. Note that
// the order we do things here is important so as to appear atomic to
// the IRQ handler.
if
(
chan
)
{
// Turn off any IRQ associated with the channel.
pyb_timer_channel_callback
(
chan
,
mp_const_none
);
// Unlink the channel from the list.
if
(
prev_chan
)
{
prev_chan
->
next
=
chan
->
next
;
}
self
->
channel
=
chan
->
next
;
chan
->
next
=
NULL
;
}
// Allocate and initialize a new channel
mp_arg_val_t
vals
[
PYB_TIMER_CHANNEL_NUM_ARGS
];
mp_arg_parse_all
(
n_args
-
3
,
args
+
3
,
kw_args
,
PYB_TIMER_CHANNEL_NUM_ARGS
,
pyb_timer_channel_args
,
vals
);
chan
=
m_new_obj
(
pyb_timer_channel_obj_t
);
memset
(
chan
,
0
,
sizeof
(
*
chan
));
chan
->
base
.
type
=
&
pyb_timer_channel_type
;
chan
->
timer
=
self
;
chan
->
channel
=
channel
;
chan
->
mode
=
mp_obj_get_int
(
args
[
2
]);
chan
->
callback
=
vals
[
0
].
u_obj
;
mp_obj_t
pin_obj
=
vals
[
1
].
u_obj
;
if
(
pin_obj
!=
mp_const_none
)
{
if
(
!
MP_OBJ_IS_TYPE
(
pin_obj
,
&
pin_type
))
{
nlr_raise
(
mp_obj_new_exception_msg
(
&
mp_type_ValueError
,
"pin argument needs to be be a Pin type"
));
}
const
pin_obj_t
*
pin
=
pin_obj
;
const
pin_af_obj_t
*
af
=
pin_find_af
(
pin
,
AF_FN_TIM
,
self
->
tim_id
);
if
(
af
==
NULL
)
{
nlr_raise
(
mp_obj_new_exception_msg_varg
(
&
mp_type_ValueError
,
"pin %s doesn't have an af for TIM%d"
,
qstr_str
(
pin
->
name
),
self
->
tim_id
));
}
// pin.init(mode=AF_PP, af=idx)
const
mp_obj_t
args
[
6
]
=
{
(
mp_obj_t
)
&
pin_init_obj
,
pin_obj
,
MP_OBJ_NEW_QSTR
(
MP_QSTR_mode
),
MP_OBJ_NEW_SMALL_INT
(
GPIO_MODE_AF_PP
),
MP_OBJ_NEW_QSTR
(
MP_QSTR_af
),
MP_OBJ_NEW_SMALL_INT
(
af
->
idx
)
};
mp_call_method_n_kw
(
0
,
2
,
args
);
}
// Link the channel to the timer before we turn the channel on.
// Note that this needs to appear atomic to the IRQ handler (the write
// to self->channel is atomic, so we're good, but I thought I'd mention
// in case this was ever changed in the future).
chan
->
next
=
self
->
channel
;
self
->
channel
=
chan
;
switch
(
chan
->
mode
)
{
case
CHANNEL_MODE_PWM_NORMAL
:
case
CHANNEL_MODE_PWM_INVERTED
:
{
TIM_OC_InitTypeDef
oc_config
;
oc_config
.
OCMode
=
gChannelMode
[
chan
->
mode
].
oc_mode
;
oc_config
.
Pulse
=
vals
[
2
].
u_int
;
oc_config
.
OCPolarity
=
TIM_OCPOLARITY_HIGH
;
oc_config
.
OCNPolarity
=
TIM_OCNPOLARITY_HIGH
;
oc_config
.
OCFastMode
=
TIM_OCFAST_DISABLE
;
oc_config
.
OCIdleState
=
TIM_OCIDLESTATE_SET
;
oc_config
.
OCNIdleState
=
TIM_OCNIDLESTATE_SET
;
HAL_TIM_PWM_ConfigChannel
(
&
self
->
tim
,
&
oc_config
,
TIMER_CHANNEL
(
chan
));
if
(
chan
->
callback
==
mp_const_none
)
{
HAL_TIM_PWM_Start
(
&
self
->
tim
,
TIMER_CHANNEL
(
chan
));
}
else
{
HAL_TIM_PWM_Start_IT
(
&
self
->
tim
,
TIMER_CHANNEL
(
chan
));
}
break
;
}
case
CHANNEL_MODE_OC_TIMING
:
case
CHANNEL_MODE_OC_ACTIVE
:
case
CHANNEL_MODE_OC_INACTIVE
:
case
CHANNEL_MODE_OC_TOGGLE
:
case
CHANNEL_MODE_OC_FORCED_ACTIVE
:
case
CHANNEL_MODE_OC_FORCED_INACTIVE
:
{
TIM_OC_InitTypeDef
oc_config
;
oc_config
.
OCMode
=
gChannelMode
[
chan
->
mode
].
oc_mode
;
oc_config
.
Pulse
=
vals
[
3
].
u_int
;
oc_config
.
OCPolarity
=
vals
[
4
].
u_int
;
if
(
oc_config
.
OCPolarity
==
0xffffffff
)
{
oc_config
.
OCPolarity
=
TIM_OCPOLARITY_HIGH
;
}
oc_config
.
OCNPolarity
=
TIM_OCNPOLARITY_HIGH
;
oc_config
.
OCFastMode
=
TIM_OCFAST_DISABLE
;
oc_config
.
OCIdleState
=
TIM_OCIDLESTATE_SET
;
oc_config
.
OCNIdleState
=
TIM_OCNIDLESTATE_SET
;
if
(
!
IS_TIM_OC_POLARITY
(
oc_config
.
OCPolarity
))
{
nlr_raise
(
mp_obj_new_exception_msg_varg
(
&
mp_type_ValueError
,
"Invalid polarity (%d)"
,
oc_config
.
OCPolarity
));
}
HAL_TIM_OC_ConfigChannel
(
&
self
->
tim
,
&
oc_config
,
TIMER_CHANNEL
(
chan
));
if
(
chan
->
callback
==
mp_const_none
)
{
HAL_TIM_OC_Start
(
&
self
->
tim
,
TIMER_CHANNEL
(
chan
));
}
else
{
HAL_TIM_OC_Start_IT
(
&
self
->
tim
,
TIMER_CHANNEL
(
chan
));
}
break
;
}
case
CHANNEL_MODE_IC
:
{
TIM_IC_InitTypeDef
ic_config
;
ic_config
.
ICPolarity
=
vals
[
4
].
u_int
;
if
(
ic_config
.
ICPolarity
==
0xffffffff
)
{
ic_config
.
ICPolarity
=
TIM_ICPOLARITY_RISING
;
}
ic_config
.
ICSelection
=
TIM_ICSELECTION_DIRECTTI
;
ic_config
.
ICPrescaler
=
TIM_ICPSC_DIV1
;
ic_config
.
ICFilter
=
0
;
if
(
!
IS_TIM_IC_POLARITY
(
ic_config
.
ICPolarity
))
{
nlr_raise
(
mp_obj_new_exception_msg_varg
(
&
mp_type_ValueError
,
"Invalid polarity (%d)"
,
ic_config
.
ICPolarity
));
}
HAL_TIM_IC_ConfigChannel
(
&
self
->
tim
,
&
ic_config
,
TIMER_CHANNEL
(
chan
));
if
(
chan
->
callback
==
mp_const_none
)
{
HAL_TIM_IC_Start
(
&
self
->
tim
,
TIMER_CHANNEL
(
chan
));
}
else
{
HAL_TIM_IC_Start_IT
(
&
self
->
tim
,
TIMER_CHANNEL
(
chan
));
}
break
;
}
default:
nlr_raise
(
mp_obj_new_exception_msg_varg
(
&
mp_type_ValueError
,
"Invalid mode (%d)"
,
chan
->
mode
));
}
return
chan
;
}
STATIC
MP_DEFINE_CONST_FUN_OBJ_KW
(
pyb_timer_channel_obj
,
3
,
pyb_timer_channel
);
/// \method counter([value])
/// Get or set the timer counter.
mp_obj_t
pyb_timer_counter
(
mp_uint_t
n_args
,
const
mp_obj_t
*
args
)
{
...
...
@@ -434,10 +772,10 @@ mp_obj_t pyb_timer_period(mp_uint_t n_args, const mp_obj_t *args) {
pyb_timer_obj_t
*
self
=
args
[
0
];
if
(
n_args
==
1
)
{
// get