servo.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #include <stdio.h>
  2. #include "misc.h"
  3. #include "mpconfig.h"
  4. #include "qstr.h"
  5. #include "nlr.h"
  6. #include "obj.h"
  7. #include "servo.h"
  8. #include "Arduino.h"
  9. #define MAX_SERVOS 12
  10. #define INVALID_SERVO -1
  11. #define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo
  12. #define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo
  13. #define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached
  14. #define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds
  15. #define PDB_CONFIG (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_PDBIE \
  16. | PDB_SC_CONT | PDB_SC_PRESCALER(2) | PDB_SC_MULT(0))
  17. #define PDB_PRESCALE 4
  18. #define usToTicks(us) ((us) * (F_BUS / 1000) / PDB_PRESCALE / 1000)
  19. #define ticksToUs(ticks) ((ticks) * PDB_PRESCALE * 1000 / (F_BUS / 1000))
  20. static uint16_t servo_active_mask = 0;
  21. static uint16_t servo_allocated_mask = 0;
  22. static uint8_t servo_pin[MAX_SERVOS];
  23. static uint16_t servo_ticks[MAX_SERVOS];
  24. typedef struct _pyb_servo_obj_t {
  25. mp_obj_base_t base;
  26. uint servo_id;
  27. uint min_usecs;
  28. uint max_usecs;
  29. } pyb_servo_obj_t;
  30. #define clamp(v, min_val, max_val) ((v) < (min_val) ? (min_val) : (v) > (max_val) ? (max_val) : (v))
  31. static float map_uint_to_float(uint x, uint in_min, uint in_max, float out_min, float out_max)
  32. {
  33. return (float)(x - in_min) * (out_max - out_min) / (float)(in_max - in_min) + (float)out_min;
  34. }
  35. static uint map_float_to_uint(float x, float in_min, float in_max, uint out_min, uint out_max)
  36. {
  37. return (int)((x - in_min) * (float)(out_max - out_min) / (in_max - in_min) + (float)out_min);
  38. }
  39. static mp_obj_t servo_obj_attach(mp_obj_t self_in, mp_obj_t pin_obj) {
  40. pyb_servo_obj_t *self = self_in;
  41. uint pin = mp_obj_get_int(pin_obj);
  42. if (pin > CORE_NUM_DIGITAL) {
  43. goto pin_error;
  44. }
  45. pinMode(pin, OUTPUT);
  46. servo_pin[self->servo_id] = pin;
  47. servo_active_mask |= (1 << self->servo_id);
  48. if (!(SIM_SCGC6 & SIM_SCGC6_PDB)) {
  49. SIM_SCGC6 |= SIM_SCGC6_PDB; // TODO: use bitband for atomic bitset
  50. PDB0_MOD = 0xFFFF;
  51. PDB0_CNT = 0;
  52. PDB0_IDLY = 0;
  53. PDB0_SC = PDB_CONFIG;
  54. // TODO: maybe this should be a higher priority than most
  55. // other interrupts (init all to some default?)
  56. PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG;
  57. }
  58. NVIC_ENABLE_IRQ(IRQ_PDB);
  59. return mp_const_none;
  60. pin_error:
  61. nlr_raise(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "pin %d does not exist", pin));
  62. }
  63. static mp_obj_t servo_obj_detach(mp_obj_t self_in) {
  64. //pyb_servo_obj_t *self = self_in;
  65. return mp_const_none;
  66. }
  67. static mp_obj_t servo_obj_pin(mp_obj_t self_in) {
  68. pyb_servo_obj_t *self = self_in;
  69. return MP_OBJ_NEW_SMALL_INT(servo_pin[self->servo_id]);
  70. }
  71. static mp_obj_t servo_obj_min_usecs(int n_args, const mp_obj_t *args) {
  72. pyb_servo_obj_t *self = args[0];
  73. if (n_args == 1) {
  74. // get min
  75. return MP_OBJ_NEW_SMALL_INT(self->min_usecs);
  76. }
  77. // Set min
  78. self->min_usecs = mp_obj_get_int(args[1]);
  79. return mp_const_none;
  80. }
  81. static mp_obj_t servo_obj_max_usecs(int n_args, const mp_obj_t *args) {
  82. pyb_servo_obj_t *self = args[0];
  83. if (n_args == 1) {
  84. // get max
  85. return MP_OBJ_NEW_SMALL_INT(self->max_usecs);
  86. }
  87. // Set max
  88. self->max_usecs = mp_obj_get_int(args[1]);
  89. return mp_const_none;
  90. }
  91. static mp_obj_t servo_obj_angle(int n_args, const mp_obj_t *args) {
  92. pyb_servo_obj_t *self = args[0];
  93. if (n_args == 1) {
  94. // get
  95. float angle = map_uint_to_float(servo_ticks[self->servo_id],
  96. usToTicks(self->min_usecs),
  97. usToTicks(self->max_usecs),
  98. 0.0, 180.0);
  99. return mp_obj_new_float(angle);
  100. }
  101. // Set
  102. float angle = mp_obj_get_float(args[1]);
  103. if (angle < 0.0F) {
  104. angle = 0.0F;
  105. }
  106. if (angle > 180.0F) {
  107. angle = 180.0F;
  108. }
  109. servo_ticks[self->servo_id] = map_float_to_uint(angle,
  110. 0.0F, 180.0F,
  111. usToTicks(self->min_usecs),
  112. usToTicks(self->max_usecs));
  113. return mp_const_none;
  114. }
  115. static mp_obj_t servo_obj_usecs(int n_args, const mp_obj_t *args) {
  116. pyb_servo_obj_t *self = args[0];
  117. uint usecs;
  118. if (n_args == 1) {
  119. // get
  120. return MP_OBJ_NEW_SMALL_INT(ticksToUs(servo_ticks[self->servo_id]));
  121. }
  122. // Set
  123. usecs = mp_obj_get_int(args[1]);
  124. if (self->min_usecs < self->max_usecs) {
  125. usecs = clamp(usecs, self->min_usecs, self->max_usecs);
  126. } else {
  127. usecs = clamp(usecs, self->max_usecs, self->min_usecs);
  128. }
  129. servo_ticks[self->servo_id] = usToTicks(usecs);
  130. return mp_const_none;
  131. }
  132. static mp_obj_t servo_obj_attached(mp_obj_t self_in) {
  133. pyb_servo_obj_t *self = self_in;
  134. uint attached = (servo_active_mask & (1 << self->servo_id)) != 0;
  135. return MP_OBJ_NEW_SMALL_INT(attached);
  136. }
  137. static void servo_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
  138. pyb_servo_obj_t *self = self_in;
  139. (void)kind;
  140. print(env, "<Servo %lu>", self->servo_id);
  141. }
  142. static MP_DEFINE_CONST_FUN_OBJ_2(servo_obj_attach_obj, servo_obj_attach);
  143. static MP_DEFINE_CONST_FUN_OBJ_1(servo_obj_detach_obj, servo_obj_detach);
  144. static MP_DEFINE_CONST_FUN_OBJ_1(servo_obj_pin_obj, servo_obj_pin);
  145. static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(servo_obj_min_usecs_obj, 1, 2, servo_obj_min_usecs);
  146. static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(servo_obj_max_usecs_obj, 1, 2, servo_obj_max_usecs);
  147. static MP_DEFINE_CONST_FUN_OBJ_1(servo_obj_attached_obj, servo_obj_attached);
  148. static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(servo_obj_angle_obj, 1, 2, servo_obj_angle);
  149. static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(servo_obj_usecs_obj, 1, 2, servo_obj_usecs);
  150. static const mp_method_t servo_methods[] = {
  151. { "attach", &servo_obj_attach_obj },
  152. { "detach", &servo_obj_detach_obj },
  153. { "pin", &servo_obj_pin_obj },
  154. { "min_usecs", &servo_obj_min_usecs_obj },
  155. { "max_usecs", &servo_obj_max_usecs_obj },
  156. { "attached", &servo_obj_attached_obj },
  157. { "angle", &servo_obj_angle_obj },
  158. { "usecs", &servo_obj_usecs_obj },
  159. { NULL, NULL },
  160. };
  161. /*
  162. * Notes:
  163. *
  164. * ISR needs to know pin #, ticks
  165. */
  166. static const mp_obj_type_t servo_obj_type = {
  167. { &mp_type_type },
  168. .name = MP_QSTR_Servo,
  169. .print = servo_obj_print,
  170. .methods = servo_methods,
  171. };
  172. /* servo = pyb.Servo(pin, [min_uecs, [max_usecs]]) */
  173. mp_obj_t pyb_Servo(void) {
  174. uint16_t mask;
  175. pyb_servo_obj_t *self = m_new_obj(pyb_servo_obj_t);
  176. self->base.type = &servo_obj_type;
  177. self->min_usecs = MIN_PULSE_WIDTH;
  178. self->max_usecs = MAX_PULSE_WIDTH;
  179. /* Find an unallocated servo id */
  180. self->servo_id = 0;
  181. for (mask=1; mask < (1<<MAX_SERVOS); mask <<= 1) {
  182. if (!(servo_allocated_mask & mask)) {
  183. servo_allocated_mask |= mask;
  184. servo_active_mask &= ~mask;
  185. servo_ticks[self->servo_id] = usToTicks(DEFAULT_PULSE_WIDTH);
  186. return self;
  187. }
  188. self->servo_id++;
  189. }
  190. m_del_obj(pyb_servo_obj_t, self);
  191. mp_raise_ValueError("No available servo ids");
  192. return mp_const_none;
  193. }
  194. void pdb_isr(void)
  195. {
  196. static int8_t channel = 0, channel_high = MAX_SERVOS;
  197. static uint32_t tick_accum = 0;
  198. uint32_t ticks;
  199. int32_t wait_ticks;
  200. // first, if any channel was left high from the previous
  201. // run, now is the time to shut it off
  202. if (servo_active_mask & (1 << channel_high)) {
  203. digitalWrite(servo_pin[channel_high], LOW);
  204. channel_high = MAX_SERVOS;
  205. }
  206. // search for the next channel to turn on
  207. while (channel < MAX_SERVOS) {
  208. if (servo_active_mask & (1 << channel)) {
  209. digitalWrite(servo_pin[channel], HIGH);
  210. channel_high = channel;
  211. ticks = servo_ticks[channel];
  212. tick_accum += ticks;
  213. PDB0_IDLY += ticks;
  214. PDB0_SC = PDB_CONFIG | PDB_SC_LDOK;
  215. channel++;
  216. return;
  217. }
  218. channel++;
  219. }
  220. // when all channels have output, wait for the
  221. // minimum refresh interval
  222. wait_ticks = usToTicks(REFRESH_INTERVAL) - tick_accum;
  223. if (wait_ticks < usToTicks(100)) wait_ticks = usToTicks(100);
  224. else if (wait_ticks > 60000) wait_ticks = 60000;
  225. tick_accum += wait_ticks;
  226. PDB0_IDLY += wait_ticks;
  227. PDB0_SC = PDB_CONFIG | PDB_SC_LDOK;
  228. // if this wait is enough to satisfy the refresh
  229. // interval, next time begin again at channel zero
  230. if (tick_accum >= usToTicks(REFRESH_INTERVAL)) {
  231. tick_accum = 0;
  232. channel = 0;
  233. }
  234. }