blob: 1be18b8a4e2824acaf99f45afbca320b43989a4e [file] [log] [blame]
Damien George626f6b82014-03-22 15:52:33 +00001#include <stdio.h>
2
3#include "stm32f4xx_hal.h"
4
5#include "misc.h"
6#include "mpconfig.h"
7#include "qstr.h"
8#include "obj.h"
9#include "servo.h"
10
11// this servo driver uses hardware PWM to drive servos on PA0, PA1, PA2, PA3 = X1, X2, X3, X4
12// TIM2 and TIM5 have CH1, CH2, CH3, CH4 on PA0-PA3 respectively
13// they are both 32-bit counters with 16-bit prescaler
14// we use TIM2
15
16STATIC TIM_HandleTypeDef servo_TimHandle;
17
18void servo_init(void) {
19 // TIM2 clock enable
20 __TIM2_CLK_ENABLE();
21
22 // 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);
29}
30
31STATIC void servo_init_channel(int channel_in) {
32 uint32_t pin;
33 uint32_t channel;
34 switch (channel_in) {
35 case 1: pin = GPIO_PIN_0; channel = TIM_CHANNEL_1; break;
36 case 2: pin = GPIO_PIN_1; channel = TIM_CHANNEL_2; break;
37 case 3: pin = GPIO_PIN_2; channel = TIM_CHANNEL_3; break;
38 case 4: pin = GPIO_PIN_3; channel = TIM_CHANNEL_4; break;
39 default: return;
40 }
41
42 // GPIO configuration
43 GPIO_InitTypeDef GPIO_InitStructure;
44 GPIO_InitStructure.Pin = pin;
45 GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
46 GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
47 GPIO_InitStructure.Pull = GPIO_NOPULL;
48 GPIO_InitStructure.Alternate = GPIO_AF1_TIM2;
49 HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
50
51 // PWM mode configuration
52 TIM_OC_InitTypeDef oc_init;
53 oc_init.OCMode = TIM_OCMODE_PWM1;
54 oc_init.Pulse = 150; // units of 10us
55 oc_init.OCPolarity = TIM_OCPOLARITY_HIGH;
56 oc_init.OCFastMode = TIM_OCFAST_DISABLE;
57 HAL_TIM_PWM_ConfigChannel(&servo_TimHandle, &oc_init, channel);
58
59 // start PWM
60 HAL_TIM_PWM_Start(&servo_TimHandle, channel);
61}
62
63/******************************************************************************/
64// Micro Python bindings
65
66STATIC mp_obj_t pyb_servo_set(mp_obj_t port, mp_obj_t value) {
67 int p = mp_obj_get_int(port);
68 int v = mp_obj_get_int(value);
69 if (v < 50) { v = 50; }
70 if (v > 250) { v = 250; }
71 switch (p) {
72 case 1: TIM2->CCR1 = v; break;
73 case 2: TIM2->CCR2 = v; break;
74 case 3: TIM2->CCR3 = v; break;
75 case 4: TIM2->CCR4 = v; break;
76 }
77 return mp_const_none;
78}
79
80MP_DEFINE_CONST_FUN_OBJ_2(pyb_servo_set_obj, pyb_servo_set);
81
82STATIC mp_obj_t pyb_pwm_set(mp_obj_t period, mp_obj_t pulse) {
83 int pe = mp_obj_get_int(period);
84 int pu = mp_obj_get_int(pulse);
85 TIM2->ARR = pe;
86 TIM2->CCR3 = pu;
87 return mp_const_none;
88}
89
90MP_DEFINE_CONST_FUN_OBJ_2(pyb_pwm_set_obj, pyb_pwm_set);
91
92typedef struct _pyb_servo_obj_t {
93 mp_obj_base_t base;
94 uint servo_id;
95} pyb_servo_obj_t;
96
97STATIC void servo_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
98 pyb_servo_obj_t *self = self_in;
99 print(env, "<Servo %lu>", self->servo_id);
100}
101
102STATIC mp_obj_t servo_obj_angle(mp_obj_t self_in, mp_obj_t angle) {
103 pyb_servo_obj_t *self = self_in;
104#if MICROPY_ENABLE_FLOAT
105 machine_int_t v = 152 + 85.0 * mp_obj_get_float(angle) / 90.0;
106#else
107 machine_int_t v = 152 + 85 * mp_obj_get_int(angle) / 90;
108#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;
116 }
117 return mp_const_none;
118}
119
120STATIC MP_DEFINE_CONST_FUN_OBJ_2(servo_obj_angle_obj, servo_obj_angle);
121
122STATIC const mp_method_t servo_methods[] = {
123 { "angle", &servo_obj_angle_obj },
124 { NULL, NULL },
125};
126
127STATIC const mp_obj_type_t servo_obj_type = {
128 { &mp_type_type },
129 .name = MP_QSTR_Servo,
130 .print = servo_obj_print,
131 .methods = servo_methods,
132};
133
134STATIC 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;
140}
141
142MP_DEFINE_CONST_FUN_OBJ_1(pyb_Servo_obj, pyb_Servo);