mirror of
https://github.com/clockworkpi/WiringPi.git
synced 2025-12-13 08:18:48 +01:00
delayMicrosecondsHard re-written - again. Added a serialRead example program, and added in the okLed to the examples too. Updated/checked some of the GPIO/PWM code. Added in some experimental servo and tone generating code and and example or 2. Tweaks to the gpio command to correctly load the I2C modules too.
363 lines
8.3 KiB
C
363 lines
8.3 KiB
C
/*
|
|
* wiringPiFace:
|
|
* Arduino compatable (ish) Wiring library for the Raspberry Pi
|
|
* Copyright (c) 2012 Gordon Henderson
|
|
*
|
|
* This file to interface with the PiFace peripheral device which
|
|
* has an MCP23S17 GPIO device connected via the SPI bus.
|
|
*
|
|
***********************************************************************
|
|
* This file is part of wiringPi:
|
|
* https://projects.drogon.net/raspberry-pi/wiringpi/
|
|
*
|
|
* wiringPi is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* wiringPi is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with wiringPi.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
***********************************************************************
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/types.h>
|
|
#include <linux/spi/spidev.h>
|
|
|
|
#include "wiringPi.h"
|
|
|
|
|
|
// The SPI bus parameters
|
|
// Variables as they need to be passed as pointers later on
|
|
|
|
static char *spiDevice = "/dev/spidev0.0" ;
|
|
static uint8_t spiMode = 0 ;
|
|
static uint8_t spiBPW = 8 ;
|
|
static uint32_t spiSpeed = 5000000 ;
|
|
static uint16_t spiDelay = 0;
|
|
|
|
// Locals here to keep track of everything
|
|
|
|
static int spiFd ;
|
|
|
|
// The MCP23S17 doesn't have bit-set operations, so it's
|
|
// cheaper to keep a copy here than to read/modify/write it
|
|
|
|
uint8_t dataOutRegister = 0 ;
|
|
uint8_t pudRegister = 0 ;
|
|
|
|
// MCP23S17 Registers
|
|
|
|
#define IOCON 0x0A
|
|
|
|
#define IODIRA 0x00
|
|
#define IPOLA 0x02
|
|
#define GPINTENA 0x04
|
|
#define DEFVALA 0x06
|
|
#define INTCONA 0x08
|
|
#define GPPUA 0x0C
|
|
#define INTFA 0x0E
|
|
#define INTCAPA 0x10
|
|
#define GPIOA 0x12
|
|
#define OLATA 0x14
|
|
|
|
#define IODIRB 0x01
|
|
#define IPOLB 0x03
|
|
#define GPINTENB 0x05
|
|
#define DEFVALB 0x07
|
|
#define INTCONB 0x09
|
|
#define GPPUB 0x0D
|
|
#define INTFB 0x0F
|
|
#define INTCAPB 0x11
|
|
#define GPIOB 0x13
|
|
#define OLATB 0x15
|
|
|
|
// Bits in the IOCON register
|
|
|
|
#define IOCON_BANK_MODE 0x80
|
|
#define IOCON_MIRROR 0x40
|
|
#define IOCON_SEQOP 0x20
|
|
#define IOCON_DISSLW 0x10
|
|
#define IOCON_HAEN 0x08
|
|
#define IOCON_ODR 0x04
|
|
#define IOCON_INTPOL 0x02
|
|
#define IOCON_UNUSED 0x01
|
|
|
|
// Default initialisation mode
|
|
|
|
#define IOCON_INIT (IOCON_SEQOP)
|
|
|
|
// Command codes
|
|
|
|
#define CMD_WRITE 0x40
|
|
#define CMD_READ 0x41
|
|
|
|
|
|
/*
|
|
* writeByte:
|
|
* Write a byte to a register on the MCP23S17 on the SPI bus.
|
|
* This is using the synchronous access mechanism.
|
|
*********************************************************************************
|
|
*/
|
|
|
|
static void writeByte (uint8_t reg, uint8_t data)
|
|
{
|
|
uint8_t spiBufTx [3] ;
|
|
uint8_t spiBufRx [3] ;
|
|
struct spi_ioc_transfer spi ;
|
|
|
|
spiBufTx [0] = CMD_WRITE ;
|
|
spiBufTx [1] = reg ;
|
|
spiBufTx [2] = data ;
|
|
|
|
spi.tx_buf = (unsigned long)spiBufTx ;
|
|
spi.rx_buf = (unsigned long)spiBufRx ;
|
|
spi.len = 3 ;
|
|
spi.delay_usecs = spiDelay ;
|
|
spi.speed_hz = spiSpeed ;
|
|
spi.bits_per_word = spiBPW ;
|
|
|
|
ioctl (spiFd, SPI_IOC_MESSAGE(1), &spi) ;
|
|
}
|
|
|
|
/*
|
|
* readByte:
|
|
* Read a byte from a register on the MCP23S17 on the SPI bus.
|
|
* This is the synchronous access mechanism.
|
|
* What appears to happen is that the data returned is at
|
|
* the same offset as the number of bytes written to the device. So if we
|
|
* write 2 bytes (e.g. command then register number), then the data returned
|
|
* will by at the 3rd byte...
|
|
*********************************************************************************
|
|
*/
|
|
|
|
static uint8_t readByte (uint8_t reg)
|
|
{
|
|
uint8_t tx [4] ;
|
|
uint8_t rx [4] ;
|
|
struct spi_ioc_transfer spi ;
|
|
|
|
tx [0] = CMD_READ ;
|
|
tx [1] = reg ;
|
|
tx [2] = 0 ;
|
|
|
|
spi.tx_buf = (unsigned long)tx ;
|
|
spi.rx_buf = (unsigned long)rx ;
|
|
spi.len = 3 ;
|
|
spi.delay_usecs = spiDelay ;
|
|
spi.speed_hz = spiSpeed ;
|
|
spi.bits_per_word = spiBPW ;
|
|
|
|
ioctl (spiFd, SPI_IOC_MESSAGE(1), &spi) ;
|
|
|
|
return rx [2] ;
|
|
}
|
|
|
|
|
|
/*
|
|
* digitalWritePiFace:
|
|
* Perform the digitalWrite function on the PiFace board
|
|
*********************************************************************************
|
|
*/
|
|
|
|
void digitalWritePiFace (int pin, int value)
|
|
{
|
|
uint8_t mask = 1 << pin ;
|
|
|
|
if (value == 0)
|
|
dataOutRegister &= (~mask) ;
|
|
else
|
|
dataOutRegister |= mask ;
|
|
|
|
writeByte (GPIOA, dataOutRegister) ;
|
|
}
|
|
|
|
void digitalWriteBytePiFace (int value)
|
|
{
|
|
writeByte (GPIOA, value) ;
|
|
}
|
|
|
|
|
|
void digitalWritePiFaceSpecial (int pin, int value)
|
|
{
|
|
uint8_t mask = 1 << pin ;
|
|
uint8_t old ;
|
|
|
|
old = readByte (GPIOA) ;
|
|
|
|
if (value == 0)
|
|
old &= (~mask) ;
|
|
else
|
|
old |= mask ;
|
|
|
|
writeByte (GPIOA, old) ;
|
|
}
|
|
|
|
|
|
/*
|
|
* digitalReadPiFace:
|
|
* Perform the digitalRead function on the PiFace board
|
|
*********************************************************************************
|
|
*/
|
|
|
|
int digitalReadPiFace (int pin)
|
|
{
|
|
uint8_t mask = 1 << pin ;
|
|
|
|
if ((readByte (GPIOB) & mask) != 0)
|
|
return HIGH ;
|
|
else
|
|
return LOW ;
|
|
}
|
|
|
|
|
|
/*
|
|
* pullUpDnControlPiFace:
|
|
* Perform the pullUpDnControl function on the PiFace board
|
|
*********************************************************************************
|
|
*/
|
|
|
|
void pullUpDnControlPiFace (int pin, int pud)
|
|
{
|
|
uint8_t mask = 1 << pin ;
|
|
|
|
if (pud == PUD_UP)
|
|
pudRegister |= mask ;
|
|
else
|
|
pudRegister &= (~mask) ;
|
|
|
|
writeByte (GPPUB, pudRegister) ;
|
|
|
|
}
|
|
|
|
|
|
void pullUpDnControlPiFaceSpecial (int pin, int pud)
|
|
{
|
|
uint8_t mask = 1 << pin ;
|
|
uint8_t old ;
|
|
|
|
old = readByte (GPPUB) ;
|
|
|
|
if (pud == PUD_UP)
|
|
old |= mask ;
|
|
else
|
|
old &= (~mask) ;
|
|
|
|
writeByte (GPPUB, old) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Dummy functions that are not used in this mode
|
|
*********************************************************************************
|
|
*/
|
|
|
|
void pinModePiFace (int pin, int mode) {}
|
|
void pwmWritePiFace (int pin, int value) {}
|
|
int waitForInterruptPiFace (int pin, int mS) { return 0 ; }
|
|
|
|
|
|
/*
|
|
* wiringPiSetupPiFace
|
|
* Setup the SPI interface and initialise the MCP23S17 chip
|
|
*********************************************************************************
|
|
*/
|
|
|
|
static int _wiringPiSetupPiFace (void)
|
|
{
|
|
if ((spiFd = open (spiDevice, O_RDWR)) < 0)
|
|
return -1 ;
|
|
|
|
// Set SPI parameters
|
|
// Why are we doing a read after write?
|
|
// I don't know - just blindliy copying an example elsewhere... -GH-
|
|
|
|
if (ioctl (spiFd, SPI_IOC_WR_MODE, &spiMode) < 0)
|
|
return -1 ;
|
|
|
|
if (ioctl (spiFd, SPI_IOC_RD_MODE, &spiMode) < 0)
|
|
return -1 ;
|
|
|
|
if (ioctl (spiFd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0)
|
|
return -1 ;
|
|
|
|
if (ioctl (spiFd, SPI_IOC_RD_BITS_PER_WORD, &spiBPW) < 0)
|
|
return -1 ;
|
|
|
|
if (ioctl (spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &spiSpeed) < 0)
|
|
return -1 ;
|
|
|
|
if (ioctl (spiFd, SPI_IOC_RD_MAX_SPEED_HZ, &spiSpeed) < 0)
|
|
return -1 ;
|
|
|
|
// Setup the MCP23S17
|
|
|
|
writeByte (IOCON, IOCON_INIT) ;
|
|
|
|
writeByte (IODIRA, 0x00) ; // Port A -> Outputs
|
|
writeByte (IODIRB, 0xFF) ; // Port B -> Inputs
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
|
|
int wiringPiSetupPiFace (void)
|
|
{
|
|
int x = _wiringPiSetupPiFace () ;
|
|
|
|
if (x != 0)
|
|
return x ;
|
|
|
|
writeByte (GPIOA, 0x00) ; // Set all outptus off
|
|
writeByte (GPPUB, 0x00) ; // Disable any pull-ups on port B
|
|
|
|
pinMode = pinModePiFace ;
|
|
pullUpDnControl = pullUpDnControlPiFace ;
|
|
digitalWrite = digitalWritePiFace ;
|
|
digitalWriteByte = digitalWriteBytePiFace ;
|
|
pwmWrite = pwmWritePiFace ;
|
|
digitalRead = digitalReadPiFace ;
|
|
waitForInterrupt = waitForInterruptPiFace ;
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
|
|
/*
|
|
* wiringPiSetupPiFaceForGpioProg:
|
|
* Setup the SPI interface and initialise the MCP23S17 chip
|
|
* Special version for the gpio program
|
|
*********************************************************************************
|
|
*/
|
|
|
|
|
|
int wiringPiSetupPiFaceForGpioProg (void)
|
|
{
|
|
int x = _wiringPiSetupPiFace () ;
|
|
|
|
if (x != 0)
|
|
return x ;
|
|
|
|
pinMode = pinModePiFace ;
|
|
pullUpDnControl = pullUpDnControlPiFaceSpecial ;
|
|
digitalWrite = digitalWritePiFaceSpecial ;
|
|
digitalWriteByte = digitalWriteBytePiFace ;
|
|
pwmWrite = pwmWritePiFace ;
|
|
digitalRead = digitalReadPiFace ;
|
|
waitForInterrupt = waitForInterruptPiFace ;
|
|
|
|
return 0 ;
|
|
}
|