Big update here.

delayMicrosecondsHard re-written - again.
Added a serialRead example program, and added in the okLed
to the examples too.
Updated/checked some of the GPIO/PWM code.
Added in some experimental servo and tone generating code and
and example or 2.
Tweaks to the gpio command to correctly load the I2C modules too.
This commit is contained in:
Gordon Henderson 2012-12-06 21:49:41 +00:00
parent 183c5a6b5c
commit 25e4ec570b
19 changed files with 874 additions and 127 deletions

5
People
View File

@ -8,3 +8,8 @@ Nick Lott: (And others)
Philipp Stefan Neininger:
Minor bug in the Makefile to do with cross compiling
Chris McSweeny
Hints and tips about the use of arithmetic in gettimeofday()
inside the dealyMicrosecondsHard() function.
And spotting a couple of schoolboy errors in the (experimental)
softServo code, prompting me to completely re-write it.

View File

@ -30,16 +30,19 @@ INCLUDE = -I/usr/local/include
CFLAGS = $(DEBUG) -Wall $(INCLUDE) -Winline -pipe
LDFLAGS = -L/usr/local/lib
LIBS = -lwiringPi
LDLIBS = -lwiringPi
# Should not alter anything below this line
###############################################################################
SRC = test1.c test2.c speed.c lcd.c wfi.c piface.c gertboard.c nes.c delayTest.c softPwm.c
SRC = test1.c test2.c speed.c lcd.c wfi.c \
piface.c gertboard.c nes.c \
pwm.c tone.c servo.c \
delayTest.c serialRead.c okLed.c
OBJ = test1.o test2.o speed.o lcd.o wfi.o piface.o gertboard.o nes.o delayTest.o softPwm.o
OBJ = $(SRC:.c=.o)
BINS = test1 test2 speed lcd wfi piface gertboard nes delayTest softPwm
BINS = $(SRC:.c=)
all:
@cat README.TXT
@ -48,43 +51,59 @@ all:
test1: test1.o
@echo [link]
$(CC) -o $@ test1.o $(LDFLAGS) $(LIBS)
@$(CC) -o $@ test1.o $(LDFLAGS) $(LDLIBS)
test2: test2.o
@echo [link]
$(CC) -o $@ test2.o $(LDFLAGS) $(LIBS)
@$(CC) -o $@ test2.o $(LDFLAGS) $(LDLIBS)
speed: speed.o
@echo [link]
$(CC) -o $@ speed.o $(LDFLAGS) $(LIBS)
@$(CC) -o $@ speed.o $(LDFLAGS) $(LDLIBS)
lcd: lcd.o
@echo [link]
$(CC) -o $@ lcd.o $(LDFLAGS) $(LIBS)
@$(CC) -o $@ lcd.o $(LDFLAGS) $(LDLIBS)
wfi: wfi.o
@echo [link]
$(CC) -o $@ wfi.o $(LDFLAGS) $(LIBS) -lpthread
@$(CC) -o $@ wfi.o $(LDFLAGS) $(LDLIBS)
piface: piface.o
@echo [link]
$(CC) -o $@ piface.o $(LDFLAGS) $(LIBS) -lpthread
@$(CC) -o $@ piface.o $(LDFLAGS) $(LDLIBS) -lpthread
gertboard: gertboard.o
@echo [link]
$(CC) -o $@ gertboard.o $(LDFLAGS) $(LIBS) -lm
@$(CC) -o $@ gertboard.o $(LDFLAGS) $(LDLIBS) -lm
nes: nes.o
@echo [link]
$(CC) -o $@ nes.o $(LDFLAGS) $(LIBS) -lm
@$(CC) -o $@ nes.o $(LDFLAGS) $(LDLIBS) -lm
softPwm: softPwm.o
pwm: pwm.o
@echo [link]
$(CC) -o $@ softPwm.o $(LDFLAGS) $(LIBS) -lm -lpthread
@$(CC) -o $@ pwm.o $(LDFLAGS) $(LDLIBS) -lm -lpthread
delayTest: delayTest.o
@echo [link]
$(CC) -o $@ delayTest.o $(LDFLAGS) $(LIBS)
@$(CC) -o $@ delayTest.o $(LDFLAGS) $(LDLIBS)
serialRead: serialRead.o
@echo [link]
@$(CC) -o $@ serialRead.o $(LDFLAGS) $(LDLIBS)
okLed: okLed.o
@echo [link]
@$(CC) -o $@ okLed.o $(LDFLAGS) $(LDLIBS)
tone: tone.o
@echo [link]
@$(CC) -o $@ tone.o $(LDFLAGS) $(LDLIBS)
servo: servo.o
@echo [link]
@$(CC) -o $@ servo.o $(LDFLAGS) $(LDLIBS)
.c.o:
@ -92,7 +111,7 @@ delayTest: delayTest.o
@$(CC) -c $(CFLAGS) $< -o $@
clean:
rm -f $(OBJ) *~ core tags test1 test2 speed lcd wfi piface gertboard nes delayTest softPwm
rm -f $(OBJ) *~ core tags $(BINS)
tags: $(SRC)
@echo [ctags]

View File

