PropWare  3.0.0.229
C++ objects and CMake build system for Parallax Propeller
servo.c
1 /*
2  * @file servo.c
3  *
4  * @author Andy Lindsay
5  *
6  * @version 0.9
7  *
8  * @copyright Copyright (C) Parallax, Inc. 2012. See end of file for
9  * terms of use (MIT License).
10  *
11  * @brief Manages control of up to 14 servos using another CMM/LMM cog.
12  *
13  * Please submit bug reports, suggestions, and improvements to
14  * this code to editor@parallax.com.
15  */
16 
17 
18 #include "simpletools.h"
19 #include "servo.h"
20 
21 
22 static void pulse_outCtr(int pin, int time); // pulseOut function definition
23 static int servo_start(void); // Function prototype for servo_start
24 static void servo(void *par); // Function prototype for servo
25 
26 
27 static volatile unsigned int servoCog = 0; // Cog initialozed to zero
28 static volatile unsigned int lockID; // Lock ID
29 static unsigned int stack[44 + 24]; // Stack
30 
31 static volatile int p[14] = {-1, -1, -1, -1, // I/O pins
32  -1, -1, -1, -1, -1, -1,
33  -1, -1, -1, -1};
34 static volatile int t[14] = {-1, -1, -1, -1, // Current iteration pulse widths
35  -1, -1, -1, -1, -1, -1,
36  -1, -1, -1, -1};
37 static volatile int tp[14] = {-1, -1, -1, -1, // Previous iteration pulse widths
38  -1, -1, -1, -1, -1, -1,
39  -1, -1, -1, -1};
40 static volatile int r[14] = {2000, 2000, 2000, 2000, // Step sizes initialized to 2000
41  2000, 2000, 2000, 2000, 2000,
42  2000, 2000, 2000, 2000, 2000};
43 
44 
45 int servo_angle(int pin, int degreeTenths) // Set continuous rotation speed
46 {
47  return servo_set(pin, degreeTenths + 500); // Add center pulse width to speed
48 }
49 
50 
51 int servo_speed(int pin, int speed) // Set continuous rotation speed
52 {
53  return servo_set(pin, speed + 1500); // Add center pulse width to speed
54 }
55 
56 
57 int servo_set(int pin, int time) // Set pulse width to servo on pin
58 {
59  if(servoCog == 0) // If cog not started
60  {
61  int result = servo_start(); // Start the cog
62  if(result == 0) return -1; // No cogs open
63  if(result == -1) return -2; // No locks open
64  }
65  int s = sizeof(p)/sizeof(int); // Array size to s
66  int i; // Index variable
67  while(lockset(lockID)); // Set the lock
68  for(i = 0; i < s; i++) // Check if existing servo
69  {
70  if(p[i] == pin) // Yes?
71  {
72  t[i] = time; // Set pulse duration
73  lockclr(lockID); // Clear lock
74  return 1; // Return success
75  }
76  }
77  for(i= 0; i < s; i++) // Look for empty slot
78  {
79  if(p[i]==-1) // Found one?
80  {
81  break; // Exit for loop, keep index
82  }
83  }
84  if(i < s) // Found empty slot?
85  {
86  p[i] = pin; // Set up pin and pulse durations
87  t[i] = time;
88  tp[i] = time;
89  lockclr(lockID); // Clear the lock
90  return pin; // Return success
91  }
92  else // servo not found, no empty slots?
93  {
94  lockclr(lockID); // Clear lock
95  return -3; // Return, no pins
96  }
97 }
98 
99 
100 int servo_setramp(int pin, int stepSize) // Set ramp step for a servo
101 {
102  int s = sizeof(p)/sizeof(int); // Get array size
103  int i; // Local index variable
104  while(lockset(lockID)); // Set lock
105  for(i = 0; i < s; i++) // Find index for servo pin
106  {
107  if(p[i] == pin) // Found pin in array?
108  {
109  r[i] = stepSize; // Set ramp step
110  lockclr(lockID); // Clear lock
111  return pin; // Return success
112  }
113  }
114  lockclr(lockID); // Clear lock
115  return -4; // Return -1, pin not found
116 }
117 
118 
119 int servo_get(int pin) // Get servo position
120 {
121  int s = sizeof(p)/sizeof(int); // Get size of servo arrays
122  int i; // Declare local index
123  for(i = 0; i < s; i++) // Look for matching pin in array
124  {
125  if(p[i] == pin) // Found matching pin?
126  {
127  return tp[i]; // Return associated pulse time
128  }
129  }
130  return -4; // No pin match? Return -4
131 }
132 
133 
134 int servo_disable(int pin)
135 {
136  // 0 to time param causes servo funciton running
137  // in the other cog to disable the servo
138  int result = servo_set(pin, 0);
139  return result;
140 }
141 
142 
143 static void servo(void *par) // servo process in other cog
144 {
145  int dtpw = (CLKFREQ/1000000)*2500;
146  int pw = CNT;
147 
148  int dtTw = (CLKFREQ/1000000)*20000;
149  int Tw = pw;
150  Tw += dtTw;
151 
152  int s = sizeof(p)/sizeof(int); // Get size of servo array
153  int i; // Local index variable
154  while(1) // servo control loop
155  {
156  while(lockset(lockID)); // Set the lock
157  for(i = 0; i < s; i++) // Go through all possible servos
158  {
159  if(t[i] == 0) // Detach servo?
160  {
161  input(p[i]); // Set I/O pin to input
162  p[i] = -1; // Remove from list
163  t[i] = -1;
164  tp[i] = -1;
165  r[i] = 2000;
166  }
167  if(p[i] != -1) // If servo entry in pin array
168  {
169  int tPulse = t[i]; // Copy requested position to var
170  int diff = tPulse - tp[i]; // Check size of change
171  int d = abs(diff); // Take absolute value
172  if(r[i] < d) // If change larger than ramp step
173  {
174  int step = r[i]; // Copy step entry to variable
175  if(diff < 0) // If negative
176  {
177  step = -step; // Make step negative
178  }
179  tPulse = tp[i] + step; // Increment pulse by step
180  }
181  pulse_outCtr(p[i], tPulse); // Send pulse to servo
182  tp[i] = tPulse; // Remember pulse for next time
183  }
184  if(i%2)
185  {
186  while((CNT - pw) <= dtpw); // Wait for servo pulse window to close
187  pw += dtpw;
188  }
189  }
190  lockclr(lockID); // Clear the lock
191  while((CNT - pw) <= dtpw); // Wait for 20 ms since first pulse
192  pw += dtpw;
193  }
194 }
195 
196 
197 void servo_stop(void) // Stop servo process, free a cog
198 {
199  if(servoCog) // If the cog is running
200  {
201  cogstop(servoCog-1); // Stop it
202  servoCog = 0; // Remember that it's stopped
203  lockclr(lockID);
204  lockret(lockID); // Return the lock
205  }
206 }
207 
208 
209 /*
210  * @brief Starts the servo process and takes over a cog.
211  *
212  * @details You do not need to call this function from your code because
213  * the servo_set function calls it if it detects that the servo cog has not
214  * been started.
215  *
216  * @returns 1..8 if successful. 0 if no available cogs, -1 if no available
217  * locks.
218  */
219 static int servo_start(void) // Take cog & start servo process
220 {
221  lockID = locknew(); // Check out a lock
222  if(lockID == -1) return -1; // Return -1 if no locks
223  else lockclr(lockID);
224  servo_stop(); // Stop in case cog is running
225  servoCog = cogstart(servo, NULL, stack, // Launch servo into new cog
226  sizeof(stack)) + 1;
227  return servoCog;
228 }
229 
230 
231 static int ta = 0, tb = 0, dta = 0, dtb = 0;
232 
233 static void pulse_outCtr(int pin, int time) // pulseOut function definition
234 {
235  /*
236  if(st_iodt == 0)
237  {
238  set_io_dt(CLKFREQ/1000000);
239  set_io_timeout(CLKFREQ/4);
240  }
241  */
242  signed long phsVal = -time * st_iodt;
243  int ctr = 0;
244  int frq = 1;
245  int phs = 0;
246  int state = get_output(pin);
247  if(state == 1)
248  {
249  phsVal = -phsVal;
250  phs = -1;
251  frq = -1;
252  }
253  if(ta == 0 || (dta && (CNT - ta > dta)))
254  {
255  PHSA = phs;
256  FRQA = frq;
257  CTRA = pin;
258  CTRA += (4 << 26);
259  low(pin);
260  PHSA = phsVal;
261  dta = abs(phsVal);
262  ta = CNT;
263  }
264  else if(tb == 0 || (dtb && (CNT - tb > dtb)))
265  {
266  PHSB = phs;
267  FRQB = frq;
268  CTRB = pin;
269  CTRB += (4 << 26);
270  low(pin);
271  PHSB = phsVal;
272  dtb = abs(phsVal);
273  tb = CNT;
274  }
275 }
276 
277 
PHSB
#define PHSB
Counter B phase accumulation register.
Definition: propeller1.h:175
servo_angle
int servo_angle(int pin, int degreeTenths)
Set Parallax Standard Servo to angle from 0 to 180 in tenths of a degree.
Definition: servo.c:45
servo_stop
void servo_stop(void)
Stops the servo process and frees a cog.
Definition: servo.c:197
PHSA
#define PHSA
Counter A phase accumulation register.
Definition: propeller1.h:173
low
void low(int pin)
Set an I/O pin to output-low.
Definition: low.c:19
FRQA
#define FRQA
Counter A frequency register.
Definition: propeller1.h:169
servo_get
int servo_get(int pin)
Reports the number of microseconds of the pulse most recently sent to a given servo.
Definition: servo.c:119
simpletools.h
This library provides convenient functions for a variety of microcontroller I/O, timing,...
servo.h
Control up to 14 servos in another core. For up to 28, add the servoAux library to your project....
FRQB
#define FRQB
Counter B frequency register.
Definition: propeller1.h:171
lockset
#define lockset(lockid)
Set a lock.
Definition: propeller.h:163
input
int input(int pin)
Set an I/O pin to input and return 1 if pin detects a high signal, or 0 if it detects low.
Definition: input.c:19
servo_speed
int servo_speed(int pin, int speed)
Set Parallax Continuous Rotation servo speed.
Definition: servo.c:51
CLKFREQ
#define CLKFREQ
Returns the current clock frequency.
Definition: propeller.h:46
CTRB
#define CTRB
Counter B control register.
Definition: propeller1.h:167
lockret
#define lockret(lockid)
Return lock to pool.
Definition: propeller.h:155
lockclr
#define lockclr(lockid)
Clear lock.
Definition: propeller.h:170
servo_disable
int servo_disable(int pin)
Temporarily or permanently disable a servo by stopping its control signals, setting its I/O pin to in...
Definition: servo.c:134
cogstop
#define cogstop(a)
Stop a COG.
Definition: propeller.h:100
st_iodt
int st_iodt
Clock ticks in a time increment used by pulse_in, pulse_out, and rc_time. Default value is the number...
Definition: timeTicks.c:24
CNT
#define CNT
The system clock count.
Definition: propeller1.h:151
locknew
#define locknew()
Get a new lock from the pool of Propeller hardware locks.
Definition: propeller.h:147
servo_set
int servo_set(int pin, int time)
Sets servo control signal to servo connected to a given pin for microsecond pulse durations.
Definition: servo.c:57
servo_setramp
int servo_setramp(int pin, int stepSize)
Set the maximum change in control signal a servo will change in a given 20 ms time period.
Definition: servo.c:100
get_output
unsigned int get_output(int pin)
Get I/O pin output state.
Definition: getOutput.c:19
cogstart
int cogstart(void(*func)(void *), void *par, void *stack, size_t stacksize)
Start a new propeller LMM function/thread in another COG.
CTRA
#define CTRA
Counter A control register.
Definition: propeller1.h:165