Browse Source

Added new SPI driver helpers.
Changed the gertboard code to use it
and ran more tests on he Gertboard code.

Gordon Henderson 11 years ago
parent
commit
99095e3fa0
7 changed files with 330 additions and 99 deletions
  1. 37 7
      examples/gertboard.c
  2. 28 4
      gpio/gpio.1
  3. 90 4
      gpio/gpio.c
  4. 3 2
      wiringPi/Makefile
  5. 20 82
      wiringPi/gertboard.c
  6. 117 0
      wiringPi/wiringPiSPI.c
  7. 35 0
      wiringPi/wiringPiSPI.h

+ 37 - 7
examples/gertboard.c

@@ -14,33 +14,63 @@
 
 #include <stdio.h>
 #include <stdint.h>
-//#include <stdlib.h>
 #include <math.h>
 
+#define	B_SIZE	200
+#undef	DO_TIMING
+
 #include <wiringPi.h>
 #include <gertboard.h>
 
 int main (void)
 {
-  int    angle ;
-  int      h1 ;
+  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 (gertboardSPISetup () == -1)
+  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 (;;)
   {
-    for (angle = 0 ; angle < 360 ; ++angle)
+#ifdef	DO_TIMING
+    then = millis () ;
+#endif
+
+    for (i = 0 ; i < B_SIZE ; ++i)
     {
-      h1 = (int)rint (sin ((double)angle * M_PI / 180.0) * 127.0 + 128.0) ;
-      gertboardAnalogWrite (0, h1) ;
+      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 ;

+ 28 - 4
gpio/gpio.1

@@ -36,14 +36,23 @@ 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
@@ -142,6 +151,21 @@ Change the PWM range register. The default is 1024.
 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"
 

+ 90 - 4
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 <wiringPi.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -32,12 +32,15 @@
 #include <sys/types.h>
 #include <fcntl.h>
 
+#include <wiringPi.h>
+#include <gertboard.h>
+
 #ifndef TRUE
 #  define	TRUE	(1==1)
 #  define	FALSE	(1==2)
 #endif
 
-#define	VERSION	"1.1"
+#define	VERSION	"1.2"
 
 static int wpMode ;
 
@@ -49,7 +52,9 @@ char *usage = "Usage: gpio -v\n"
 	      "       gpio drive <group> <value>\n"
 	      "       gpio pwm-bal/pwm-ms \n"
 	      "       gpio pwmr <range> \n"
-	      "       gpio load spi/i2c" ;
+	      "       gpio load spi/i2c\n"
+	      "       gpio gbr <channel>\n"
+	      "       gpio gbw <channel> <value>\n" ;
 
 
 /*
@@ -518,6 +523,82 @@ static void doPadDrive (int argc, char *argv [])
 }
 
 
+/*
+ * doGbw:
+ *	gpio gbw channel value
+ *********************************************************************************
+ */
+
+static void doGbw (int argc, char *argv [])
+{
+  int channel, value ;
+
+  if (argc != 4)
+  {
+    fprintf (stderr, "Usage: %s gbr <channel> <value>\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 <channel>\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
@@ -709,6 +790,11 @@ int main (int argc, char *argv [])
   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
 
   if (strcasecmp (argv [1], "-g") == 0)

+ 3 - 2
wiringPi/Makefile

@@ -38,12 +38,12 @@ LIBS    =
 SRC	=	wiringPi.c wiringPiFace.c wiringSerial.c wiringShift.c	\
 		gertboard.c						\
 		piNes.c							\
-		lcd.c piHiPri.c piThread.c softPwm.c
+		lcd.c piHiPri.c piThread.c softPwm.c wiringPiSPI.c
 
 OBJ	=	wiringPi.o wiringPiFace.o wiringSerial.o wiringShift.o	\
 		gertboard.o						\
 		piNes.o							\
-		lcd.o piHiPri.o piThread.o softPwm.o
+		lcd.o piHiPri.o piThread.o softPwm.o wiringPiSPI.o
 
 all:		$(TARGET)
 
@@ -78,6 +78,7 @@ install:	$(TARGET)
 	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
 
 uninstall:

+ 20 - 82
wiringPi/gertboard.c

@@ -38,23 +38,16 @@
 #include <sys/ioctl.h>
 #include <linux/spi/spidev.h>
 
-#include "gertboard.h"
-
+#include "wiringPiSPI.h"
 
-// The SPI bus parameters
-//	Variables as they need to be passed as pointers later on
-
-static char       *spiA2D = "/dev/spidev0.0" ;
-static char       *spiD2A = "/dev/spidev0.1" ;
-static uint8_t     spiMode   = 0 ;
-static uint8_t     spiBPW    = 8 ;
-static uint32_t    spiSpeed  = 100000 ;	// 1MHz
-static uint16_t    spiDelay  = 0;
+#include "gertboard.h"
 
-// Locals here to keep track of everything
+// The A-D convertor won't run at more than 1MHz @ 3.3v
 
-static int spiFdA2D ;
-static int spiFdD2A ;
+#define	SPI_ADC_SPEED	 1000000
+#define	SPI_DAC_SPEED	 1000000
+#define	SPI_A2D		0
+#define	SPI_D2A		1
 
 
 /*
@@ -66,10 +59,7 @@ static int spiFdD2A ;
 
 void gertboardAnalogWrite (int chan, int value)
 {
-  uint8_t spiBufTx [2] ;
-  uint8_t spiBufRx [2] ;
-  struct spi_ioc_transfer spi ;
-
+  uint8_t spiData [2] ;
   uint8_t chanBits, dataBits ;
 
   if (chan == 0)
@@ -80,17 +70,10 @@ void gertboardAnalogWrite (int chan, int value)
   chanBits |= ((value >> 4) & 0x0F) ;
   dataBits  = ((value << 4) & 0xF0) ;
 
-  spiBufTx [0] = chanBits ;
-  spiBufTx [1] = dataBits ;
-
-  spi.tx_buf        = (unsigned long)spiBufTx ;
-  spi.rx_buf        = (unsigned long)spiBufRx ;
-  spi.len           = 2 ;
-  spi.delay_usecs   = spiDelay ;
-  spi.speed_hz      = spiSpeed ;
-  spi.bits_per_word = spiBPW ;
+  spiData [0] = chanBits ;
+  spiData [1] = dataBits ;
 
-  ioctl (spiFdD2A, SPI_IOC_MESSAGE(1), &spi) ;
+  wiringPiSPIDataRW (SPI_D2A, spiData, 2) ;
 }
 
 
@@ -103,60 +86,21 @@ void gertboardAnalogWrite (int chan, int value)
 
 int gertboardAnalogRead (int chan)
 {
-  uint8_t spiBufTx [4] ;
-  uint8_t spiBufRx [4] ;
-  struct spi_ioc_transfer spi ;
+  uint8_t spiData [2] ;
 
   uint8_t chanBits ;
 
   if (chan == 0)
-    chanBits = 0b0110100 ;
+    chanBits = 0b11010000 ;
   else
-    chanBits = 0b0111100 ;
-
-  spiBufTx [0] = chanBits ;
-  spiBufTx [1] = 0 ;
-
-  spi.tx_buf        = (unsigned long)spiBufTx ;
-  spi.rx_buf        = (unsigned long)spiBufRx ;
-  spi.len           = 4 ;
-  spi.delay_usecs   = spiDelay ;
-  spi.speed_hz      = spiSpeed ;
-  spi.bits_per_word = spiBPW ;
-
-  ioctl (spiFdA2D, SPI_IOC_MESSAGE(1), &spi) ;
-
-  return spiBufRx [0] << 8 | spiBufRx [1] ;
-}
-
-
-/*
- * setParams:
- *	Output the SPI bus parameters to the given device
- *********************************************************************************
- */
+    chanBits = 0b11110000 ;
 
-static int setParams (int fd)
-{
-  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 ;
+  spiData [0] = chanBits ;
+  spiData [1] = 0 ;
 
-  if (ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &spiSpeed) < 0)
-    return -1 ;
-
-  if (ioctl (fd, SPI_IOC_RD_MAX_SPEED_HZ, &spiSpeed) < 0)
-    return -1 ;
+  wiringPiSPIDataRW (SPI_A2D, spiData, 2) ;
 
-  return 0 ;
+  return ((spiData [0] << 7) | (spiData [1] >> 1)) & 0x3FF ;
 }
 
 
@@ -168,16 +112,10 @@ static int setParams (int fd)
 
 int gertboardSPISetup (void)
 {
-  if ((spiFdA2D = open (spiA2D, O_RDWR)) < 0)
-    return -1 ;
-
-  if (setParams (spiFdA2D) != 0)
-    return -1 ;
-
-  if ((spiFdD2A = open (spiD2A, O_RDWR)) < 0)
+  if (wiringPiSPISetup (SPI_A2D, SPI_ADC_SPEED) < 0)
     return -1 ;
 
-  if (setParams (spiFdD2A) != 0)
+  if (wiringPiSPISetup (SPI_D2A, SPI_DAC_SPEED) < 0)
     return -1 ;
 
   return 0 ;

+ 117 - 0
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 <http://www.gnu.org/licenses/>.
+ ***********************************************************************
+ */
+
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/spi/spidev.h>
+
+#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 ;
+}

+ 35 - 0
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 <http://www.gnu.org/licenses/>.
+ ***********************************************************************
+ */
+
+#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