@ -3,30 +3,24 @@
#include <unistd.h>
#include <wiringPi.h>
#include <time.h>
#include <sys/types.h>
#include <sys/time.h>
#define CYCLES 1000
#define DELAY 99
int main()
{
int x ;
struct timeval t1, t2 ;
long long t ;
unsigned int max, min ;
unsigned int values [CYCLES] ;
max = 0 ;
min = 1000000 ;
int t ;
int max, min ;
int del ;
int underRuns, overRuns, exactRuns, total ;
int descheds ;
if (wiringPiSetup () == -1)
return 1 ;
piHiPri (10) ;
sleep (1) ;
piHiPri (10) ; sleep (1) ;
// Baseline test
@ -34,35 +28,56 @@ int main()
gettimeofday (&t2, NULL) ;
t = t2.tv_usec - t1.tv_usec ;
printf ("Baseline test: %lld\n", t);
printf ("Baseline test: %d\n", t);
for (x = 0 ; x < CYCLES ; ++x)
for (del = 1 ; del < 200 ; ++del)
{
gettimeofday (&t1, NULL) ;
delayMicroseconds (DELAY) ;
gettimeofday (&t2, NULL) ;
t = t2.tv_usec - t1.tv_usec ;
if (t > max) max = t ;
if (t < min) min = t ;
values [x] = t ;
}
underRuns = overRuns = exactRuns = total = 0 ;
descheds = 0 ;
max = del ;
min = del ;
printf ("Done: Max: %d, min: %d\n", max, min) ;
for (x = 0 ; x < CYCLES ; ++x)
{
for (;;) // Repeat this if we get a delay over 999uS
{ // -> High probability Linux has deschedulled us
gettimeofday (&t1, NULL) ;
delayMicroseconds (del) ;
gettimeofday (&t2, NULL) ;
for (x = 0 ; x < CYCLES ; ++x)
{
printf ("%4d", values [x]) ;
if (values [x] > DELAY)
printf (".") ;
else if (values [x] < DELAY)
printf ("-") ;
else
printf (" ") ;
if (((x + 1) % 20) == 0)
printf ("\n") ;
if (t2.tv_usec < t1.tv_usec) // Counter wrapped
t = (1000000 + t2.tv_usec) - t1.tv_usec;
else
t = t2.tv_usec - t1.tv_usec ;
if (t > 999)
{
++descheds ;
continue ;
}
else
break ;
}
if (t > max)
{
max = t ;
++overRuns ;
}
else if (t < min)
{
min = t ;
++underRuns ;
}
else
++exactRuns ;
total += t ;
}
printf ("Delay: %3d. Min: %3d, Max: %3d, Unders: %3d, Overs: %3d, Exacts: %3d, Average: %3d, Descheds: %2d\n",
del, min, max, underRuns, overRuns, exactRuns, total / CYCLES, descheds) ;
fflush (stdout) ;
delay (1) ;
}
printf ("\n") ;
return 0 ;
}

65
examples/okLed.c Normal file
View File

@ -0,0 +1,65 @@
/*
* okLed:
* Make the OK LED on the Pi Pulsate...
* Copyright (c) 2012 gordon Henderson, but please Share and Enjoy!
*
* Originally posted to the Raspberry Pi forums:
* http://www.raspberrypi.org/phpBB3/viewtopic.php?p=162581#p162581
*
* Compile this and store it somewhere, then kick it off at boot time
* e.g. by putting it in /etc/rc.local and running it in the
* background &
*
*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <wiringPi.h>
#include <softPwm.h>
#define OK_LED 16
int main ()
{
int fd, i ;
if ((fd = open ("/sys/class/leds/led0/trigger", O_RDWR)) < 0)
{
fprintf (stderr, "Unable to change LED trigger: %s\n", strerror (errno)) ;
return 1 ;
}
write (fd, "none\n", 5) ;
close (fd) ;
if (wiringPiSetupGpio () < 0)
{
fprintf (stderr, "Unable to setup GPIO: %s\n", strerror (errno)) ;
return 1 ;
}
softPwmCreate (OK_LED, 0, 100) ;
for (;;)
{
for (i = 0 ; i <= 100 ; ++i)
{
softPwmWrite (OK_LED, i) ;
delay (10) ;
}
delay (50) ;
for (i = 100 ; i >= 0 ; --i)
{
softPwmWrite (OK_LED, i) ;
delay (10) ;
}
delay (10) ;
}
return 0 ;
}

31
examples/serialRead.c Normal file
View File

@ -0,0 +1,31 @@
/*
* serialRead.c:
* Example program to read bytes from the Serial line
*
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <wiringSerial.h>
int main ()
{
int fd ;
if ((fd = serialOpen ("/dev/ttyAMA0", 115200)) < 0)
{
fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
return 1 ;
}
// Loop, getting and printing characters
for (;;)
{
putchar (serialGetchar (fd)) ;
fflush (stdout) ;
}
}

33
examples/servo.c Normal file
View File

@ -0,0 +1,33 @@
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <wiringPi.h>
#include <softServo.h>
int main ()
{
if (wiringPiSetup () == -1)
{
fprintf (stdout, "oops: %s\n", strerror (errno)) ;
return 1 ;
}
softServoSetup (0, 1, 2, 3, 4, 5, 6, 7) ;
softServoWrite (0, 0) ;
/*
softServoWrite (1, 1000) ;
softServoWrite (2, 1100) ;
softServoWrite (3, 1200) ;
softServoWrite (4, 1300) ;
softServoWrite (5, 1400) ;
softServoWrite (6, 1500) ;
softServoWrite (7, 2200) ;
*/
for (;;)
delay (10) ;
}

37
examples/tone.c Normal file
View File

