1
0
mirror of https://github.com/richardghirst/PiBits.git synced 2024-11-28 12:24:11 +01:00

Add alternative command format in the style of "P1-12=100". Add /dev/servoblaster-cfg describing which pins are currently configured for use.

This commit is contained in:
Richard Hirst 2013-09-29 16:17:40 +01:00
parent 3f4804aa90
commit ab34d81e53
2 changed files with 103 additions and 25 deletions

View File

@ -18,15 +18,30 @@ widths between 0 and 100% of the 20ms cycle time, making it suitable for
controling the brightness of up to 21 LEDs, for example.
The driver creates a device file, /dev/servoblaster, in to which you can send
commands. The command format is "<servo-number>=<sero-position>", where servo
number is by default a number from 0 to 7 inclusive, and servo position is the
pulse width you want in units of 10us. So, if you want to set servo 3 to a
pulse width of 1.2ms you could do this at the shell prompt:
commands. The command format is either
<servo-number>=<servo-position>
or
P<header>-<pin>=<servo-postion>
For the first format <servo-number> is the sevo number, which by default is a
number between 0 and 7, inclusive. For the second format <header> is either
'1' or '5', depending on which header your servo is connected to, and <pin> is
the pin number on that header you have connected it to. In both cases
<servo-position> is the pulse width you want in units of 10us.
So, if you want to set servo 3 to a pulse width of 1.2ms you could do this at
the shell prompt:
echo 3=120 > /dev/servoblaster
120 is in units of 10us, so that is 1200us, or 1.2ms.
Alternatively, using the second command format, if you had a servo connected to
P1 pin 12 you could set that to a width of 1.2ms as follows:
echo P1-12=120 > /dev/servoblaster
If you set a servo width to 0 it turns off the servo output, without changing
the current servo position.
@ -46,7 +61,15 @@ connected to P1 header pins as follows:
P1-13 is connected to either GPIO-21 or GPIO-27, depending on board revision.
Command line options described later in this document allow you to configure
which header pins map to which servo numbers.
which header pins are used for servo control, and what servo numbers they map
to.
Note that servoblaster must know at startup which header pins it is control of.
If you want to use a header pin that is not in the default list above, you
must use the appropriate command line option to inform servoblaster.
The driver also creates a /dev/servoblaster-cfg file, which describes which
pins servoblaster is currently configured to use.
When the driver is first loaded the GPIO pins are configure to be outputs, and
their pulse widths are set to 0. This is so that servos don't jump to some
@ -257,7 +280,8 @@ the kernel implementation (servoblaster.ko) has been depreciated.
The kernel implementation is missing most of the command line options available
in the user space implementation, and always uses the default set of 8 pins
described above.
described above. In addition, the kernel implementation only supports the
first command format described above.
Upon reading /dev/servoblaster, the device file provides feedback as to what
position each servo is currently set. For example, after starting the driver

View File

