From ae40bdaf6a1b0267737365c2e1c5be17dda122b0 Mon Sep 17 00:00:00 2001 From: Gordon Henderson Date: Tue, 28 Aug 2012 18:37:54 +0100 Subject: [PATCH] Merged from git.drogon.net, SPI driver helpers, C++ wrappers, softPwm, piNes, gertboard, SPI --- examples/Makefile | 25 ++- examples/delayTest.c | 68 ++++++++ examples/gertboard.c | 77 +++++++++ examples/gertboard.png | Bin 0 -> 4834 bytes examples/nes.c | 44 +++++ examples/softPwm.c | 69 ++++++++ gpio/Makefile | 2 +- gpio/gpio.1 | 102 +++++++++-- gpio/gpio.c | 450 ++++++++++++++++++++++++++++++++++++++---------- wiringPi/gertboard.c | 122 +++++++++++++ wiringPi/gertboard.h | 39 +++++ wiringPi/lcd.h | 8 + wiringPi/piNes.c | 113 ++++++++++++ wiringPi/piNes.h | 45 +++++ wiringPi/softPwm.c | 130 ++++++++++++++ wiringPi/softPwm.h | 34 ++++ wiringPi/wiringPi.c | 431 +++++++++++++++++++++++++++++++--------------- wiringPi/wiringPi.h | 21 ++- wiringPi/wiringPiSPI.c | 117 +++++++++++++ wiringPi/wiringPiSPI.h | 35 ++++ wiringPi/wiringSerial.c | 44 +++-- wiringPi/wiringSerial.h | 1 + 22 files changed, 1703 insertions(+), 274 deletions(-) create mode 100644 examples/delayTest.c create mode 100644 examples/gertboard.c create mode 100644 examples/gertboard.png create mode 100644 examples/nes.c create mode 100644 examples/softPwm.c create mode 100644 wiringPi/gertboard.c create mode 100644 wiringPi/gertboard.h create mode 100644 wiringPi/piNes.c create mode 100644 wiringPi/piNes.h create mode 100644 wiringPi/softPwm.c create mode 100644 wiringPi/softPwm.h create mode 100644 wiringPi/wiringPiSPI.c create mode 100644 wiringPi/wiringPiSPI.h diff --git a/examples/Makefile b/examples/Makefile index df00d79..450e0dc 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -35,11 +35,11 @@ LIBS = -lwiringPi # Should not alter anything below this line ############################################################################### -SRC = test1.c test2.c speed.c lcd.c wfi.c piface.c +SRC = test1.c test2.c speed.c lcd.c wfi.c piface.c gertboard.c nes.c delayTest.c softPwm.c -OBJ = test1.o test2.o speed.o lcd.o wfi.o piface.o +OBJ = test1.o test2.o speed.o lcd.o wfi.o piface.o gertboard.o nes.o delayTest.o softPwm.o -all: test1 test2 speed lcd wfi piface +all: test1 test2 speed lcd wfi piface gertboard nes softPwm test1: test1.o @echo [link] @@ -65,13 +65,30 @@ piface: piface.o @echo [link] $(CC) -o $@ piface.o $(LDFLAGS) $(LIBS) -lpthread +gertboard: gertboard.o + @echo [link] + $(CC) -o $@ gertboard.o $(LDFLAGS) $(LIBS) -lm + +nes: nes.o + @echo [link] + $(CC) -o $@ nes.o $(LDFLAGS) $(LIBS) -lm + +softPwm: softPwm.o + @echo [link] + $(CC) -o $@ softPwm.o $(LDFLAGS) $(LIBS) -lm -lpthread + + +delayTest: delayTest.o + @echo [link] + $(CC) -o $@ delayTest.o $(LDFLAGS) $(LIBS) + .c.o: @echo [CC] $< @$(CC) -c $(CFLAGS) $< -o $@ clean: - rm -f $(OBJ) *~ core tags test1 test2 speed lcd wfi piface + rm -f $(OBJ) *~ core tags test1 test2 speed lcd wfi piface gertboard nes delayTest softPwm tags: $(SRC) @echo [ctags] diff --git a/examples/delayTest.c b/examples/delayTest.c new file mode 100644 index 0000000..8c95522 --- /dev/null +++ b/examples/delayTest.c @@ -0,0 +1,68 @@ + +#include +#include +#include + +#include +#include +#include + +#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 ; + + if (wiringPiSetup () == -1) + return 1 ; + + piHiPri (10) ; + sleep (1) ; + +// Baseline test + + gettimeofday (&t1, NULL) ; + gettimeofday (&t2, NULL) ; + + t = t2.tv_usec - t1.tv_usec ; + printf ("Baseline test: %lld\n", t); + + for (x = 0 ; x < CYCLES ; ++x) + { + 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 ; + } + + printf ("Done: Max: %d, min: %d\n", max, min) ; + + 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") ; + } + printf ("\n") ; + + return 0 ; +} diff --git a/examples/gertboard.c b/examples/gertboard.c new file mode 100644 index 0000000..8f26dd4 --- /dev/null +++ b/examples/gertboard.c @@ -0,0 +1,77 @@ + +/* + * gertboard.c: + * Simple test for the SPI bus on the Gertboard + * + * Hardware setup: + * D/A port 0 jumpered to A/D port 0. + * + * We output a sine wave on D/A port 0 and sample A/D port 0. We then + * copy this value to D/A port 1 and use a 'scope on both D/A ports + * to check all's well. + * + */ + +#include +#include +#include + +#define B_SIZE 200 +#undef DO_TIMING + +#include +#include + +int main (void) +{ + double angle ; + int i ; + uint32_t x1 ; + int buffer [B_SIZE] ; + +#ifdef DO_TIMING + unsigned int now, then ; +#endif + + printf ("Raspberry Pi Gertboard SPI test program\n") ; + + if (wiringPiSetupSys () < 0) + return -1 ; + + if (gertboardSPISetup () < 0) + return 1 ; + +// Generate a Sine Wave + + for (i = 0 ; i < B_SIZE ; ++i) + { + angle = ((double)i / (double)B_SIZE) * M_PI * 2.0 ; + buffer [i] = (int)rint ((sin (angle)) * 127.0 + 128.0) ; + } + + + for (;;) + { +#ifdef DO_TIMING + then = millis () ; +#endif + + for (i = 0 ; i < B_SIZE ; ++i) + { + gertboardAnalogWrite (0, buffer [i]) ; + +#ifndef DO_TIMING + x1 = gertboardAnalogRead (0) ; + gertboardAnalogWrite (1, x1 >> 2) ; // 10-bit A/D, 8-bit D/A +#endif + } + +#ifdef DO_TIMING + now = millis () ; + printf ("%4d mS, %9.7f S/sample", now - then, ((double)(now - then) / 1000.0) / (double)B_SIZE) ; + printf (" -> %9.4f samples/sec \n", 1 / (((double)(now - then) / 1000.0) / (double)B_SIZE)) ; +#endif + } + + return 0 ; +} diff --git a/examples/gertboard.png b/examples/gertboard.png new file mode 100644 index 0000000000000000000000000000000000000000..03c5cdd63dbb163330d19400cb9d896211e86ae7 GIT binary patch literal 4834 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 IM6N<$f;V*&MF0Q* literal 0 HcmV?d00001 diff --git a/examples/nes.c b/examples/nes.c new file mode 100644 index 0000000..1a485bd --- /dev/null +++ b/examples/nes.c @@ -0,0 +1,44 @@ + +#include +#include +#include + +#include +#include + +#define BLANK "| " + +int main () +{ + int joystick ; + unsigned int buttons ; + + if (wiringPiSetup () == -1) + { + fprintf (stdout, "oops: %s\n", strerror (errno)) ; + return 1 ; + } + + if ((joystick = setupNesJoystick (2, 1, 0)) == -1) + { + fprintf (stdout, "Unable to setup joystick\n") ; + return 1 ; + } + + for (;;) + { + buttons = readNesJoystick (joystick) ; + + if ((buttons & NES_UP) != 0) printf ("| UP " ) ; else printf (BLANK) ; + if ((buttons & NES_DOWN) != 0) printf ("| DOWN " ) ; else printf (BLANK) ; + if ((buttons & NES_LEFT) != 0) printf ("| LEFT " ) ; else printf (BLANK) ; + if ((buttons & NES_RIGHT) != 0) printf ("|RIGHT " ) ; else printf (BLANK) ; + if ((buttons & NES_SELECT) != 0) printf ("|SELECT" ) ; else printf (BLANK) ; + if ((buttons & NES_START) != 0) printf ("|START " ) ; else printf (BLANK) ; + if ((buttons & NES_A) != 0) printf ("| A " ) ; else printf (BLANK) ; + if ((buttons & NES_B) != 0) printf ("| B " ) ; else printf (BLANK) ; + printf ("|\n") ; + } + + return 0 ; +} diff --git a/examples/softPwm.c b/examples/softPwm.c new file mode 100644 index 0000000..09b4ae0 --- /dev/null +++ b/examples/softPwm.c @@ -0,0 +1,69 @@ + +#include +#include +#include + +#include +#include + +#define RANGE 100 +#define NUM_LEDS 12 + +int ledMap [NUM_LEDS] = { 0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13 } ; + +int values [NUM_LEDS] = { 0, 17, 32, 50, 67, 85, 100, 85, 67, 50, 32, 17 } ; + +int main () +{ + int i, j ; + char buf [80] ; + + if (wiringPiSetup () == -1) + { + fprintf (stdout, "oops: %s\n", strerror (errno)) ; + return 1 ; + } + + for (i = 0 ; i < NUM_LEDS ; ++i) + { + softPwmCreate (ledMap [i], 0, RANGE) ; + printf ("%3d, %3d, %3d\n", i, ledMap [i], values [i]) ; + } + + fgets (buf, 80, stdin) ; + +// Bring all up one by one: + + for (i = 0 ; i < NUM_LEDS ; ++i) + for (j = 0 ; j <= 100 ; ++j) + { + softPwmWrite (ledMap [i], j) ; + delay (10) ; + } + + fgets (buf, 80, stdin) ; + +// Down fast + + for (i = 100 ; i > 0 ; --i) + { + for (j = 0 ; j < NUM_LEDS ; ++j) + softPwmWrite (ledMap [j], i) ; + delay (10) ; + } + + fgets (buf, 80, stdin) ; + + for (;;) + { + for (i = 0 ; i < NUM_LEDS ; ++i) + softPwmWrite (ledMap [i], values [i]) ; + + delay (50) ; + + i = values [0] ; + for (j = 0 ; j < NUM_LEDS - 1 ; ++j) + values [j] = values [j + 1] ; + values [NUM_LEDS - 1] = i ; + } +} diff --git a/gpio/Makefile b/gpio/Makefile index c0740c9..a92dd5f 100644 --- a/gpio/Makefile +++ b/gpio/Makefile @@ -41,7 +41,7 @@ OBJ = gpio.o all: gpio -gpio: gpio.o +gpio: gpio.o /usr/local/lib/libwiringPi.a @echo [LD] @$(CC) -o $@ gpio.o $(LDFLAGS) $(LIBS) diff --git a/gpio/gpio.1 b/gpio/gpio.1 index 7da64b2..bc8e36e 100644 --- a/gpio/gpio.1 +++ b/gpio/gpio.1 @@ -4,28 +4,55 @@ gpio \- Command-line access to Raspberry Pi and PiFace GPIO .SH SYNOPSIS -.TP .B gpio -.RB [ \-v ] -.TP +.B \-v +.PP .B gpio -.RB [ \-g ] -.RB < read/write/pwm/mode ...> -.TP +.B [ \-g ] +.B read/write/pwm/mode ... +.PP .B gpio -.RB [ \-p ] -.RB < read/write/mode ...> -.TP +.B [ \-p ] +.B read/write/mode +.B ... +.PP +.B gpio +.B unexportall/exports +.PP +.B gpio +.B export/edge/unexport +.B ... +.PP .B gpio -.RB < export/edge/unexport/unexportall/exports ...> +.B drive +group value +.PP +.B gpio +.B pwm-bal/pwm-ms +.PP +.B gpio +.B pwmr +range +.PP +.B gpio +.B load \ i2c/spi +.PP +.B gpio +.B gbr +channel +.PP +.B gpio +.B gbw +channel value .SH DESCRIPTION .B GPIO -is a command line tool to allow the user easy access to the GPIO pins -on the Raspberry Pi. It's designed for simple testing and diagnostic -purposes, but can be used in shell scripts for general if somewhat slow -control of the GPIO pins. +is a swiss army knofe of a command line tool to allow the user easy +access to the GPIO pins on the Raspberry Pi and the SPI A/D and D/A +convertors on the Gertboard. It's designed for simple testing and +diagnostic purposes, but can be used in shell scripts for general if +somewhat slow control of the GPIO pins. Additionally, it can be used to set the exports in the \fI/sys/class/gpio\fR system directory to allow subsequent programs to use the \fR/sys/class/gpio\fR @@ -65,6 +92,14 @@ use the literals \fIup\fR, \fIdown\fR or \fItri\fR to set the internal pull-up, pull-down or tristate (off) controls. .TP +.B unexportall +Un-Export all the GPIO pins in the /sys/class/gpio directory. + +.TP +.B exports +Print a list (if any) of all the exported GPIO pins and their current values. + +.TP .B export Export a GPIO pin in the \fI/sys/class/gpio\fR directory. Use like the mode command above however only \fIin\fR and \fIout\fR are supported at @@ -96,12 +131,41 @@ requiring root/sudo. Un-Export a GPIO pin in the /sys/class/gpio directory. .TP -.B unexportall -Un-Export all the GPIO pins in the /sys/class/gpio directory. +.B drive +group value + +Change the pad driver value for the given pad group to the supplied drive +value. Group is 0, 1 or 2 and value is 0-7. Do not use unless you are +absolutely sure you know what you're doing. .TP -.B exports -Print a list (if any) of all the exported GPIO pins and their current values. +.B pwm-bal/pwm-ms +Change the PWM mode to balanced (the default) or mark:space ratio (traditional) + +.TP +.B pwmr +Change the PWM range register. The default is 1024. + +.TP +.B load i2c/spi +This loads the i2c or the spi drivers into the system and changes the permissions on +the associated /dev/ entries so that the current user has access to them. + +.TP +.B gbr +channel + +This reads the analog to digital convertor on the Gertboard on the given +channel. The board jumpers need to be in-place to do this operation. + +.TP +.B gbw +channel value + +This writes the supplied value to the output channel on the Gertboards +SPI digital to analogue convertor. +The board jumpers need to be in-place to do this operation. + .SH "WiringPi vs. GPIO Pin numbering" @@ -170,7 +234,7 @@ Gordon Henderson .SH "REPORTING BUGS" -Report bugs to +Report bugs to .SH COPYRIGHT diff --git a/gpio/gpio.c b/gpio/gpio.c index 8467b3e..b696542 100644 --- a/gpio/gpio.c +++ b/gpio/gpio.c @@ -1,6 +1,7 @@ /* * gpio.c: - * Set-UID command-line interface to the Raspberry Pi's GPIO + * Swiss-Army-Knife, Set-UID command-line interface to the Raspberry + * Pi's GPIO. * Copyright (c) 2012 Gordon Henderson *********************************************************************** * This file is part of wiringPi: @@ -21,7 +22,6 @@ *********************************************************************** */ -#include #include #include @@ -32,15 +32,144 @@ #include #include +#include +#include + +#ifndef TRUE +# define TRUE (1==1) +# define FALSE (1==2) +#endif -#define VERSION "1.0" +#define VERSION "1.2" static int wpMode ; char *usage = "Usage: gpio -v\n" + " gpio -h\n" " gpio [-g] ...\n" " gpio [-p] ...\n" - " gpio ..." ; + " gpio export/edge/unexport/unexportall/exports ...\n" + " gpio drive \n" + " gpio pwm-bal/pwm-ms \n" + " gpio pwmr \n" + " gpio load spi/i2c\n" + " gpio gbr \n" + " gpio gbw \n" ; + + +/* + * changeOwner: + * Change the ownership of the file to the real userId of the calling + * program so we can access it. + ********************************************************************************* + */ + +static void changeOwner (char *cmd, char *file) +{ + uid_t uid = getuid () ; + uid_t gid = getgid () ; + + if (chown (file, uid, gid) != 0) + { + if (errno == ENOENT) // Warn that it's not there + fprintf (stderr, "%s: Warning: File not present: %s\n", cmd, file) ; + else + { + fprintf (stderr, "%s: Unable to change ownership of %s: %s\n", cmd, file, strerror (errno)) ; + exit (1) ; + } + } +} + + +/* + * moduleLoaded: + * Return true/false if the supplied module is loaded + ********************************************************************************* + */ + +static int moduleLoaded (char *modName) +{ + int len = strlen (modName) ; + int found = FALSE ; + FILE *fd = fopen ("/proc/modules", "r") ; + char line [80] ; + + if (fd == NULL) + { + fprintf (stderr, "gpio: Unable to check modules: %s\n", strerror (errno)) ; + exit (1) ; + } + + while (fgets (line, 80, fd) != NULL) + { + if (strncmp (line, modName, len) != 0) + continue ; + + found = TRUE ; + break ; + } + + fclose (fd) ; + + return found ; +} + + +/* + * doLoad: + * Load either the spi or i2c modules and change device ownerships, etc. + ********************************************************************************* + */ + +static void _doLoadUsage (char *argv []) +{ + fprintf (stderr, "Usage: %s load \n", argv [0]) ; + exit (1) ; +} + +static void doLoad (int argc, char *argv []) +{ + char *module ; + char cmd [80] ; + char *file1, *file2 ; + + if (argc != 3) + _doLoadUsage (argv) ; + + /**/ if (strcasecmp (argv [2], "spi") == 0) + { + module = "spi_bcm2708" ; + file1 = "/dev/spidev0.0" ; + file2 = "/dev/spidev0.1" ; + } + else if (strcasecmp (argv [2], "i2c") == 0) + { + module = "i2c_bcm2708" ; + file1 = "/dev/i2c-0" ; + file2 = "/dev/i2c-1" ; + } + else + _doLoadUsage (argv) ; + + if (!moduleLoaded (module)) + { + sprintf (cmd, "modprobe %s", module) ; + system (cmd) ; + } + + if (!moduleLoaded (module)) + { + fprintf (stderr, "%s: Unable to load %s\n", argv [0], module) ; + exit (1) ; + } + + sleep (1) ; // To let things get settled + + changeOwner (argv [0], file1) ; + changeOwner (argv [0], file2) ; +} + /* @@ -49,7 +178,7 @@ char *usage = "Usage: gpio -v\n" ********************************************************************************* */ -void doExports (void) +static void doExports (int argc, char *argv []) { int fd ; int i, l, first ; @@ -140,8 +269,6 @@ void doExport (int argc, char *argv []) int pin ; char *mode ; char fName [128] ; - uid_t uid ; - gid_t gid ; if (argc != 4) { @@ -183,27 +310,11 @@ void doExport (int argc, char *argv []) // Change ownership so the current user can actually use it! - uid = getuid () ; - gid = getgid () ; - sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ; - if (chown (fName, uid, gid) != 0) - { - fprintf (stderr, "%s: Unable to change ownership of the value file: %s\n", argv [1], strerror (errno)) ; - exit (1) ; - } - -// Also change ownership of the edge file - if it exists + changeOwner (argv [0], fName) ; sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ; - if (chown (fName, uid, gid) != 0) - { - if (errno != ENOENT) // Silently ignore File not found - older kernel - { - fprintf (stderr, "%s: Unable to change ownership of the value file: %s\n", argv [1], strerror (errno)) ; - exit (1) ; - } - } + changeOwner (argv [0], fName) ; } @@ -222,8 +333,6 @@ void doEdge (int argc, char *argv []) int pin ; char *mode ; char fName [128] ; - uid_t uid ; - gid_t gid ; if (argc != 4) { @@ -231,8 +340,7 @@ void doEdge (int argc, char *argv []) exit (1) ; } - pin = atoi (argv [2]) ; - + pin = atoi (argv [2]) ; mode = argv [3] ; // Export the pin and set direction to input @@ -263,40 +371,23 @@ void doEdge (int argc, char *argv []) exit (1) ; } - /**/ if (strcasecmp (mode, "none") == 0) - fprintf (fd, "none\n") ; - else if (strcasecmp (mode, "rising") == 0) - fprintf (fd, "rising\n") ; - else if (strcasecmp (mode, "falling") == 0) - fprintf (fd, "falling\n") ; - else if (strcasecmp (mode, "both") == 0) - fprintf (fd, "both\n") ; + /**/ if (strcasecmp (mode, "none") == 0) fprintf (fd, "none\n") ; + else if (strcasecmp (mode, "rising") == 0) fprintf (fd, "rising\n") ; + else if (strcasecmp (mode, "falling") == 0) fprintf (fd, "falling\n") ; + else if (strcasecmp (mode, "both") == 0) fprintf (fd, "both\n") ; else { fprintf (stderr, "%s: Invalid mode: %s. Should be none, rising, falling or both\n", argv [1], mode) ; exit (1) ; } -// Change ownership so the current user can actually use it! - - uid = getuid () ; - gid = getgid () ; +// Change ownership of the value and edge files, so the current user can actually use it! sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ; - if (chown (fName, uid, gid) != 0) - { - fprintf (stderr, "%s: Unable to change ownership of the value file: %s\n", argv [1], strerror (errno)) ; - exit (1) ; - } - -// Also change ownership of the edge file + changeOwner (argv [0], fName) ; sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ; - if (chown (fName, uid, gid) != 0) - { - fprintf (stderr, "%s: Unable to change ownership of the value file: %s\n", argv [1], strerror (errno)) ; - exit (1) ; - } + changeOwner (argv [0], fName) ; fclose (fd) ; } @@ -383,18 +474,12 @@ void doMode (int argc, char *argv []) mode = argv [3] ; - /**/ if (strcasecmp (mode, "in") == 0) - pinMode (pin, INPUT) ; - else if (strcasecmp (mode, "out") == 0) - pinMode (pin, OUTPUT) ; - else if (strcasecmp (mode, "pwm") == 0) - pinMode (pin, PWM_OUTPUT) ; - else if (strcasecmp (mode, "up") == 0) - pullUpDnControl (pin, PUD_UP) ; - else if (strcasecmp (mode, "down") == 0) - pullUpDnControl (pin, PUD_DOWN) ; - else if (strcasecmp (mode, "tri") == 0) - pullUpDnControl (pin, PUD_OFF) ; + /**/ if (strcasecmp (mode, "in") == 0) pinMode (pin, INPUT) ; + else if (strcasecmp (mode, "out") == 0) pinMode (pin, OUTPUT) ; + else if (strcasecmp (mode, "pwm") == 0) pinMode (pin, PWM_OUTPUT) ; + else if (strcasecmp (mode, "up") == 0) pullUpDnControl (pin, PUD_UP) ; + else if (strcasecmp (mode, "down") == 0) pullUpDnControl (pin, PUD_DOWN) ; + else if (strcasecmp (mode, "tri") == 0) pullUpDnControl (pin, PUD_OFF) ; else { fprintf (stderr, "%s: Invalid mode: %s. Should be in/out/pwm/up/down/tri\n", argv [1], mode) ; @@ -402,13 +487,125 @@ void doMode (int argc, char *argv []) } } + +/* + * doPadDrive: + * gpio drive group value + ********************************************************************************* + */ + +static void doPadDrive (int argc, char *argv []) +{ + int group, val ; + + if (argc != 4) + { + fprintf (stderr, "Usage: %s drive group value\n", argv [0]) ; + exit (1) ; + } + + group = atoi (argv [2]) ; + val = atoi (argv [3]) ; + + if ((group < 0) || (group > 2)) + { + fprintf (stderr, "%s: drive group not 0, 1 or 2: %d\n", argv [0], group) ; + exit (1) ; + } + + if ((val < 0) || (val > 7)) + { + fprintf (stderr, "%s: drive value not 0-7: %d\n", argv [0], val) ; + exit (1) ; + } + + setPadDrive (group, val) ; +} + + +/* + * doGbw: + * gpio gbw channel value + ********************************************************************************* + */ + +static void doGbw (int argc, char *argv []) +{ + int channel, value ; + + if (argc != 4) + { + fprintf (stderr, "Usage: %s gbr \n", argv [0]) ; + exit (1) ; + } + + channel = atoi (argv [2]) ; + value = atoi (argv [3]) ; + + if ((channel < 0) || (channel > 1)) + { + fprintf (stderr, "%s: channel must be 0 or 1\n", argv [0]) ; + exit (1) ; + } + + if ((value < 0) || (value > 1023)) + { + fprintf (stderr, "%s: value must be from 0 to 255\n", argv [0]) ; + exit (1) ; + } + + if (gertboardSPISetup () == -1) + { + fprintf (stderr, "Unable to initialise the Gertboard SPI interface: %s\n", strerror (errno)) ; + exit (1) ; + } + + gertboardAnalogWrite (channel, value) ; +} + + +/* + * doGbr: + * gpio gbr channel + ********************************************************************************* + */ + +static void doGbr (int argc, char *argv []) +{ + int channel ; + + if (argc != 3) + { + fprintf (stderr, "Usage: %s gbr \n", argv [0]) ; + exit (1) ; + } + + channel = atoi (argv [2]) ; + + if ((channel < 0) || (channel > 1)) + { + fprintf (stderr, "%s: channel must be 0 or 1\n", argv [0]) ; + exit (1) ; + } + + if (gertboardSPISetup () == -1) + { + fprintf (stderr, "Unable to initialise the Gertboard SPI interface: %s\n", strerror (errno)) ; + exit (1) ; + } + + printf ("%d\n",gertboardAnalogRead (channel)) ; +} + + + /* * doWrite: * gpio write pin value ********************************************************************************* */ -void doWrite (int argc, char *argv []) +static void doWrite (int argc, char *argv []) { int pin, val ; @@ -490,6 +687,39 @@ void doPwm (int argc, char *argv []) /* + * doPwmMode: doPwmRange: + * Change the PWM mode and Range values + ********************************************************************************* + */ + +static void doPwmMode (int mode) +{ + pwmSetMode (mode) ; +} + +static void doPwmRange (int argc, char *argv []) +{ + unsigned int range ; + + if (argc != 3) + { + fprintf (stderr, "Usage: %s pwmr \n", argv [0]) ; + exit (1) ; + } + + range = (unsigned int)strtoul (argv [2], NULL, 10) ; + + if (range == 0) + { + fprintf (stderr, "%s: range must be > 0\n", argv [0]) ; + exit (1) ; + } + + pwmSetRange (range) ; +} + + +/* * main: * Start here ********************************************************************************* @@ -505,10 +735,10 @@ int main (int argc, char *argv []) return 1 ; } - if (geteuid () != 0) + if (strcasecmp (argv [1], "-h") == 0) { - fprintf (stderr, "%s: Must be root to run\n", argv [0]) ; - return 1 ; + printf ("%s: %s\n", argv [0], usage) ; + return 0 ; } if (strcasecmp (argv [1], "-v") == 0) @@ -516,21 +746,54 @@ int main (int argc, char *argv []) printf ("gpio version: %s\n", VERSION) ; printf ("Copyright (c) 2012 Gordon Henderson\n") ; printf ("This is free software with ABSOLUTELY NO WARRANTY.\n") ; + printf ("For details type: %s -warranty\n", argv [0]) ; return 0 ; } + if (strcasecmp (argv [1], "-warranty") == 0) + { + printf ("gpio version: %s\n", VERSION) ; + printf ("Copyright (c) 2012 Gordon Henderson\n") ; + printf ("\n") ; + printf (" This program is free software; you can redistribute it and/or modify\n") ; + printf (" it under the terms of the GNU Leser General Public License as published\n") ; + printf (" by the Free Software Foundation, either version 3 of the License, or\n") ; + printf (" (at your option) any later version.\n") ; + printf ("\n") ; + printf (" This program is distributed in the hope that it will be useful,\n") ; + printf (" but WITHOUT ANY WARRANTY; without even the implied warranty of\n") ; + printf (" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n") ; + printf (" GNU Lesser General Public License for more details.\n") ; + printf ("\n") ; + printf (" You should have received a copy of the GNU Lesser General Public License\n") ; + printf (" along with this program. If not, see .\n") ; + printf ("\n") ; + return 0 ; + } + + if (geteuid () != 0) + { + fprintf (stderr, "%s: Must be root to run. Program should be suid root. This is an error.\n", argv [0]) ; + return 1 ; + } + // Initial test for /sys/class/gpio operations: - /**/ if (strcasecmp (argv [1], "exports" ) == 0) - { doExports () ; return 0 ; } - else if (strcasecmp (argv [1], "export" ) == 0) - { doExport (argc, argv) ; return 0 ; } - else if (strcasecmp (argv [1], "edge" ) == 0) - { doEdge (argc, argv) ; return 0 ; } - else if (strcasecmp (argv [1], "unexportall") == 0) - { doUnexportall (argc, argv) ; return 0 ; } - else if (strcasecmp (argv [1], "unexport") == 0) - { doUnexport (argc, argv) ; return 0 ; } + /**/ if (strcasecmp (argv [1], "exports" ) == 0) { doExports (argc, argv) ; return 0 ; } + else if (strcasecmp (argv [1], "export" ) == 0) { doExport (argc, argv) ; return 0 ; } + else if (strcasecmp (argv [1], "edge" ) == 0) { doEdge (argc, argv) ; return 0 ; } + else if (strcasecmp (argv [1], "unexportall") == 0) { doUnexportall (argc, argv) ; return 0 ; } + else if (strcasecmp (argv [1], "unexport" ) == 0) { doUnexport (argc, argv) ; return 0 ; } + +// Check for drive or load commands: + + if (strcasecmp (argv [1], "drive") == 0) { doPadDrive (argc, argv) ; return 0 ; } + if (strcasecmp (argv [1], "load" ) == 0) { doLoad (argc, argv) ; return 0 ; } + +// Gertboard commands + + if (strcasecmp (argv [1], "gbr" ) == 0) { doGbr (argc, argv) ; return 0 ; } + if (strcasecmp (argv [1], "gbw" ) == 0) { doGbw (argc, argv) ; return 0 ; } // Check for -g argument @@ -538,7 +801,7 @@ int main (int argc, char *argv []) { if (wiringPiSetupGpio () == -1) { - fprintf (stderr, "%s: Unable to initialise GPIO in GPIO mode.\n", argv [0]) ; + fprintf (stderr, "%s: Unable to initialise GPIO mode.\n", argv [0]) ; exit (1) ; } @@ -570,23 +833,30 @@ int main (int argc, char *argv []) { if (wiringPiSetup () == -1) { - fprintf (stderr, "%s: Unable to initialise GPIO in wiringPi mode\n", argv [0]) ; + fprintf (stderr, "%s: Unable to initialise wiringPi mode\n", argv [0]) ; exit (1) ; } wpMode = WPI_MODE_PINS ; } - /**/ if (strcasecmp (argv [1], "write" ) == 0) - doWrite (argc, argv) ; - else if (strcasecmp (argv [1], "read" ) == 0) - doRead (argc, argv) ; - else if (strcasecmp (argv [1], "mode" ) == 0) - doMode (argc, argv) ; - else if (strcasecmp (argv [1], "pwm" ) == 0) - doPwm (argc, argv) ; +// Check for PWM operations + + if (wpMode != WPI_MODE_PIFACE) + { + if (strcasecmp (argv [1], "pwm-bal") == 0) { doPwmMode (PWM_MODE_BAL) ; return 0 ; } + if (strcasecmp (argv [1], "pwm-ms") == 0) { doPwmMode (PWM_MODE_MS) ; return 0 ; } + if (strcasecmp (argv [1], "pwmr") == 0) { doPwmRange (argc, argv) ; return 0 ; } + } + +// Check for wiring commands + + /**/ 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) ; else { - fprintf (stderr, "%s: Unknown command: %s. (read/write/pwm/mode expected)\n", argv [0], argv [1]) ; + fprintf (stderr, "%s: Unknown command: %s.\n", argv [0], argv [1]) ; exit (1) ; } return 0 ; diff --git a/wiringPi/gertboard.c b/wiringPi/gertboard.c new file mode 100644 index 0000000..a8795d3 --- /dev/null +++ b/wiringPi/gertboard.c @@ -0,0 +1,122 @@ +/* + * gertboard.c: + * Access routines for the SPI devices on the Gertboard + * Copyright (c) 2012 Gordon Henderson + * + * The Gertboard has: + * + * An MCP3002 dual-channel A to D convertor connected + * to the SPI bus, selected by chip-select A, and: + * + * An MCP4802 dual-channel D to A convertor connected + * to the SPI bus, selected via chip-select B. + * + *********************************************************************** + * 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 . + *********************************************************************** + */ + + +#include +#include +#include +#include +#include + +#include "wiringPiSPI.h" + +#include "gertboard.h" + +// The A-D convertor won't run at more than 1MHz @ 3.3v + +#define SPI_ADC_SPEED 1000000 +#define SPI_DAC_SPEED 1000000 +#define SPI_A2D 0 +#define SPI_D2A 1 + + +/* + * gertboardAnalogWrite: + * Write an 8-bit data value to the MCP4802 Analog to digital + * convertor on the Gertboard. + ********************************************************************************* + */ + +void gertboardAnalogWrite (int chan, int value) +{ + uint8_t spiData [2] ; + uint8_t chanBits, dataBits ; + + if (chan == 0) + chanBits = 0x30 ; + else + chanBits = 0xB0 ; + + chanBits |= ((value >> 4) & 0x0F) ; + dataBits = ((value << 4) & 0xF0) ; + + spiData [0] = chanBits ; + spiData [1] = dataBits ; + + wiringPiSPIDataRW (SPI_D2A, spiData, 2) ; +} + + +/* + * gertboardAnalogRead: + * Return the analog value of the given channel (0/1). + * The A/D is a 10-bit device + ********************************************************************************* + */ + +int gertboardAnalogRead (int chan) +{ + uint8_t spiData [2] ; + + uint8_t chanBits ; + + if (chan == 0) + chanBits = 0b11010000 ; + else + chanBits = 0b11110000 ; + + spiData [0] = chanBits ; + spiData [1] = 0 ; + + wiringPiSPIDataRW (SPI_A2D, spiData, 2) ; + + return ((spiData [0] << 7) | (spiData [1] >> 1)) & 0x3FF ; +} + + +/* + * gertboardSPISetup: + * Initialise the SPI bus, etc. + ********************************************************************************* + */ + +int gertboardSPISetup (void) +{ + if (wiringPiSPISetup (SPI_A2D, SPI_ADC_SPEED) < 0) + return -1 ; + + if (wiringPiSPISetup (SPI_D2A, SPI_DAC_SPEED) < 0) + return -1 ; + + return 0 ; +} diff --git a/wiringPi/gertboard.h b/wiringPi/gertboard.h new file mode 100644 index 0000000..98fd1e7 --- /dev/null +++ b/wiringPi/gertboard.h @@ -0,0 +1,39 @@ +/* + * gertboard.h: + * Access routines for the SPI devices on the Gertboard + * Copyright (c) 2012 Gordon Henderson + * + * The Gertboard has an MCP4802 dual-channel D to A convertor + * connected to the SPI bus, selected via chip-select B. + * + *********************************************************************** + * 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void gertboardAnalogWrite (int chan, int value) ; +extern int gertboardAnalogRead (int chan) ; +extern int gertboardSPISetup (void) ; + +#ifdef __cplusplus +} +#endif diff --git a/wiringPi/lcd.h b/wiringPi/lcd.h index 094f5f5..d4c724c 100644 --- a/wiringPi/lcd.h +++ b/wiringPi/lcd.h @@ -33,5 +33,13 @@ extern void lcdPutchar (int fd, uint8_t data) ; extern void lcdPuts (int fd, char *string) ; extern void lcdPrintf (int fd, char *message, ...) ; +#ifdef __cplusplus +extern "C" { +#endif + extern int lcdInit (int rows, int cols, int bits, int rs, int strb, int d0, int d1, int d2, int d3, int d4, int d5, int d6, int d7) ; + +#ifdef __cplusplus +} +#endif diff --git a/wiringPi/piNes.c b/wiringPi/piNes.c new file mode 100644 index 0000000..a115050 --- /dev/null +++ b/wiringPi/piNes.c @@ -0,0 +1,113 @@ +/* + * piNes.c: + * Driver for the NES Joystick controller on the Raspberry Pi + * 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 . + *********************************************************************** + */ + +#include + +#include "piNes.h" + +#define MAX_NES_JOYSTICKS 8 + +#define NES_RIGHT 0x01 +#define NES_LEFT 0x02 +#define NES_DOWN 0x04 +#define NES_UP 0x08 +#define NES_START 0x10 +#define NES_SELECT 0x20 +#define NES_B 0x40 +#define NES_A 0x80 + + +#define PULSE_TIME 25 + +// Data to store the pins for each controller + +struct nesPinsStruct +{ + unsigned int cPin, dPin, lPin ; +} ; + +static struct nesPinsStruct nesPins [MAX_NES_JOYSTICKS] ; + +static int joysticks = 0 ; + + +/* + * setupNesJoystick: + * Create a new NES joystick interface, program the pins, etc. + ********************************************************************************* + */ + +int setupNesJoystick (int dPin, int cPin, int lPin) +{ + if (joysticks == MAX_NES_JOYSTICKS) + return -1 ; + + nesPins [joysticks].dPin = dPin ; + nesPins [joysticks].cPin = cPin ; + nesPins [joysticks].lPin = lPin ; + + digitalWrite (lPin, LOW) ; + digitalWrite (cPin, LOW) ; + + pinMode (lPin, OUTPUT) ; + pinMode (cPin, OUTPUT) ; + pinMode (dPin, INPUT) ; + + return joysticks++ ; +} + + +/* + * readNesJoystick: + * Do a single scan of the NES Joystick. + ********************************************************************************* + */ + +unsigned int readNesJoystick (int joystick) +{ + unsigned int value = 0 ; + int i ; + + struct nesPinsStruct *pins = &nesPins [joystick] ; + +// Toggle Latch - which presents the first bit + + digitalWrite (pins->lPin, HIGH) ; delayMicroseconds (PULSE_TIME) ; + digitalWrite (pins->lPin, LOW) ; delayMicroseconds (PULSE_TIME) ; + +// Read first bit + + value = digitalRead (pins->dPin) ; + +// Now get the next 7 bits with the clock + + for (i = 0 ; i < 7 ; ++i) + { + digitalWrite (pins->cPin, HIGH) ; delayMicroseconds (PULSE_TIME) ; + digitalWrite (pins->cPin, LOW) ; delayMicroseconds (PULSE_TIME) ; + value = (value << 1) | digitalRead (pins->dPin) ; + } + + return value ^ 0xFF ; +} diff --git a/wiringPi/piNes.h b/wiringPi/piNes.h new file mode 100644 index 0000000..897f181 --- /dev/null +++ b/wiringPi/piNes.h @@ -0,0 +1,45 @@ +/* + * piNes.h: + * Driver for the NES Joystick controller on the Raspberry Pi + * 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 . + *********************************************************************** + */ + +#define MAX_NES_JOYSTICKS 8 + +#define NES_RIGHT 0x01 +#define NES_LEFT 0x02 +#define NES_DOWN 0x04 +#define NES_UP 0x08 +#define NES_START 0x10 +#define NES_SELECT 0x20 +#define NES_B 0x40 +#define NES_A 0x80 + +#ifdef __cplusplus +extern "C" { +#endif + +extern int setupNesJoystick (int dPin, int cPin, int lPin) ; +extern unsigned int readNesJoystick (int joystick) ; + +#ifdef __cplusplus +} +#endif diff --git a/wiringPi/softPwm.c b/wiringPi/softPwm.c new file mode 100644 index 0000000..b568dfb --- /dev/null +++ b/wiringPi/softPwm.c @@ -0,0 +1,130 @@ +/* + * softPwm.c: + * Provide 2 channels of software driven PWM. + * 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 . + *********************************************************************** + */ + +#include +#include + +#include "wiringPi.h" +#include "softPwm.h" + +#define MAX_PINS 64 + +// The PWM Frequency is derived from the "pulse time" below. Essentially, +// the frequency is a function of the range and this pulse time. +// The total period will be range * pulse time in uS, so a pulse time +// of 100 and a range of 100 gives a period of 100 * 100 = 10,000 uS +// which is a frequency of 100Hz. +// +// It's possible to get a higher frequency by lowering the pulse time, +// however CPU uage will skyrocket as wiringPi uses a hard-loop to time +// periods under 100uS - this is because the Linux timer calls are just +// accurate at all, and have an overhead. +// +// Another way to increase the frequency is to reduce the range - however +// that reduces the overall output accuracy... + +#define PULSE_TIME 100 + +static int marks [MAX_PINS] ; +static int range [MAX_PINS] ; + +int newPin = -1 ; + + +/* + * softPwmThread: + * Thread to do the actual PWM output + ********************************************************************************* + */ + +static PI_THREAD (softPwmThread) +{ + int pin, mark, space ; + + pin = newPin ; + newPin = -1 ; + + piHiPri (50) ; + + for (;;) + { + mark = marks [pin] ; + space = range [pin] - mark ; + + if (mark != 0) + digitalWrite (pin, HIGH) ; + delayMicroseconds (mark * 100) ; + + if (space != 0) + digitalWrite (pin, LOW) ; + delayMicroseconds (space * 100) ; + } + + return NULL ; +} + + +/* + * softPwmWrite: + * Write a PWM value to the given pin + ********************************************************************************* + */ + +void softPwmWrite (int pin, int value) +{ + pin &= 63 ; + + /**/ if (value < 0) + value = 0 ; + else if (value > range [pin]) + value = range [pin] ; + + marks [pin] = value ; +} + + +/* + * softPwmCreate: + * Create a new PWM thread. + ********************************************************************************* + */ + +int softPwmCreate (int pin, int initialValue, int pwmRange) +{ + int res ; + + pinMode (pin, OUTPUT) ; + digitalWrite (pin, LOW) ; + + marks [pin] = initialValue ; + range [pin] = pwmRange ; + + newPin = pin ; + res = piThreadCreate (softPwmThread) ; + + while (newPin != -1) + delay (1) ; + + return res ; +} diff --git a/wiringPi/softPwm.h b/wiringPi/softPwm.h new file mode 100644 index 0000000..28ad299 --- /dev/null +++ b/wiringPi/softPwm.h @@ -0,0 +1,34 @@ +/* + * softPwm.h: + * Provide 2 channels of software driven PWM. + * 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int softPwmCreate (int pin, int value, int range) ; +extern void softPwmWrite (int pin, int value) ; + +#ifdef __cplusplus +} +#endif diff --git a/wiringPi/wiringPi.c b/wiringPi/wiringPi.c index d99c863..39c34da 100644 --- a/wiringPi/wiringPi.c +++ b/wiringPi/wiringPi.c @@ -71,12 +71,16 @@ // Function stubs -void (*pinMode) (int pin, int mode) ; -void (*pullUpDnControl) (int pin, int pud) ; -void (*digitalWrite) (int pin, int value) ; -void (*pwmWrite) (int pin, int value) ; -int (*digitalRead) (int pin) ; -int (*waitForInterrupt) (int pin, int mS) ; +void (*pinMode) (int pin, int mode) ; +void (*pullUpDnControl) (int pin, int pud) ; +void (*digitalWrite) (int pin, int value) ; +void (*pwmWrite) (int pin, int value) ; +void (*setPadDrive) (int group, int value) ; +int (*digitalRead) (int pin) ; +int (*waitForInterrupt) (int pin, int mS) ; +void (*delayMicroseconds) (unsigned int howLong) ; +void (*pwmSetMode) (int mode) ; +void (*pwmSetRange) (unsigned int range) ; #ifndef TRUE @@ -84,6 +88,11 @@ int (*waitForInterrupt) (int pin, int mS) ; #define FALSE (1==2) #endif +// BCM Magic + +#define BCM_PASSWORD 0x5A000000 + + // Port function select bits #define FSEL_INPT 0b000 @@ -100,10 +109,11 @@ int (*waitForInterrupt) (int pin, int mS) ; // Take from Gert/Doms code. Some of this is not in the manual // that I can find )-: -#define BCM2708_PERI_BASE 0x20000000 +#define BCM2708_PERI_BASE 0x20000000 #define GPIO_PADS (BCM2708_PERI_BASE + 0x100000) #define CLOCK_BASE (BCM2708_PERI_BASE + 0x101000) #define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) +#define GPIO_TIMER (BCM2708_PERI_BASE + 0x00B000) #define GPIO_PWM (BCM2708_PERI_BASE + 0x20C000) #define PAGE_SIZE (4*1024) @@ -137,12 +147,27 @@ int (*waitForInterrupt) (int pin, int mS) ; #define PWM0_SERIAL 0x0002 // Run in serial mode #define PWM0_ENABLE 0x0001 // Channel Enable +// Timer + +#define TIMER_LOAD (0x400 >> 2) +#define TIMER_VALUE (0x404 >> 2) +#define TIMER_CONTROL (0x408 >> 2) +#define TIMER_IRQ_CLR (0x40C >> 2) +#define TIMER_IRQ_RAW (0x410 >> 2) +#define TIMER_IRQ_MASK (0x414 >> 2) +#define TIMER_RELOAD (0x418 >> 2) +#define TIMER_PRE_DIV (0x41C >> 2) +#define TIMER_COUNTER (0x420 >> 2) // Locals to hold pointers to the hardware static volatile uint32_t *gpio ; static volatile uint32_t *pwm ; static volatile uint32_t *clk ; +static volatile uint32_t *pads ; +static volatile uint32_t *timer ; + +static volatile uint32_t *timerIrqRaw ; // The BCM2835 has 54 GPIO pins. // BCM2835 data sheet, Page 90 onwards. @@ -273,6 +298,8 @@ static uint8_t gpioToFEN [] = // gpioToPUDCLK // (Word) offset to the Pull Up Down Clock regsiter +#define GPPUD 37 + static uint8_t gpioToPUDCLK [] = { 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38, @@ -352,30 +379,42 @@ void pinModeGpio (int pin, int mode) if (!pwmRunning) { -// Gert/Doms Values - *(clk + PWMCLK_DIV) = 0x5A000000 | (32<<12) ; // set pwm div to 32 (19.2/3 = 600KHz) - *(clk + PWMCLK_CNTL) = 0x5A000011 ; // Source=osc and enable - digitalWrite (pin, LOW) ; - *(pwm + PWM_CONTROL) = 0 ; // Disable PWM + *(pwm + PWM_CONTROL) = 0 ; // Stop PWM delayMicroseconds (10) ; - *(pwm + PWM0_RANGE) = 0x400 ; - delayMicroseconds (10) ; - *(pwm + PWM1_RANGE) = 0x400 ; + +// Gert/Doms Values + *(clk + PWMCLK_DIV) = BCM_PASSWORD | (32<<12) ; // set pwm div to 32 (19.2/32 = 600KHz) + *(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x11 ; // Source=osc and enable + delayMicroseconds (10) ; + *(pwm + PWM0_RANGE) = 0x400 ; delayMicroseconds (10) ; + *(pwm + PWM1_RANGE) = 0x400 ; delayMicroseconds (10) ; + // Enable PWMs *(pwm + PWM0_DATA) = 512 ; *(pwm + PWM1_DATA) = 512 ; +// Balanced mode (default) + *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ; + + pwmRunning = TRUE ; } } // 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 +// not quite gotten to the bottom of why this happens +// The down-side is that the pull up/downs are rememberd in the SoC between +// power cycles, so it's going to be a good idea to explicitly set them in +// any new code. +// +// pullUpDnControl (pin, PUD_OFF) ; - pullUpDnControl (pin, PUD_OFF) ; } void pinModeWPi (int pin, int mode) @@ -389,6 +428,38 @@ void pinModeSys (int pin, int mode) } +/* + * pwmControl: + * Allow the user to control some of the PWM functions + ********************************************************************************* + */ + +void pwmSetModeWPi (int mode) +{ + if (mode == PWM_MODE_MS) + *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE | PWM0_MS_MODE | PWM1_MS_MODE ; + else + *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ; +} + +void pwmSetModeSys (int mode) +{ + return ; +} + + +void pwmSetRangeWPi (unsigned int range) +{ + *(pwm + PWM0_RANGE) = range ; delayMicroseconds (10) ; + *(pwm + PWM1_RANGE) = range ; delayMicroseconds (10) ; +} + +void pwmSetRangeSys (unsigned int range) +{ + return ; +} + + #ifdef notYetReady /* * pinED01: @@ -414,12 +485,12 @@ void pinEnableED01Pi (int pin) void digitalWriteWPi (int pin, int value) { - int gpioPin = pinToGpio [pin & 63] ; + pin = pinToGpio [pin & 63] ; if (value == LOW) - *(gpio + gpioToGPCLR [gpioPin]) = 1 << gpioPin ; + *(gpio + gpioToGPCLR [pin]) = 1 << (pin & 31) ; else - *(gpio + gpioToGPSET [gpioPin]) = 1 << gpioPin ; + *(gpio + gpioToGPSET [pin]) = 1 << (pin & 31) ; } void digitalWriteGpio (int pin, int value) @@ -427,9 +498,9 @@ void digitalWriteGpio (int pin, int value) pin &= 63 ; if (value == LOW) - *(gpio + gpioToGPCLR [pin]) = 1 << pin ; + *(gpio + gpioToGPCLR [pin]) = 1 << (pin & 31) ; else - *(gpio + gpioToGPSET [pin]) = 1 << pin ; + *(gpio + gpioToGPSET [pin]) = 1 << (pin & 31) ; } void digitalWriteSys (int pin, int value) @@ -452,28 +523,55 @@ void digitalWriteSys (int pin, int value) ********************************************************************************* */ -void pwmWriteWPi (int pin, int value) +void pwmWriteGpio (int pin, int value) { - int port, gpioPin ; + int port ; - gpioPin = pinToGpio [pin & 63] ; - port = gpioToPwmPort [gpioPin] ; + pin = pin & 63 ; + port = gpioToPwmPort [pin] ; - *(pwm + port) = value & 0x3FF ; + *(pwm + port) = value ; } -void pwmWriteGpio (int pin, int value) +void pwmWriteWPi (int pin, int value) +{ + pwmWriteGpio (pinToGpio [pin & 63], value) ; +} + +void pwmWriteSys (int pin, int value) +{ + return ; +} + + +/* + * setPadDrive: + * Set the PAD driver value + ********************************************************************************* + */ + +void setPadDriveWPi (int group, int value) { - int port, gpioPin ; + uint32_t wrVal ; - gpioPin = pin & 63 ; - port = gpioToPwmPort [gpioPin] ; + if ((group < 0) || (group > 2)) + return ; - *(pwm + port) = value & 0x3FF ; + wrVal = BCM_PASSWORD | 0x18 | (value & 7) ; + *(pads + group + 11) = wrVal ; + +#ifdef DEBUG_PADS + printf ("setPadDrive: Group: %d, value: %d (%08X)\n", group, value, wrVal) ; + printf ("Read : %08X\n", *(pads + group + 11)) ; +#endif } +void setPadDriveGpio (int group, int value) +{ + setPadDriveWPi (group, value) ; +} -void pwmWriteSys (int pin, int value) +void setPadDriveSys (int group, int value) { return ; } @@ -487,13 +585,9 @@ void pwmWriteSys (int pin, int value) int digitalReadWPi (int pin) { - int gpioPin ; - - pin &= 63 ; - - gpioPin = pinToGpio [pin] ; + pin = pinToGpio [pin & 63] ; - if ((*(gpio + gpioToGPLEV [gpioPin]) & (1 << gpioPin)) != 0) + if ((*(gpio + gpioToGPLEV [pin]) & (1 << (pin & 31))) != 0) return HIGH ; else return LOW ; @@ -503,7 +597,7 @@ int digitalReadGpio (int pin) { pin &= 63 ; - if ((*(gpio + gpioToGPLEV [pin]) & (1 << pin)) != 0) + if ((*(gpio + gpioToGPLEV [pin]) & (1 << (pin & 31))) != 0) return HIGH ; else return LOW ; @@ -533,30 +627,21 @@ int digitalReadSys (int pin) ********************************************************************************* */ -void pullUpDnControlWPi (int pin, int pud) +void pullUpDnControlGpio (int pin, int pud) { - pin = pinToGpio [pin & 63] ; + pin &= 63 ; + pud &= 3 ; - *(gpio + 37) = pud ; - delayMicroseconds (10) ; - *(gpio + gpioToPUDCLK [pin]) = 1 << pin ; - delayMicroseconds (10) ; + *(gpio + GPPUD) = pud ; delayMicroseconds (5) ; + *(gpio + gpioToPUDCLK [pin]) = 1 << (pin & 31) ; delayMicroseconds (5) ; - *(gpio + 37) = 0 ; - *(gpio + gpioToPUDCLK [pin]) = 0 ; + *(gpio + GPPUD) = 0 ; delayMicroseconds (5) ; + *(gpio + gpioToPUDCLK [pin]) = 0 ; delayMicroseconds (5) ; } -void pullUpDnControlGpio (int pin, int pud) +void pullUpDnControlWPi (int pin, int pud) { - pin &= 63 ; - - *(gpio + 37) = pud ; - delayMicroseconds (10) ; - *(gpio + gpioToPUDCLK [pin]) = 1 << pin ; - delayMicroseconds (10) ; - - *(gpio + 37) = 0 ; - *(gpio + gpioToPUDCLK [pin]) = 0 ; + pullUpDnControlGpio (pinToGpio [pin & 63], pud) ; } void pullUpDnControlSys (int pin, int pud) @@ -615,6 +700,94 @@ int waitForInterruptGpio (int pin, int mS) + +/* + * delay: + * Wait for some number of milli seconds + ********************************************************************************* + */ + +void delay (unsigned int howLong) +{ + struct timespec sleeper, dummy ; + + sleeper.tv_sec = (time_t)(howLong / 1000) ; + sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ; + + nanosleep (&sleeper, &dummy) ; +} + + +/* + * delayMicroseconds: + * This is somewhat intersting. It seems that on the Pi, a single call + * to nanosleep takes some 80 to 130 microseconds anyway, so while + * obeying the standards (may take longer), it's not always what we + * want! + * + * So what I'll do now is if the delay is less than 100uS we'll do it + * in a hard loop, watching a built-in counter on the ARM chip. This is + * 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 )-: + ********************************************************************************* + */ + +void delayMicrosecondsSys (unsigned int howLong) +{ + struct timespec sleeper, dummy ; + + sleeper.tv_sec = 0 ; + sleeper.tv_nsec = (long)(howLong * 1000) ; + + nanosleep (&sleeper, &dummy) ; +} + +void delayMicrosecondsHard (unsigned int howLong) +{ + *(timer + TIMER_LOAD) = howLong ; + *(timer + TIMER_IRQ_CLR) = 0 ; + + while (*timerIrqRaw == 0) + ; +} + +void delayMicrosecondsWPi (unsigned int howLong) +{ + struct timespec sleeper, dummy ; + + /**/ if (howLong == 0) + return ; + else if (howLong < 100) + delayMicrosecondsHard (howLong) ; + else + { + sleeper.tv_sec = 0 ; + sleeper.tv_nsec = (long)(howLong * 1000) ; + nanosleep (&sleeper, &dummy) ; + } +} + + +/* + * millis: + * Return a number of milliseconds as an unsigned int. + ********************************************************************************* + */ + +unsigned int millis (void) +{ + struct timeval tv ; + unsigned long long t1 ; + + gettimeofday (&tv, NULL) ; + + t1 = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ; + + return (uint32_t)(t1 - epoch) ; +} + + /* * wiringPiSetup: * Must be called once at the start of your program execution. @@ -627,20 +800,19 @@ int waitForInterruptGpio (int pin, int mS) int wiringPiSetup (void) { int fd ; - uint8_t *gpioMem, *pwmMem, *clkMem ; + uint8_t *gpioMem, *pwmMem, *clkMem, *padsMem, *timerMem ; struct timeval tv ; -#ifdef DEBUG_PADS - uint8_t *gpioMem, *padsMem, *pwmMem, *clkMem ; - uint32_t *pads ; -#endif - - pinMode = pinModeWPi ; - pullUpDnControl = pullUpDnControlWPi ; - digitalWrite = digitalWriteWPi ; - pwmWrite = pwmWriteWPi ; - digitalRead = digitalReadWPi ; - waitForInterrupt = waitForInterruptWPi ; + pinMode = pinModeWPi ; + pullUpDnControl = pullUpDnControlWPi ; + digitalWrite = digitalWriteWPi ; + pwmWrite = pwmWriteWPi ; + setPadDrive = setPadDriveWPi ; + digitalRead = digitalReadWPi ; + waitForInterrupt = waitForInterruptWPi ; + delayMicroseconds = delayMicrosecondsWPi ; + pwmSetMode = pwmSetModeWPi ; + pwmSetRange = pwmSetRangeWPi ; // Open the master /dev/memory device @@ -711,7 +883,8 @@ int wiringPiSetup (void) return -1 ; } -#ifdef DEBUG_PADS +// The drive pads + if ((padsMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) { fprintf (stderr, "wiringPiSetup: padsMem malloc failed: %s\n", strerror (errno)) ; @@ -728,14 +901,41 @@ int wiringPiSetup (void) fprintf (stderr, "wiringPiSetup: mmap failed (pads): %s\n", strerror (errno)) ; return -1 ; } - - printf ("Checking pads @ 0x%08X\n", (unsigned int)pads) ; - printf ("%08X %08X %08X\n", *(pads + 11), *(pads + 12), *(pads + 13)) ; -// *(pads + 11) = 0x1F ; - printf ("%08X %08X %08X\n", *(pads + 11), *(pads + 12), *(pads + 13)) ; +#ifdef DEBUG_PADS + printf ("Checking pads @ 0x%08X\n", (unsigned int)pads) ; + printf (" -> %08X %08X %08X\n", *(pads + 11), *(pads + 12), *(pads + 13)) ; #endif +// The system timer + + if ((timerMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) + { + fprintf (stderr, "wiringPiSetup: timerMem malloc failed: %s\n", strerror (errno)) ; + return -1 ; + } + + if (((uint32_t)timerMem % PAGE_SIZE) != 0) + timerMem += PAGE_SIZE - ((uint32_t)timerMem % PAGE_SIZE) ; + + timer = (uint32_t *)mmap(timerMem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, GPIO_TIMER) ; + + if ((int32_t)timer < 0) + { + fprintf (stderr, "wiringPiSetup: mmap failed (timer): %s\n", strerror (errno)) ; + return -1 ; + } + +// Set the timer to free-running, 1MHz. +// 0xF9 is 249, the timer divide is base clock / (divide+1) +// so base clock is 250MHz / 250 = 1MHz. + + *(timer + TIMER_CONTROL) = 0x0000280 ; + *(timer + TIMER_PRE_DIV) = 0x00000F9 ; + timerIrqRaw = timer + TIMER_IRQ_RAW ; + +// Initialise our epoch for millis() + gettimeofday (&tv, NULL) ; epoch = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ; @@ -759,12 +959,16 @@ int wiringPiSetupGpio (void) if (x != 0) return x ; - pinMode = pinModeGpio ; - pullUpDnControl = pullUpDnControlGpio ; - digitalWrite = digitalWriteGpio ; - pwmWrite = pwmWriteGpio ; - digitalRead = digitalReadGpio ; - waitForInterrupt = waitForInterruptGpio ; + pinMode = pinModeGpio ; + pullUpDnControl = pullUpDnControlGpio ; + digitalWrite = digitalWriteGpio ; + pwmWrite = pwmWriteGpio ; + setPadDrive = setPadDriveGpio ; + digitalRead = digitalReadGpio ; + waitForInterrupt = waitForInterruptGpio ; + delayMicroseconds = delayMicrosecondsWPi ; // Same + pwmSetMode = pwmSetModeWPi ; + pwmSetRange = pwmSetRangeWPi ; return 0 ; } @@ -785,12 +989,17 @@ int wiringPiSetupSys (void) struct timeval tv ; char fName [128] ; - pinMode = pinModeSys ; - pullUpDnControl = pullUpDnControlSys ; - digitalWrite = digitalWriteSys ; - pwmWrite = pwmWriteSys ; - digitalRead = digitalReadSys ; - waitForInterrupt = waitForInterruptSys ; + pinMode = pinModeSys ; + pullUpDnControl = pullUpDnControlSys ; + digitalWrite = digitalWriteSys ; + pwmWrite = pwmWriteSys ; + setPadDrive = setPadDriveSys ; + digitalRead = digitalReadSys ; + waitForInterrupt = waitForInterruptSys ; + delayMicroseconds = delayMicrosecondsSys ; + pwmSetMode = pwmSetModeSys ; + pwmSetRange = pwmSetRangeSys ; + // Open and scan the directory, looking for exported GPIOs, and pre-open // the 'value' interface to speed things up for later @@ -808,51 +1017,3 @@ int wiringPiSetupSys (void) return 0 ; } - - - - - -/* - * delay: delayMicroseconds - * Wait for some number of milli/micro seconds - ********************************************************************************* - */ - -void delay (unsigned int howLong) -{ - struct timespec sleeper, dummy ; - - sleeper.tv_sec = (time_t)(howLong / 1000) ; - sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ; - - nanosleep (&sleeper, &dummy) ; -} - -void delayMicroseconds (unsigned int howLong) -{ - struct timespec sleeper, dummy ; - - sleeper.tv_sec = 0 ; - sleeper.tv_nsec = (long)(howLong * 1000) ; - - nanosleep (&sleeper, &dummy) ; -} - -/* - * millis: - * Return a number of milliseconds as an unsigned int. - ********************************************************************************* - */ - -unsigned int millis (void) -{ - struct timeval tv ; - unsigned long long t1 ; - - gettimeofday (&tv, NULL) ; - - t1 = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ; - - return (uint32_t)(t1 - epoch) ; -} diff --git a/wiringPi/wiringPi.h b/wiringPi/wiringPi.h index a81511a..1d21fa0 100644 --- a/wiringPi/wiringPi.h +++ b/wiringPi/wiringPi.h @@ -41,6 +41,12 @@ #define PUD_DOWN 1 #define PUD_UP 2 +// PWM + +#define PWM_MODE_MS 0 +#define PWM_MODE_BAL 1 + + // Function prototypes // c++ wrappers thanks to a commend by Nick Lott // (and others on the Raspberry Pi forums) @@ -58,11 +64,15 @@ extern int wiringPiSetupPiFace (void) ; extern int wiringPiSetupPiFaceForGpioProg (void) ; // Don't use this - for gpio program only -extern void (*pinMode) (int pin, int mode) ; -extern void (*pullUpDnControl) (int pin, int pud) ; -extern void (*digitalWrite) (int pin, int value) ; -extern void (*pwmWrite) (int pin, int value) ; -extern int (*digitalRead) (int pin) ; +extern void (*pinMode) (int pin, int mode) ; +extern void (*pullUpDnControl) (int pin, int pud) ; +extern void (*digitalWrite) (int pin, int value) ; +extern void (*pwmWrite) (int pin, int value) ; +extern void (*setPadDrive) (int group, int value) ; +extern int (*digitalRead) (int pin) ; +extern void (*delayMicroseconds) (unsigned int howLong) ; +extern void (*pwmSetMode) (int mode) ; +extern void (*pwmSetRange) (unsigned int range) ; // Interrupts @@ -84,7 +94,6 @@ extern int piHiPri (int pri) ; // Extras from arduino land extern void delay (unsigned int howLong) ; -extern void delayMicroseconds (unsigned int howLong) ; extern unsigned int millis (void) ; #ifdef __cplusplus diff --git a/wiringPi/wiringPiSPI.c b/wiringPi/wiringPiSPI.c new file mode 100644 index 0000000..f2e3000 --- /dev/null +++ b/wiringPi/wiringPiSPI.c @@ -0,0 +1,117 @@ +/* + * wiringPiSPI.c: + * Simplified SPI access routines + * 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 . + *********************************************************************** + */ + + +#include +#include +#include +#include + +#include "wiringPiSPI.h" + + +// The SPI bus parameters +// Variables as they need to be passed as pointers later on + +static char *spiDev0 = "/dev/spidev0.0" ; +static char *spiDev1 = "/dev/spidev0.1" ; +static uint8_t spiMode = 0 ; +static uint8_t spiBPW = 8 ; +static uint16_t spiDelay = 0; + +static uint32_t spiSpeeds [2] ; +static int spiFds [2] ; + + +/* + * wiringPiSPIGetFd: + * Return the file-descriptor for the given channel + ********************************************************************************* + */ + +int wiringPiSPIGetFd (int channel) +{ + return spiFds [channel &1] ; +} + + +/* + * wiringPiSPIDataRW: + * Write and Read a block of data over the SPI bus. + * Note the data ia being read into the transmit buffer, so will + * overwrite it! + * This is also a full-duplex operation. + ********************************************************************************* + */ + +int wiringPiSPIDataRW (int channel, unsigned char *data, int len) +{ + struct spi_ioc_transfer spi ; + + channel &= 1 ; + + spi.tx_buf = (unsigned long)data ; + spi.rx_buf = (unsigned long)data ; + spi.len = len ; + spi.delay_usecs = spiDelay ; + spi.speed_hz = spiSpeeds [channel] ; + spi.bits_per_word = spiBPW ; + + return ioctl (spiFds [channel], SPI_IOC_MESSAGE(1), &spi) ; +} + + +/* + * wiringPiSPISetup: + * Open the SPI device, and set it up, etc. + ********************************************************************************* + */ + +int wiringPiSPISetup (int channel, int speed) +{ + int fd ; + + channel &= 1 ; + + if ((fd = open (channel == 0 ? spiDev0 : spiDev1, O_RDWR)) < 0) + return -1 ; + + spiSpeeds [channel] = speed ; + spiFds [channel] = fd ; + +// Set SPI parameters. +// Why are we reading it afterwriting it? I've no idea, but for now I'm blindly +// copying example code I've seen online... + + if (ioctl (fd, SPI_IOC_WR_MODE, &spiMode) < 0) return -1 ; + if (ioctl (fd, SPI_IOC_RD_MODE, &spiMode) < 0) return -1 ; + + if (ioctl (fd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0) return -1 ; + if (ioctl (fd, SPI_IOC_RD_BITS_PER_WORD, &spiBPW) < 0) return -1 ; + + if (ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) return -1 ; + if (ioctl (fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) return -1 ; + + return fd ; +} diff --git a/wiringPi/wiringPiSPI.h b/wiringPi/wiringPiSPI.h new file mode 100644 index 0000000..f53697d --- /dev/null +++ b/wiringPi/wiringPiSPI.h @@ -0,0 +1,35 @@ +/* + * wiringPiSPI.h: + * Simplified SPI access routines + * 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +int wiringPiSPIGetFd (int channel) ; +int wiringPiSPIDataRW (int channel, unsigned char *data, int len) ; +int wiringPiSPISetup (int channel, int speed) ; + +#ifdef __cplusplus +} +#endif diff --git a/wiringPi/wiringSerial.c b/wiringPi/wiringSerial.c index c3dae67..28ec598 100644 --- a/wiringPi/wiringSerial.c +++ b/wiringPi/wiringSerial.c @@ -20,8 +20,6 @@ *********************************************************************** */ -#undef DEBUG - #include #include #include @@ -49,10 +47,6 @@ int serialOpen (char *device, int baud) speed_t myBaud ; int status, fd ; -#ifdef DEBUG - printf ("openSerialPort: <%s> baud: $d\n", device, baud) ; -#endif - switch (baud) { case 50: myBaud = B50 ; break ; @@ -86,22 +80,22 @@ int serialOpen (char *device, int baud) tcgetattr (fd, &options) ; - cfmakeraw (&options) ; - cfsetispeed (&options, myBaud) ; - cfsetospeed (&options, myBaud) ; + cfmakeraw (&options) ; + cfsetispeed (&options, myBaud) ; + cfsetospeed (&options, myBaud) ; - options.c_cflag |= (CLOCAL | CREAD) ; - options.c_cflag &= ~PARENB ; - options.c_cflag &= ~CSTOPB ; - options.c_cflag &= ~CSIZE ; - options.c_cflag |= CS8 ; - options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ; - options.c_oflag &= ~OPOST ; + options.c_cflag |= (CLOCAL | CREAD) ; + options.c_cflag &= ~PARENB ; + options.c_cflag &= ~CSTOPB ; + options.c_cflag &= ~CSIZE ; + options.c_cflag |= CS8 ; + options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ; + options.c_oflag &= ~OPOST ; - options.c_cc [VMIN] = 0 ; - options.c_cc [VTIME] = 100 ; // Ten seconds (100 deciseconds) + options.c_cc [VMIN] = 0 ; + options.c_cc [VTIME] = 100 ; // Ten seconds (100 deciseconds) - tcsetattr (fd, TCSANOW, &options) ; + tcsetattr (fd, TCSANOW | TCSAFLUSH, &options) ; ioctl (fd, TIOCMGET, &status); @@ -117,6 +111,18 @@ int serialOpen (char *device, int baud) /* + * serialFlush: + * Flush the serial buffers (both tx & rx) + ********************************************************************************* + */ + +void serialFlush (int fd) +{ + tcflush (fd, TCIOFLUSH) ; +} + + +/* * serialClose: * Release the serial port ********************************************************************************* diff --git a/wiringPi/wiringSerial.h b/wiringPi/wiringSerial.h index 609838d..1a4198c 100644 --- a/wiringPi/wiringSerial.h +++ b/wiringPi/wiringSerial.h @@ -26,6 +26,7 @@ extern "C" { extern int serialOpen (char *device, int baud) ; extern void serialClose (int fd) ; +extern void serialFlush (int fd) ; extern void serialPutchar (int fd, unsigned char c) ; extern void serialPuts (int fd, char *s) ; extern void serialPrintf (int fd, char *message, ...) ;