@ -0,0 +1,37 @@
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <wiringPi.h>
#include <softTone.h>
#define RANGE 100
#define NUM_LEDS 12
int scale [8] = { 262, 294, 330, 349, 392, 440, 494, 525 } ;
int main ()
{
int i, j ;
char buf [80] ;
if (wiringPiSetup () == -1)
{
fprintf (stdout, "oops: %s\n", strerror (errno)) ;
return 1 ;
}
softToneCreate (3) ;
for (;;)
{
for (i = 0 ; i < 8 ; ++i)
{
printf ("%3d\n", i) ;
softToneWrite (3, scale [i]) ;
delay (500) ;
}
}
}

View File

@ -9,11 +9,11 @@ gpio \- Command-line access to Raspberry Pi and PiFace GPIO
.PP
.B gpio
.B [ \-g ]
.B read/write/pwm/mode ...
.B read/write/wb/pwm/mode ...
.PP
.B gpio
.B [ \-p ]
.B read/write/mode
.B read/write/wb
.B ...
.PP
.B gpio
@ -82,7 +82,14 @@ respective logic levels.
.TP
.B write <pin> <value>
Write the given value (0 or 1) to the pin.
Write the given value (0 or 1) to the pin. You need to set the pin
to output mode first.
.TP
.B wb <value>
Write the given byte to the 8 main GPIO pins. You can prefix it with 0x
to specify a hexadecimal number. You need to set pins to output mode
first.
.TP
.B readall

View File

