mirror of
https://github.com/richardghirst/PiBits.git
synced 2025-02-26 19:54:16 +01:00
Updates to allow tweaking timing via module parameters
This commit is contained in:
parent
7a3345778e
commit
2b9f76dd88
@ -1,9 +1,11 @@
|
|||||||
KERNEL_TREE := /home/richard/Pi/git/linux
|
KERNEL_TREE := /home/richard/github/linux
|
||||||
|
|
||||||
all: servoblaster.ko servodemo
|
all: servoblaster.ko
|
||||||
|
|
||||||
servoblaster.ko: servoblaster.c servoblaster.h
|
servoblaster.ko: servoblaster.c servoblaster.h
|
||||||
make -C ${KERNEL_TREE} ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- M=$(PWD) modules
|
@[ -d ${KERNEL_TREE} ] || { echo "Edit Makefile to set KERNEL_TREE to point at your kernel"; exit 1; }
|
||||||
|
@[ -e ${KERNEL_TREE}/Module.symvers ] || { echo "KERNEL_TREE/Module.symvers does not exist, you need to configure and compile your kernel"; exit 1; }
|
||||||
|
make -C ${KERNEL_TREE} ARCH=arm M=$(PWD) modules
|
||||||
|
|
||||||
servodemo: servodemo.c servoblaster.h
|
servodemo: servodemo.c servoblaster.h
|
||||||
gcc -Wall -g -O2 -o servodemo servodemo.c -Wl,--export-dynamic `pkg-config --cflags gtk+-3.0 gmodule-export-2.0` `pkg-config --libs gtk+-3.0 gmodule-export-2.0`
|
gcc -Wall -g -O2 -o servodemo servodemo.c -Wl,--export-dynamic `pkg-config --cflags gtk+-3.0 gmodule-export-2.0` `pkg-config --libs gtk+-3.0 gmodule-export-2.0`
|
||||||
|
@ -77,6 +77,42 @@ take the 5 volts for it from the header pins on the Pi, but I find that doing
|
|||||||
anything non-trivial with four servos connected pulls the 5 volts down far
|
anything non-trivial with four servos connected pulls the 5 volts down far
|
||||||
enough to crash the Pi!
|
enough to crash the Pi!
|
||||||
|
|
||||||
|
If you wish to compile the module yourself, the approach I took was to run
|
||||||
|
rpi-update to get the latest kernel from github, then follow the instructions
|
||||||
|
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.
|
||||||
|
|
||||||
|
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,
|
||||||
|
and so are repeated every 2.5ms rather than every 20ms. To work round this I
|
||||||
|
have added two module parameters:
|
||||||
|
|
||||||
|
tick_scale defaults to 6, which should be a divisor of 600KHz, which should
|
||||||
|
give a tick of 10us. You set the pulse width in ticks (echo 2=27 >
|
||||||
|
/dev/panalyzer to set 27 ticks).
|
||||||
|
|
||||||
|
cycle_ticks is the cycle time in ticks, and defaults to 2000 to give 20ms if
|
||||||
|
one tick is 10us. cycle_ticks should be a multiple of 8. The max pulse width
|
||||||
|
you can specify by writing to /dev/servoblaster is (cycle_ticks/8 - 1), so for
|
||||||
|
the default parameters it is 249, or 2.49ms.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
sudo insmod ./servoblaster.ko tick_scale=48
|
||||||
|
|
||||||
|
should slow it down by a factor of 8 (6*8=48).
|
||||||
|
|
||||||
|
If you can't get quite what you want with tick_scale, you can also tweak
|
||||||
|
cycle_ticks.
|
||||||
|
|
||||||
|
Eventually I might get round to letting you specify how many servo control
|
||||||
|
outputs you want, and which outputs to use, via module parameters.
|
||||||
|
|
||||||
|
As of August 30th 2012 the servoblaster.ko module is built against a 2.6.27+
|
||||||
|
kernel source from github.
|
||||||
|
|
||||||
|
|
||||||
Richard Hirst <richardghirst@gmail.com> August 2012
|
Richard Hirst <richardghirst@gmail.com> August 2012
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
#include <mach/platform.h>
|
#include <mach/platform.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <mach/dma.h>
|
#include <mach/dma.h>
|
||||||
#include "servoblaster.h"
|
//#include "servoblaster.h"
|
||||||
|
|
||||||
#define GPIO_LEN 0xb4
|
#define GPIO_LEN 0xb4
|
||||||
#define DMA_LEN 0x24
|
#define DMA_LEN 0x24
|
||||||
@ -139,6 +139,8 @@ static volatile uint32_t *pwm_reg;
|
|||||||
static dev_t devno;
|
static dev_t devno;
|
||||||
static struct cdev my_cdev;
|
static struct cdev my_cdev;
|
||||||
static int my_major;
|
static int my_major;
|
||||||
|
static int cycle_ticks = 2000;
|
||||||
|
static int tick_scale = 6;
|
||||||
|
|
||||||
// Wait until we're not processing the given servo (actually wait until
|
// 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
|
// we are not processing the low period of the previous servo, or the
|
||||||
@ -187,7 +189,7 @@ int init_module(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctldatabase = __get_free_pages(GFP_KERNEL, 0);
|
ctldatabase = __get_free_pages(GFP_KERNEL, 0);
|
||||||
printk(KERN_INFO "ServoBlaster: Control page is at 0x%lx\n", ctldatabase);
|
printk(KERN_INFO "ServoBlaster: Control page is at 0x%lx, cycle_ticks %d, tick_scale %d\n", ctldatabase, cycle_ticks, tick_scale);
|
||||||
if (ctldatabase == 0) {
|
if (ctldatabase == 0) {
|
||||||
printk(KERN_WARNING "ServoBlaster: alloc_pages failed\n");
|
printk(KERN_WARNING "ServoBlaster: alloc_pages failed\n");
|
||||||
cdev_del(&my_cdev);
|
cdev_del(&my_cdev);
|
||||||
@ -234,7 +236,7 @@ int init_module(void)
|
|||||||
ctl->cb[i].info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(5);
|
ctl->cb[i].info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(5);
|
||||||
ctl->cb[i].src = (uint32_t)(&ctl->pwmdata) & 0x7fffffff;
|
ctl->cb[i].src = (uint32_t)(&ctl->pwmdata) & 0x7fffffff;
|
||||||
ctl->cb[i].dst = ((PWM_BASE + PWM_FIFO*4) & 0x00ffffff) | 0x7e000000;
|
ctl->cb[i].dst = ((PWM_BASE + PWM_FIFO*4) & 0x00ffffff) | 0x7e000000;
|
||||||
ctl->cb[i].length = sizeof(uint32_t) * 100; // default 1000us high
|
ctl->cb[i].length = sizeof(uint32_t) * 1; // default 1 tick high
|
||||||
ctl->cb[i].stride = 0;
|
ctl->cb[i].stride = 0;
|
||||||
ctl->cb[i].next = (uint32_t)(ctl->cb + i + 1) & 0x7fffffff;
|
ctl->cb[i].next = (uint32_t)(ctl->cb + i + 1) & 0x7fffffff;
|
||||||
// Set gpio lo
|
// Set gpio lo
|
||||||
@ -250,7 +252,7 @@ int init_module(void)
|
|||||||
ctl->cb[i].info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(5);
|
ctl->cb[i].info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(5);
|
||||||
ctl->cb[i].src = (uint32_t)(&ctl->pwmdata) & 0x7fffffff;
|
ctl->cb[i].src = (uint32_t)(&ctl->pwmdata) & 0x7fffffff;
|
||||||
ctl->cb[i].dst = ((PWM_BASE + PWM_FIFO*4) & 0x00ffffff) | 0x7e000000;
|
ctl->cb[i].dst = ((PWM_BASE + PWM_FIFO*4) & 0x00ffffff) | 0x7e000000;
|
||||||
ctl->cb[i].length = sizeof(uint32_t) * 150; // default 1500us, to give 2.5ms per servo
|
ctl->cb[i].length = sizeof(uint32_t) * (cycle_ticks / 8 - 1);
|
||||||
ctl->cb[i].stride = 0;
|
ctl->cb[i].stride = 0;
|
||||||
ctl->cb[i].next = (uint32_t)(ctl->cb + i + 1) & 0x7fffffff;
|
ctl->cb[i].next = (uint32_t)(ctl->cb + i + 1) & 0x7fffffff;
|
||||||
}
|
}
|
||||||
@ -262,7 +264,7 @@ int init_module(void)
|
|||||||
udelay(10);
|
udelay(10);
|
||||||
clk_reg[PWMCLK_DIV] = 0x5A000000 | (32<<12); // set pwm div to 32 (19.2MHz/32 = 600KHz)
|
clk_reg[PWMCLK_DIV] = 0x5A000000 | (32<<12); // set pwm div to 32 (19.2MHz/32 = 600KHz)
|
||||||
clk_reg[PWMCLK_CNTL] = 0x5A000011; // Source=osc and enable
|
clk_reg[PWMCLK_CNTL] = 0x5A000011; // Source=osc and enable
|
||||||
pwm_reg[PWM_RNG1] = 6; // 600KHz/6 = 10us per FIFO write
|
pwm_reg[PWM_RNG1] = tick_scale; // 600KHz/6 = 10us per FIFO write
|
||||||
udelay(10);
|
udelay(10);
|
||||||
ctl->pwmdata = 1; // Give a pulse of one clock width for each fifo write
|
ctl->pwmdata = 1; // Give a pulse of one clock width for each fifo write
|
||||||
pwm_reg[PWM_DMAC] = PWMDMAC_ENAB | PWMDMAC_THRSHLD;
|
pwm_reg[PWM_DMAC] = PWMDMAC_ENAB | PWMDMAC_THRSHLD;
|
||||||
@ -346,7 +348,7 @@ static ssize_t dev_write(struct file *filp,const char *buf,size_t count,loff_t *
|
|||||||
printk(KERN_WARNING "ServoBlaster: Bad servo number %d\n", servo);
|
printk(KERN_WARNING "ServoBlaster: Bad servo number %d\n", servo);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (cnt < 0 || cnt > 249) {
|
if (cnt < 0 || cnt > cycle_ticks / 8 - 1) {
|
||||||
printk(KERN_WARNING "ServoBlaster: Bad value %d\n", cnt);
|
printk(KERN_WARNING "ServoBlaster: Bad value %d\n", cnt);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -357,7 +359,7 @@ static ssize_t dev_write(struct file *filp,const char *buf,size_t count,loff_t *
|
|||||||
} else {
|
} else {
|
||||||
ctl->cb[servo*4+0].dst = ((GPIO_BASE + GPSET0*4) & 0x00ffffff) | 0x7e000000;
|
ctl->cb[servo*4+0].dst = ((GPIO_BASE + GPSET0*4) & 0x00ffffff) | 0x7e000000;
|
||||||
ctl->cb[servo*4+1].length = cnt * sizeof(uint32_t);
|
ctl->cb[servo*4+1].length = cnt * sizeof(uint32_t);
|
||||||
ctl->cb[servo*4+3].length = (250 - cnt) * sizeof(uint32_t);
|
ctl->cb[servo*4+3].length = (cycle_ticks / 8 - cnt) * sizeof(uint32_t);
|
||||||
}
|
}
|
||||||
local_irq_enable();
|
local_irq_enable();
|
||||||
|
|
||||||
@ -378,3 +380,9 @@ MODULE_DESCRIPTION("ServoBlaster, Multiple Servo Driver for the RaspberryPi");
|
|||||||
MODULE_AUTHOR("Richard Hirst <richardghirst@gmail.com>");
|
MODULE_AUTHOR("Richard Hirst <richardghirst@gmail.com>");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|
||||||
|
module_param(cycle_ticks, int, 0);
|
||||||
|
MODULE_PARM_DESC(cycle_ticks, "number of ticks per cycle, max pulse is cycle_ticks/8");
|
||||||
|
|
||||||
|
module_param(tick_scale, int, 0);
|
||||||
|
MODULE_PARM_DESC(tick_scale, "scale the tick length, 6 should be 10us");
|
||||||
|
|
||||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user