From 99095e3fa0c9e028c2c00d020392b1e22210379a Mon Sep 17 00:00:00 2001 From: Gordon Henderson Date: Mon, 27 Aug 2012 20:56:14 +0100 Subject: [PATCH] Added new SPI driver helpers. Changed the gertboard code to use it and ran more tests on he Gertboard code. --- examples/gertboard.c | 44 ++++++++++++++++--- gpio/gpio.1 | 32 ++++++++++++-- gpio/gpio.c | 94 +++++++++++++++++++++++++++++++++++++-- wiringPi/Makefile | 5 ++- wiringPi/gertboard.c | 102 +++++++++--------------------------------- wiringPi/wiringPiSPI.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++ wiringPi/wiringPiSPI.h | 35 +++++++++++++++ 7 files changed, 330 insertions(+), 99 deletions(-) create mode 100644 wiringPi/wiringPiSPI.c create mode 100644 wiringPi/wiringPiSPI.h diff --git a/examples/gertboard.c b/examples/gertboard.c index 8344d48..8f26dd4 100644 --- a/examples/gertboard.c +++ b/examples/gertboard.c @@ -14,33 +14,63 @@ #include #include -//#include #include +#define B_SIZE 200 +#undef DO_TIMING + #include #include 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 ; diff --git a/gpio/gpio.1 b/gpio/gpio.1 index 73e43c8..bc8e36e 100644 --- a/gpio/gpio.1 +++ b/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" diff --git a/gpio/gpio.c b/gpio/gpio.c index 5a97aab..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,12 +32,15 @@ #include #include +#include +#include + #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 \n" " gpio pwm-bal/pwm-ms \n" " gpio pwmr \n" - " gpio load spi/i2c" ; + " gpio load spi/i2c\n" + " gpio gbr \n" + " gpio gbw \n" ; /* @@ -519,6 +524,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 \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 ********************************************************************************* @@ -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) diff --git a/wiringPi/Makefile b/wiringPi/Makefile index b80caea..dc189cd 100644 --- a/wiringPi/Makefile +++ b/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: diff --git a/wiringPi/gertboard.c b/wiringPi/gertboard.c index bd7e60a..a8795d3 100644 --- a/wiringPi/gertboard.c +++ b/wiringPi/gertboard.c @@ -38,23 +38,16 @@ #include #include -#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 ; 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