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
e8ea0724
Commit
e8ea0724
authored
Sep 25, 2014
by
Damien George
Browse files
stmhal, timer: Factor code to compute PWM percent; improve 32bit case.
Also do the same for teensy timer code.
parent
3fafe730
Changes
2
Hide whitespace changes
Inline
Side-by-side
stmhal/timer.c
View file @
e8ea0724
...
...
@@ -139,7 +139,7 @@ typedef struct _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 ? 0x
3
fffffff : 0xffff)
#define TIMER_CNT_MASK(self) ((self)->is_32bit ? 0x
f
fffffff : 0xffff)
#define TIMER_CHANNEL(self) ((((self)->channel) - 1) << 2)
TIM_HandleTypeDef
TIM3_Handle
;
...
...
@@ -268,6 +268,37 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
STATIC
const
mp_obj_type_t
pyb_timer_channel_type
;
// Helper function to compute PWM value from timer period and percent value.
// 'val' can be an int or a float between 0 and 100 (out of range values are
// clamped).
STATIC
uint32_t
compute_pwm_value_from_percent
(
uint32_t
period
,
mp_obj_t
val
)
{
uint32_t
cmp
;
if
(
0
)
{
#if MICROPY_PY_BUILTINS_FLOAT
}
else
if
(
MP_OBJ_IS_TYPE
(
val
,
&
mp_type_float
))
{
cmp
=
mp_obj_get_float
(
val
)
/
100
.
0
*
period
;
#endif
}
else
{
// For integer arithmetic, if period is large and 100*period will
// overflow, then divide period before multiplying by cmp. Otherwise
// do it the other way round to retain precision.
// TODO we really need an mp_obj_get_uint_clamped function here so
// that we can get long-int values as large as 0xffffffff.
cmp
=
mp_obj_get_int
(
val
);
if
(
period
>
(
1
<<
31
)
/
100
)
{
cmp
=
cmp
*
(
period
/
100
);
}
else
{
cmp
=
(
cmp
*
period
)
/
100
;
}
}
if
(
cmp
<
0
)
{
cmp
=
0
;
}
else
if
(
cmp
>
period
)
{
cmp
=
period
;
}
return
cmp
;
}
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
;
...
...
@@ -568,7 +599,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
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
xffffffff
}
},
{
MP_QSTR_pulse_width
,
MP_ARG_KW_ONLY
|
MP_ARG_INT
,
{.
u_int
=
0
}
},
{
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_polarity
,
MP_ARG_KW_ONLY
|
MP_ARG_INT
,
{.
u_int
=
0xffffffff
}
},
...
...
@@ -663,30 +694,19 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *args, mp_map
case
CHANNEL_MODE_PWM_INVERTED
:
{
TIM_OC_InitTypeDef
oc_config
;
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
;
}
else
if
(
vals
[
3
].
u_obj
!=
mp_const_none
)
{
if
(
vals
[
3
].
u_obj
!=
mp_const_none
)
{
// pulse width percent given
uint32_t
period
=
(
__HAL_TIM_GetAutoreload
(
&
self
->
tim
)
&
TIMER_CNT_MASK
(
self
))
+
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
;
// For 32-bit timer, maximum period + 1 will overflow. In that
// case we set the period back to 0xffffffff which will give very
// close to the correct result for the percentage calculation.
if
(
period
==
0
)
{
period
=
0xffffffff
;
}
oc_config
.
Pulse
=
cmp
;
oc_config
.
Pulse
=
c
o
mp
ute_pwm_value_from_percent
(
period
,
vals
[
3
].
u_obj
)
;
}
else
{
//
nothing given,
default to
pulse width of 0
oc_config
.
Pulse
=
0
;
//
use absolute pulse width value (
default
s
to
0 if nothing given)
oc_config
.
Pulse
=
vals
[
2
].
u_int
;
}
oc_config
.
OCPolarity
=
TIM_OCPOLARITY_HIGH
;
oc_config
.
OCNPolarity
=
TIM_OCNPOLARITY_HIGH
;
...
...
@@ -910,38 +930,33 @@ STATIC mp_obj_t pyb_timer_channel_capture_compare(mp_uint_t n_args, const mp_obj
}
STATIC
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN
(
pyb_timer_channel_capture_compare_obj
,
1
,
2
,
pyb_timer_channel_capture_compare
);
/// \method pulse_width_ratio([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.
/// \method pulse_width_percent([value])
/// Get or set the pulse width percentage associated with a channel. The value
/// is a number between 0 and 100 and sets the percentage of the timer period
/// for which the pulse is active. The value can be an integer or
/// floating-point number for more accuracy. For example, a value of 25 gives
/// a duty cycle of 25%.
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
];
uint32_t
period
=
(
__HAL_TIM_GetAutoreload
(
&
self
->
timer
->
tim
)
&
TIMER_CNT_MASK
(
self
->
timer
))
+
1
;
// For 32-bit timer, maximum period + 1 will overflow. In that case we set
// the period back to 0xffffffff which will give very close to the correct
// result for the percentage calculation.
if
(
period
==
0
)
{
period
=
0xffffffff
;
}
if
(
n_args
==
1
)
{
// get
uint32_t
cmp
=
__HAL_TIM_GetCompare
(
&
self
->
timer
->
tim
,
TIMER_CHANNEL
(
self
))
&
TIMER_CNT_MASK
(
self
->
timer
);
#if MICROPY_PY_BUILTINS_FLOAT
return
mp_obj_new_float
((
float
)
cmp
*
100
.
0
/
(
float
)
period
);
#else
#if MICROPY_PY_BUILTINS_FLOAT
return
mp_obj_new_float
((
float
)
cmp
/
(
float
)
period
*
100
.
0
);
#else
// TODO handle overflow of multiplication for 32-bit timer
return
mp_obj_new_int
(
cmp
*
100
/
period
);
#endif
#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
;
}
uint32_t
cmp
=
compute_pwm_value_from_percent
(
period
,
args
[
1
]);
__HAL_TIM_SetCompare
(
&
self
->
timer
->
tim
,
TIMER_CHANNEL
(
self
),
cmp
&
TIMER_CNT_MASK
(
self
->
timer
));
return
mp_const_none
;
}
...
...
teensy/timer.c
View file @
e8ea0724
...
...
@@ -128,6 +128,37 @@ mp_uint_t get_prescaler_shift(mp_int_t prescaler) {
STATIC
const
mp_obj_type_t
pyb_timer_channel_type
;
// Helper function to compute PWM value from timer period and percent value.
// 'val' can be an int or a float between 0 and 100 (out of range values are
// clamped).
STATIC
uint32_t
compute_pwm_value_from_percent
(
uint32_t
period
,
mp_obj_t
val
)
{
uint32_t
cmp
;
if
(
0
)
{
#if MICROPY_PY_BUILTINS_FLOAT
}
else
if
(
MP_OBJ_IS_TYPE
(
val
,
&
mp_type_float
))
{
cmp
=
mp_obj_get_float
(
val
)
/
100
.
0
*
period
;
#endif
}
else
{
// For integer arithmetic, if period is large and 100*period will
// overflow, then divide period before multiplying by cmp. Otherwise
// do it the other way round to retain precision.
// TODO we really need an mp_obj_get_uint_clamped function here so
// that we can get long-int values as large as 0xffffffff.
cmp
=
mp_obj_get_int
(
val
);
if
(
period
>
(
1
<<
31
)
/
100
)
{
cmp
=
cmp
*
(
period
/
100
);
}
else
{
cmp
=
(
cmp
*
period
)
/
100
;
}
}
if
(
cmp
<
0
)
{
cmp
=
0
;
}
else
if
(
cmp
>
period
)
{
cmp
=
period
;
}
return
cmp
;
}
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
;
...
...
@@ -373,7 +404,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
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
xffffffff
}
},
{
MP_QSTR_pulse_width
,
MP_ARG_KW_ONLY
|
MP_ARG_INT
,
{.
u_int
=
0
}
},
{
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_polarity
,
MP_ARG_KW_ONLY
|
MP_ARG_INT
,
{.
u_int
=
0xffffffff
}
},
...
...
@@ -468,30 +499,13 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *args, mp_map
case
CHANNEL_MODE_PWM_INVERTED
:
{
FTM_OC_InitTypeDef
oc_config
;
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
;
}
else
if
(
vals
[
3
].
u_obj
!=
mp_const_none
)
{
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
;
oc_config
.
Pulse
=
compute_pwm_value_from_percent
(
period
,
vals
[
3
].
u_obj
);
}
else
{
//
nothing given,
default to
pulse width of 0
oc_config
.
Pulse
=
0
;
//
use absolute pulse width value (
default
s
to
0 if nothing given)
oc_config
.
Pulse
=
vals
[
2
].
u_int
;
}
oc_config
.
OCPolarity
=
FTM_OCPOLARITY_HIGH
;
...
...
@@ -748,10 +762,11 @@ STATIC mp_obj_t pyb_timer_channel_capture_compare(mp_uint_t n_args, const mp_obj
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.
/// Get or set the pulse width percentage associated with a channel. The value
/// is a number between 0 and 100 and sets the percentage of the timer period
/// for which the pulse is active. The value can be an integer or
/// floating-point number for more accuracy. For example, a value of 25 gives
/// a duty cycle of 25%.
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
;
...
...
@@ -759,27 +774,14 @@ STATIC mp_obj_t pyb_timer_channel_pulse_width_percent(mp_uint_t n_args, const mp
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
#if MICROPY_PY_BUILTINS_FLOAT
return
mp_obj_new_float
((
float
)
cmp
/
(
float
)
period
*
100
.
0
);
#else
return
mp_obj_new_int
(
cmp
*
100
/
period
);
#endif
#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
;
}
uint32_t
cmp
=
compute_pwm_value_from_percent
(
period
,
args
[
1
]);
FTMx
->
channel
[
self
->
channel
].
CV
=
cmp
&
0xffff
;
return
mp_const_none
;
}
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment