mirror of
https://github.com/richardghirst/PiBits.git
synced 2024-11-28 12:24:11 +01:00
Add idle_timeout module parameter which automatically turns a servo
control line off some period after the last command.
This commit is contained in:
parent
e8bdd9054b
commit
1a3f7c10a0
@ -27,14 +27,14 @@ is currently set. For example, after starting the driver and running the
|
||||
previous command, you would see:
|
||||
|
||||
pi@raspberrypi ~ $ cat /dev/servoblaster
|
||||
0=0
|
||||
1=0
|
||||
2=0
|
||||
3=120
|
||||
4=0
|
||||
5=0
|
||||
6=0
|
||||
7=0
|
||||
0 0
|
||||
1 0
|
||||
2 0
|
||||
3 120
|
||||
4 0
|
||||
5 0
|
||||
6 0
|
||||
7 0
|
||||
pi@raspberrypi ~ $
|
||||
|
||||
When the driver is first loaded the GPIO pins are configure to be outputs, and
|
||||
@ -83,31 +83,11 @@ directory will also create the necessary files. Further to this, running
|
||||
"make install_autostart" will create those files, plus perform the necessary
|
||||
changes to make servoblaster be automatically loaded at boot.
|
||||
|
||||
Note that there are three different ways of referring to a specific servo
|
||||
control pin: by servo number, by GPIO pin on the processor, or by pin number
|
||||
on the P1 header on the Pi itself. The following table shows the mapping
|
||||
between these number schemes:
|
||||
|
||||
Servo GPIO number P1 Pin
|
||||
0 4 7
|
||||
1 17 11
|
||||
2 18 12
|
||||
3 21 13
|
||||
4 22 15
|
||||
5 23 16
|
||||
6 24 18
|
||||
7 25 22
|
||||
|
||||
The driver uses DMA channel 0, and PWM channel 1. It makes no attempt to
|
||||
protect against other code using those peripherals. It sets the relevant GPIO
|
||||
pins to be outputs when the driver is loaded, so please ensure that you are not
|
||||
driving those pins externally.
|
||||
|
||||
ServoBlaster currently uses the PWM hardware for timing purposes, so cannot be
|
||||
used at the same time as PWM audio on the 3.5mm jack, and if you play PWM audio
|
||||
after loading servoblaster.ko, you'll need to unload and reload servoblaster.ko
|
||||
in order to recover.
|
||||
|
||||
I would of course recommend some buffering between the GPIO outputs and the
|
||||
servo controls, to protect the Pi. That said, I'm living dangerously and doing
|
||||
without :-) If you just want to experiment with a small servo you can probably
|
||||
@ -121,6 +101,21 @@ on the wiki (http://elinux.org/RPi_Kernel_Compilation) to compile the kernel,
|
||||
then edit the servoblaster Makefile to point at your kernel tree, then build
|
||||
servoblaster.
|
||||
|
||||
Some people have requested that a servo output turns off automatically if no
|
||||
new pulse width has been requested recently, and I've had two reports of
|
||||
servos overheating when driven for long periods of time. To support this
|
||||
request, ServoBlaster implements an idle timeout which can be specified at
|
||||
module load time. The value is specified in milliseconds, so if you want
|
||||
to drive your servos for 2 seconds following each new width request you would
|
||||
do this:
|
||||
|
||||
sudo insmod ./servoblaster.ko idle_timeout=2000
|
||||
|
||||
Typical small servos take a few 100 milliseconds to rotate from one extreme
|
||||
to the other, so for small values of idle_timeout you might find the control
|
||||
pulse is turned off before your servo has reached the required position.
|
||||
idle_timeout defaults to 0, which disables the feature.
|
||||
|
||||
NOTE: There is some doubt over how to configure the PWM clock at present. For
|
||||
me the clock is 600KHz, which leads to a tick lenght of 10us. However at least
|
||||
one person has reported that the pulses are out by about a factor of about 8,
|
||||
@ -152,5 +147,15 @@ As of August 30th 2012 the servoblaster.ko module is built against a 2.6.27+
|
||||
kernel source from github.
|
||||
|
||||
|
||||
Related projects:
|
||||
|
||||
Ville has written a simple Qt wrapper for servoblaster, which you can find
|
||||
here: https://github.com/vranki/kittinger/blob/master/servocontrol.cpp & .h
|
||||
|
||||
Todd wrote a nice script to provide a simple user interface to control your
|
||||
servos, see his sbcontrol.sh script here:
|
||||
http://www.raspberrypi.org/phpBB3/viewtopic.php?f=37&t=15011&start=25#p187675
|
||||
|
||||
|
||||
Richard Hirst <richardghirst@gmail.com> August 2012
|
||||
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timer.h>
|
||||
#include <mach/platform.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <mach/dma.h>
|
||||
@ -123,6 +124,11 @@ static uint8_t servo2gpio[] = {
|
||||
};
|
||||
#define NUM_SERVOS (sizeof(servo2gpio)/sizeof(servo2gpio[0]))
|
||||
|
||||
// Per-servo timeouts, so we can shut down a servo output after some period
|
||||
// without a new command - some people want this because the report servos
|
||||
// overheating after a time.
|
||||
static struct timer_list idle_timer[NUM_SERVOS];
|
||||
|
||||
// This struct is used to store all temporary data associated with a given
|
||||
// open() of /dev/servoblaster
|
||||
struct private_data
|
||||
@ -161,12 +167,19 @@ static struct cdev my_cdev;
|
||||
static int my_major;
|
||||
static int cycle_ticks = 2000;
|
||||
static int tick_scale = 6;
|
||||
static int idle_timeout = 0;
|
||||
|
||||
// This records the written count values so we can display them on a read()
|
||||
// call. Cannot derive data directly from DMA control blocks as current
|
||||
// algorithm has a special case for a count of zero.
|
||||
static int servo_pos[NUM_SERVOS] = { 0 };
|
||||
|
||||
static void servo_timeout(unsigned long servo)
|
||||
{
|
||||
// Clear GPIO output next time round
|
||||
ctl->cb[servo*4+0].dst = ((GPIO_BASE + GPCLR0*4) & 0x00ffffff) | 0x7e000000;
|
||||
}
|
||||
|
||||
// Wait until we're not processing the given servo (actually wait until
|
||||
// we are not processing the low period of the previous servo, or the
|
||||
// high period of this one).
|
||||
@ -213,8 +226,17 @@ int init_module(void)
|
||||
return res;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_SERVOS; i++)
|
||||
setup_timer(idle_timer + i, servo_timeout, i);
|
||||
|
||||
if (idle_timeout && idle_timeout < 20) {
|
||||
printk(KERN_WARNING "ServoBlaster: Increased idle timeout to minimum of 20ms\n");
|
||||
idle_timeout = 20;
|
||||
}
|
||||
|
||||
ctldatabase = __get_free_pages(GFP_KERNEL, 0);
|
||||
printk(KERN_INFO "ServoBlaster: Control page is at 0x%lx, cycle_ticks %d, tick_scale %d\n", ctldatabase, cycle_ticks, tick_scale);
|
||||
printk(KERN_INFO "ServoBlaster: Control page is at 0x%lx, cycle_ticks %d, tick_scale %d, idle_timeout %d\n",
|
||||
ctldatabase, cycle_ticks, tick_scale, idle_timeout);
|
||||
if (ctldatabase == 0) {
|
||||
printk(KERN_WARNING "ServoBlaster: alloc_pages failed\n");
|
||||
cdev_del(&my_cdev);
|
||||
@ -330,6 +352,7 @@ void cleanup_module(void)
|
||||
// Take care to stop servos with outputs low, so we don't get
|
||||
// spurious movement on module unload
|
||||
for (servo = 0; servo < NUM_SERVOS; servo++) {
|
||||
del_timer(idle_timer + servo);
|
||||
// Wait until we're not driving this servo
|
||||
if (wait_for_servo(servo))
|
||||
break;
|
||||
@ -411,6 +434,9 @@ static int set_servo(int servo, int cnt)
|
||||
if (wait_for_servo(servo))
|
||||
return -EINTR;
|
||||
|
||||
if (idle_timeout)
|
||||
mod_timer(idle_timer + servo, jiffies + msecs_to_jiffies(idle_timeout));
|
||||
|
||||
// Normally, the first GPIO transfer sets the output, while the second
|
||||
// clears it after a delay. For the special case of a delay of 0, we
|
||||
// ensure that the first GPIO transfer also clears the output.
|
||||
@ -511,3 +537,6 @@ MODULE_PARM_DESC(cycle_ticks, "number of ticks per cycle, max pulse is cycle_tic
|
||||
module_param(tick_scale, int, 0);
|
||||
MODULE_PARM_DESC(tick_scale, "scale the tick length, 6 should be 10us");
|
||||
|
||||
module_param(idle_timeout, int, 0);
|
||||
MODULE_PARM_DESC(idle_timeout, "Idle timeout, after which we turn off a servo output (ms)");
|
||||
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user