diff --git a/ServoBlaster/Makefile b/ServoBlaster/Makefile index 623dea7..54f8d54 100644 --- a/ServoBlaster/Makefile +++ b/ServoBlaster/Makefile @@ -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 - 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 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` diff --git a/ServoBlaster/README.txt b/ServoBlaster/README.txt index aaa5080..a7e0319 100644 --- a/ServoBlaster/README.txt +++ b/ServoBlaster/README.txt @@ -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 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 August 2012 diff --git a/ServoBlaster/servoblaster.c b/ServoBlaster/servoblaster.c index a6b1c80..4d59df5 100644 --- a/ServoBlaster/servoblaster.c +++ b/ServoBlaster/servoblaster.c @@ -50,7 +50,7 @@ #include #include #include -#include "servoblaster.h" +//#include "servoblaster.h" #define GPIO_LEN 0xb4 #define DMA_LEN 0x24 @@ -139,6 +139,8 @@ static volatile uint32_t *pwm_reg; static dev_t devno; static struct cdev my_cdev; 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 // 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); - 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) { printk(KERN_WARNING "ServoBlaster: alloc_pages failed\n"); 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].src = (uint32_t)(&ctl->pwmdata) & 0x7fffffff; 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].next = (uint32_t)(ctl->cb + i + 1) & 0x7fffffff; // 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].src = (uint32_t)(&ctl->pwmdata) & 0x7fffffff; 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].next = (uint32_t)(ctl->cb + i + 1) & 0x7fffffff; } @@ -262,7 +264,7 @@ int init_module(void) udelay(10); 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 - 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); ctl->pwmdata = 1; // Give a pulse of one clock width for each fifo write 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); return -EINVAL; } - if (cnt < 0 || cnt > 249) { + if (cnt < 0 || cnt > cycle_ticks / 8 - 1) { printk(KERN_WARNING "ServoBlaster: Bad value %d\n", cnt); return -EINVAL; } @@ -357,7 +359,7 @@ static ssize_t dev_write(struct file *filp,const char *buf,size_t count,loff_t * } else { 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+3].length = (250 - cnt) * sizeof(uint32_t); + ctl->cb[servo*4+3].length = (cycle_ticks / 8 - cnt) * sizeof(uint32_t); } local_irq_enable(); @@ -378,3 +380,9 @@ MODULE_DESCRIPTION("ServoBlaster, Multiple Servo Driver for the RaspberryPi"); MODULE_AUTHOR("Richard Hirst "); 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"); + diff --git a/ServoBlaster/servoblaster.ko b/ServoBlaster/servoblaster.ko index afd9fcb..4e8cd67 100644 Binary files a/ServoBlaster/servoblaster.ko and b/ServoBlaster/servoblaster.ko differ