@ -137,6 +137,8 @@ static uint8_t rev2_p5pin2gpio_map[] = {
};
static uint8_t servo2gpio[MAX_SERVOS];
static uint8_t p1pin2servo[NUM_P1PINS+1];
static uint8_t p5pin2servo[NUM_P5PINS+1];
static int servostart[MAX_SERVOS];
static int servowidth[MAX_SERVOS];
static int num_servos;
@ -144,6 +146,7 @@ static uint32_t gpiomode[MAX_SERVOS];
static int restore_gpio_modes;
#define DEVFILE "/dev/servoblaster"
#define CFGFILE "/dev/servoblaster-cfg"
#define PAGE_SIZE 4096
#define PAGE_SHIFT 12
@ -271,6 +274,7 @@ static int servo_max = DEFAULT_MAX;
static void set_servo(int servo, int width);
static void gpio_set_mode(uint32_t gpio, uint32_t mode);
static char *gpio2pinname(uint8_t gpio);
static void
udelay(int us)
@ -301,6 +305,7 @@ terminate(int dummy)
}
}
unlink(DEVFILE);
unlink(CFGFILE);
exit(1);
}
@ -430,8 +435,10 @@ set_servo(int servo, int width)
if (width == servowidth[servo])
return;
if (width == 0)
if (width == 0) {
ctl->turnon[servo] = 0;
return;
}
if (width > servowidth[servo]) {
dp = ctl->turnoff + servostart[servo] + width;
@ -458,10 +465,7 @@ set_servo(int servo, int width)
}
}
servowidth[servo] = width;
if (width)
ctl->turnon[servo] = mask;
ctl->turnon[servo] = mask;
update_idle_time(servo);
}
@ -713,19 +717,48 @@ go_go_go(void)
if (line[nchars] == '\n') {
line[++nchars] = '\0';
nchars = 0;
n = sscanf(line, "%d=%d%c", &servo, &width, &nl);
if (!strcmp(line, "debug\n")) {
do_debug();
} else if (n !=3 || nl != '\n') {
fprintf(stderr, "Bad input: %s", line);
} else if (servo < 0 || servo >= MAX_SERVOS) {
fprintf(stderr, "Invalid servo number %d\n", servo);
} else if (servo2gpio[servo] == DMY) {
fprintf(stderr, "Servo %d is not mapped to a GPIO pin\n", servo);
} else if (width && (width < servo_min || width > servo_max)) {
fprintf(stderr, "Invalid width %d\n", width);
if (line[0] == 'p' || line[0] == 'P') {
int hdr, pin, width;
n = sscanf(line+1, "%d-%d=%d%c", &hdr, &pin, &width, &nl);
if (n != 4 || nl != '\n') {
fprintf(stderr, "Bad input: %s", line);
} else if (hdr != 1 && hdr != 5) {
fprintf(stderr, "Invalid header P%d\n", hdr);
} else if (pin < 1 ||
(hdr == 1 && pin > NUM_P1PINS) ||
(hdr == 5 && pin > NUM_P5PINS)) {
fprintf(stderr, "Invalid pin number P%d-%d\n", hdr, pin);
} else if ((hdr == 1 && p1pin2servo[pin] == DMY) ||
(hdr == 5 && p5pin2servo[pin] == DMY)) {
fprintf(stderr, "P%d-%d is not mapped to a servo\n", hdr, pin);
} else {
if (hdr == 1) {
servo = p1pin2servo[pin];
} else {
servo = p5pin2servo[pin];
}
if (width && (width < servo_min || width > servo_max)) {
fprintf(stderr, "Invalid width %d\n", width);
} else {
set_servo(servo, width);
}
}
} else {
set_servo(servo, width);
n = sscanf(line, "%d=%d%c", &servo, &width, &nl);
if (!strcmp(line, "debug\n")) {
do_debug();
} else if (n !=3 || nl != '\n') {
fprintf(stderr, "Bad input: %s", line);
} else if (servo < 0 || servo >= MAX_SERVOS) {
fprintf(stderr, "Invalid servo number %d\n", servo);
} else if (servo2gpio[servo] == DMY) {
fprintf(stderr, "Servo %d is not mapped to a GPIO pin\n", servo);
} else if (width && (width < servo_min || width > servo_max)) {
fprintf(stderr, "Invalid width %d\n", width);
} else {
set_servo(servo, width);
}
}
} else {
if (++nchars >= 126) {
@ -785,11 +818,14 @@ static void
parse_pin_lists(int p1first, char *p1pins, char*p5pins)
{
char *name, *pins;
int mapcnt;
uint8_t *map;
int i, mapcnt;
uint8_t *map, *pNpin2servo;
int lst, servo = 0;
FILE *fp;
memset(servo2gpio, DMY, sizeof(servo2gpio));
memset(p1pin2servo, DMY, sizeof(p1pin2servo));
memset(p5pin2servo, DMY, sizeof(p5pin2servo));
for (lst = 0; lst < 2; lst++) {
if (lst == 0 && p1first) {
name = "P1";
@ -801,6 +837,7 @@ parse_pin_lists(int p1first, char *p1pins, char*p5pins)
map = rev2_p1pin2gpio_map;
mapcnt = sizeof(rev2_p1pin2gpio_map);
}
pNpin2servo = p1pin2servo;
} else {
name = "P5";
pins = p5pins;
@ -811,6 +848,7 @@ parse_pin_lists(int p1first, char *p1pins, char*p5pins)
map = rev2_p5pin2gpio_map;
mapcnt = sizeof(rev2_p5pin2gpio_map);
}
pNpin2servo = p5pin2servo;
}
while (*pins) {
char *end;
@ -827,6 +865,7 @@ parse_pin_lists(int p1first, char *p1pins, char*p5pins)
} else {
if (map[pin-1] == DMY)
fatal("Pin %d on header %s cannot be used for a servo output\n", pin, name);
pNpin2servo[pin] = servo;
servo2gpio[servo++] = map[pin-1];
num_servos++;
}
@ -835,6 +874,21 @@ parse_pin_lists(int p1first, char *p1pins, char*p5pins)
pins++;
}
}
/* Write a cfg file so can tell which pins are used for servos */
fp = fopen(CFGFILE, "w");
if (fp) {
if (p1first)
fprintf(fp, "p1pins=%s\np5pins=%s\n", p1pins, p5pins);
else
fprintf(fp, "p5pins=%s\np1pins=%s\n", p5pins, p1pins);
fprintf(fp, "\nServo mapping:\n");
for (i = 0; i < MAX_SERVOS; i++) {
if (servo2gpio[i] == DMY)
continue;
fprintf(fp, " %2d on %-5s GPIO-%d\n", i, gpio2pinname(servo2gpio[i]), servo2gpio[i]);
}
fclose(fp);
}
}
static uint8_t gpiosearch(uint8_t gpio, uint8_t *map, int len)