22
33#include "stm32f4xx_hal.h"
44
5+ #include "nlr.h"
56#include "misc.h"
67#include "mpconfig.h"
78#include "qstr.h"
1314// they are both 32-bit counters with 16-bit prescaler
1415// we use TIM2
1516
16- STATIC TIM_HandleTypeDef servo_TimHandle ;
17+ #define PYB_SERVO_NUM (4)
18+
19+ typedef struct _pyb_servo_obj_t {
20+ mp_obj_base_t base ;
21+ uint16_t servo_id ;
22+ uint16_t time_left ;
23+ int16_t pulse_accum ;
24+ uint16_t pulse_cur ;
25+ uint16_t pulse_dest ;
26+ } pyb_servo_obj_t ;
27+
28+ STATIC const mp_obj_type_t servo_obj_type ;
29+
30+ STATIC pyb_servo_obj_t pyb_servo_obj [PYB_SERVO_NUM ];
31+
32+ TIM_HandleTypeDef servo_TIM2_Handle ;
1733
1834void servo_init (void ) {
1935 // TIM2 clock enable
2036 __TIM2_CLK_ENABLE ();
2137
38+ // set up and enable interrupt
39+ HAL_NVIC_SetPriority (TIM2_IRQn , 6 , 0 );
40+ HAL_NVIC_EnableIRQ (TIM2_IRQn );
41+
2242 // PWM clock configuration
23- servo_TimHandle .Instance = TIM2 ;
24- servo_TimHandle .Init .Period = 2000 ; // timer cycles at 50Hz
25- servo_TimHandle .Init .Prescaler = ((SystemCoreClock / 2 ) / 100000 ) - 1 ; // timer runs at 100kHz
26- servo_TimHandle .Init .ClockDivision = 0 ;
27- servo_TimHandle .Init .CounterMode = TIM_COUNTERMODE_UP ;
28- HAL_TIM_PWM_Init (& servo_TimHandle );
43+ servo_TIM2_Handle .Instance = TIM2 ;
44+ servo_TIM2_Handle .Init .Period = 2000 ; // timer cycles at 50Hz
45+ servo_TIM2_Handle .Init .Prescaler = ((SystemCoreClock / 2 ) / 100000 ) - 1 ; // timer runs at 100kHz
46+ servo_TIM2_Handle .Init .ClockDivision = 0 ;
47+ servo_TIM2_Handle .Init .CounterMode = TIM_COUNTERMODE_UP ;
48+ HAL_TIM_PWM_Init (& servo_TIM2_Handle );
49+
50+ // reset servo objects
51+ for (int i = 0 ; i < PYB_SERVO_NUM ; i ++ ) {
52+ pyb_servo_obj [i ].base .type = & servo_obj_type ;
53+ pyb_servo_obj [i ].servo_id = i + 1 ;
54+ pyb_servo_obj [i ].time_left = 0 ;
55+ pyb_servo_obj [i ].pulse_cur = 150 ; // units of 10us
56+ pyb_servo_obj [i ].pulse_dest = 0 ;
57+ }
58+ }
59+
60+ #include "led.h"
61+ void servo_timer_irq_callback (void ) {
62+ led_toggle (1 );
63+ bool need_it = false;
64+ for (int i = 0 ; i < PYB_SERVO_NUM ; i ++ ) {
65+ pyb_servo_obj_t * s = & pyb_servo_obj [i ];
66+ if (s -> pulse_cur != s -> pulse_dest ) {
67+ if (s -> time_left <= 1 ) {
68+ s -> pulse_cur = s -> pulse_dest ;
69+ s -> time_left = 0 ;
70+ } else {
71+ s -> pulse_accum += s -> pulse_dest - s -> pulse_cur ;
72+ s -> pulse_cur += s -> pulse_accum / s -> time_left ;
73+ s -> pulse_accum %= s -> time_left ;
74+ s -> time_left -- ;
75+ need_it = true;
76+ }
77+ switch (s -> servo_id ) {
78+ case 1 : TIM2 -> CCR1 = s -> pulse_cur ; break ;
79+ case 2 : TIM2 -> CCR2 = s -> pulse_cur ; break ;
80+ case 3 : TIM2 -> CCR3 = s -> pulse_cur ; break ;
81+ case 4 : TIM2 -> CCR4 = s -> pulse_cur ; break ;
82+ }
83+ }
84+ }
85+ if (need_it ) {
86+ __HAL_TIM_ENABLE_IT (& servo_TIM2_Handle , TIM_IT_UPDATE );
87+ } else {
88+ __HAL_TIM_DISABLE_IT (& servo_TIM2_Handle , TIM_IT_UPDATE );
89+ }
2990}
3091
31- STATIC void servo_init_channel (int channel_in ) {
92+ STATIC void servo_init_channel (pyb_servo_obj_t * s ) {
3293 uint32_t pin ;
3394 uint32_t channel ;
34- switch (channel_in ) {
95+ switch (s -> servo_id ) {
3596 case 1 : pin = GPIO_PIN_0 ; channel = TIM_CHANNEL_1 ; break ;
3697 case 2 : pin = GPIO_PIN_1 ; channel = TIM_CHANNEL_2 ; break ;
3798 case 3 : pin = GPIO_PIN_2 ; channel = TIM_CHANNEL_3 ; break ;
@@ -51,13 +112,13 @@ STATIC void servo_init_channel(int channel_in) {
51112 // PWM mode configuration
52113 TIM_OC_InitTypeDef oc_init ;
53114 oc_init .OCMode = TIM_OCMODE_PWM1 ;
54- oc_init .Pulse = 150 ; // units of 10us
115+ oc_init .Pulse = s -> pulse_cur ; // units of 10us
55116 oc_init .OCPolarity = TIM_OCPOLARITY_HIGH ;
56117 oc_init .OCFastMode = TIM_OCFAST_DISABLE ;
57- HAL_TIM_PWM_ConfigChannel (& servo_TimHandle , & oc_init , channel );
118+ HAL_TIM_PWM_ConfigChannel (& servo_TIM2_Handle , & oc_init , channel );
58119
59120 // start PWM
60- HAL_TIM_PWM_Start (& servo_TimHandle , channel );
121+ HAL_TIM_PWM_Start (& servo_TIM2_Handle , channel );
61122}
62123
63124/******************************************************************************/
@@ -89,35 +150,39 @@ STATIC mp_obj_t pyb_pwm_set(mp_obj_t period, mp_obj_t pulse) {
89150
90151MP_DEFINE_CONST_FUN_OBJ_2 (pyb_pwm_set_obj , pyb_pwm_set );
91152
92- typedef struct _pyb_servo_obj_t {
93- mp_obj_base_t base ;
94- uint servo_id ;
95- } pyb_servo_obj_t ;
96-
97153STATIC void servo_obj_print (void (* print )(void * env , const char * fmt , ...), void * env , mp_obj_t self_in , mp_print_kind_t kind ) {
98154 pyb_servo_obj_t * self = self_in ;
99- print (env , "<Servo %lu>" , self -> servo_id );
155+ print (env , "<Servo %lu at %lu >" , self -> servo_id , self -> pulse_cur );
100156}
101157
102- STATIC mp_obj_t servo_obj_angle (mp_obj_t self_in , mp_obj_t angle ) {
103- pyb_servo_obj_t * self = self_in ;
158+ STATIC mp_obj_t servo_obj_angle (uint n_args , const mp_obj_t * args ) {
159+ pyb_servo_obj_t * self = args [0 ];
160+ if (n_args == 1 ) {
161+ // get angle
162+ return mp_obj_new_int ((self -> pulse_cur - 152 ) * 90 / 85 );
163+ } else {
104164#if MICROPY_ENABLE_FLOAT
105- machine_int_t v = 152 + 85.0 * mp_obj_get_float (angle ) / 90.0 ;
165+ machine_int_t v = 152 + 85.0 * mp_obj_get_float (args [ 1 ] ) / 90.0 ;
106166#else
107- machine_int_t v = 152 + 85 * mp_obj_get_int (angle ) / 90 ;
167+ machine_int_t v = 152 + 85 * mp_obj_get_int (args [ 1 ] ) / 90 ;
108168#endif
109- if (v < 65 ) { v = 65 ; }
110- if (v > 210 ) { v = 210 ; }
111- switch (self -> servo_id ) {
112- case 1 : TIM2 -> CCR1 = v ; break ;
113- case 2 : TIM2 -> CCR2 = v ; break ;
114- case 3 : TIM2 -> CCR3 = v ; break ;
115- case 4 : TIM2 -> CCR4 = v ; break ;
169+ if (v < 65 ) { v = 65 ; }
170+ if (v > 210 ) { v = 210 ; }
171+ self -> pulse_dest = v ;
172+ if (n_args == 2 ) {
173+ // set angle immediately
174+ self -> time_left = 0 ;
175+ } else {
176+ // set angle over a given time (given in milli seconds)
177+ self -> time_left = mp_obj_get_int (args [2 ]) / 20 ;
178+ self -> pulse_accum = 0 ;
179+ }
180+ servo_timer_irq_callback ();
181+ return mp_const_none ;
116182 }
117- return mp_const_none ;
118183}
119184
120- STATIC MP_DEFINE_CONST_FUN_OBJ_2 (servo_obj_angle_obj , servo_obj_angle );
185+ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (servo_obj_angle_obj , 1 , 3 , servo_obj_angle );
121186
122187STATIC const mp_method_t servo_methods [] = {
123188 { "angle" , & servo_obj_angle_obj },
@@ -131,12 +196,17 @@ STATIC const mp_obj_type_t servo_obj_type = {
131196 .methods = servo_methods ,
132197};
133198
134- STATIC mp_obj_t pyb_Servo (mp_obj_t servo_id ) {
135- pyb_servo_obj_t * o = m_new_obj (pyb_servo_obj_t );
136- o -> base .type = & servo_obj_type ;
137- o -> servo_id = mp_obj_get_int (servo_id );
138- servo_init_channel (o -> servo_id );
139- return o ;
199+ STATIC mp_obj_t pyb_Servo (mp_obj_t servo_id_o ) {
200+ machine_int_t servo_id = mp_obj_get_int (servo_id_o ) - 1 ;
201+ if (0 <= servo_id && servo_id < PYB_SERVO_NUM ) {
202+ pyb_servo_obj_t * s = & pyb_servo_obj [servo_id ];
203+ s -> pulse_dest = s -> pulse_cur ;
204+ s -> time_left = 0 ;
205+ servo_init_channel (s );
206+ return s ;
207+ } else {
208+ nlr_jump (mp_obj_new_exception_msg_varg (& mp_type_ValueError , "Servo %d does not exist" , servo_id ));
209+ }
140210}
141211
142212MP_DEFINE_CONST_FUN_OBJ_1 (pyb_Servo_obj , pyb_Servo );
0 commit comments