3 * Arduino compatable (ish) Wiring library for the Raspberry Pi
4 * Copyright (c) 2012 Gordon Henderson
6 * This file to interface with the PiFace peripheral device which
7 * has an MCP23S17 GPIO device connected via the SPI bus.
9 ***********************************************************************
10 * This file is part of wiringPi:
11 * https://projects.drogon.net/raspberry-pi/wiringpi/
13 * wiringPi is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as
15 * published by the Free Software Foundation, either version 3 of the
16 * License, or (at your option) any later version.
18 * wiringPi is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with wiringPi.
25 * If not, see <http://www.gnu.org/licenses/>.
26 ***********************************************************************
33 #include <sys/ioctl.h>
34 #include <sys/types.h>
35 #include <linux/spi/spidev.h>
40 // The SPI bus parameters
41 // Variables as they need to be passed as pointers later on
43 static char *spiDevice = "/dev/spidev0.0" ;
44 static uint8_t spiMode = 0 ;
45 static uint8_t spiBPW = 8 ;
46 static uint32_t spiSpeed = 5000000 ;
47 static uint16_t spiDelay = 0;
49 // Locals here to keep track of everything
53 // The MCP23S17 doesn't have bit-set operations, so it's
54 // cheaper to keep a copy here than to read/modify/write it
56 uint8_t dataOutRegister = 0 ;
57 uint8_t pudRegister = 0 ;
85 // Bits in the IOCON register
87 #define IOCON_BANK_MODE 0x80
88 #define IOCON_MIRROR 0x40
89 #define IOCON_SEQOP 0x20
90 #define IOCON_DISSLW 0x10
91 #define IOCON_HAEN 0x08
92 #define IOCON_ODR 0x04
93 #define IOCON_INTPOL 0x02
94 #define IOCON_UNUSED 0x01
96 // Default initialisation mode
98 #define IOCON_INIT (IOCON_SEQOP)
102 #define CMD_WRITE 0x40
103 #define CMD_READ 0x41
108 * Write a byte to a register on the MCP23S17 on the SPI bus.
109 * This is using the synchronous access mechanism.
110 *********************************************************************************
113 static void writeByte (uint8_t reg, uint8_t data)
115 uint8_t spiBufTx [3] ;
116 uint8_t spiBufRx [3] ;
117 struct spi_ioc_transfer spi ;
119 spiBufTx [0] = CMD_WRITE ;
121 spiBufTx [2] = data ;
123 spi.tx_buf = (unsigned long)spiBufTx ;
124 spi.rx_buf = (unsigned long)spiBufRx ;
126 spi.delay_usecs = spiDelay ;
127 spi.speed_hz = spiSpeed ;
128 spi.bits_per_word = spiBPW ;
130 ioctl (spiFd, SPI_IOC_MESSAGE(1), &spi) ;
135 * Read a byte from a register on the MCP23S17 on the SPI bus.
136 * This is the synchronous access mechanism.
137 * What appears to happen is that the data returned is at
138 * the same offset as the number of bytes written to the device. So if we
139 * write 2 bytes (e.g. command then register number), then the data returned
140 * will by at the 3rd byte...
141 *********************************************************************************
144 static uint8_t readByte (uint8_t reg)
148 struct spi_ioc_transfer spi ;
154 spi.tx_buf = (unsigned long)tx ;
155 spi.rx_buf = (unsigned long)rx ;
157 spi.delay_usecs = spiDelay ;
158 spi.speed_hz = spiSpeed ;
159 spi.bits_per_word = spiBPW ;
161 ioctl (spiFd, SPI_IOC_MESSAGE(1), &spi) ;
168 * digitalWritePiFace:
169 * Perform the digitalWrite function on the PiFace board
170 *********************************************************************************
173 void digitalWritePiFace (int pin, int value)
175 uint8_t mask = 1 << pin ;
178 dataOutRegister &= (~mask) ;
180 dataOutRegister |= mask ;
182 writeByte (GPIOA, dataOutRegister) ;
186 void digitalWritePiFaceSpecial (int pin, int value)
188 uint8_t mask = 1 << pin ;
191 old = readByte (GPIOA) ;
198 writeByte (GPIOA, old) ;
204 * Perform the digitalRead function on the PiFace board
205 *********************************************************************************
208 int digitalReadPiFace (int pin)
210 uint8_t mask = 1 << pin ;
212 if ((readByte (GPIOB) & mask) != 0)
220 * pullUpDnControlPiFace:
221 * Perform the pullUpDnControl function on the PiFace board
222 *********************************************************************************
225 void pullUpDnControlPiFace (int pin, int pud)
227 uint8_t mask = 1 << pin ;
230 pudRegister |= mask ;
232 pudRegister &= (~mask) ;
234 writeByte (GPPUB, pudRegister) ;
239 void pullUpDnControlPiFaceSpecial (int pin, int pud)
241 uint8_t mask = 1 << pin ;
244 old = readByte (GPPUB) ;
251 writeByte (GPPUB, old) ;
258 * Dummy functions that are not used in this mode
259 *********************************************************************************
262 void pinModePiFace (int pin, int mode) {}
263 void pwmWritePiFace (int pin, int value) {}
264 int waitForInterruptPiFace (int pin, int mS) { return 0 ; }
268 * wiringPiSetupPiFace
269 * Setup the SPI interface and initialise the MCP23S17 chip
270 *********************************************************************************
273 static int _wiringPiSetupPiFace (void)
275 if ((spiFd = open (spiDevice, O_RDWR)) < 0)
278 // Set SPI parameters
279 // Why are we doing a read after write?
280 // I don't know - just blindliy copying an example elsewhere... -GH-
282 if (ioctl (spiFd, SPI_IOC_WR_MODE, &spiMode) < 0)
285 if (ioctl (spiFd, SPI_IOC_RD_MODE, &spiMode) < 0)
288 if (ioctl (spiFd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0)
291 if (ioctl (spiFd, SPI_IOC_RD_BITS_PER_WORD, &spiBPW) < 0)
294 if (ioctl (spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &spiSpeed) < 0)
297 if (ioctl (spiFd, SPI_IOC_RD_MAX_SPEED_HZ, &spiSpeed) < 0)
300 // Setup the MCP23S17
302 writeByte (IOCON, IOCON_INIT) ;
304 writeByte (IODIRA, 0x00) ; // Port A -> Outputs
305 writeByte (IODIRB, 0xFF) ; // Port B -> Inputs
311 int wiringPiSetupPiFace (void)
313 int x = _wiringPiSetupPiFace () ;
318 writeByte (GPIOA, 0x00) ; // Set all outptus off
319 writeByte (GPPUB, 0x00) ; // Disable any pull-ups on port B
321 pinMode = pinModePiFace ;
322 pullUpDnControl = pullUpDnControlPiFace ;
323 digitalWrite = digitalWritePiFace ;
324 pwmWrite = pwmWritePiFace ;
325 digitalRead = digitalReadPiFace ;
326 waitForInterrupt = waitForInterruptPiFace ;
333 * wiringPiSetupPiFaceForGpioProg:
334 * Setup the SPI interface and initialise the MCP23S17 chip
335 * Special version for the gpio program
336 *********************************************************************************
340 int wiringPiSetupPiFaceForGpioProg (void)
342 int x = _wiringPiSetupPiFace () ;
347 pinMode = pinModePiFace ;
348 pullUpDnControl = pullUpDnControlPiFaceSpecial ;
349 digitalWrite = digitalWritePiFaceSpecial ;
350 pwmWrite = pwmWritePiFace ;
351 digitalRead = digitalReadPiFace ;
352 waitForInterrupt = waitForInterruptPiFace ;