From 213d89909e4d9c61d91c7b9155df110771ceab74 Mon Sep 17 00:00:00 2001 From: Chang YiYu Date: Tue, 22 Sep 2015 21:24:30 +0800 Subject: [PATCH 1/7] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b3479d4..9d772fe 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Java Embedded 7. [GPIO的基礎應用與實作(上)](http://www.codedata.com.tw/java/java-embedded-7-raspberry-pi-gpio-implementation-1/) 8. [GPIO的基礎應用與實作(下)](http://www.codedata.com.tw/java/java-embedded-7-raspberry-pi-gpio-implementation-2/) 9. [紅外線測距模組與類比數位轉換](http://www.codedata.com.tw/java/java-embedded-9-gpio-ultrasonic-wave/) -10. [GPIO進階應用 – 步進馬達達](http://www.codedata.com.tw/java/java-embedded-10-gpio-motor/) +10. [GPIO進階應用 – 步進馬達](http://www.codedata.com.tw/java/java-embedded-10-gpio-motor/) 11. [控制直流馬達 - 使用L293D晶片](http://www.codedata.com.tw/java/java-embedded-11-parking-lot/) 12. [整合應用 – PiFan](http://www.codedata.com.tw/java/java-embedded-12-parking-lot-2/) From 1e2c15d9665f69945c832790a639bbd0dc5b53ae Mon Sep 17 00:00:00 2001 From: Chang YiYu Date: Thu, 4 Feb 2016 17:41:04 +0800 Subject: [PATCH 2/7] ServoBlaster update --- files/ServoBlaster20160204.zip | Bin 0 -> 22405 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 files/ServoBlaster20160204.zip diff --git a/files/ServoBlaster20160204.zip b/files/ServoBlaster20160204.zip new file mode 100644 index 0000000000000000000000000000000000000000..7ab3134f78bef11a6f7715d327d71fe987eaf925 GIT binary patch literal 22405 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 G-+uu{ildGI literal 0 HcmV?d00001 From ed871e9a2356d2a99a6576dcb309a3cf455fd255 Mon Sep 17 00:00:00 2001 From: Chang YiYu Date: Thu, 4 Feb 2016 17:44:57 +0800 Subject: [PATCH 3/7] Update ServoBlaster --- files/ServoBlaster20160204.gz | Bin 0 -> 16743 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 files/ServoBlaster20160204.gz diff --git a/files/ServoBlaster20160204.gz b/files/ServoBlaster20160204.gz new file mode 100644 index 0000000000000000000000000000000000000000..2e6232ae37250da7ca7976892a12f396cd2bd960 GIT binary patch literal 16743 zcmZs?V~j68{4Bh-ZQHhO+qSK3pU$ zgfUP+{`f5#K%h5&bN>hV3UCEgAz58%iH!KBOGEeZ*@N

}u{rW1}wRMpj-H>_Yc+gS+^e&F~Tfy(x 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 literal 0 HcmV?d00001 From 0d904512ca0ff64c034a63177dfe3e2e3cdecb5e Mon Sep 17 00:00:00 2001 From: Chang YiYu Date: Thu, 4 Feb 2016 17:51:03 +0800 Subject: [PATCH 4/7] Update --- files/ServoBlaster20160204.tgz | Bin 0 -> 16743 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 files/ServoBlaster20160204.tgz diff --git a/files/ServoBlaster20160204.tgz b/files/ServoBlaster20160204.tgz new file mode 100644 index 0000000000000000000000000000000000000000..2e6232ae37250da7ca7976892a12f396cd2bd960 GIT binary patch literal 16743 zcmZs?V~j68{4Bh-ZQHhO+qSK3pU$ zgfUP+{`f5#K%h5&bN>hV3UCEgAz58%iH!KBOGEeZ*@N

}u{rW1}wRMpj-H>_Yc+gS+^e&F~Tfy(x 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 literal 0 HcmV?d00001 From 4e5e5458eb9c94680691ac731b56319c479ba48f Mon Sep 17 00:00:00 2001 From: Chang YiYu Date: Thu, 4 Feb 2016 17:57:10 +0800 Subject: [PATCH 5/7] Update --- files/ServoBlaster.tar.gz | Bin 0 -> 16732 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 files/ServoBlaster.tar.gz diff --git a/files/ServoBlaster.tar.gz b/files/ServoBlaster.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..f37c7debd28e19970cad3b613d4052c4fbc3fe8e GIT binary patch literal 16732 zcmV(qK<~dFiwFoiAhT8g15;&kc5gy#VRLk4axQdXasX_*V~j3bu&vv+ZQHhO+qSLM zwr$(C&DHLH+qSvdIN#pMxyik`l~I4@OzKZnGM|ymB8-6o;vs6$00O=FBkzhkm5jB= z!@&VGQIGF&E%A0(c>qTq2qxtQT1XYNq6-5?etoo-yl>TtgS{ojIcWfFCFdDJ=veCc zuxdFG9uRE$=T*@u^v}~D#`ycGCS-wi$p+Sz>h79uTp)JErN6!*Fv4Kf&Hoeq|0RGE z&|?`NaKn$QC4BxSTR@~nlP39(r(_`K%W-up^ku8z;urZnaP0~ zk`PrO0FvO{9>0iRoT&mIUf zPU6o~vCYb?&QaHyK0>aeCCm?rU9~#fK{f9^_BiN=8^f{U)!63UHw=6%c!AMA1Bry zDRUq}4shGk*k5(jO@hteB<(uJ@!xqAjHBOqp7ZZt)#o4Y?}6&rU*%uON%7xbyo2IL z_s>Lrorc4Nfd1BJ!x1XK$Jm^>4ASY4O zZmClNg)j_bWDH}Ox1+LZYqfs8pWyGA0Ouc5)E20i#{ZWJxI>Q&>AsIpH1EEz$m=sd z#}Z_hNa%+Df8=*;v>_||`bqhQdag0S`ZL8{~J6X5Hi0vbhbBS z2~;o;lmJTzDWL!Mh5Lp#a+YylHFQS%_C@=4y#MqIbSF4?7BF}=Fmg69cqTY*EO*1BXVrH0V4!_MwqOisDXpVQ$Dpc4pM;I0~4Z3Och=vhbJGkq-lr$!e*K}N z=+QFL`@c+%hVkveG^aidZzthrgy%gc4km0*KKFj>G#blj$4^O3oqw;MLdU)v3fvby zekm`$T|Wnu*;T#=UabDRX$iHWm<)J7$+*_O^8So$OW4GJbNuD{CFgzUvt9EDrlf

T`z#wPiv=|5DnX%!MN(nT4SQF73B4 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 DS`D0( literal 0 HcmV?d00001 From 745a865b1b3c7ccdf4e694df721e66d368e7de63 Mon Sep 17 00:00:00 2001 From: Chang YiYu Date: Thu, 4 Feb 2016 17:59:04 +0800 Subject: [PATCH 6/7] ServoBlaster --- ServoBlaster/Makefile | 25 + ServoBlaster/init-script | 41 ++ ServoBlaster/mailbox.c | 261 ++++++++ ServoBlaster/mailbox.h | 47 ++ ServoBlaster/ripple.sh | 30 + ServoBlaster/servod.c | 1324 +++++++++++++++++++++++++++++++++++++ ServoBlaster/servodebug.c | 220 ++++++ 7 files changed, 1948 insertions(+) create mode 100644 ServoBlaster/Makefile create mode 100755 ServoBlaster/init-script create mode 100644 ServoBlaster/mailbox.c create mode 100644 ServoBlaster/mailbox.h create mode 100755 ServoBlaster/ripple.sh create mode 100644 ServoBlaster/servod.c create mode 100644 ServoBlaster/servodebug.c diff --git a/ServoBlaster/Makefile b/ServoBlaster/Makefile new file mode 100644 index 0000000..fbcee13 --- /dev/null +++ b/ServoBlaster/Makefile @@ -0,0 +1,25 @@ + +.PHONY: all install uninstall +all: servod + +servod: servod.c mailbox.c + gcc -Wall -g -O2 -o servod servod.c mailbox.c -lm + +install: servod + [ "`id -u`" = "0" ] || { echo "Must be run as root"; exit 1; } + cp -f servod /usr/local/sbin + cp -f init-script /etc/init.d/servoblaster + chmod 755 /etc/init.d/servoblaster + update-rc.d servoblaster defaults 92 08 + /etc/init.d/servoblaster start + +uninstall: + [ "`id -u`" = "0" ] || { echo "Must be run as root"; exit 1; } + [ -e /etc/init.d/servoblaster ] && /etc/init.d/servoblaster stop || : + update-rc.d servoblaster remove + rm -f /usr/local/sbin/servod + rm -f /etc/init.d/servoblaster + +clean: + rm -f servod + diff --git a/ServoBlaster/init-script b/ServoBlaster/init-script new file mode 100755 index 0000000..269b053 --- /dev/null +++ b/ServoBlaster/init-script @@ -0,0 +1,41 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: servoblaster +# Required-Start: hostname $local_fs +# Required-Stop: +# Should-Start: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start/stop servod. +# Description: This script starts/stops servod. +### END INIT INFO + +PATH=/sbin:/usr/sbin:/bin:/usr/bin +. /lib/init/vars.sh + +OPTS="--idle-timeout=2000" + +res=0 + +case "$1" in + start) + /usr/local/sbin/servod $OPTS >/dev/null + ;; + restart|reload|force-reload) + killall servod + /usr/local/sbin/servod $OPTS >/dev/null + ;; + stop) + killall servod + ;; + status) + [ -e /dev/servoblaster ] || res=4 + ;; + *) + echo "Usage: servoblaster [start|stop|status]" >&2 + res=3 + ;; +esac + +exit $res + diff --git a/ServoBlaster/mailbox.c b/ServoBlaster/mailbox.c new file mode 100644 index 0000000..d019cc7 --- /dev/null +++ b/ServoBlaster/mailbox.c @@ -0,0 +1,261 @@ +/* +Copyright (c) 2012, Broadcom Europe Ltd. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mailbox.h" + +#define PAGE_SIZE (4*1024) + +void *mapmem(unsigned base, unsigned size) +{ + int mem_fd; + unsigned offset = base % PAGE_SIZE; + base = base - offset; + /* open /dev/mem */ + if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) { + printf("can't open /dev/mem\nThis program should be run as root. Try prefixing command with: sudo\n"); + exit (-1); + } + void *mem = mmap( + 0, + size, + PROT_READ|PROT_WRITE, + MAP_SHARED/*|MAP_FIXED*/, + mem_fd, + base); +#ifdef DEBUG + printf("base=0x%x, mem=%p\n", base, mem); +#endif + if (mem == MAP_FAILED) { + printf("mmap error %d\n", (int)mem); + exit (-1); + } + close(mem_fd); + return (char *)mem + offset; +} + +void *unmapmem(void *addr, unsigned size) +{ + int s = munmap(addr, size); + if (s != 0) { + printf("munmap error %d\n", s); + exit (-1); + } + + return NULL; +} + +/* + * use ioctl to send mbox property message + */ + +static int mbox_property(int file_desc, void *buf) +{ + int ret_val = ioctl(file_desc, IOCTL_MBOX_PROPERTY, buf); + + if (ret_val < 0) { + printf("ioctl_set_msg failed:%d\n", ret_val); + } + +#ifdef DEBUG + unsigned *p = buf; int i; unsigned size = *(unsigned *)buf; + for (i=0; i + +#define MAJOR_NUM 100 +#define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM, 0, char *) +#define DEVICE_FILE_NAME "/dev/servoblaster-mb" + +int mbox_open(); +void mbox_close(int file_desc); + +unsigned get_version(int file_desc); +unsigned mem_alloc(int file_desc, unsigned size, unsigned align, unsigned flags); +unsigned mem_free(int file_desc, unsigned handle); +unsigned mem_lock(int file_desc, unsigned handle); +unsigned mem_unlock(int file_desc, unsigned handle); +void *mapmem(unsigned base, unsigned size); +void *unmapmem(void *addr, unsigned size); + +unsigned execute_code(int file_desc, unsigned code, unsigned r0, unsigned r1, unsigned r2, unsigned r3, unsigned r4, unsigned r5); +unsigned execute_qpu(int file_desc, unsigned num_qpus, unsigned control, unsigned noflush, unsigned timeout); +unsigned qpu_enable(int file_desc, unsigned enable); diff --git a/ServoBlaster/ripple.sh b/ServoBlaster/ripple.sh new file mode 100755 index 0000000..4cb1a6b --- /dev/null +++ b/ServoBlaster/ripple.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +leds() +{ + echo 0=$1 > /dev/servoblaster + echo 1=$2 > /dev/servoblaster + echo 2=$3 > /dev/servoblaster + echo 4=$4 > /dev/servoblaster +} + +b=0 +d=0.1 + +while true; do + leds $b 0 0 0 + sleep $d + leds 0 $b 0 0 + sleep $d + leds 0 0 $b 0 + sleep $d + leds 0 0 0 $b + sleep $d + leds 0 0 $b 0 + sleep $d + leds 0 $b 0 0 + sleep $d + b=$(( b + 100 )) + [ $b = 2000 ] && b=0 +done + diff --git a/ServoBlaster/servod.c b/ServoBlaster/servod.c new file mode 100644 index 0000000..407e9ed --- /dev/null +++ b/ServoBlaster/servod.c @@ -0,0 +1,1324 @@ +/* + * servod.c Multiple Servo Driver for the RaspberryPi + * Copyright (c) 2013 Richard Hirst + * + * This program provides very similar functionality to servoblaster, except + * that rather than implementing it as a kernel module, servod implements + * the functionality as a usr space daemon. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* TODO: Separate idle timeout handling from genuine set-to-zero requests */ +/* TODO: Add ability to specify time frame over which an adjustment should be made */ +/* TODO: Add servoctl utility to set and query servo positions, etc */ +/* TODO: Add slow-start option */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mailbox.h" + +#define DMY 255 // Used to represent an invalid P1 pin, or unmapped servo + +#define NUM_P1PINS 26 +#define NUM_P5PINS 8 + +#define MAX_SERVOS 32 /* Only 21 really, but this lets you map servo IDs + * to P1 pins, if you want to + */ +#define MAX_MEMORY_USAGE (16*1024*1024) /* Somewhat arbitrary limit of 16MB */ + +#define DEFAULT_CYCLE_TIME_US 20000 +#define DEFAULT_STEP_TIME_US 10 +#define DEFAULT_SERVO_MIN_US 500 +#define DEFAULT_SERVO_MAX_US 2500 + +#define DEVFILE "/dev/servoblaster" +#define CFGFILE "/dev/servoblaster-cfg" +#define MBFILE DEVICE_FILE_NAME /* From mailbox.h */ + +#define PAGE_SIZE 4096 +#define PAGE_SHIFT 12 + +#define DMA_CHAN_SIZE 0x100 +#define DMA_CHAN_MIN 0 +#define DMA_CHAN_MAX 14 +#define DMA_CHAN_DEFAULT 14 + +#define DMA_BASE_OFFSET 0x00007000 +#define DMA_LEN DMA_CHAN_SIZE * (DMA_CHAN_MAX+1) +#define PWM_BASE_OFFSET 0x0020C000 +#define PWM_LEN 0x28 +#define CLK_BASE_OFFSET 0x00101000 +#define CLK_LEN 0xA8 +#define GPIO_BASE_OFFSET 0x00200000 +#define GPIO_LEN 0x100 +#define PCM_BASE_OFFSET 0x00203000 +#define PCM_LEN 0x24 + +#define DMA_VIRT_BASE (periph_virt_base + DMA_BASE_OFFSET) +#define PWM_VIRT_BASE (periph_virt_base + PWM_BASE_OFFSET) +#define CLK_VIRT_BASE (periph_virt_base + CLK_BASE_OFFSET) +#define GPIO_VIRT_BASE (periph_virt_base + GPIO_BASE_OFFSET) +#define PCM_VIRT_BASE (periph_virt_base + PCM_BASE_OFFSET) + +#define PWM_PHYS_BASE (periph_phys_base + PWM_BASE_OFFSET) +#define PCM_PHYS_BASE (periph_phys_base + PCM_BASE_OFFSET) +#define GPIO_PHYS_BASE (periph_phys_base + GPIO_BASE_OFFSET) + +#define DMA_NO_WIDE_BURSTS (1<<26) +#define DMA_WAIT_RESP (1<<3) +#define DMA_D_DREQ (1<<6) +#define DMA_PER_MAP(x) ((x)<<16) +#define DMA_END (1<<1) +#define DMA_RESET (1<<31) +#define DMA_INT (1<<2) + +#define DMA_CS (0x00/4) +#define DMA_CONBLK_AD (0x04/4) +#define DMA_DEBUG (0x20/4) + +#define GPIO_FSEL0 (0x00/4) +#define GPIO_SET0 (0x1c/4) +#define GPIO_CLR0 (0x28/4) +#define GPIO_LEV0 (0x34/4) +#define GPIO_PULLEN (0x94/4) +#define GPIO_PULLCLK (0x98/4) + +#define GPIO_MODE_IN 0 +#define GPIO_MODE_OUT 1 + +#define PWM_CTL (0x00/4) +#define PWM_DMAC (0x08/4) +#define PWM_RNG1 (0x10/4) +#define PWM_FIFO (0x18/4) + +#define PWMCLK_CNTL 40 +#define PWMCLK_DIV 41 + +#define PWMCTL_MODE1 (1<<1) +#define PWMCTL_PWEN1 (1<<0) +#define PWMCTL_CLRF (1<<6) +#define PWMCTL_USEF1 (1<<5) + +#define PWMDMAC_ENAB (1<<31) +#define PWMDMAC_THRSHLD ((15<<8)|(15<<0)) + +#define PCM_CS_A (0x00/4) +#define PCM_FIFO_A (0x04/4) +#define PCM_MODE_A (0x08/4) +#define PCM_RXC_A (0x0c/4) +#define PCM_TXC_A (0x10/4) +#define PCM_DREQ_A (0x14/4) +#define PCM_INTEN_A (0x18/4) +#define PCM_INT_STC_A (0x1c/4) +#define PCM_GRAY (0x20/4) + +#define PCMCLK_CNTL 38 +#define PCMCLK_DIV 39 + +#define DELAY_VIA_PWM 0 +#define DELAY_VIA_PCM 1 + +#define ROUNDUP(val, blksz) (((val)+((blksz)-1)) & ~(blksz-1)) + +typedef struct { + uint32_t info, src, dst, length, + stride, next, pad[2]; +} dma_cb_t; + +#define BUS_TO_PHYS(x) ((x)&~0xC0000000) + +/* Define which P1 header pins to use by default. These are the eight standard + * GPIO pins (those coloured green in the diagram on this page: + * http://elinux.org/Rpi_Low-level_peripherals + * + * Which P1 header pins are actually used can be overridden via command line + * parameter '--p1pins=...'. + */ + +static char *default_p1_pins = "7,11,12,13,15,16,18,22"; +static char *default_p5_pins = ""; + +static uint8_t rev1_p1pin2gpio_map[] = { + DMY, // P1-1 3v3 + DMY, // P1-2 5v + 0, // P1-3 GPIO 0 (SDA) + DMY, // P1-4 5v + 1, // P1-5 GPIO 1 (SCL) + DMY, // P1-6 Ground + 4, // P1-7 GPIO 4 (GPCLK0) + 14, // P1-8 GPIO 14 (TXD) + DMY, // P1-9 Ground + 15, // P1-10 GPIO 15 (RXD) + 17, // P1-11 GPIO 17 + 18, // P1-12 GPIO 18 (PCM_CLK) + 21, // P1-13 GPIO 21 + DMY, // P1-14 Ground + 22, // P1-15 GPIO 22 + 23, // P1-16 GPIO 23 + DMY, // P1-17 3v3 + 24, // P1-18 GPIO 24 + 10, // P1-19 GPIO 10 (MOSI) + DMY, // P1-20 Ground + 9, // P1-21 GPIO 9 (MISO) + 25, // P1-22 GPIO 25 + 11, // P1-23 GPIO 11 (SCLK) + 8, // P1-24 GPIO 8 (CE0) + DMY, // P1-25 Ground + 7, // P1-26 GPIO 7 (CE1) +}; + +static uint8_t rev1_p5pin2gpio_map[] = { + DMY, // (P5-1 on rev 2 boards) + DMY, // (P5-2 on rev 2 boards) + DMY, // (P5-3 on rev 2 boards) + DMY, // (P5-4 on rev 2 boards) + DMY, // (P5-5 on rev 2 boards) + DMY, // (P5-6 on rev 2 boards) + DMY, // (P5-7 on rev 2 boards) + DMY, // (P5-8 on rev 2 boards) +}; + +static uint8_t rev2_p1pin2gpio_map[] = { + DMY, // P1-1 3v3 + DMY, // P1-2 5v + 2, // P1-3 GPIO 2 (SDA) + DMY, // P1-4 5v + 3, // P1-5 GPIO 3 (SCL) + DMY, // P1-6 Ground + 4, // P1-7 GPIO 4 (GPCLK0) + 14, // P1-8 GPIO 14 (TXD) + DMY, // P1-9 Ground + 15, // P1-10 GPIO 15 (RXD) + 17, // P1-11 GPIO 17 + 18, // P1-12 GPIO 18 (PCM_CLK) + 27, // P1-13 GPIO 27 + DMY, // P1-14 Ground + 22, // P1-15 GPIO 22 + 23, // P1-16 GPIO 23 + DMY, // P1-17 3v3 + 24, // P1-18 GPIO 24 + 10, // P1-19 GPIO 10 (MOSI) + DMY, // P1-20 Ground + 9, // P1-21 GPIO 9 (MISO) + 25, // P1-22 GPIO 25 + 11, // P1-23 GPIO 11 (SCLK) + 8, // P1-24 GPIO 8 (CE0) + DMY, // P1-25 Ground + 7, // P1-26 GPIO 7 (CE1) +}; + +static uint8_t rev2_p5pin2gpio_map[] = { + DMY, // P5-1 5v0 + DMY, // P5-2 3v3 + 28, // P5-3 GPIO 28 (I2C0_SDA) + 29, // P5-4 GPIO 29 (I2C0_SCL) + 30, // P5-5 GPIO 30 + 31, // P5-6 GPIO 31 + DMY, // P5-7 Ground + DMY, // P5-8 Ground +}; + +// cycle_time_us is the pulse cycle time per servo, in microseconds. +// Typically it should be 20ms, or 20000us. + +// step_time_us is the pulse width increment granularity, again in microseconds. +// Setting step_time_us too low will likely cause problems as the DMA controller +// will use too much memory bandwidth. 10us is a good value, though you +// might be ok setting it as low as 2us. + +static int cycle_time_us; +static int step_time_us; + +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; +static uint32_t gpiomode[MAX_SERVOS]; +static int restore_gpio_modes; + +static volatile uint32_t *pwm_reg; +static volatile uint32_t *pcm_reg; +static volatile uint32_t *clk_reg; +static volatile uint32_t *dma_reg; +static volatile uint32_t *gpio_reg; + +static int delay_hw = DELAY_VIA_PWM; + +static struct timeval *servo_kill_time; + +static int dma_chan; +static int idle_timeout; +static int invert = 0; +static int servo_min_ticks; +static int servo_max_ticks; +static int num_samples; +static int num_cbs; +static int num_pages; +static uint32_t *turnoff_mask; +static uint32_t *turnon_mask; +static dma_cb_t *cb_base; + +static int board_model; +static int board_revision; + +static uint32_t periph_phys_base; +static uint32_t periph_virt_base; +static uint32_t dram_phys_base; +static uint32_t mem_flag; + +static struct { + int handle; /* From mbox_open() */ + unsigned mem_ref; /* From mem_alloc() */ + unsigned bus_addr; /* From mem_lock() */ + uint8_t *virt_addr; /* From mapmem() */ +} mbox; + +static void set_servo(int servo, int width); +static void set_servo_idle(int servo); +static void gpio_set_mode(uint32_t gpio, uint32_t mode); +static char *gpio2pinname(uint8_t gpio); + +static void +udelay(int us) +{ + struct timespec ts = { 0, us * 1000 }; + + nanosleep(&ts, NULL); +} + +static void +terminate(int dummy) +{ + int i; + + if (dma_reg && mbox.virt_addr) { + for (i = 0; i < MAX_SERVOS; i++) { + if (servo2gpio[i] != DMY) + set_servo(i, 0); + } + udelay(cycle_time_us); + dma_reg[DMA_CS] = DMA_RESET; + udelay(10); + } + if (restore_gpio_modes) { + for (i = 0; i < MAX_SERVOS; i++) { + if (servo2gpio[i] != DMY) + gpio_set_mode(servo2gpio[i], gpiomode[i]); + } + } + if (mbox.virt_addr != NULL) { + unmapmem(mbox.virt_addr, num_pages * 4096); + mem_unlock(mbox.handle, mbox.mem_ref); + mem_free(mbox.handle, mbox.mem_ref); + } + + unlink(DEVFILE); + unlink(CFGFILE); + exit(1); +} + +static void +fatal(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + terminate(0); +} + +static void +init_idle_timers(void) +{ + servo_kill_time = calloc(MAX_SERVOS, sizeof(struct timeval)); + if (!servo_kill_time) + fatal("servod: calloc() failed\n"); +} + +static void +update_idle_time(int servo) +{ + if (idle_timeout == 0) + return; + + gettimeofday(servo_kill_time + servo, NULL); + servo_kill_time[servo].tv_sec += idle_timeout / 1000; + servo_kill_time[servo].tv_usec += (idle_timeout % 1000) * 1000; + while (servo_kill_time[servo].tv_usec >= 1000000) { + servo_kill_time[servo].tv_usec -= 1000000; + servo_kill_time[servo].tv_sec++; + } +} + +static void +get_next_idle_timeout(struct timeval *tv) +{ + int i; + struct timeval now; + struct timeval min = { 60, 0 }; + long this_diff, min_diff; + + gettimeofday(&now, NULL); + for (i = 0; i < MAX_SERVOS; i++) { + if (servo2gpio[i] == DMY || servo_kill_time[i].tv_sec == 0) + continue; + else if (servo_kill_time[i].tv_sec < now.tv_sec || + (servo_kill_time[i].tv_sec == now.tv_sec && + servo_kill_time[i].tv_usec <= now.tv_usec)) { + servo_kill_time[i].tv_sec = 0; + set_servo_idle(i); + } else { + this_diff = (servo_kill_time[i].tv_sec - now.tv_sec) * 1000000 + + servo_kill_time[i].tv_usec - now.tv_usec; + min_diff = min.tv_sec * 1000000 + min.tv_usec; + if (this_diff < min_diff) { + min.tv_sec = this_diff / 1000000; + min.tv_usec = this_diff % 1000000; + } + } + } + *tv = min; +} + +static uint32_t gpio_get_mode(uint32_t gpio) +{ + uint32_t fsel = gpio_reg[GPIO_FSEL0 + gpio/10]; + + return (fsel >> ((gpio % 10) * 3)) & 7; +} + +static void +gpio_set_mode(uint32_t gpio, uint32_t mode) +{ + uint32_t fsel = gpio_reg[GPIO_FSEL0 + gpio/10]; + + fsel &= ~(7 << ((gpio % 10) * 3)); + fsel |= mode << ((gpio % 10) * 3); + gpio_reg[GPIO_FSEL0 + gpio/10] = fsel; +} + +static void +gpio_set(int gpio, int level) +{ + if (level) + gpio_reg[GPIO_SET0] = 1 << gpio; + else + gpio_reg[GPIO_CLR0] = 1 << gpio; +} + +static uint32_t +mem_virt_to_phys(void *virt) +{ + uint32_t offset = (uint8_t *)virt - mbox.virt_addr; + + return mbox.bus_addr + offset; +} + +static void * +map_peripheral(uint32_t base, uint32_t len) +{ + int fd = open("/dev/mem", O_RDWR|O_SYNC); + void * vaddr; + + if (fd < 0) + fatal("servod: Failed to open /dev/mem: %m\n"); + vaddr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, base); + if (vaddr == MAP_FAILED) + fatal("servod: Failed to map peripheral at 0x%08x: %m\n", base); + close(fd); + + return vaddr; +} + +static void +set_servo_idle(int servo) +{ + /* Just remove the 'turn-on' action and allow the 'turn-off' action at + * the end of the current pulse to turn it off. Special case if + * current width is 100%; in that case there will be no 'turn-off' + * action, so we will need to force the output off here. We must not + * force the output in other cases, because that might lead to + * truncated pulses which would make a servo change position. + */ + turnon_mask[servo] = 0; + if (servowidth[servo] == num_samples) + gpio_set(servo2gpio[servo], invert ? 1 : 0); +} + +/* Carefully add or remove bits from the turnoff_mask such that regardless + * of where the DMA controller is in its cycle, and whether we are increasing + * or decreasing the pulse width, the generated pulse will only ever be the + * old width or the new width. If we don't take such care then there could be + * a cycle with some pulse width between the two requested ones. That doesn't + * really matter for servos, but when driving LEDs some odd intensity for one + * cycle can be noticeable. It may be that the servo output has been turned + * off via the inactivity timer, which is handled by always setting the turnon + * mask appropriately at the end of this function. + */ +static void +set_servo(int servo, int width) +{ + volatile uint32_t *dp; + int i; + uint32_t mask = 1 << servo2gpio[servo]; + + + if (width > servowidth[servo]) { + dp = turnoff_mask + servostart[servo] + width; + if (dp >= turnoff_mask + num_samples) + dp -= num_samples; + + for (i = width; i > servowidth[servo]; i--) { + dp--; + if (dp < turnoff_mask) + dp = turnoff_mask + num_samples - 1; + //printf("%5d, clearing at %p\n", dp - ctl->turnoff, dp); + *dp &= ~mask; + } + } else if (width < servowidth[servo]) { + dp = turnoff_mask + servostart[servo] + width; + if (dp >= turnoff_mask + num_samples) + dp -= num_samples; + + for (i = width; i < servowidth[servo]; i++) { + //printf("%5d, setting at %p\n", dp - ctl->turnoff, dp); + *dp++ |= mask; + if (dp >= turnoff_mask + num_samples) + dp = turnoff_mask; + } + } + servowidth[servo] = width; + if (width == 0) { + turnon_mask[servo] = 0; + } else { + turnon_mask[servo] = mask; + } + update_idle_time(servo); +} + +static void +setup_sighandlers(void) +{ + int i; + + // Catch all signals possible - it is vital we kill the DMA engine + // on process exit! + for (i = 0; i < 64; i++) { + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = terminate; + sigaction(i, &sa, NULL); + } +} + +static void +init_ctrl_data(void) +{ + dma_cb_t *cbp = cb_base; + uint32_t phys_fifo_addr, cbinfo; + uint32_t phys_gpclr0; + uint32_t phys_gpset0; + int servo, i, numservos = 0, curstart = 0; + uint32_t maskall = 0; + + if (invert) { + phys_gpclr0 = GPIO_PHYS_BASE + 0x1c; + phys_gpset0 = GPIO_PHYS_BASE + 0x28; + } else { + phys_gpclr0 = GPIO_PHYS_BASE + 0x28; + phys_gpset0 = GPIO_PHYS_BASE + 0x1c; + } + + if (delay_hw == DELAY_VIA_PWM) { + phys_fifo_addr = PWM_PHYS_BASE + 0x18; + cbinfo = DMA_NO_WIDE_BURSTS | DMA_WAIT_RESP | DMA_D_DREQ | DMA_PER_MAP(5); + } else { + phys_fifo_addr = PCM_PHYS_BASE + 0x04; + cbinfo = DMA_NO_WIDE_BURSTS | DMA_WAIT_RESP | DMA_D_DREQ | DMA_PER_MAP(2); + } + + memset(turnon_mask, 0, MAX_SERVOS * sizeof(*turnon_mask)); + + for (servo = 0 ; servo < MAX_SERVOS; servo++) { + servowidth[servo] = 0; + if (servo2gpio[servo] != DMY) { + numservos++; + maskall |= 1 << servo2gpio[servo]; + } + } + + for (i = 0; i < num_samples; i++) + turnoff_mask[i] = maskall; + + for (servo = 0; servo < MAX_SERVOS; servo++) { + if (servo2gpio[servo] != DMY) { + servostart[servo] = curstart; + curstart += num_samples / num_servos; + } + } + + servo = 0; + while (servo < MAX_SERVOS && servo2gpio[servo] == DMY) + servo++; + + for (i = 0; i < num_samples; i++) { + cbp->info = DMA_NO_WIDE_BURSTS | DMA_WAIT_RESP; + cbp->src = mem_virt_to_phys(turnoff_mask + i); + cbp->dst = phys_gpclr0; + cbp->length = 4; + cbp->stride = 0; + cbp->next = mem_virt_to_phys(cbp + 1); + cbp++; + if (i == servostart[servo]) { + cbp->info = DMA_NO_WIDE_BURSTS | DMA_WAIT_RESP; + cbp->src = mem_virt_to_phys(turnon_mask + servo); + cbp->dst = phys_gpset0; + cbp->length = 4; + cbp->stride = 0; + cbp->next = mem_virt_to_phys(cbp + 1); + cbp++; + servo++; + while (servo < MAX_SERVOS && servo2gpio[servo] == DMY) + servo++; + } + // Delay + cbp->info = cbinfo; + cbp->src = mem_virt_to_phys(turnoff_mask); // Any data will do + cbp->dst = phys_fifo_addr; + cbp->length = 4; + cbp->stride = 0; + cbp->next = mem_virt_to_phys(cbp + 1); + cbp++; + } + cbp--; + cbp->next = mem_virt_to_phys(cb_base); +} + +static void +init_hardware(void) +{ + if (delay_hw == DELAY_VIA_PWM) { + // Initialise PWM + pwm_reg[PWM_CTL] = 0; + udelay(10); + clk_reg[PWMCLK_CNTL] = 0x5A000006; // Source=PLLD (500MHz) + udelay(100); + clk_reg[PWMCLK_DIV] = 0x5A000000 | (500<<12); // set pwm div to 500, giving 1MHz + udelay(100); + clk_reg[PWMCLK_CNTL] = 0x5A000016; // Source=PLLD and enable + udelay(100); + pwm_reg[PWM_RNG1] = step_time_us; + udelay(10); + pwm_reg[PWM_DMAC] = PWMDMAC_ENAB | PWMDMAC_THRSHLD; + udelay(10); + pwm_reg[PWM_CTL] = PWMCTL_CLRF; + udelay(10); + pwm_reg[PWM_CTL] = PWMCTL_USEF1 | PWMCTL_PWEN1; + udelay(10); + } else { + // Initialise PCM + pcm_reg[PCM_CS_A] = 1; // Disable Rx+Tx, Enable PCM block + udelay(100); + clk_reg[PCMCLK_CNTL] = 0x5A000006; // Source=PLLD (500MHz) + udelay(100); + clk_reg[PCMCLK_DIV] = 0x5A000000 | (500<<12); // Set pcm div to 500, giving 1MHz + udelay(100); + clk_reg[PCMCLK_CNTL] = 0x5A000016; // Source=PLLD and enable + udelay(100); + pcm_reg[PCM_TXC_A] = 0<<31 | 1<<30 | 0<<20 | 0<<16; // 1 channel, 8 bits + udelay(100); + pcm_reg[PCM_MODE_A] = (step_time_us - 1) << 10; + udelay(100); + pcm_reg[PCM_CS_A] |= 1<<4 | 1<<3; // Clear FIFOs + udelay(100); + pcm_reg[PCM_DREQ_A] = 64<<24 | 64<<8; // DMA Req when one slot is free? + udelay(100); + pcm_reg[PCM_CS_A] |= 1<<9; // Enable DMA + udelay(100); + } + + // Initialise the DMA + dma_reg[DMA_CS] = DMA_RESET; + udelay(10); + dma_reg[DMA_CS] = DMA_INT | DMA_END; + dma_reg[DMA_CONBLK_AD] = mem_virt_to_phys(cb_base); + dma_reg[DMA_DEBUG] = 7; // clear debug error flags + dma_reg[DMA_CS] = 0x10880001; // go, mid priority, wait for outstanding writes + + if (delay_hw == DELAY_VIA_PCM) { + pcm_reg[PCM_CS_A] |= 1<<2; // Enable Tx + } +} + +static void +do_debug(void) +{ + int i; + uint32_t mask = 0; + uint32_t last = 0xffffffff; + + printf("---------------------------\n"); + printf("Servo Start Width TurnOn\n"); + for (i = 0; i < MAX_SERVOS; i++) { + if (servo2gpio[i] != DMY) { + printf("%3d: %6d %6d %6d\n", i, servostart[i], + servowidth[i], !!turnon_mask[i]); + mask |= 1 << servo2gpio[i]; + } + } + printf("\nData:\n"); + for (i = 0; i < num_samples; i++) { + uint32_t curr = turnoff_mask[i] & mask; + if (curr != last) + printf("@%5d: %08x\n", i, curr); + last = curr; + } + printf("---------------------------\n"); +} + +static int +parse_width(int servo, char *width_arg) +{ + char *p; + char *digits = width_arg; + double width; + + if (*width_arg == '-' || *width_arg == '+') { + digits++; + } + + if (*digits < '0' || *digits > '9') { + return -1; + } + width = strtod(digits, &p); + + if (*p == '\0') { + /* Specified in steps */ + } else if (!strcmp(p, "us")) { + width /= step_time_us; + } else if (!strcmp(p, "%")) { + width = width * (servo_max_ticks - servo_min_ticks) / 100.0 + servo_min_ticks; + } else { + return -1; + } + width = floor(width); + if (*width_arg == '+') { + width = servowidth[servo] + width; + if (width > servo_max_ticks) + width = servo_max_ticks; + } else if (*width_arg == '-') { + width = servowidth[servo] - width; + if (width < servo_min_ticks) + width = servo_min_ticks; + } + + if (width == 0) { + return (int)width; + } else if (width < servo_min_ticks || width > servo_max_ticks) { + return -1; + } else { + return (int)width; + } +} + +static void +go_go_go(void) +{ + int fd; + struct timeval tv; + static char line[128]; + int nchars = 0; + + if ((fd = open(DEVFILE, O_RDWR|O_NONBLOCK)) == -1) + fatal("servod: Failed to open %s: %m\n", DEVFILE); + + for (;;) { + int n, width, servo; + fd_set ifds; + char width_arg[64]; + + FD_ZERO(&ifds); + FD_SET(fd, &ifds); + get_next_idle_timeout(&tv); + if ((n = select(fd+1, &ifds, NULL, NULL, &tv)) != 1) + continue; + while (read(fd, line+nchars, 1) == 1) { + if (line[nchars] == '\n') { + line[++nchars] = '\0'; + nchars = 0; + if (line[0] == 'p' || line[0] == 'P') { + int hdr, pin, width; + + n = sscanf(line+1, "%d-%d=%s", &hdr, &pin, width_arg); + if (n != 3) { + 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 = parse_width(servo, width_arg)) < 0) { + fprintf(stderr, "Invalid width specified\n"); + } else { + set_servo(servo, width); + } + } + } else { + n = sscanf(line, "%d=%s", &servo, width_arg); + if (!strcmp(line, "debug\n")) { + do_debug(); + } else if (n != 2) { + 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 = parse_width(servo, width_arg)) < 0) { + fprintf(stderr, "Invalid width specified\n"); + } else { + set_servo(servo, width); + } + } + } else { + if (++nchars >= 126) { + fprintf(stderr, "Input too long\n"); + nchars = 0; + } + } + } + } +} + +/* Determining the board revision is a lot more complicated than it should be + * (see comments in wiringPi for details). We will just look at the last two + * digits of the Revision string and treat '00' and '01' as errors, '02' and + * '03' as rev 1, and any other hex value as rev 2. + * TODO: This is wrong. Fix in line with current WiringPi. + */ +static void +get_model_and_revision(void) +{ + char buf[128], revstr[128], modelstr[128]; + char *ptr, *end, *res; + FILE *fp; + + revstr[0] = modelstr[0] = '\0'; + + fp = fopen("/proc/cpuinfo", "r"); + + if (!fp) + fatal("Unable to open /proc/cpuinfo: %m\n"); + + while ((res = fgets(buf, 128, fp))) { + if (!strncasecmp("model name", buf, 8)) + memcpy(modelstr, buf, 128); + else if (!strncasecmp(buf, "revision", 8)) + memcpy(revstr, buf, 128); + } + fclose(fp); + + if (modelstr[0] == '\0') + fatal("servod: No 'Model name' record in /proc/cpuinfo\n"); + if (revstr[0] == '\0') + fatal("servod: No 'Revision' record in /proc/cpuinfo\n"); + + if (strstr(modelstr, "ARMv6")) + board_model = 1; + else if (strstr(modelstr, "ARMv7")) + board_model = 2; + else + fatal("servod: Cannot parse the model name string\n"); + + ptr = revstr + strlen(revstr) - 3; + board_revision = strtol(ptr, &end, 16); + if (end != ptr + 2) + fatal("servod: Failed to parse Revision string\n"); + if (board_revision < 1) + fatal("servod: Invalid board Revision\n"); + else if (board_revision < 4) + board_revision = 1; + else + board_revision = 2; + + if (board_model == 1) { + periph_virt_base = 0x20000000; + periph_phys_base = 0x7e000000; + dram_phys_base = 0x40000000; + mem_flag = 0x0c; + } else { + periph_virt_base = 0x3f000000; + periph_phys_base = 0x7e000000; + dram_phys_base = 0xc0000000; + mem_flag = 0x04; + } +} + +static void +parse_pin_lists(int p1first, char *p1pins, char*p5pins) +{ + char *name, *pins; + 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"; + pins = p1pins; + if (board_model == 1 && board_revision == 1) { + map = rev1_p1pin2gpio_map; + mapcnt = sizeof(rev1_p1pin2gpio_map); + } else { + map = rev2_p1pin2gpio_map; + mapcnt = sizeof(rev2_p1pin2gpio_map); + } + pNpin2servo = p1pin2servo; + } else { + name = "P5"; + pins = p5pins; + if (board_model == 1 && board_revision == 1) { + map = rev1_p5pin2gpio_map; + mapcnt = sizeof(rev1_p5pin2gpio_map); + } else { + map = rev2_p5pin2gpio_map; + mapcnt = sizeof(rev2_p5pin2gpio_map); + } + pNpin2servo = p5pin2servo; + } + while (*pins) { + char *end; + long pin = strtol(pins, &end, 0); + + if (*end && (end == pins || *end != ',')) + fatal("Invalid character '%c' in %s pin list\n", *end, name); + if (pin < 0 || pin > mapcnt) + fatal("Invalid pin number %d in %s pin list\n", pin, name); + if (servo == MAX_SERVOS) + fatal("Too many servos specified\n"); + if (pin == 0) { + servo++; + } 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++; + } + pins = end; + if (*pins == ',') + 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) +{ + while (--len) { + if (map[len] == gpio) + return len+1; + } + return 0; +} + +static char * +gpio2pinname(uint8_t gpio) +{ + static char res[16]; + uint8_t pin; + + if (board_model == 1 && board_revision == 1) { + if ((pin = gpiosearch(gpio, rev1_p1pin2gpio_map, sizeof(rev1_p1pin2gpio_map)))) + sprintf(res, "P1-%d", pin); + else if ((pin = gpiosearch(gpio, rev1_p5pin2gpio_map, sizeof(rev1_p5pin2gpio_map)))) + sprintf(res, "P5-%d", pin); + else + fatal("Cannot map GPIO %d to a header pin\n", gpio); + } else { + if ((pin = gpiosearch(gpio, rev2_p1pin2gpio_map, sizeof(rev2_p1pin2gpio_map)))) + sprintf(res, "P1-%d", pin); + else if ((pin = gpiosearch(gpio, rev2_p5pin2gpio_map, sizeof(rev2_p5pin2gpio_map)))) + sprintf(res, "P5-%d", pin); + else + fatal("Cannot map GPIO %d to a header pin\n", gpio); + } + + return res; +} + +static int +parse_min_max_arg(char *arg, char *name) +{ + char *p; + double val = strtod(arg, &p); + + if (*arg < '0' || *arg > '9' || val < 0) { + fatal("Invalid %s value specified\n", name); + } else if (*p == '\0') { + if (val != floor(val)) { + fatal("Invalid %s value specified\n", name); + } + return (int)val; + } else if (!strcmp(p, "us")) { + if (val != floor(val)) { + fatal("Invalid %s value specified\n", name); + } + if ((int)val % step_time_us) { + fatal("%s value is not a multiple of step-time\n", name); + } + return val / step_time_us; + } else if (!strcmp(p, "%")) { + if (val < 0 || val > 100.0) { + fatal("%s value must be between 0% and 100% inclusive\n", name); + } + return (int)(val * (double)cycle_time_us / 100.0 / step_time_us); + } else { + fatal("Invalid %s value specified\n", name); + } + + return -1; /* Never reached */ +} + +int +main(int argc, char **argv) +{ + int i; + char *p1pins = default_p1_pins; + char *p5pins = default_p5_pins; + int p1first = 1, hadp1 = 0, hadp5 = 0; + char *servo_min_arg = NULL; + char *servo_max_arg = NULL; + char *idle_timeout_arg = NULL; + char *cycle_time_arg = NULL; + char *step_time_arg = NULL; + char *dma_chan_arg = NULL; + char *p; + int daemonize = 1; + + setvbuf(stdout, NULL, _IOLBF, 0); + + while (1) { + int c; + int option_index; + + static struct option long_options[] = { + { "pcm", no_argument, 0, 'p' }, + { "idle-timeout", required_argument, 0, 't' }, + { "help", no_argument, 0, 'h' }, + { "p1pins", required_argument, 0, '1' }, + { "p5pins", required_argument, 0, '5' }, + { "min", required_argument, 0, 'm' }, + { "max", required_argument, 0, 'x' }, + { "invert", no_argument, 0, 'i' }, + { "cycle-time", required_argument, 0, 'c' }, + { "step-size", required_argument, 0, 's' }, + { "debug", no_argument, 0, 'f' }, + { "dma-chan", required_argument, 0, 'd' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "mxhnt:15icsfd", long_options, &option_index); + if (c == -1) { + break; + } else if (c =='d') { + dma_chan_arg = optarg; + } else if (c == 'f') { + daemonize = 0; + } else if (c == 'p') { + delay_hw = DELAY_VIA_PCM; + } else if (c == 't') { + idle_timeout_arg = optarg; + } else if (c == 'c') { + cycle_time_arg = optarg; + } else if (c == 's') { + step_time_arg = optarg; + } else if (c == 'm') { + servo_min_arg = optarg; + } else if (c == 'x') { + servo_max_arg = optarg; + } else if (c == 'i') { + invert = 1; + } else if (c == 'h') { + printf("\nUsage: %s \n\n" + "Options:\n" + " --pcm tells servod to use PCM rather than PWM hardware\n" + " to implement delays\n" + " --idle-timeout=Nms tells servod to stop sending servo pulses for a\n" + " given output N milliseconds after the last update\n" + " --cycle-time=Nus Control pulse cycle time in microseconds, default\n" + " %dus\n" + " --step-size=Nus Pulse width increment step size in microseconds,\n" + " default %dus\n" + " --min={N|Nus|N%%} specifies the minimum allowed pulse width, default\n" + " %d steps or %dus\n" + " --max={N|Nus|N%%} specifies the maximum allowed pulse width, default\n" + " %d steps or %dus\n" + " --invert Inverts outputs\n" + " --dma-chan=N tells servod which dma channel to use, default %d\n" + " --p1pins= tells servod which pins on the P1 header to use\n" + " --p5pins= tells servod which pins on the P5 header to use\n" + "\nwhere defaults to \"%s\" for p1pins and\n" + "\"%s\" for p5pins. p5pins is only valid on rev 2 boards.\n\n" + "min and max values can be specified in units of steps, in microseconds,\n" + "or as a percentage of the cycle time. So, for example, if cycle time is\n" + "20000us and step size is 10us then the following are equivalent:\n\n" + " --min=50 --min=500us --min=2.5%%\n\n" + "For the default configuration, example commands to set the first servo\n" + "to the mid position would be any of:\n\n" + " echo 0=150 > /dev/servoblaster # Specify as a number of steps\n" + " echo 0=50%% > /dev/servoblaster # Specify as a percentage\n" + " echo 0=1500us > /dev/servoblaster # Specify as microseconds\n" + " echo P1-7=150 > /dev/servoblaster # Using P1 pin number rather\n" + " echo P1-7=50%% > /dev/servoblaster # ... than servo number\n" + " echo P1-7=1500us > /dev/servoblaster\n\n" + "Servo adjustments may also be specified relative to the current\n" + "position by adding a '+' or '-' prefix to the width as follows:\n\n" + " echo 0=+10 > /dev/servoblaster\n" + " echo 0=-20 > /dev/servoblaster\n\n", + argv[0], + DEFAULT_CYCLE_TIME_US, + DEFAULT_STEP_TIME_US, + DEFAULT_SERVO_MIN_US/DEFAULT_STEP_TIME_US, DEFAULT_SERVO_MIN_US, + DEFAULT_SERVO_MAX_US/DEFAULT_STEP_TIME_US, DEFAULT_SERVO_MAX_US, + DMA_CHAN_DEFAULT, default_p1_pins, default_p5_pins); + exit(0); + } else if (c == '1') { + p1pins = optarg; + hadp1 = 1; + if (!hadp5) + p1first = 1; + } else if (c == '5') { + p5pins = optarg; + hadp5 = 1; + if (!hadp1) + p1first = 0; + } else { + fatal("Invalid parameter\n"); + } + } + get_model_and_revision(); + if (board_model == 1 && board_revision == 1 && p5pins[0]) + fatal("Board model 1 revision 1 does not have a P5 header\n"); + + parse_pin_lists(p1first, p1pins, p5pins); + + if (dma_chan_arg) { + dma_chan = strtol(dma_chan_arg, &p, 10); + if (*dma_chan_arg < '0' || *dma_chan_arg > '9' || + *p || dma_chan < DMA_CHAN_MIN || dma_chan > DMA_CHAN_MAX) + fatal("Invalid dma-chan specified\n"); + } else { + dma_chan = DMA_CHAN_DEFAULT; + } + + if (idle_timeout_arg) { + idle_timeout = strtol(idle_timeout_arg, &p, 10); + if (*idle_timeout_arg < '0' || *idle_timeout_arg > '9' || + (*p && strcmp(p, "ms")) || + idle_timeout < 10 || idle_timeout > 3600000) + fatal("Invalid idle-timeout specified\n"); + } else { + idle_timeout = 0; + } + + if (cycle_time_arg) { + cycle_time_us = strtol(cycle_time_arg, &p, 10); + if (*cycle_time_arg < '0' || *cycle_time_arg > '9' || + (*p && strcmp(p, "us")) || + cycle_time_us < 1000 || cycle_time_us > 1000000) + fatal("Invalid cycle-time specified\n"); + } else { + cycle_time_us = DEFAULT_CYCLE_TIME_US; + } + + if (step_time_arg) { + step_time_us = strtol(step_time_arg, &p, 10); + if (*step_time_arg < '0' || *step_time_arg > '9' || + (*p && strcmp(p, "us")) || + step_time_us < 2 || step_time_us > 1000) { + fatal("Invalid step-size specified\n"); + } + } else { + step_time_us = DEFAULT_STEP_TIME_US; + } + + if (cycle_time_us % step_time_us) { + fatal("cycle-time is not a multiple of step-size\n"); + } + + if (cycle_time_us / step_time_us < 100) { + fatal("cycle-time must be at least 100 * step-size\n"); + } + + if (servo_min_arg) { + servo_min_ticks = parse_min_max_arg(servo_min_arg, "min"); + } else { + servo_min_ticks = DEFAULT_SERVO_MIN_US / step_time_us; + } + + if (servo_max_arg) { + servo_max_ticks = parse_min_max_arg(servo_max_arg, "max"); + } else { + servo_max_ticks = DEFAULT_SERVO_MAX_US / step_time_us; + } + + num_samples = cycle_time_us / step_time_us; + num_cbs = num_samples * 2 + MAX_SERVOS; + num_pages = (num_cbs * sizeof(dma_cb_t) + num_samples * 4 + + MAX_SERVOS * 4 + PAGE_SIZE - 1) >> PAGE_SHIFT; + + if (num_pages > MAX_MEMORY_USAGE / PAGE_SIZE) { + fatal("Using too much memory; reduce cycle-time or increase step-size\n"); + } + + if (servo_max_ticks > num_samples) { + fatal("max value is larger than cycle time\n"); + } + if (servo_min_ticks >= servo_max_ticks) { + fatal("min value is >= max value\n"); + } + + printf("\nBoard model: %7d\n", board_model); + printf("Board revision: %7d\n", board_revision); + printf("Using hardware: %s\n", delay_hw == DELAY_VIA_PWM ? "PWM" : "PCM"); + printf("Using DMA channel: %7d\n", dma_chan); + if (idle_timeout) + printf("Idle timeout: %7dms\n", idle_timeout); + else + printf("Idle timeout: Disabled\n"); + printf("Number of servos: %7d\n", num_servos); + printf("Servo cycle time: %7dus\n", cycle_time_us); + printf("Pulse increment step size: %7dus\n", step_time_us); + printf("Minimum width value: %7d (%dus)\n", servo_min_ticks, + servo_min_ticks * step_time_us); + printf("Maximum width value: %7d (%dus)\n", servo_max_ticks, + servo_max_ticks * step_time_us); + printf("Output levels: %s\n", invert ? "Inverted" : " Normal"); + printf("\nUsing P1 pins: %s\n", p1pins); + if (board_model > 1 || board_revision > 1) + printf("Using P5 pins: %s\n", p5pins); + printf("\nServo mapping:\n"); + for (i = 0; i < MAX_SERVOS; i++) { + if (servo2gpio[i] == DMY) + continue; + printf(" %2d on %-5s GPIO-%d\n", i, gpio2pinname(servo2gpio[i]), servo2gpio[i]); + } + printf("\n"); + + init_idle_timers(); + setup_sighandlers(); + + dma_reg = map_peripheral(DMA_VIRT_BASE, DMA_LEN); + dma_reg += dma_chan * DMA_CHAN_SIZE / sizeof(uint32_t); + pwm_reg = map_peripheral(PWM_VIRT_BASE, PWM_LEN); + pcm_reg = map_peripheral(PCM_VIRT_BASE, PCM_LEN); + clk_reg = map_peripheral(CLK_VIRT_BASE, CLK_LEN); + gpio_reg = map_peripheral(GPIO_VIRT_BASE, GPIO_LEN); + + /* Use the mailbox interface to the VC to ask for physical memory */ + unlink(MBFILE); + if (mknod(MBFILE, S_IFCHR|0600, makedev(249, 0)) < 0) + fatal("Failed to create mailbox device\n"); + mbox.handle = mbox_open(); + if (mbox.handle < 0) + fatal("Failed to open mailbox\n"); + mbox.mem_ref = mem_alloc(mbox.handle, num_pages * 4096, 4096, mem_flag); + /* TODO: How do we know that succeeded? */ + printf("mem_ref %u\n", mbox.mem_ref); + mbox.bus_addr = mem_lock(mbox.handle, mbox.mem_ref); + printf("bus_addr = %u\n", mbox.bus_addr); + mbox.virt_addr = mapmem(BUS_TO_PHYS(mbox.bus_addr), num_pages * 4096); + printf("virt_addr %p\n", mbox.virt_addr); + + turnoff_mask = (uint32_t *)mbox.virt_addr; + turnon_mask = (uint32_t *)(mbox.virt_addr + num_samples * sizeof(uint32_t)); + cb_base = (dma_cb_t *)(mbox.virt_addr + + ROUNDUP(num_samples + MAX_SERVOS, 8) * sizeof(uint32_t)); + + for (i = 0; i < MAX_SERVOS; i++) { + if (servo2gpio[i] == DMY) + continue; + gpiomode[i] = gpio_get_mode(servo2gpio[i]); + gpio_set(servo2gpio[i], invert ? 1 : 0); + gpio_set_mode(servo2gpio[i], GPIO_MODE_OUT); + } + restore_gpio_modes = 1; + + init_ctrl_data(); + init_hardware(); + + unlink(DEVFILE); + if (mkfifo(DEVFILE, 0666) < 0) + fatal("servod: Failed to create %s: %m\n", DEVFILE); + if (chmod(DEVFILE, 0666) < 0) + fatal("servod: Failed to set permissions on %s: %m\n", DEVFILE); + + if (daemonize && daemon(0,1) < 0) + fatal("servod: Failed to daemonize process: %m\n"); + + go_go_go(); + + return 0; +} + diff --git a/ServoBlaster/servodebug.c b/ServoBlaster/servodebug.c new file mode 100644 index 0000000..8db7005 --- /dev/null +++ b/ServoBlaster/servodebug.c @@ -0,0 +1,220 @@ +/* + * servodebug.c - a utility to help debug issues with ServoBlaster + * + * This code should be compiled with the command: + * + * gcc -Wall -O2 -o servodebug servodebug.c + * + * It should be run with the command: + * + * sudo chrt 1 ./servodebug + * + * Richard Hirst - Nov 25th 2012 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BCM2708_DMA_NO_WIDE_BURSTS (1<<26) +#define BCM2708_DMA_WAIT_RESP (1<<3) +#define BCM2708_DMA_D_DREQ (1<<6) +#define BCM2708_DMA_PER_MAP(x) ((x)<<16) +#define BCM2708_DMA_END (1<<1) +#define BCM2708_DMA_RESET (1<<31) +#define BCM2708_DMA_INT (1<<2) + +#define DMA_CHAN_SIZE 0x100 +#define DMA_CHAN_MIN 0 +#define DMA_CHAN_MAX 14 +#define DMA_CHAN_DEFAULT 14 + +#define DMA_CS (0x00/4) +#define DMA_CONBLK_AD (0x04/4) +#define DMA_DEBUG (0x20/4) + +#define GPIO_BASE 0x3f200000 +#define GPIO_LEN 0xB4 +#define DMA_BASE 0x3f007000 +#define DMA_LEN DMA_CHAN_SIZE * (DMA_CHAN_MAX+1) +#define PWM_BASE 0x3f20C000 +#define PWM_LEN 0x28 +#define CLK_BASE 0x3f101000 +#define CLK_LEN 0xA8 +#define TICK_BASE 0x3f003000 +#define TICK_LEN 0x08 + +#define PWM_CTL (0x00/4) +#define PWM_DMAC (0x08/4) +#define PWM_RNG1 (0x10/4) +#define PWM_FIFO (0x18/4) + +#define PWMCLK_CNTL 40 +#define PWMCLK_DIV 41 + +#define PWMCTL_MODE1 (1<<1) +#define PWMCTL_PWEN1 (1<<0) +#define PWMCTL_CLRF (1<<6) +#define PWMCTL_USEF1 (1<<5) + +#define PWMDMAC_ENAB (1<<31) +// I think this means it requests as soon as there is one free slot in the FIFO +// which is what we want as burst DMA would mess up our timing.. +#define PWMDMAC_THRSHLD ((15<<8)|(15<<0)) + +#define GPFSEL0 (0x00/4) +#define GPCLR0 (0x28/4) +#define GPLEV0 (0x34/4) + +typedef struct { + uint32_t info, src, dst, length, + stride, next, pad[2]; +} dma_cb_t; + +static volatile uint32_t *gpio_reg; +static volatile uint32_t *pwm_reg; +static volatile uint32_t *clk_reg; +static volatile uint32_t *dma_reg; +static volatile uint32_t *tick_reg; + +static uint32_t dma_chan = DMA_CHAN_DEFAULT; + +static uint8_t servo2gpio[] = { + 4, // P1-7 + 17, // P1-11 +#ifdef PWM0_ON_GPIO18 + 1, // P1-5 (GPIO-18, P1-12 is currently PWM0, for debug) +#else + 18, // P1-12 +#endif + 21, // P1-13 + 22, // P1-15 + 23, // P1-16 + 24, // P1-18 + 25, // P1-22 +}; +#define NUM_SERVOS (sizeof(servo2gpio)/sizeof(servo2gpio[0])) + +struct { + uint32_t stamp; + uint32_t levels; +} trans[20]; + +static void +fatal(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); +} + +static void +msleep(int ms) +{ + struct timespec ts = { 0, ms * 1000 * 1000 }; + + if (nanosleep(&ts, NULL)) { + fprintf(stderr, "nanosleep() failed: %s\n", strerror(errno)); + exit(1); + } +} + +static void * +map_peripheral(uint32_t base, uint32_t len) +{ + int fd = open("/dev/mem", O_RDWR); + void * vaddr; + + if (fd < 0) + fatal("Failed to open /dev/mem: %m\n"); + vaddr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, base); + if (vaddr == MAP_FAILED) + fatal("Failed to map peripheral at 0x%08x: %m\n", base); + close(fd); + + return vaddr; +} + +int +main(int argc, char **argv) +{ + int tr, i; + uint32_t v1, v2, mask, t1; + struct timeval tv1, tv2; + + printf("This code should be compiled with the command:\n\n"); + printf(" gcc -Wall -O2 -o servodebug servodebug.c\n"); + printf("\nIt should be run with the command:\n\n"); + printf(" sudo chrt 1 ./servodebug\n\n"); + gpio_reg = map_peripheral(GPIO_BASE, GPIO_LEN); + dma_reg = map_peripheral(DMA_BASE, DMA_LEN); + dma_reg += dma_chan * DMA_CHAN_SIZE / sizeof(uint32_t); + pwm_reg = map_peripheral(PWM_BASE, PWM_LEN); + clk_reg = map_peripheral(CLK_BASE, CLK_LEN); + tick_reg = map_peripheral(TICK_BASE, TICK_LEN); + + v1 = dma_reg[DMA_CONBLK_AD]; + msleep(5); + v2 = dma_reg[DMA_CONBLK_AD]; + + if (v1 == v2) + fatal("DMA controller is not running - is the module loaded?\n"); + printf("\nGood, DMA controller is running\n"); + + printf("\nTiming 1M cycles of system tick, should take 1000000us\n"); + printf("but small variations are to be expected\n"); + gettimeofday(&tv1, NULL); + v1 = tick_reg[1]; + while (tick_reg[1] - v1 < 1000000) + ; + gettimeofday(&tv2, NULL); + i = (tv2.tv_sec - tv1.tv_sec) * 1000000 + tv2.tv_usec - tv1.tv_usec; + printf("\n1M increments of system tick measured at %dus\n", i); + + printf("\nMonitoring for the first 20 transitions on servo control lines\n"); + + for (i = 0, mask = 0; i < NUM_SERVOS; i++) + mask |= 1 << servo2gpio[i]; + + t1 = tick_reg[1]; + v1 = gpio_reg[GPLEV0] & mask; + for (tr = 0; tr < 20; tr++) { + do { + if (tick_reg[1] - t1 > 1000000) + fatal("No servo pulses generated - have you tried \"echo 0=100 > /dev/servoblaster\"?\n"); + v2 = gpio_reg[GPLEV0] & mask; + } while (v1 == v2); + trans[tr].stamp = tick_reg[1]; + trans[tr].levels = v2; + v1 = v2; + } + + for (tr = 1; tr < 20; tr++) + trans[tr].stamp -= trans[0].stamp; + trans[0].stamp = 0; + printf("\n time outputs\n (us) 76543210\n"); + for (tr = 0; tr < 20; tr++) { + printf(" %6d ", trans[tr].stamp); + for (i = NUM_SERVOS - 1; i >= 0; i--) + printf("%s", trans[tr].levels & (1 << servo2gpio[i]) ? "1" : "0"); + printf("\n"); + } + printf("\n"); + + return 0; +} + From 37a7c6d383a921a61934ab8219b52b786bfa6082 Mon Sep 17 00:00:00 2001 From: Chang YiYu Date: Thu, 4 Feb 2016 18:01:56 +0800 Subject: [PATCH 7/7] Remove --- ServoBlaster/Makefile | 25 - ServoBlaster/init-script | 41 - ServoBlaster/mailbox.c | 261 ------- ServoBlaster/mailbox.h | 47 -- ServoBlaster/ripple.sh | 30 - ServoBlaster/servod.c | 1324 -------------------------------- ServoBlaster/servodebug.c | 220 ------ files/ServoBlaster.tar.gz | Bin 16732 -> 0 bytes files/ServoBlaster20160204.gz | Bin 16743 -> 0 bytes files/ServoBlaster20160204.tgz | Bin 16743 -> 0 bytes files/ServoBlaster20160204.zip | Bin 22405 -> 0 bytes 11 files changed, 1948 deletions(-) delete mode 100644 ServoBlaster/Makefile delete mode 100755 ServoBlaster/init-script delete mode 100644 ServoBlaster/mailbox.c delete mode 100644 ServoBlaster/mailbox.h delete mode 100755 ServoBlaster/ripple.sh delete mode 100644 ServoBlaster/servod.c delete mode 100644 ServoBlaster/servodebug.c delete mode 100644 files/ServoBlaster.tar.gz delete mode 100644 files/ServoBlaster20160204.gz delete mode 100644 files/ServoBlaster20160204.tgz delete mode 100644 files/ServoBlaster20160204.zip diff --git a/ServoBlaster/Makefile b/ServoBlaster/Makefile deleted file mode 100644 index fbcee13..0000000 --- a/ServoBlaster/Makefile +++ /dev/null @@ -1,25 +0,0 @@ - -.PHONY: all install uninstall -all: servod - -servod: servod.c mailbox.c - gcc -Wall -g -O2 -o servod servod.c mailbox.c -lm - -install: servod - [ "`id -u`" = "0" ] || { echo "Must be run as root"; exit 1; } - cp -f servod /usr/local/sbin - cp -f init-script /etc/init.d/servoblaster - chmod 755 /etc/init.d/servoblaster - update-rc.d servoblaster defaults 92 08 - /etc/init.d/servoblaster start - -uninstall: - [ "`id -u`" = "0" ] || { echo "Must be run as root"; exit 1; } - [ -e /etc/init.d/servoblaster ] && /etc/init.d/servoblaster stop || : - update-rc.d servoblaster remove - rm -f /usr/local/sbin/servod - rm -f /etc/init.d/servoblaster - -clean: - rm -f servod - diff --git a/ServoBlaster/init-script b/ServoBlaster/init-script deleted file mode 100755 index 269b053..0000000 --- a/ServoBlaster/init-script +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh -### BEGIN INIT INFO -# Provides: servoblaster -# Required-Start: hostname $local_fs -# Required-Stop: -# Should-Start: -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Start/stop servod. -# Description: This script starts/stops servod. -### END INIT INFO - -PATH=/sbin:/usr/sbin:/bin:/usr/bin -. /lib/init/vars.sh - -OPTS="--idle-timeout=2000" - -res=0 - -case "$1" in - start) - /usr/local/sbin/servod $OPTS >/dev/null - ;; - restart|reload|force-reload) - killall servod - /usr/local/sbin/servod $OPTS >/dev/null - ;; - stop) - killall servod - ;; - status) - [ -e /dev/servoblaster ] || res=4 - ;; - *) - echo "Usage: servoblaster [start|stop|status]" >&2 - res=3 - ;; -esac - -exit $res - diff --git a/ServoBlaster/mailbox.c b/ServoBlaster/mailbox.c deleted file mode 100644 index d019cc7..0000000 --- a/ServoBlaster/mailbox.c +++ /dev/null @@ -1,261 +0,0 @@ -/* -Copyright (c) 2012, Broadcom Europe Ltd. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mailbox.h" - -#define PAGE_SIZE (4*1024) - -void *mapmem(unsigned base, unsigned size) -{ - int mem_fd; - unsigned offset = base % PAGE_SIZE; - base = base - offset; - /* open /dev/mem */ - if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) { - printf("can't open /dev/mem\nThis program should be run as root. Try prefixing command with: sudo\n"); - exit (-1); - } - void *mem = mmap( - 0, - size, - PROT_READ|PROT_WRITE, - MAP_SHARED/*|MAP_FIXED*/, - mem_fd, - base); -#ifdef DEBUG - printf("base=0x%x, mem=%p\n", base, mem); -#endif - if (mem == MAP_FAILED) { - printf("mmap error %d\n", (int)mem); - exit (-1); - } - close(mem_fd); - return (char *)mem + offset; -} - -void *unmapmem(void *addr, unsigned size) -{ - int s = munmap(addr, size); - if (s != 0) { - printf("munmap error %d\n", s); - exit (-1); - } - - return NULL; -} - -/* - * use ioctl to send mbox property message - */ - -static int mbox_property(int file_desc, void *buf) -{ - int ret_val = ioctl(file_desc, IOCTL_MBOX_PROPERTY, buf); - - if (ret_val < 0) { - printf("ioctl_set_msg failed:%d\n", ret_val); - } - -#ifdef DEBUG - unsigned *p = buf; int i; unsigned size = *(unsigned *)buf; - for (i=0; i - -#define MAJOR_NUM 100 -#define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM, 0, char *) -#define DEVICE_FILE_NAME "/dev/servoblaster-mb" - -int mbox_open(); -void mbox_close(int file_desc); - -unsigned get_version(int file_desc); -unsigned mem_alloc(int file_desc, unsigned size, unsigned align, unsigned flags); -unsigned mem_free(int file_desc, unsigned handle); -unsigned mem_lock(int file_desc, unsigned handle); -unsigned mem_unlock(int file_desc, unsigned handle); -void *mapmem(unsigned base, unsigned size); -void *unmapmem(void *addr, unsigned size); - -unsigned execute_code(int file_desc, unsigned code, unsigned r0, unsigned r1, unsigned r2, unsigned r3, unsigned r4, unsigned r5); -unsigned execute_qpu(int file_desc, unsigned num_qpus, unsigned control, unsigned noflush, unsigned timeout); -unsigned qpu_enable(int file_desc, unsigned enable); diff --git a/ServoBlaster/ripple.sh b/ServoBlaster/ripple.sh deleted file mode 100755 index 4cb1a6b..0000000 --- a/ServoBlaster/ripple.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -leds() -{ - echo 0=$1 > /dev/servoblaster - echo 1=$2 > /dev/servoblaster - echo 2=$3 > /dev/servoblaster - echo 4=$4 > /dev/servoblaster -} - -b=0 -d=0.1 - -while true; do - leds $b 0 0 0 - sleep $d - leds 0 $b 0 0 - sleep $d - leds 0 0 $b 0 - sleep $d - leds 0 0 0 $b - sleep $d - leds 0 0 $b 0 - sleep $d - leds 0 $b 0 0 - sleep $d - b=$(( b + 100 )) - [ $b = 2000 ] && b=0 -done - diff --git a/ServoBlaster/servod.c b/ServoBlaster/servod.c deleted file mode 100644 index 407e9ed..0000000 --- a/ServoBlaster/servod.c +++ /dev/null @@ -1,1324 +0,0 @@ -/* - * servod.c Multiple Servo Driver for the RaspberryPi - * Copyright (c) 2013 Richard Hirst - * - * This program provides very similar functionality to servoblaster, except - * that rather than implementing it as a kernel module, servod implements - * the functionality as a usr space daemon. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* TODO: Separate idle timeout handling from genuine set-to-zero requests */ -/* TODO: Add ability to specify time frame over which an adjustment should be made */ -/* TODO: Add servoctl utility to set and query servo positions, etc */ -/* TODO: Add slow-start option */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mailbox.h" - -#define DMY 255 // Used to represent an invalid P1 pin, or unmapped servo - -#define NUM_P1PINS 26 -#define NUM_P5PINS 8 - -#define MAX_SERVOS 32 /* Only 21 really, but this lets you map servo IDs - * to P1 pins, if you want to - */ -#define MAX_MEMORY_USAGE (16*1024*1024) /* Somewhat arbitrary limit of 16MB */ - -#define DEFAULT_CYCLE_TIME_US 20000 -#define DEFAULT_STEP_TIME_US 10 -#define DEFAULT_SERVO_MIN_US 500 -#define DEFAULT_SERVO_MAX_US 2500 - -#define DEVFILE "/dev/servoblaster" -#define CFGFILE "/dev/servoblaster-cfg" -#define MBFILE DEVICE_FILE_NAME /* From mailbox.h */ - -#define PAGE_SIZE 4096 -#define PAGE_SHIFT 12 - -#define DMA_CHAN_SIZE 0x100 -#define DMA_CHAN_MIN 0 -#define DMA_CHAN_MAX 14 -#define DMA_CHAN_DEFAULT 14 - -#define DMA_BASE_OFFSET 0x00007000 -#define DMA_LEN DMA_CHAN_SIZE * (DMA_CHAN_MAX+1) -#define PWM_BASE_OFFSET 0x0020C000 -#define PWM_LEN 0x28 -#define CLK_BASE_OFFSET 0x00101000 -#define CLK_LEN 0xA8 -#define GPIO_BASE_OFFSET 0x00200000 -#define GPIO_LEN 0x100 -#define PCM_BASE_OFFSET 0x00203000 -#define PCM_LEN 0x24 - -#define DMA_VIRT_BASE (periph_virt_base + DMA_BASE_OFFSET) -#define PWM_VIRT_BASE (periph_virt_base + PWM_BASE_OFFSET) -#define CLK_VIRT_BASE (periph_virt_base + CLK_BASE_OFFSET) -#define GPIO_VIRT_BASE (periph_virt_base + GPIO_BASE_OFFSET) -#define PCM_VIRT_BASE (periph_virt_base + PCM_BASE_OFFSET) - -#define PWM_PHYS_BASE (periph_phys_base + PWM_BASE_OFFSET) -#define PCM_PHYS_BASE (periph_phys_base + PCM_BASE_OFFSET) -#define GPIO_PHYS_BASE (periph_phys_base + GPIO_BASE_OFFSET) - -#define DMA_NO_WIDE_BURSTS (1<<26) -#define DMA_WAIT_RESP (1<<3) -#define DMA_D_DREQ (1<<6) -#define DMA_PER_MAP(x) ((x)<<16) -#define DMA_END (1<<1) -#define DMA_RESET (1<<31) -#define DMA_INT (1<<2) - -#define DMA_CS (0x00/4) -#define DMA_CONBLK_AD (0x04/4) -#define DMA_DEBUG (0x20/4) - -#define GPIO_FSEL0 (0x00/4) -#define GPIO_SET0 (0x1c/4) -#define GPIO_CLR0 (0x28/4) -#define GPIO_LEV0 (0x34/4) -#define GPIO_PULLEN (0x94/4) -#define GPIO_PULLCLK (0x98/4) - -#define GPIO_MODE_IN 0 -#define GPIO_MODE_OUT 1 - -#define PWM_CTL (0x00/4) -#define PWM_DMAC (0x08/4) -#define PWM_RNG1 (0x10/4) -#define PWM_FIFO (0x18/4) - -#define PWMCLK_CNTL 40 -#define PWMCLK_DIV 41 - -#define PWMCTL_MODE1 (1<<1) -#define PWMCTL_PWEN1 (1<<0) -#define PWMCTL_CLRF (1<<6) -#define PWMCTL_USEF1 (1<<5) - -#define PWMDMAC_ENAB (1<<31) -#define PWMDMAC_THRSHLD ((15<<8)|(15<<0)) - -#define PCM_CS_A (0x00/4) -#define PCM_FIFO_A (0x04/4) -#define PCM_MODE_A (0x08/4) -#define PCM_RXC_A (0x0c/4) -#define PCM_TXC_A (0x10/4) -#define PCM_DREQ_A (0x14/4) -#define PCM_INTEN_A (0x18/4) -#define PCM_INT_STC_A (0x1c/4) -#define PCM_GRAY (0x20/4) - -#define PCMCLK_CNTL 38 -#define PCMCLK_DIV 39 - -#define DELAY_VIA_PWM 0 -#define DELAY_VIA_PCM 1 - -#define ROUNDUP(val, blksz) (((val)+((blksz)-1)) & ~(blksz-1)) - -typedef struct { - uint32_t info, src, dst, length, - stride, next, pad[2]; -} dma_cb_t; - -#define BUS_TO_PHYS(x) ((x)&~0xC0000000) - -/* Define which P1 header pins to use by default. These are the eight standard - * GPIO pins (those coloured green in the diagram on this page: - * http://elinux.org/Rpi_Low-level_peripherals - * - * Which P1 header pins are actually used can be overridden via command line - * parameter '--p1pins=...'. - */ - -static char *default_p1_pins = "7,11,12,13,15,16,18,22"; -static char *default_p5_pins = ""; - -static uint8_t rev1_p1pin2gpio_map[] = { - DMY, // P1-1 3v3 - DMY, // P1-2 5v - 0, // P1-3 GPIO 0 (SDA) - DMY, // P1-4 5v - 1, // P1-5 GPIO 1 (SCL) - DMY, // P1-6 Ground - 4, // P1-7 GPIO 4 (GPCLK0) - 14, // P1-8 GPIO 14 (TXD) - DMY, // P1-9 Ground - 15, // P1-10 GPIO 15 (RXD) - 17, // P1-11 GPIO 17 - 18, // P1-12 GPIO 18 (PCM_CLK) - 21, // P1-13 GPIO 21 - DMY, // P1-14 Ground - 22, // P1-15 GPIO 22 - 23, // P1-16 GPIO 23 - DMY, // P1-17 3v3 - 24, // P1-18 GPIO 24 - 10, // P1-19 GPIO 10 (MOSI) - DMY, // P1-20 Ground - 9, // P1-21 GPIO 9 (MISO) - 25, // P1-22 GPIO 25 - 11, // P1-23 GPIO 11 (SCLK) - 8, // P1-24 GPIO 8 (CE0) - DMY, // P1-25 Ground - 7, // P1-26 GPIO 7 (CE1) -}; - -static uint8_t rev1_p5pin2gpio_map[] = { - DMY, // (P5-1 on rev 2 boards) - DMY, // (P5-2 on rev 2 boards) - DMY, // (P5-3 on rev 2 boards) - DMY, // (P5-4 on rev 2 boards) - DMY, // (P5-5 on rev 2 boards) - DMY, // (P5-6 on rev 2 boards) - DMY, // (P5-7 on rev 2 boards) - DMY, // (P5-8 on rev 2 boards) -}; - -static uint8_t rev2_p1pin2gpio_map[] = { - DMY, // P1-1 3v3 - DMY, // P1-2 5v - 2, // P1-3 GPIO 2 (SDA) - DMY, // P1-4 5v - 3, // P1-5 GPIO 3 (SCL) - DMY, // P1-6 Ground - 4, // P1-7 GPIO 4 (GPCLK0) - 14, // P1-8 GPIO 14 (TXD) - DMY, // P1-9 Ground - 15, // P1-10 GPIO 15 (RXD) - 17, // P1-11 GPIO 17 - 18, // P1-12 GPIO 18 (PCM_CLK) - 27, // P1-13 GPIO 27 - DMY, // P1-14 Ground - 22, // P1-15 GPIO 22 - 23, // P1-16 GPIO 23 - DMY, // P1-17 3v3 - 24, // P1-18 GPIO 24 - 10, // P1-19 GPIO 10 (MOSI) - DMY, // P1-20 Ground - 9, // P1-21 GPIO 9 (MISO) - 25, // P1-22 GPIO 25 - 11, // P1-23 GPIO 11 (SCLK) - 8, // P1-24 GPIO 8 (CE0) - DMY, // P1-25 Ground - 7, // P1-26 GPIO 7 (CE1) -}; - -static uint8_t rev2_p5pin2gpio_map[] = { - DMY, // P5-1 5v0 - DMY, // P5-2 3v3 - 28, // P5-3 GPIO 28 (I2C0_SDA) - 29, // P5-4 GPIO 29 (I2C0_SCL) - 30, // P5-5 GPIO 30 - 31, // P5-6 GPIO 31 - DMY, // P5-7 Ground - DMY, // P5-8 Ground -}; - -// cycle_time_us is the pulse cycle time per servo, in microseconds. -// Typically it should be 20ms, or 20000us. - -// step_time_us is the pulse width increment granularity, again in microseconds. -// Setting step_time_us too low will likely cause problems as the DMA controller -// will use too much memory bandwidth. 10us is a good value, though you -// might be ok setting it as low as 2us. - -static int cycle_time_us; -static int step_time_us; - -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; -static uint32_t gpiomode[MAX_SERVOS]; -static int restore_gpio_modes; - -static volatile uint32_t *pwm_reg; -static volatile uint32_t *pcm_reg; -static volatile uint32_t *clk_reg; -static volatile uint32_t *dma_reg; -static volatile uint32_t *gpio_reg; - -static int delay_hw = DELAY_VIA_PWM; - -static struct timeval *servo_kill_time; - -static int dma_chan; -static int idle_timeout; -static int invert = 0; -static int servo_min_ticks; -static int servo_max_ticks; -static int num_samples; -static int num_cbs; -static int num_pages; -static uint32_t *turnoff_mask; -static uint32_t *turnon_mask; -static dma_cb_t *cb_base; - -static int board_model; -static int board_revision; - -static uint32_t periph_phys_base; -static uint32_t periph_virt_base; -static uint32_t dram_phys_base; -static uint32_t mem_flag; - -static struct { - int handle; /* From mbox_open() */ - unsigned mem_ref; /* From mem_alloc() */ - unsigned bus_addr; /* From mem_lock() */ - uint8_t *virt_addr; /* From mapmem() */ -} mbox; - -static void set_servo(int servo, int width); -static void set_servo_idle(int servo); -static void gpio_set_mode(uint32_t gpio, uint32_t mode); -static char *gpio2pinname(uint8_t gpio); - -static void -udelay(int us) -{ - struct timespec ts = { 0, us * 1000 }; - - nanosleep(&ts, NULL); -} - -static void -terminate(int dummy) -{ - int i; - - if (dma_reg && mbox.virt_addr) { - for (i = 0; i < MAX_SERVOS; i++) { - if (servo2gpio[i] != DMY) - set_servo(i, 0); - } - udelay(cycle_time_us); - dma_reg[DMA_CS] = DMA_RESET; - udelay(10); - } - if (restore_gpio_modes) { - for (i = 0; i < MAX_SERVOS; i++) { - if (servo2gpio[i] != DMY) - gpio_set_mode(servo2gpio[i], gpiomode[i]); - } - } - if (mbox.virt_addr != NULL) { - unmapmem(mbox.virt_addr, num_pages * 4096); - mem_unlock(mbox.handle, mbox.mem_ref); - mem_free(mbox.handle, mbox.mem_ref); - } - - unlink(DEVFILE); - unlink(CFGFILE); - exit(1); -} - -static void -fatal(char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - terminate(0); -} - -static void -init_idle_timers(void) -{ - servo_kill_time = calloc(MAX_SERVOS, sizeof(struct timeval)); - if (!servo_kill_time) - fatal("servod: calloc() failed\n"); -} - -static void -update_idle_time(int servo) -{ - if (idle_timeout == 0) - return; - - gettimeofday(servo_kill_time + servo, NULL); - servo_kill_time[servo].tv_sec += idle_timeout / 1000; - servo_kill_time[servo].tv_usec += (idle_timeout % 1000) * 1000; - while (servo_kill_time[servo].tv_usec >= 1000000) { - servo_kill_time[servo].tv_usec -= 1000000; - servo_kill_time[servo].tv_sec++; - } -} - -static void -get_next_idle_timeout(struct timeval *tv) -{ - int i; - struct timeval now; - struct timeval min = { 60, 0 }; - long this_diff, min_diff; - - gettimeofday(&now, NULL); - for (i = 0; i < MAX_SERVOS; i++) { - if (servo2gpio[i] == DMY || servo_kill_time[i].tv_sec == 0) - continue; - else if (servo_kill_time[i].tv_sec < now.tv_sec || - (servo_kill_time[i].tv_sec == now.tv_sec && - servo_kill_time[i].tv_usec <= now.tv_usec)) { - servo_kill_time[i].tv_sec = 0; - set_servo_idle(i); - } else { - this_diff = (servo_kill_time[i].tv_sec - now.tv_sec) * 1000000 - + servo_kill_time[i].tv_usec - now.tv_usec; - min_diff = min.tv_sec * 1000000 + min.tv_usec; - if (this_diff < min_diff) { - min.tv_sec = this_diff / 1000000; - min.tv_usec = this_diff % 1000000; - } - } - } - *tv = min; -} - -static uint32_t gpio_get_mode(uint32_t gpio) -{ - uint32_t fsel = gpio_reg[GPIO_FSEL0 + gpio/10]; - - return (fsel >> ((gpio % 10) * 3)) & 7; -} - -static void -gpio_set_mode(uint32_t gpio, uint32_t mode) -{ - uint32_t fsel = gpio_reg[GPIO_FSEL0 + gpio/10]; - - fsel &= ~(7 << ((gpio % 10) * 3)); - fsel |= mode << ((gpio % 10) * 3); - gpio_reg[GPIO_FSEL0 + gpio/10] = fsel; -} - -static void -gpio_set(int gpio, int level) -{ - if (level) - gpio_reg[GPIO_SET0] = 1 << gpio; - else - gpio_reg[GPIO_CLR0] = 1 << gpio; -} - -static uint32_t -mem_virt_to_phys(void *virt) -{ - uint32_t offset = (uint8_t *)virt - mbox.virt_addr; - - return mbox.bus_addr + offset; -} - -static void * -map_peripheral(uint32_t base, uint32_t len) -{ - int fd = open("/dev/mem", O_RDWR|O_SYNC); - void * vaddr; - - if (fd < 0) - fatal("servod: Failed to open /dev/mem: %m\n"); - vaddr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, base); - if (vaddr == MAP_FAILED) - fatal("servod: Failed to map peripheral at 0x%08x: %m\n", base); - close(fd); - - return vaddr; -} - -static void -set_servo_idle(int servo) -{ - /* Just remove the 'turn-on' action and allow the 'turn-off' action at - * the end of the current pulse to turn it off. Special case if - * current width is 100%; in that case there will be no 'turn-off' - * action, so we will need to force the output off here. We must not - * force the output in other cases, because that might lead to - * truncated pulses which would make a servo change position. - */ - turnon_mask[servo] = 0; - if (servowidth[servo] == num_samples) - gpio_set(servo2gpio[servo], invert ? 1 : 0); -} - -/* Carefully add or remove bits from the turnoff_mask such that regardless - * of where the DMA controller is in its cycle, and whether we are increasing - * or decreasing the pulse width, the generated pulse will only ever be the - * old width or the new width. If we don't take such care then there could be - * a cycle with some pulse width between the two requested ones. That doesn't - * really matter for servos, but when driving LEDs some odd intensity for one - * cycle can be noticeable. It may be that the servo output has been turned - * off via the inactivity timer, which is handled by always setting the turnon - * mask appropriately at the end of this function. - */ -static void -set_servo(int servo, int width) -{ - volatile uint32_t *dp; - int i; - uint32_t mask = 1 << servo2gpio[servo]; - - - if (width > servowidth[servo]) { - dp = turnoff_mask + servostart[servo] + width; - if (dp >= turnoff_mask + num_samples) - dp -= num_samples; - - for (i = width; i > servowidth[servo]; i--) { - dp--; - if (dp < turnoff_mask) - dp = turnoff_mask + num_samples - 1; - //printf("%5d, clearing at %p\n", dp - ctl->turnoff, dp); - *dp &= ~mask; - } - } else if (width < servowidth[servo]) { - dp = turnoff_mask + servostart[servo] + width; - if (dp >= turnoff_mask + num_samples) - dp -= num_samples; - - for (i = width; i < servowidth[servo]; i++) { - //printf("%5d, setting at %p\n", dp - ctl->turnoff, dp); - *dp++ |= mask; - if (dp >= turnoff_mask + num_samples) - dp = turnoff_mask; - } - } - servowidth[servo] = width; - if (width == 0) { - turnon_mask[servo] = 0; - } else { - turnon_mask[servo] = mask; - } - update_idle_time(servo); -} - -static void -setup_sighandlers(void) -{ - int i; - - // Catch all signals possible - it is vital we kill the DMA engine - // on process exit! - for (i = 0; i < 64; i++) { - struct sigaction sa; - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = terminate; - sigaction(i, &sa, NULL); - } -} - -static void -init_ctrl_data(void) -{ - dma_cb_t *cbp = cb_base; - uint32_t phys_fifo_addr, cbinfo; - uint32_t phys_gpclr0; - uint32_t phys_gpset0; - int servo, i, numservos = 0, curstart = 0; - uint32_t maskall = 0; - - if (invert) { - phys_gpclr0 = GPIO_PHYS_BASE + 0x1c; - phys_gpset0 = GPIO_PHYS_BASE + 0x28; - } else { - phys_gpclr0 = GPIO_PHYS_BASE + 0x28; - phys_gpset0 = GPIO_PHYS_BASE + 0x1c; - } - - if (delay_hw == DELAY_VIA_PWM) { - phys_fifo_addr = PWM_PHYS_BASE + 0x18; - cbinfo = DMA_NO_WIDE_BURSTS | DMA_WAIT_RESP | DMA_D_DREQ | DMA_PER_MAP(5); - } else { - phys_fifo_addr = PCM_PHYS_BASE + 0x04; - cbinfo = DMA_NO_WIDE_BURSTS | DMA_WAIT_RESP | DMA_D_DREQ | DMA_PER_MAP(2); - } - - memset(turnon_mask, 0, MAX_SERVOS * sizeof(*turnon_mask)); - - for (servo = 0 ; servo < MAX_SERVOS; servo++) { - servowidth[servo] = 0; - if (servo2gpio[servo] != DMY) { - numservos++; - maskall |= 1 << servo2gpio[servo]; - } - } - - for (i = 0; i < num_samples; i++) - turnoff_mask[i] = maskall; - - for (servo = 0; servo < MAX_SERVOS; servo++) { - if (servo2gpio[servo] != DMY) { - servostart[servo] = curstart; - curstart += num_samples / num_servos; - } - } - - servo = 0; - while (servo < MAX_SERVOS && servo2gpio[servo] == DMY) - servo++; - - for (i = 0; i < num_samples; i++) { - cbp->info = DMA_NO_WIDE_BURSTS | DMA_WAIT_RESP; - cbp->src = mem_virt_to_phys(turnoff_mask + i); - cbp->dst = phys_gpclr0; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; - if (i == servostart[servo]) { - cbp->info = DMA_NO_WIDE_BURSTS | DMA_WAIT_RESP; - cbp->src = mem_virt_to_phys(turnon_mask + servo); - cbp->dst = phys_gpset0; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; - servo++; - while (servo < MAX_SERVOS && servo2gpio[servo] == DMY) - servo++; - } - // Delay - cbp->info = cbinfo; - cbp->src = mem_virt_to_phys(turnoff_mask); // Any data will do - cbp->dst = phys_fifo_addr; - cbp->length = 4; - cbp->stride = 0; - cbp->next = mem_virt_to_phys(cbp + 1); - cbp++; - } - cbp--; - cbp->next = mem_virt_to_phys(cb_base); -} - -static void -init_hardware(void) -{ - if (delay_hw == DELAY_VIA_PWM) { - // Initialise PWM - pwm_reg[PWM_CTL] = 0; - udelay(10); - clk_reg[PWMCLK_CNTL] = 0x5A000006; // Source=PLLD (500MHz) - udelay(100); - clk_reg[PWMCLK_DIV] = 0x5A000000 | (500<<12); // set pwm div to 500, giving 1MHz - udelay(100); - clk_reg[PWMCLK_CNTL] = 0x5A000016; // Source=PLLD and enable - udelay(100); - pwm_reg[PWM_RNG1] = step_time_us; - udelay(10); - pwm_reg[PWM_DMAC] = PWMDMAC_ENAB | PWMDMAC_THRSHLD; - udelay(10); - pwm_reg[PWM_CTL] = PWMCTL_CLRF; - udelay(10); - pwm_reg[PWM_CTL] = PWMCTL_USEF1 | PWMCTL_PWEN1; - udelay(10); - } else { - // Initialise PCM - pcm_reg[PCM_CS_A] = 1; // Disable Rx+Tx, Enable PCM block - udelay(100); - clk_reg[PCMCLK_CNTL] = 0x5A000006; // Source=PLLD (500MHz) - udelay(100); - clk_reg[PCMCLK_DIV] = 0x5A000000 | (500<<12); // Set pcm div to 500, giving 1MHz - udelay(100); - clk_reg[PCMCLK_CNTL] = 0x5A000016; // Source=PLLD and enable - udelay(100); - pcm_reg[PCM_TXC_A] = 0<<31 | 1<<30 | 0<<20 | 0<<16; // 1 channel, 8 bits - udelay(100); - pcm_reg[PCM_MODE_A] = (step_time_us - 1) << 10; - udelay(100); - pcm_reg[PCM_CS_A] |= 1<<4 | 1<<3; // Clear FIFOs - udelay(100); - pcm_reg[PCM_DREQ_A] = 64<<24 | 64<<8; // DMA Req when one slot is free? - udelay(100); - pcm_reg[PCM_CS_A] |= 1<<9; // Enable DMA - udelay(100); - } - - // Initialise the DMA - dma_reg[DMA_CS] = DMA_RESET; - udelay(10); - dma_reg[DMA_CS] = DMA_INT | DMA_END; - dma_reg[DMA_CONBLK_AD] = mem_virt_to_phys(cb_base); - dma_reg[DMA_DEBUG] = 7; // clear debug error flags - dma_reg[DMA_CS] = 0x10880001; // go, mid priority, wait for outstanding writes - - if (delay_hw == DELAY_VIA_PCM) { - pcm_reg[PCM_CS_A] |= 1<<2; // Enable Tx - } -} - -static void -do_debug(void) -{ - int i; - uint32_t mask = 0; - uint32_t last = 0xffffffff; - - printf("---------------------------\n"); - printf("Servo Start Width TurnOn\n"); - for (i = 0; i < MAX_SERVOS; i++) { - if (servo2gpio[i] != DMY) { - printf("%3d: %6d %6d %6d\n", i, servostart[i], - servowidth[i], !!turnon_mask[i]); - mask |= 1 << servo2gpio[i]; - } - } - printf("\nData:\n"); - for (i = 0; i < num_samples; i++) { - uint32_t curr = turnoff_mask[i] & mask; - if (curr != last) - printf("@%5d: %08x\n", i, curr); - last = curr; - } - printf("---------------------------\n"); -} - -static int -parse_width(int servo, char *width_arg) -{ - char *p; - char *digits = width_arg; - double width; - - if (*width_arg == '-' || *width_arg == '+') { - digits++; - } - - if (*digits < '0' || *digits > '9') { - return -1; - } - width = strtod(digits, &p); - - if (*p == '\0') { - /* Specified in steps */ - } else if (!strcmp(p, "us")) { - width /= step_time_us; - } else if (!strcmp(p, "%")) { - width = width * (servo_max_ticks - servo_min_ticks) / 100.0 + servo_min_ticks; - } else { - return -1; - } - width = floor(width); - if (*width_arg == '+') { - width = servowidth[servo] + width; - if (width > servo_max_ticks) - width = servo_max_ticks; - } else if (*width_arg == '-') { - width = servowidth[servo] - width; - if (width < servo_min_ticks) - width = servo_min_ticks; - } - - if (width == 0) { - return (int)width; - } else if (width < servo_min_ticks || width > servo_max_ticks) { - return -1; - } else { - return (int)width; - } -} - -static void -go_go_go(void) -{ - int fd; - struct timeval tv; - static char line[128]; - int nchars = 0; - - if ((fd = open(DEVFILE, O_RDWR|O_NONBLOCK)) == -1) - fatal("servod: Failed to open %s: %m\n", DEVFILE); - - for (;;) { - int n, width, servo; - fd_set ifds; - char width_arg[64]; - - FD_ZERO(&ifds); - FD_SET(fd, &ifds); - get_next_idle_timeout(&tv); - if ((n = select(fd+1, &ifds, NULL, NULL, &tv)) != 1) - continue; - while (read(fd, line+nchars, 1) == 1) { - if (line[nchars] == '\n') { - line[++nchars] = '\0'; - nchars = 0; - if (line[0] == 'p' || line[0] == 'P') { - int hdr, pin, width; - - n = sscanf(line+1, "%d-%d=%s", &hdr, &pin, width_arg); - if (n != 3) { - 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 = parse_width(servo, width_arg)) < 0) { - fprintf(stderr, "Invalid width specified\n"); - } else { - set_servo(servo, width); - } - } - } else { - n = sscanf(line, "%d=%s", &servo, width_arg); - if (!strcmp(line, "debug\n")) { - do_debug(); - } else if (n != 2) { - 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 = parse_width(servo, width_arg)) < 0) { - fprintf(stderr, "Invalid width specified\n"); - } else { - set_servo(servo, width); - } - } - } else { - if (++nchars >= 126) { - fprintf(stderr, "Input too long\n"); - nchars = 0; - } - } - } - } -} - -/* Determining the board revision is a lot more complicated than it should be - * (see comments in wiringPi for details). We will just look at the last two - * digits of the Revision string and treat '00' and '01' as errors, '02' and - * '03' as rev 1, and any other hex value as rev 2. - * TODO: This is wrong. Fix in line with current WiringPi. - */ -static void -get_model_and_revision(void) -{ - char buf[128], revstr[128], modelstr[128]; - char *ptr, *end, *res; - FILE *fp; - - revstr[0] = modelstr[0] = '\0'; - - fp = fopen("/proc/cpuinfo", "r"); - - if (!fp) - fatal("Unable to open /proc/cpuinfo: %m\n"); - - while ((res = fgets(buf, 128, fp))) { - if (!strncasecmp("model name", buf, 8)) - memcpy(modelstr, buf, 128); - else if (!strncasecmp(buf, "revision", 8)) - memcpy(revstr, buf, 128); - } - fclose(fp); - - if (modelstr[0] == '\0') - fatal("servod: No 'Model name' record in /proc/cpuinfo\n"); - if (revstr[0] == '\0') - fatal("servod: No 'Revision' record in /proc/cpuinfo\n"); - - if (strstr(modelstr, "ARMv6")) - board_model = 1; - else if (strstr(modelstr, "ARMv7")) - board_model = 2; - else - fatal("servod: Cannot parse the model name string\n"); - - ptr = revstr + strlen(revstr) - 3; - board_revision = strtol(ptr, &end, 16); - if (end != ptr + 2) - fatal("servod: Failed to parse Revision string\n"); - if (board_revision < 1) - fatal("servod: Invalid board Revision\n"); - else if (board_revision < 4) - board_revision = 1; - else - board_revision = 2; - - if (board_model == 1) { - periph_virt_base = 0x20000000; - periph_phys_base = 0x7e000000; - dram_phys_base = 0x40000000; - mem_flag = 0x0c; - } else { - periph_virt_base = 0x3f000000; - periph_phys_base = 0x7e000000; - dram_phys_base = 0xc0000000; - mem_flag = 0x04; - } -} - -static void -parse_pin_lists(int p1first, char *p1pins, char*p5pins) -{ - char *name, *pins; - 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"; - pins = p1pins; - if (board_model == 1 && board_revision == 1) { - map = rev1_p1pin2gpio_map; - mapcnt = sizeof(rev1_p1pin2gpio_map); - } else { - map = rev2_p1pin2gpio_map; - mapcnt = sizeof(rev2_p1pin2gpio_map); - } - pNpin2servo = p1pin2servo; - } else { - name = "P5"; - pins = p5pins; - if (board_model == 1 && board_revision == 1) { - map = rev1_p5pin2gpio_map; - mapcnt = sizeof(rev1_p5pin2gpio_map); - } else { - map = rev2_p5pin2gpio_map; - mapcnt = sizeof(rev2_p5pin2gpio_map); - } - pNpin2servo = p5pin2servo; - } - while (*pins) { - char *end; - long pin = strtol(pins, &end, 0); - - if (*end && (end == pins || *end != ',')) - fatal("Invalid character '%c' in %s pin list\n", *end, name); - if (pin < 0 || pin > mapcnt) - fatal("Invalid pin number %d in %s pin list\n", pin, name); - if (servo == MAX_SERVOS) - fatal("Too many servos specified\n"); - if (pin == 0) { - servo++; - } 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++; - } - pins = end; - if (*pins == ',') - 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) -{ - while (--len) { - if (map[len] == gpio) - return len+1; - } - return 0; -} - -static char * -gpio2pinname(uint8_t gpio) -{ - static char res[16]; - uint8_t pin; - - if (board_model == 1 && board_revision == 1) { - if ((pin = gpiosearch(gpio, rev1_p1pin2gpio_map, sizeof(rev1_p1pin2gpio_map)))) - sprintf(res, "P1-%d", pin); - else if ((pin = gpiosearch(gpio, rev1_p5pin2gpio_map, sizeof(rev1_p5pin2gpio_map)))) - sprintf(res, "P5-%d", pin); - else - fatal("Cannot map GPIO %d to a header pin\n", gpio); - } else { - if ((pin = gpiosearch(gpio, rev2_p1pin2gpio_map, sizeof(rev2_p1pin2gpio_map)))) - sprintf(res, "P1-%d", pin); - else if ((pin = gpiosearch(gpio, rev2_p5pin2gpio_map, sizeof(rev2_p5pin2gpio_map)))) - sprintf(res, "P5-%d", pin); - else - fatal("Cannot map GPIO %d to a header pin\n", gpio); - } - - return res; -} - -static int -parse_min_max_arg(char *arg, char *name) -{ - char *p; - double val = strtod(arg, &p); - - if (*arg < '0' || *arg > '9' || val < 0) { - fatal("Invalid %s value specified\n", name); - } else if (*p == '\0') { - if (val != floor(val)) { - fatal("Invalid %s value specified\n", name); - } - return (int)val; - } else if (!strcmp(p, "us")) { - if (val != floor(val)) { - fatal("Invalid %s value specified\n", name); - } - if ((int)val % step_time_us) { - fatal("%s value is not a multiple of step-time\n", name); - } - return val / step_time_us; - } else if (!strcmp(p, "%")) { - if (val < 0 || val > 100.0) { - fatal("%s value must be between 0% and 100% inclusive\n", name); - } - return (int)(val * (double)cycle_time_us / 100.0 / step_time_us); - } else { - fatal("Invalid %s value specified\n", name); - } - - return -1; /* Never reached */ -} - -int -main(int argc, char **argv) -{ - int i; - char *p1pins = default_p1_pins; - char *p5pins = default_p5_pins; - int p1first = 1, hadp1 = 0, hadp5 = 0; - char *servo_min_arg = NULL; - char *servo_max_arg = NULL; - char *idle_timeout_arg = NULL; - char *cycle_time_arg = NULL; - char *step_time_arg = NULL; - char *dma_chan_arg = NULL; - char *p; - int daemonize = 1; - - setvbuf(stdout, NULL, _IOLBF, 0); - - while (1) { - int c; - int option_index; - - static struct option long_options[] = { - { "pcm", no_argument, 0, 'p' }, - { "idle-timeout", required_argument, 0, 't' }, - { "help", no_argument, 0, 'h' }, - { "p1pins", required_argument, 0, '1' }, - { "p5pins", required_argument, 0, '5' }, - { "min", required_argument, 0, 'm' }, - { "max", required_argument, 0, 'x' }, - { "invert", no_argument, 0, 'i' }, - { "cycle-time", required_argument, 0, 'c' }, - { "step-size", required_argument, 0, 's' }, - { "debug", no_argument, 0, 'f' }, - { "dma-chan", required_argument, 0, 'd' }, - { 0, 0, 0, 0 } - }; - - c = getopt_long(argc, argv, "mxhnt:15icsfd", long_options, &option_index); - if (c == -1) { - break; - } else if (c =='d') { - dma_chan_arg = optarg; - } else if (c == 'f') { - daemonize = 0; - } else if (c == 'p') { - delay_hw = DELAY_VIA_PCM; - } else if (c == 't') { - idle_timeout_arg = optarg; - } else if (c == 'c') { - cycle_time_arg = optarg; - } else if (c == 's') { - step_time_arg = optarg; - } else if (c == 'm') { - servo_min_arg = optarg; - } else if (c == 'x') { - servo_max_arg = optarg; - } else if (c == 'i') { - invert = 1; - } else if (c == 'h') { - printf("\nUsage: %s \n\n" - "Options:\n" - " --pcm tells servod to use PCM rather than PWM hardware\n" - " to implement delays\n" - " --idle-timeout=Nms tells servod to stop sending servo pulses for a\n" - " given output N milliseconds after the last update\n" - " --cycle-time=Nus Control pulse cycle time in microseconds, default\n" - " %dus\n" - " --step-size=Nus Pulse width increment step size in microseconds,\n" - " default %dus\n" - " --min={N|Nus|N%%} specifies the minimum allowed pulse width, default\n" - " %d steps or %dus\n" - " --max={N|Nus|N%%} specifies the maximum allowed pulse width, default\n" - " %d steps or %dus\n" - " --invert Inverts outputs\n" - " --dma-chan=N tells servod which dma channel to use, default %d\n" - " --p1pins= tells servod which pins on the P1 header to use\n" - " --p5pins= tells servod which pins on the P5 header to use\n" - "\nwhere defaults to \"%s\" for p1pins and\n" - "\"%s\" for p5pins. p5pins is only valid on rev 2 boards.\n\n" - "min and max values can be specified in units of steps, in microseconds,\n" - "or as a percentage of the cycle time. So, for example, if cycle time is\n" - "20000us and step size is 10us then the following are equivalent:\n\n" - " --min=50 --min=500us --min=2.5%%\n\n" - "For the default configuration, example commands to set the first servo\n" - "to the mid position would be any of:\n\n" - " echo 0=150 > /dev/servoblaster # Specify as a number of steps\n" - " echo 0=50%% > /dev/servoblaster # Specify as a percentage\n" - " echo 0=1500us > /dev/servoblaster # Specify as microseconds\n" - " echo P1-7=150 > /dev/servoblaster # Using P1 pin number rather\n" - " echo P1-7=50%% > /dev/servoblaster # ... than servo number\n" - " echo P1-7=1500us > /dev/servoblaster\n\n" - "Servo adjustments may also be specified relative to the current\n" - "position by adding a '+' or '-' prefix to the width as follows:\n\n" - " echo 0=+10 > /dev/servoblaster\n" - " echo 0=-20 > /dev/servoblaster\n\n", - argv[0], - DEFAULT_CYCLE_TIME_US, - DEFAULT_STEP_TIME_US, - DEFAULT_SERVO_MIN_US/DEFAULT_STEP_TIME_US, DEFAULT_SERVO_MIN_US, - DEFAULT_SERVO_MAX_US/DEFAULT_STEP_TIME_US, DEFAULT_SERVO_MAX_US, - DMA_CHAN_DEFAULT, default_p1_pins, default_p5_pins); - exit(0); - } else if (c == '1') { - p1pins = optarg; - hadp1 = 1; - if (!hadp5) - p1first = 1; - } else if (c == '5') { - p5pins = optarg; - hadp5 = 1; - if (!hadp1) - p1first = 0; - } else { - fatal("Invalid parameter\n"); - } - } - get_model_and_revision(); - if (board_model == 1 && board_revision == 1 && p5pins[0]) - fatal("Board model 1 revision 1 does not have a P5 header\n"); - - parse_pin_lists(p1first, p1pins, p5pins); - - if (dma_chan_arg) { - dma_chan = strtol(dma_chan_arg, &p, 10); - if (*dma_chan_arg < '0' || *dma_chan_arg > '9' || - *p || dma_chan < DMA_CHAN_MIN || dma_chan > DMA_CHAN_MAX) - fatal("Invalid dma-chan specified\n"); - } else { - dma_chan = DMA_CHAN_DEFAULT; - } - - if (idle_timeout_arg) { - idle_timeout = strtol(idle_timeout_arg, &p, 10); - if (*idle_timeout_arg < '0' || *idle_timeout_arg > '9' || - (*p && strcmp(p, "ms")) || - idle_timeout < 10 || idle_timeout > 3600000) - fatal("Invalid idle-timeout specified\n"); - } else { - idle_timeout = 0; - } - - if (cycle_time_arg) { - cycle_time_us = strtol(cycle_time_arg, &p, 10); - if (*cycle_time_arg < '0' || *cycle_time_arg > '9' || - (*p && strcmp(p, "us")) || - cycle_time_us < 1000 || cycle_time_us > 1000000) - fatal("Invalid cycle-time specified\n"); - } else { - cycle_time_us = DEFAULT_CYCLE_TIME_US; - } - - if (step_time_arg) { - step_time_us = strtol(step_time_arg, &p, 10); - if (*step_time_arg < '0' || *step_time_arg > '9' || - (*p && strcmp(p, "us")) || - step_time_us < 2 || step_time_us > 1000) { - fatal("Invalid step-size specified\n"); - } - } else { - step_time_us = DEFAULT_STEP_TIME_US; - } - - if (cycle_time_us % step_time_us) { - fatal("cycle-time is not a multiple of step-size\n"); - } - - if (cycle_time_us / step_time_us < 100) { - fatal("cycle-time must be at least 100 * step-size\n"); - } - - if (servo_min_arg) { - servo_min_ticks = parse_min_max_arg(servo_min_arg, "min"); - } else { - servo_min_ticks = DEFAULT_SERVO_MIN_US / step_time_us; - } - - if (servo_max_arg) { - servo_max_ticks = parse_min_max_arg(servo_max_arg, "max"); - } else { - servo_max_ticks = DEFAULT_SERVO_MAX_US / step_time_us; - } - - num_samples = cycle_time_us / step_time_us; - num_cbs = num_samples * 2 + MAX_SERVOS; - num_pages = (num_cbs * sizeof(dma_cb_t) + num_samples * 4 + - MAX_SERVOS * 4 + PAGE_SIZE - 1) >> PAGE_SHIFT; - - if (num_pages > MAX_MEMORY_USAGE / PAGE_SIZE) { - fatal("Using too much memory; reduce cycle-time or increase step-size\n"); - } - - if (servo_max_ticks > num_samples) { - fatal("max value is larger than cycle time\n"); - } - if (servo_min_ticks >= servo_max_ticks) { - fatal("min value is >= max value\n"); - } - - printf("\nBoard model: %7d\n", board_model); - printf("Board revision: %7d\n", board_revision); - printf("Using hardware: %s\n", delay_hw == DELAY_VIA_PWM ? "PWM" : "PCM"); - printf("Using DMA channel: %7d\n", dma_chan); - if (idle_timeout) - printf("Idle timeout: %7dms\n", idle_timeout); - else - printf("Idle timeout: Disabled\n"); - printf("Number of servos: %7d\n", num_servos); - printf("Servo cycle time: %7dus\n", cycle_time_us); - printf("Pulse increment step size: %7dus\n", step_time_us); - printf("Minimum width value: %7d (%dus)\n", servo_min_ticks, - servo_min_ticks * step_time_us); - printf("Maximum width value: %7d (%dus)\n", servo_max_ticks, - servo_max_ticks * step_time_us); - printf("Output levels: %s\n", invert ? "Inverted" : " Normal"); - printf("\nUsing P1 pins: %s\n", p1pins); - if (board_model > 1 || board_revision > 1) - printf("Using P5 pins: %s\n", p5pins); - printf("\nServo mapping:\n"); - for (i = 0; i < MAX_SERVOS; i++) { - if (servo2gpio[i] == DMY) - continue; - printf(" %2d on %-5s GPIO-%d\n", i, gpio2pinname(servo2gpio[i]), servo2gpio[i]); - } - printf("\n"); - - init_idle_timers(); - setup_sighandlers(); - - dma_reg = map_peripheral(DMA_VIRT_BASE, DMA_LEN); - dma_reg += dma_chan * DMA_CHAN_SIZE / sizeof(uint32_t); - pwm_reg = map_peripheral(PWM_VIRT_BASE, PWM_LEN); - pcm_reg = map_peripheral(PCM_VIRT_BASE, PCM_LEN); - clk_reg = map_peripheral(CLK_VIRT_BASE, CLK_LEN); - gpio_reg = map_peripheral(GPIO_VIRT_BASE, GPIO_LEN); - - /* Use the mailbox interface to the VC to ask for physical memory */ - unlink(MBFILE); - if (mknod(MBFILE, S_IFCHR|0600, makedev(249, 0)) < 0) - fatal("Failed to create mailbox device\n"); - mbox.handle = mbox_open(); - if (mbox.handle < 0) - fatal("Failed to open mailbox\n"); - mbox.mem_ref = mem_alloc(mbox.handle, num_pages * 4096, 4096, mem_flag); - /* TODO: How do we know that succeeded? */ - printf("mem_ref %u\n", mbox.mem_ref); - mbox.bus_addr = mem_lock(mbox.handle, mbox.mem_ref); - printf("bus_addr = %u\n", mbox.bus_addr); - mbox.virt_addr = mapmem(BUS_TO_PHYS(mbox.bus_addr), num_pages * 4096); - printf("virt_addr %p\n", mbox.virt_addr); - - turnoff_mask = (uint32_t *)mbox.virt_addr; - turnon_mask = (uint32_t *)(mbox.virt_addr + num_samples * sizeof(uint32_t)); - cb_base = (dma_cb_t *)(mbox.virt_addr + - ROUNDUP(num_samples + MAX_SERVOS, 8) * sizeof(uint32_t)); - - for (i = 0; i < MAX_SERVOS; i++) { - if (servo2gpio[i] == DMY) - continue; - gpiomode[i] = gpio_get_mode(servo2gpio[i]); - gpio_set(servo2gpio[i], invert ? 1 : 0); - gpio_set_mode(servo2gpio[i], GPIO_MODE_OUT); - } - restore_gpio_modes = 1; - - init_ctrl_data(); - init_hardware(); - - unlink(DEVFILE); - if (mkfifo(DEVFILE, 0666) < 0) - fatal("servod: Failed to create %s: %m\n", DEVFILE); - if (chmod(DEVFILE, 0666) < 0) - fatal("servod: Failed to set permissions on %s: %m\n", DEVFILE); - - if (daemonize && daemon(0,1) < 0) - fatal("servod: Failed to daemonize process: %m\n"); - - go_go_go(); - - return 0; -} - diff --git a/ServoBlaster/servodebug.c b/ServoBlaster/servodebug.c deleted file mode 100644 index 8db7005..0000000 --- a/ServoBlaster/servodebug.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * servodebug.c - a utility to help debug issues with ServoBlaster - * - * This code should be compiled with the command: - * - * gcc -Wall -O2 -o servodebug servodebug.c - * - * It should be run with the command: - * - * sudo chrt 1 ./servodebug - * - * Richard Hirst - Nov 25th 2012 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define BCM2708_DMA_NO_WIDE_BURSTS (1<<26) -#define BCM2708_DMA_WAIT_RESP (1<<3) -#define BCM2708_DMA_D_DREQ (1<<6) -#define BCM2708_DMA_PER_MAP(x) ((x)<<16) -#define BCM2708_DMA_END (1<<1) -#define BCM2708_DMA_RESET (1<<31) -#define BCM2708_DMA_INT (1<<2) - -#define DMA_CHAN_SIZE 0x100 -#define DMA_CHAN_MIN 0 -#define DMA_CHAN_MAX 14 -#define DMA_CHAN_DEFAULT 14 - -#define DMA_CS (0x00/4) -#define DMA_CONBLK_AD (0x04/4) -#define DMA_DEBUG (0x20/4) - -#define GPIO_BASE 0x3f200000 -#define GPIO_LEN 0xB4 -#define DMA_BASE 0x3f007000 -#define DMA_LEN DMA_CHAN_SIZE * (DMA_CHAN_MAX+1) -#define PWM_BASE 0x3f20C000 -#define PWM_LEN 0x28 -#define CLK_BASE 0x3f101000 -#define CLK_LEN 0xA8 -#define TICK_BASE 0x3f003000 -#define TICK_LEN 0x08 - -#define PWM_CTL (0x00/4) -#define PWM_DMAC (0x08/4) -#define PWM_RNG1 (0x10/4) -#define PWM_FIFO (0x18/4) - -#define PWMCLK_CNTL 40 -#define PWMCLK_DIV 41 - -#define PWMCTL_MODE1 (1<<1) -#define PWMCTL_PWEN1 (1<<0) -#define PWMCTL_CLRF (1<<6) -#define PWMCTL_USEF1 (1<<5) - -#define PWMDMAC_ENAB (1<<31) -// I think this means it requests as soon as there is one free slot in the FIFO -// which is what we want as burst DMA would mess up our timing.. -#define PWMDMAC_THRSHLD ((15<<8)|(15<<0)) - -#define GPFSEL0 (0x00/4) -#define GPCLR0 (0x28/4) -#define GPLEV0 (0x34/4) - -typedef struct { - uint32_t info, src, dst, length, - stride, next, pad[2]; -} dma_cb_t; - -static volatile uint32_t *gpio_reg; -static volatile uint32_t *pwm_reg; -static volatile uint32_t *clk_reg; -static volatile uint32_t *dma_reg; -static volatile uint32_t *tick_reg; - -static uint32_t dma_chan = DMA_CHAN_DEFAULT; - -static uint8_t servo2gpio[] = { - 4, // P1-7 - 17, // P1-11 -#ifdef PWM0_ON_GPIO18 - 1, // P1-5 (GPIO-18, P1-12 is currently PWM0, for debug) -#else - 18, // P1-12 -#endif - 21, // P1-13 - 22, // P1-15 - 23, // P1-16 - 24, // P1-18 - 25, // P1-22 -}; -#define NUM_SERVOS (sizeof(servo2gpio)/sizeof(servo2gpio[0])) - -struct { - uint32_t stamp; - uint32_t levels; -} trans[20]; - -static void -fatal(char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - exit(1); -} - -static void -msleep(int ms) -{ - struct timespec ts = { 0, ms * 1000 * 1000 }; - - if (nanosleep(&ts, NULL)) { - fprintf(stderr, "nanosleep() failed: %s\n", strerror(errno)); - exit(1); - } -} - -static void * -map_peripheral(uint32_t base, uint32_t len) -{ - int fd = open("/dev/mem", O_RDWR); - void * vaddr; - - if (fd < 0) - fatal("Failed to open /dev/mem: %m\n"); - vaddr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, base); - if (vaddr == MAP_FAILED) - fatal("Failed to map peripheral at 0x%08x: %m\n", base); - close(fd); - - return vaddr; -} - -int -main(int argc, char **argv) -{ - int tr, i; - uint32_t v1, v2, mask, t1; - struct timeval tv1, tv2; - - printf("This code should be compiled with the command:\n\n"); - printf(" gcc -Wall -O2 -o servodebug servodebug.c\n"); - printf("\nIt should be run with the command:\n\n"); - printf(" sudo chrt 1 ./servodebug\n\n"); - gpio_reg = map_peripheral(GPIO_BASE, GPIO_LEN); - dma_reg = map_peripheral(DMA_BASE, DMA_LEN); - dma_reg += dma_chan * DMA_CHAN_SIZE / sizeof(uint32_t); - pwm_reg = map_peripheral(PWM_BASE, PWM_LEN); - clk_reg = map_peripheral(CLK_BASE, CLK_LEN); - tick_reg = map_peripheral(TICK_BASE, TICK_LEN); - - v1 = dma_reg[DMA_CONBLK_AD]; - msleep(5); - v2 = dma_reg[DMA_CONBLK_AD]; - - if (v1 == v2) - fatal("DMA controller is not running - is the module loaded?\n"); - printf("\nGood, DMA controller is running\n"); - - printf("\nTiming 1M cycles of system tick, should take 1000000us\n"); - printf("but small variations are to be expected\n"); - gettimeofday(&tv1, NULL); - v1 = tick_reg[1]; - while (tick_reg[1] - v1 < 1000000) - ; - gettimeofday(&tv2, NULL); - i = (tv2.tv_sec - tv1.tv_sec) * 1000000 + tv2.tv_usec - tv1.tv_usec; - printf("\n1M increments of system tick measured at %dus\n", i); - - printf("\nMonitoring for the first 20 transitions on servo control lines\n"); - - for (i = 0, mask = 0; i < NUM_SERVOS; i++) - mask |= 1 << servo2gpio[i]; - - t1 = tick_reg[1]; - v1 = gpio_reg[GPLEV0] & mask; - for (tr = 0; tr < 20; tr++) { - do { - if (tick_reg[1] - t1 > 1000000) - fatal("No servo pulses generated - have you tried \"echo 0=100 > /dev/servoblaster\"?\n"); - v2 = gpio_reg[GPLEV0] & mask; - } while (v1 == v2); - trans[tr].stamp = tick_reg[1]; - trans[tr].levels = v2; - v1 = v2; - } - - for (tr = 1; tr < 20; tr++) - trans[tr].stamp -= trans[0].stamp; - trans[0].stamp = 0; - printf("\n time outputs\n (us) 76543210\n"); - for (tr = 0; tr < 20; tr++) { - printf(" %6d ", trans[tr].stamp); - for (i = NUM_SERVOS - 1; i >= 0; i--) - printf("%s", trans[tr].levels & (1 << servo2gpio[i]) ? "1" : "0"); - printf("\n"); - } - printf("\n"); - - return 0; -} - diff --git a/files/ServoBlaster.tar.gz b/files/ServoBlaster.tar.gz deleted file mode 100644 index f37c7debd28e19970cad3b613d4052c4fbc3fe8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16732 zcmV(qK<~dFiwFoiAhT8g15;&kc5gy#VRLk4axQdXasX_*V~j3bu&vv+ZQHhO+qSLM zwr$(C&DHLH+qSvdIN#pMxyik`l~I4@OzKZnGM|ymB8-6o;vs6$00O=FBkzhkm5jB= z!@&VGQIGF&E%A0(c>qTq2qxtQT1XYNq6-5?etoo-yl>TtgS{ojIcWfFCFdDJ=veCc zuxdFG9uRE$=T*@u^v}~D#`ycGCS-wi$p+Sz>h79uTp)JErN6!*Fv4Kf&Hoeq|0RGE z&|?`NaKn$QC4BxSTR@~nlP39(r(_`K%W-up^ku8z;urZnaP0~ zk`PrO0FvO{9>0iRoT&mIUf zPU6o~vCYb?&QaHyK0>aeCCm?rU9~#fK{f9^_BiN=8^f{U)!63UHw=6%c!AMA1Bry zDRUq}4shGk*k5(jO@hteB<(uJ@!xqAjHBOqp7ZZt)#o4Y?}6&rU*%uON%7xbyo2IL z_s>Lrorc4Nfd1BJ!x1XK$Jm^>4ASY4O zZmClNg)j_bWDH}Ox1+LZYqfs8pWyGA0Ouc5)E20i#{ZWJxI>Q&>AsIpH1EEz$m=sd z#}Z_hNa%+Df8=*;v>_||`bqhQdag0S`ZL8{~J6X5Hi0vbhbBS z2~;o;lmJTzDWL!Mh5Lp#a+YylHFQS%_C@=4y#MqIbSF4?7BF}=Fmg69cqTY*EO*1BXVrH0V4!_MwqOisDXpVQ$Dpc4pM;I0~4Z3Och=vhbJGkq-lr$!e*K}N z=+QFL`@c+%hVkveG^aidZzthrgy%gc4km0*KKFj>G#blj$4^O3oqw;MLdU)v3fvby zekm`$T|Wnu*;T#=UabDRX$iHWm<)J7$+*_O^8So$OW4GJbNuD{CFgzUvt9EDrlf

T`z#wPiv=|5DnX%!MN(nT4SQF73B4 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 DS`D0( diff --git a/files/ServoBlaster20160204.gz b/files/ServoBlaster20160204.gz deleted file mode 100644 index 2e6232ae37250da7ca7976892a12f396cd2bd960..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16743 zcmZs?V~j68{4Bh-ZQHhO+qSK3pU$ zgfUP+{`f5#K%h5&bN>hV3UCEgAz58%iH!KBOGEeZ*@N

}u{rW1}wRMpj-H>_Yc+gS+^e&F~Tfy(x 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 diff --git a/files/ServoBlaster20160204.tgz b/files/ServoBlaster20160204.tgz deleted file mode 100644 index 2e6232ae37250da7ca7976892a12f396cd2bd960..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16743 zcmZs?V~j68{4Bh-ZQHhO+qSK3pU$ zgfUP+{`f5#K%h5&bN>hV3UCEgAz58%iH!KBOGEeZ*@N

}u{rW1}wRMpj-H>_Yc+gS+^e&F~Tfy(x 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 diff --git a/files/ServoBlaster20160204.zip b/files/ServoBlaster20160204.zip deleted file mode 100644 index 7ab3134f78bef11a6f7715d327d71fe987eaf925..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22405 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 G-+uu{ildGI