@ -40,14 +40,14 @@
# define FALSE (1==2)
#endif
#define VERSION "1.4"
#define VERSION "1.5"
static int wpMode ;
char *usage = "Usage: gpio -v\n"
" gpio -h\n"
" gpio [-g] <read/write/pwm/mode> ...\n"
" gpio [-p] <read/write/mode> ...\n"
" gpio [-g] <read/write/wb/pwm/mode> ...\n"
" gpio [-p] <read/write/wb> ...\n"
" gpio readall\n"
" gpio unexportall/exports ...\n"
" gpio export/edge/unexport ...\n"
@ -133,7 +133,7 @@ static void _doLoadUsage (char *argv [])
static void doLoad (int argc, char *argv [])
{
char *module ;
char *module1, *module2 ;
char cmd [80] ;
char *file1, *file2 ;
@ -142,28 +142,36 @@ static void doLoad (int argc, char *argv [])
/**/ if (strcasecmp (argv [2], "spi") == 0)
{
module = "spi_bcm2708" ;
module1 = "spidev" ;
module2 = "spi_bcm2708" ;
file1 = "/dev/spidev0.0" ;
file2 = "/dev/spidev0.1" ;
}
else if (strcasecmp (argv [2], "i2c") == 0)
{
module = "i2c_bcm2708" ;
module1 = "i2c_dev" ;
module2 = "i2c_bcm2708" ;
file1 = "/dev/i2c-0" ;
file2 = "/dev/i2c-1" ;
}
else
_doLoadUsage (argv) ;
if (!moduleLoaded (module))
if (!moduleLoaded (module1))
{
sprintf (cmd, "modprobe %s", module) ;
sprintf (cmd, "modprobe %s", module1) ;
system (cmd) ;
}
if (!moduleLoaded (module))
if (!moduleLoaded (module2))
{
fprintf (stderr, "%s: Unable to load %s\n", argv [0], module) ;
sprintf (cmd, "modprobe %s", module2) ;
system (cmd) ;
}
if (!moduleLoaded (module2))
{
fprintf (stderr, "%s: Unable to load %s\n", argv [0], module2) ;
exit (1) ;
}
@ -588,6 +596,7 @@ static void doPadDrive (int argc, char *argv [])
/*
* doGbw:
* gpio gbw channel value
* Gertboard Write - To the Analog output
*********************************************************************************
*/
@ -629,6 +638,7 @@ static void doGbw (int argc, char *argv [])
/*
* doGbr:
* gpio gbr channel
* From the analog input
*********************************************************************************
*/
@ -682,7 +692,12 @@ static void doWrite (int argc, char *argv [])
if ((wpMode == WPI_MODE_PINS) && ((pin < 0) || (pin >= NUM_PINS)))
return ;
val = atoi (argv [3]) ;
/**/ if ((strcasecmp (argv [3], "up") == 0) || (strcasecmp (argv [3], "on") == 0))
val = 1 ;
else if ((strcasecmp (argv [3], "down") == 0) || (strcasecmp (argv [3], "off") == 0))
val = 0 ;
else
val = atoi (argv [3]) ;
/**/ if (val == 0)
digitalWrite (pin, LOW) ;
@ -690,6 +705,27 @@ static void doWrite (int argc, char *argv [])
digitalWrite (pin, HIGH) ;
}
/*
* doWriteByte:
* gpio write value
*********************************************************************************
*/
static void doWriteByte (int argc, char *argv [])
{
int val ;
if (argc != 3)
{
fprintf (stderr, "Usage: %s wb value\n", argv [0]) ;
exit (1) ;
}
val = (int)strtol (argv [2], NULL, 0) ;
digitalWriteByte (val) ;
}
/*
* doRead:
@ -936,11 +972,12 @@ int main (int argc, char *argv [])
// Check for wiring commands
/**/ if (strcasecmp (argv [1], "readall" ) == 0) doReadall () ;
else if (strcasecmp (argv [1], "read" ) == 0) doRead (argc, argv) ;
else if (strcasecmp (argv [1], "write") == 0) doWrite (argc, argv) ;
else if (strcasecmp (argv [1], "pwm" ) == 0) doPwm (argc, argv) ;
else if (strcasecmp (argv [1], "mode" ) == 0) doMode (argc, argv) ;
/**/ if (strcasecmp (argv [1], "readall" ) == 0) doReadall () ;
else if (strcasecmp (argv [1], "read" ) == 0) doRead (argc, argv) ;
else if (strcasecmp (argv [1], "write") == 0) doWrite (argc, argv) ;
else if (strcasecmp (argv [1], "wb") == 0) doWriteByte (argc, argv) ;
else if (strcasecmp (argv [1], "pwm" ) == 0) doPwm (argc, argv) ;
else if (strcasecmp (argv [1], "mode" ) == 0) doMode (argc, argv) ;
else
{
fprintf (stderr, "%s: Unknown command: %s.\n", argv [0], argv [1]) ;

View File

@ -24,8 +24,12 @@
DYN_VERS_MAJ=1
DYN_VERS_MIN=0
VERSION=$(DYN_VERS_MAJ).$(DYN_VERS_MIN)
DESTDIR=/usr
PREFIX=/local
STATIC=libwiringPi.a
DYNAMIC=libwiringPi.so.$(DYN_VERS_MAJ).$(DYN_VERS_MIN)
DYNAMIC=libwiringPi.so.$(VERSION)
#DEBUG = -g -O0
DEBUG = -O2
@ -41,21 +45,22 @@ LIBS =
SRC = wiringPi.c wiringPiFace.c wiringSerial.c wiringShift.c \
gertboard.c \
piNes.c \
lcd.c piHiPri.c piThread.c softPwm.c wiringPiSPI.c
lcd.c piHiPri.c piThread.c wiringPiSPI.c \
softPwm.c softServo.c softTone.c
OBJ = $(SRC:.c=.o)
#all: $(STATIC) $(DYNAMIC)
all: $(DYNAMIC)
all: $(STATIC) $(DYNAMIC)
#all: $(DYNAMIC)
$(STATIC): $(OBJ)
@echo [Link (Static)]
@echo "[Link (Static)]"
@ar rcs $(STATIC) $(OBJ)
@ranlib $(STATIC)
@size $(STATIC)
# @size $(STATIC)
$(DYNAMIC): $(OBJ)
@echo [Link]
@echo "[Link (Dynamic)]"
@$(CC) -shared -Wl,-soname,libwiringPi.so.1 -o libwiringPi.so.1.0 -lpthread $(OBJ)
.c.o:
@ -74,34 +79,38 @@ tags: $(SRC)
.PHONEY: install
install: $(TARGET)
@echo "[Install]"
@install -m 0755 -d /usr/local/lib
@install -m 0755 -d /usr/local/include
@install -m 0644 wiringPi.h /usr/local/include
@install -m 0644 wiringSerial.h /usr/local/include
@install -m 0644 wiringShift.h /usr/local/include
@install -m 0644 gertboard.h /usr/local/include
@install -m 0644 piNes.h /usr/local/include
@install -m 0644 softPwm.h /usr/local/include
@install -m 0644 lcd.h /usr/local/include
@install -m 0644 wiringPiSPI.h /usr/local/include
# @install -m 0644 libwiringPi.a /usr/local/lib
@install -m 0755 libwiringPi.so.1.0 /usr/local/lib
@ln -sf /usr/local/lib/libwiringPi.so.1.0 /usr/local/lib/libwiringPi.so
@ln -sf /usr/local/lib/libwiringPi.so.1.0 /usr/local/lib/libwiringPi.so.1
@install -m 0755 -d $(DESTDIR)$(PREFIX)/lib
@install -m 0755 -d $(DESTDIR)$(PREFIX)/include
@install -m 0644 wiringPi.h $(DESTDIR)$(PREFIX)/include
@install -m 0644 wiringSerial.h $(DESTDIR)$(PREFIX)/include
@install -m 0644 wiringShift.h $(DESTDIR)$(PREFIX)/include
@install -m 0644 gertboard.h $(DESTDIR)$(PREFIX)/include
@install -m 0644 piNes.h $(DESTDIR)$(PREFIX)/include
@install -m 0644 softPwm.h $(DESTDIR)$(PREFIX)/include
@install -m 0644 softServo.h $(DESTDIR)$(PREFIX)/include
@install -m 0644 softTone.h $(DESTDIR)$(PREFIX)/include
@install -m 0644 lcd.h $(DESTDIR)$(PREFIX)/include
@install -m 0644 wiringPiSPI.h $(DESTDIR)$(PREFIX)/include
@install -m 0755 libwiringPi.a $(DESTDIR)$(PREFIX)/lib
@install -m 0755 libwiringPi.so.$(VERSION) $(DESTDIR)$(PREFIX)/lib
@ln -sf $(DESTDIR)$(PREFIX)/lib/libwiringPi.so.$(VERSION) $(DESTDIR)/lib/libwiringPi.so
@ln -sf $(DESTDIR)$(PREFIX)/lib/libwiringPi.so.$(VERSION) $(DESTDIR)/lib/libwiringPi.so.1
@ldconfig
.PHONEY: uninstall
uninstall:
@echo "[UnInstall]"
@rm -f /usr/local/include/wiringPi.h
@rm -f /usr/local/include/wiringSerial.h
@rm -f /usr/local/include/wiringShift.h
@rm -f /usr/local/include/gertboard.h
@rm -f /usr/local/include/piNes.h
@rm -f /usr/local/include/softPwm.h
@rm -f /usr/local/include/lcd.h
@rm -f /usr/local/include/wiringPiSPI.h
@rm -f /usr/local/lib/libwiringPi.*
@rm -f $(DESTDIR)$(PREFIX)/include/wiringPi.h
@rm -f $(DESTDIR)$(PREFIX)/include/wiringSerial.h
@rm -f $(DESTDIR)$(PREFIX)/include/wiringShift.h
@rm -f $(DESTDIR)$(PREFIX)/include/gertboard.h
@rm -f $(DESTDIR)$(PREFIX)/include/piNes.h
@rm -f $(DESTDIR)$(PREFIX)/include/softPwm.h
@rm -f $(DESTDIR)$(PREFIX)/include/softServo.h
@rm -f $(DESTDIR)$(PREFIX)/include/softTone.h
@rm -f $(DESTDIR)$(PREFIX)/include/lcd.h
@rm -f $(DESTDIR)$(PREFIX)/include/wiringPiSPI.h
@rm -f $(DESTDIR)$(PREFIX)/lib/libwiringPi.*
@ldconfig

202
wiringPi/softServo.c Normal file
View File

@ -0,0 +1,202 @@
/*
* softServo.c:
* Provide N channels of software driven PWM suitable for RC
* servo motors.
* Copyright (c) 2012 Gordon Henderson
***********************************************************************
* This file is part of wiringPi:
* https://projects.drogon.net/raspberry-pi/wiringpi/
*
* wiringPi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* wiringPi 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with wiringPi.
* If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
//#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <pthread.h>
#include "wiringPi.h"
#include "softServo.h"
// RC Servo motors are a bit of an oddity - designed in the days when
// radio control was experimental and people were tryin to make
// things as simple as possible as it was all very expensive...
//
// So... To drive an RC Servo motor, you need to send it a modified PWM
// signal - it needs anything from 1ms to 2ms - with 1ms meaning
// to move the server fully left, and 2ms meaning to move it fully
// right. Then you need a long gap before sending the next pulse.
// The reason for this is that you send a multiplexed stream of these
// pulses up the radio signal into the reciever which de-multiplexes
// them into the signals for each individual servo. Typically there
// might be 8 channels, so you need at least 8 "slots" of 2mS pulses
// meaning the entire frame must fit into a 16mS slot - which would
// then be repeated...
//
// In practice we have a total slot width of about 20mS - so we're sending 50
// updates per second to each servo.
//
// In this code, we don't need to be too fussy about the gap as we're not doing
// the multipexing, but it does need to be at least 10mS, and preferably 16
// from what I've been able to determine.
#define MAX_SERVOS 8
static int pinMap [MAX_SERVOS] ; // Keep track of our pins
static int pulseWidth [MAX_SERVOS] ; // microseconds
/*
* softServoThread:
* Thread to do the actual Servo PWM output
*********************************************************************************
*/
static PI_THREAD (softServoThread)
{
register int i, j, k, m, tmp ;
int lastDelay, pin, servo ;
int myDelays [MAX_SERVOS] ;
int myPins [MAX_SERVOS] ;
struct timeval tNow, tStart, tPeriod, tGap, tTotal ;
struct timespec tNs ;
tTotal.tv_sec = 0 ;
tTotal.tv_usec = 8000 ;
piHiPri (50) ;
for (;;)
{
gettimeofday (&tStart, NULL) ;
memcpy (myDelays, pulseWidth, sizeof (myDelays)) ;
memcpy (myPins, pinMap, sizeof (myPins)) ;
// Sort the delays (& pins), shortest first
for (m = MAX_SERVOS / 2 ; m > 0 ; m /= 2 )
for (j = m ; j < MAX_SERVOS ; ++j)
for (i = j - m ; i >= 0 ; i -= m)
{
k = i + m ;
if (myDelays [k] >= myDelays [i])
break ;
else // Swap
{
tmp = myDelays [i] ; myDelays [i] = myDelays [k] ; myDelays [k] = tmp ;
tmp = myPins [i] ; myPins [i] = myPins [k] ; myPins [k] = tmp ;
}
}
// All on
lastDelay = 0 ;
for (servo = 0 ; servo < MAX_SERVOS ; ++servo)
{
if ((pin = myPins [servo]) == -1)
continue ;
digitalWrite (pin, HIGH) ;
myDelays [servo] = myDelays [servo] - lastDelay ;
lastDelay += myDelays [servo] ;
}
// Now loop, turning them all off as required
for (servo = 0 ; servo < MAX_SERVOS ; ++servo)
{
if ((pin = myPins [servo]) == -1)
continue ;
delayMicroseconds (myDelays [servo]) ;
digitalWrite (pin, LOW) ;
}
// Wait until the end of an 8mS time-slot
gettimeofday (&tNow, NULL) ;
timersub (&tNow, &tStart, &tPeriod) ;
timersub (&tTotal, &tPeriod, &tGap) ;
tNs.tv_sec = tGap.tv_sec ;
tNs.tv_nsec = tGap.tv_usec * 1000 ;
nanosleep (&tNs, NULL) ;
}
return NULL ;
}
/*
* softServoWrite:
* Write a Servo value to the given pin
*********************************************************************************
*/
void softServoWrite (int servoPin, int value)
{
int servo ;
servoPin &= 63 ;
/**/ if (value < -250)
value = -250 ;
else if (value > 1250)
value = 1250 ;
for (servo = 0 ; servo < MAX_SERVOS ; ++servo)
if (pinMap [servo] == servoPin)
pulseWidth [servo] = value + 1000 ; // uS
}
/*
* softServoSetup:
* Setup the software servo system
*********************************************************************************
*/
int softServoSetup (int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7)
{
int servo ;
if (p0 != -1) { pinMode (p0, OUTPUT) ; digitalWrite (p0, LOW) ; }
if (p1 != -1) { pinMode (p1, OUTPUT) ; digitalWrite (p1, LOW) ; }
if (p2 != -1) { pinMode (p2, OUTPUT) ; digitalWrite (p2, LOW) ; }
if (p3 != -1) { pinMode (p3, OUTPUT) ; digitalWrite (p3, LOW) ; }
if (p4 != -1) { pinMode (p4, OUTPUT) ; digitalWrite (p4, LOW) ; }
if (p5 != -1) { pinMode (p5, OUTPUT) ; digitalWrite (p5, LOW) ; }
if (p6 != -1) { pinMode (p6, OUTPUT) ; digitalWrite (p6, LOW) ; }
if (p7 != -1) { pinMode (p7, OUTPUT) ; digitalWrite (p7, LOW) ; }
pinMap [0] = p0 ;
pinMap [1] = p1 ;
pinMap [2] = p2 ;
pinMap [3] = p3 ;
pinMap [4] = p4 ;
pinMap [5] = p5 ;
pinMap [6] = p6 ;
pinMap [7] = p7 ;
for (servo = 0 ; servo < MAX_SERVOS ; ++servo)
pulseWidth [servo] = 1500 ; // Mid point
return piThreadCreate (softServoThread) ;
}

35
wiringPi/softServo.h Normal file
View File

@ -0,0 +1,35 @@
/*
* softServo.h:
* Provide N channels of software driven PWM suitable for RC
* servo motors.
* Copyright (c) 2012 Gordon Henderson
***********************************************************************
* This file is part of wiringPi:
* https://projects.drogon.net/raspberry-pi/wiringpi/
*
* wiringPi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* wiringPi 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with wiringPi.
* If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
#ifdef __cplusplus
extern "C" {
#endif
extern void softServoWrite (int pin, int value) ;
extern int softServoSetup (int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7) ;
#ifdef __cplusplus
}
#endif

119
wiringPi/softTone.c Normal file
View File

@ -0,0 +1,119 @@
/*
* softTone.c:
* For that authentic retro sound...
* Er... A little experiment to produce tones out of a Pi using
* one (or 2) GPIO pins and a piezeo "speaker" element.
* (Or a high impedance speaker, but don'y blame me if you blow-up
* the GPIO pins!)
* Copyright (c) 2012 Gordon Henderson
***********************************************************************
* This file is part of wiringPi:
* https://projects.drogon.net/raspberry-pi/wiringpi/
*
* wiringPi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* wiringPi 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with wiringPi.
* If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
#include <stdio.h>
#include <pthread.h>
#include "wiringPi.h"
#include "softTone.h"
#define MAX_PINS 64
#define PULSE_TIME 100
static int frewqs [MAX_PINS] ;
static int newPin = -1 ;
/*
* softToneThread:
* Thread to do the actual PWM output
*********************************************************************************
*/
static PI_THREAD (softToneThread)
{
int pin, frewq, halfPeriod ;
pin = newPin ;
newPin = -1 ;
piHiPri (50) ;
for (;;)
{
frewq = frewqs [pin] ;
if (frewq != 0)
{
halfPeriod = 500000 / frewq ;
digitalWrite (pin, HIGH) ;
delayMicroseconds (halfPeriod) ;
digitalWrite (pin, LOW) ;
delayMicroseconds (halfPeriod) ;
}
}
return NULL ;
}
/*
* softToneWrite:
* Write a frequency value to the given pin
*********************************************************************************
*/
void softToneWrite (int pin, int frewq)
{
pin &= 63 ;
/**/ if (frewq < 0)
frewq = 0 ;
else if (frewq > 5000) // Max 5KHz
frewq = 5000 ;
frewqs [pin] = frewq ;
}
/*
* softToneCreate:
* Create a new tone thread.
*********************************************************************************
*/
int softToneCreate (int pin)
{
int res ;
pinMode (pin, OUTPUT) ;
digitalWrite (pin, LOW) ;
frewqs [pin] = 0 ;
newPin = pin ;
res = piThreadCreate (softToneThread) ;
while (newPin != -1)
delay (1) ;
return res ;
}

38
wiringPi/softTone.h Normal file
View File

@ -0,0 +1,38 @@
/*
* softTone.c:
* For that authentic retro sound...
* Er... A little experiment to produce tones out of a Pi using
* one (or 2) GPIO pins and a piezeo "speaker" element.
* (Or a high impedance speaker, but don'y blame me if you blow-up
* the GPIO pins!)
* Copyright (c) 2012 Gordon Henderson
***********************************************************************
* This file is part of wiringPi:
* https://projects.drogon.net/raspberry-pi/wiringpi/
*
* wiringPi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* wiringPi 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with wiringPi.
* If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
#ifdef __cplusplus
extern "C" {
#endif
extern int softToneCreate (int pin) ;
extern void softToneWrite (int pin, int frewq) ;
#ifdef __cplusplus
}
#endif

View File

@ -77,6 +77,7 @@
void (*pinMode) (int pin, int mode) ;
void (*pullUpDnControl) (int pin, int pud) ;
void (*digitalWrite) (int pin, int value) ;
void (*digitalWriteByte) (int value) ;
void (*pwmWrite) (int pin, int value) ;
void (*setPadDrive) (int group, int value) ;
int (*digitalRead) (int pin) ;
@ -399,15 +400,15 @@ int wpiPinToGpio (int wpiPin)
* Revision is currently 1 or 2. -1 is returned on error.
*
* Much confusion here )-:
* Seems there ar esome boards with 0000 in them (mistake in manufacture)
* and some board with 0005 in them (another mistake in manufacture).
* Seems there are some boards with 0000 in them (mistake in manufacture)
* and some board with 0005 in them (another mistake in manufacture?)
* So the distinction between boards that I can see is:
* 0000 - Error
* 0001 - Not used
* 0002 - Rev 1
* 0003 - Rev 1
* 0004 - Rev 2
* 0005 - Rev 2
* 0005 - Rev 2 (but error)
* 0006 - Rev 2
* 000f - Rev 2 + 512MB
*
@ -499,6 +500,8 @@ int piBoardRev (void)
void pinModeGpio (int pin, int mode)
{
// register int barrier ;
int fSel, shift, alt ;
pin &= 63 ;
@ -519,30 +522,40 @@ void pinModeGpio (int pin, int mode)
*(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (alt << shift) ;
delayMicroseconds (110) ; // See comments in pwmSetClockWPi
*(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (alt << shift) ;
// Page 107 of the BCM Peripherals manual talks about the GPIO clocks,
// but I'm assuming (hoping!) that this applies to other clocks too.
*(pwm + PWM_CONTROL) = 0 ; // Stop PWM
*(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x01 ; // Stop PWM Clock
delayMicroseconds (110) ; // See comments in pwmSetClockWPi
(void)*(pwm + PWM_CONTROL) ;
while ((*(pwm + PWM_CONTROL) & 0x80) != 0) // Wait for clock to be !BUSY
*(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x01 ; // Stop PWM Clock
delayMicroseconds (110) ; // See comments in pwmSetClockWPi
while ((*(clk + PWMCLK_CNTL) & 0x80) != 0) // Wait for clock to be !BUSY
delayMicroseconds (1) ;
*(clk + PWMCLK_DIV) = BCM_PASSWORD | (32 << 12) ; // set pwm div to 32 (19.2/32 = 600KHz)
*(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x11 ; // enable clk
// Default range regsiter of 1024
delayMicroseconds (110) ; // See comments in pwmSetClockWPi
*(pwm + PWM0_DATA) = 0 ; *(pwm + PWM0_RANGE) = 1024 ;
*(pwm + PWM1_DATA) = 0 ; *(pwm + PWM1_RANGE) = 1024 ;
// Default range register of 1024
*(pwm + PWM0_RANGE) = 1024 ; delayMicroseconds (10) ;
*(pwm + PWM1_RANGE) = 1024 ; delayMicroseconds (10) ;
*(pwm + PWM0_DATA) = 0 ; delayMicroseconds (10) ;
*(pwm + PWM1_DATA) = 0 ; delayMicroseconds (10) ;
// Enable PWMs in balanced mode (default)
*(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ;
delay (100) ;
}
// When we change mode of any pin, we remove the pull up/downs
// Or we used to... Hm. Commented out now because for some wieird reason,
// it seems to block subsequent attempts to set the pull up/downs and I've
@ -629,7 +642,7 @@ void pwmSetClockWPi (int divisor)
*(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x01 ; // Stop PWM Clock
delayMicroseconds (110) ; // prevents clock going sloooow
while ((*(pwm + PWM_CONTROL) & 0x80) != 0) // Wait for clock to be !BUSY
while ((*(clk + PWMCLK_CNTL) & 0x80) != 0) // Wait for clock to be !BUSY
delayMicroseconds (1) ;
*(clk + PWMCLK_DIV) = BCM_PASSWORD | (divisor << 12) ;
@ -704,6 +717,50 @@ void digitalWriteSys (int pin, int value)
}
/*
* digitalWriteByte:
* Write an 8-bit byte to the first 8 GPIO pins - try to do it as
* fast as possible.
* However it still needs 2 operations to set the bits, so any external
* hardware must not rely on seeing a change as there will be a change
* to set the outputs bits to zero, then another change to set the 1's
*********************************************************************************
*/
void digitalWriteByteGpio (int value)
{
uint32_t pinSet = 0 ;
uint32_t pinClr = 0 ;
int mask = 1 ;
int pin ;
for (pin = 0 ; pin < 8 ; ++pin)
{
if ((value & mask) == 0)
pinClr |= (1 << pinToGpio [pin]) ;
else
pinSet |= (1 << pinToGpio [pin]) ;
*(gpio + gpioToGPCLR [0]) = pinClr ;
*(gpio + gpioToGPSET [0]) = pinSet ;
mask <<= 1 ;
}
}
void digitalWriteByteSys (int value)
{
int mask = 1 ;
int pin ;
for (pin = 0 ; pin < 8 ; ++pin)
{
digitalWriteSys (pinToGpio [pin], value & mask) ;
mask <<= 1 ;
}
}
/*
* pwmWrite:
* Set an output PWM value
@ -915,6 +972,9 @@ void delay (unsigned int howLong)
* somewhat sub-optimal in that it uses 100% CPU, something not an issue
* in a microcontroller, but under a multi-tasking, multi-user OS, it's
* wastefull, however we've no real choice )-:
*
* Plan B: It seems all might not be well with that plan, so changing it
* to use gettimeofday () and poll on that instead...
*********************************************************************************
*/
@ -930,16 +990,31 @@ void delayMicrosecondsSys (unsigned int howLong)
void delayMicrosecondsHard (unsigned int howLong)
{
#ifdef HARD_TIMER
volatile unsigned int dummy ;
*(timer + TIMER_LOAD) = howLong ;
*(timer + TIMER_IRQ_CLR) = 0 ;
while (*timerIrqRaw == 0)
;
dummy = *timerIrqRaw ;
while (dummy == 0)
dummy = *timerIrqRaw ;
#else
struct timeval tNow, tLong, tEnd ;
gettimeofday (&tNow, NULL) ;
tLong.tv_sec = howLong / 1000000 ;
tLong.tv_usec = howLong % 1000000 ;
timeradd (&tNow, &tLong, &tEnd) ;
while (timercmp (&tNow, &tEnd, <))
gettimeofday (&tNow, NULL) ;
#endif
}
void delayMicrosecondsWPi (unsigned int howLong)
{
struct timespec sleeper, dummy ;
struct timespec sleeper ;
/**/ if (howLong == 0)
return ;
@ -949,7 +1024,7 @@ void delayMicrosecondsWPi (unsigned int howLong)
{
sleeper.tv_sec = 0 ;
sleeper.tv_nsec = (long)(howLong * 1000) ;
nanosleep (&sleeper, &dummy) ;
nanosleep (&sleeper, NULL) ;
}
}
@ -998,6 +1073,7 @@ int wiringPiSetup (void)
pinMode = pinModeWPi ;
pullUpDnControl = pullUpDnControlWPi ;
digitalWrite = digitalWriteWPi ;
digitalWriteByte = digitalWriteByteGpio ; // Same code
pwmWrite = pwmWriteWPi ;
setPadDrive = setPadDriveWPi ;
digitalRead = digitalReadWPi ;
@ -1166,6 +1242,7 @@ int wiringPiSetupGpio (void)
pinMode = pinModeGpio ;
pullUpDnControl = pullUpDnControlGpio ;
digitalWrite = digitalWriteGpio ;
digitalWriteByte = digitalWriteByteGpio ;
pwmWrite = pwmWriteGpio ;
setPadDrive = setPadDriveGpio ;
digitalRead = digitalReadGpio ;
@ -1190,6 +1267,7 @@ int wiringPiSetupGpio (void)
int wiringPiSetupSys (void)
{
int boardRev ;
int pin ;
struct timeval tv ;
char fName [128] ;
@ -1200,6 +1278,7 @@ int wiringPiSetupSys (void)
pinMode = pinModeSys ;
pullUpDnControl = pullUpDnControlSys ;
digitalWrite = digitalWriteSys ;
digitalWriteByte = digitalWriteByteSys ;
pwmWrite = pwmWriteSys ;
setPadDrive = setPadDriveSys ;
digitalRead = digitalReadSys ;
@ -1209,6 +1288,14 @@ int wiringPiSetupSys (void)
pwmSetRange = pwmSetRangeSys ;
pwmSetClock = pwmSetClockSys ;
if ((boardRev = piBoardRev ()) < 0)
return -1 ;
if (boardRev == 1)
pinToGpio = pinToGpioR1 ;
else
pinToGpio = pinToGpioR2 ;
// Open and scan the directory, looking for exported GPIOs, and pre-open
// the 'value' interface to speed things up for later

View File

@ -70,6 +70,7 @@ extern int wiringPiSetupPiFaceForGpioProg (void) ; // Don't use this - for gpio
extern void (*pinMode) (int pin, int mode) ;
extern void (*pullUpDnControl) (int pin, int pud) ;
extern void (*digitalWrite) (int pin, int value) ;
extern void (*digitalWriteByte) (int value) ;
extern void (*pwmWrite) (int pin, int value) ;
extern void (*setPadDrive) (int group, int value) ;
extern int (*digitalRead) (int pin) ;

View File

@ -182,6 +182,11 @@ void digitalWritePiFace (int pin, int value)
writeByte (GPIOA, dataOutRegister) ;
}
void digitalWriteBytePiFace (int value)
{
writeByte (GPIOA, value) ;
}
void digitalWritePiFaceSpecial (int pin, int value)
{
@ -318,12 +323,13 @@ int wiringPiSetupPiFace (void)
writeByte (GPIOA, 0x00) ; // Set all outptus off
writeByte (GPPUB, 0x00) ; // Disable any pull-ups on port B
pinMode = pinModePiFace ;
pullUpDnControl = pullUpDnControlPiFace ;
digitalWrite = digitalWritePiFace ;
pwmWrite = pwmWritePiFace ;
digitalRead = digitalReadPiFace ;
waitForInterrupt = waitForInterruptPiFace ;
pinMode = pinModePiFace ;
pullUpDnControl = pullUpDnControlPiFace ;
digitalWrite = digitalWritePiFace ;
digitalWriteByte = digitalWriteBytePiFace ;
pwmWrite = pwmWritePiFace ;
digitalRead = digitalReadPiFace ;
waitForInterrupt = waitForInterruptPiFace ;
return 0 ;
}
@ -344,12 +350,13 @@ int wiringPiSetupPiFaceForGpioProg (void)
if (x != 0)
return x ;
pinMode = pinModePiFace ;
pinMode = pinModePiFace ;
pullUpDnControl = pullUpDnControlPiFaceSpecial ;
digitalWrite = digitalWritePiFaceSpecial ;
pwmWrite = pwmWritePiFace ;
digitalRead = digitalReadPiFace ;
waitForInterrupt = waitForInterruptPiFace ;
digitalWriteByte = digitalWriteBytePiFace ;
pwmWrite = pwmWritePiFace ;
digitalRead = digitalReadPiFace ;
waitForInterrupt = waitForInterruptPiFace ;
return 0 ;
}

View File

@ -52,7 +52,7 @@ static int spiFds [2] ;
int wiringPiSPIGetFd (int channel)
{
return spiFds [channel &1] ;
return spiFds [channel & 1] ;
}