1
0
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:
Richard Hirst 2012-08-30 21:58:53 +01:00
parent 7a3345778e
commit 2b9f76dd88
4 changed files with 56 additions and 10 deletions

View File

@ -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`

View File

@ -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

View File

@ -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.