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) ;
185 void digitalWriteBytePiFace (int value)
187 writeByte (GPIOA, value) ;
191 void digitalWritePiFaceSpecial (int pin, int value)
193 uint8_t mask = 1 << pin ;
196 old = readByte (GPIOA) ;
203 writeByte (GPIOA, old) ;
209 * Perform the digitalRead function on the PiFace board
210 *********************************************************************************
213 int digitalReadPiFace (int pin)
215 uint8_t mask = 1 << pin ;
217 if ((readByte (GPIOB) & mask) != 0)
225 * pullUpDnControlPiFace:
226 * Perform the pullUpDnControl function on the PiFace board
227 *********************************************************************************
230 void pullUpDnControlPiFace (int pin, int pud)
232 uint8_t mask = 1 << pin ;
235 pudRegister |= mask ;
237 pudRegister &= (~mask) ;
239 writeByte (GPPUB, pudRegister) ;
244 void pullUpDnControlPiFaceSpecial (int pin, int pud)
246 uint8_t mask = 1 << pin ;
249 old = readByte (GPPUB) ;
256 writeByte (GPPUB, old) ;
263 * Dummy functions that are not used in this mode
264 *********************************************************************************
267 void pinModePiFace (int pin, int mode) {}
268 void pwmWritePiFace (int pin, int value) {}
269 int waitForInterruptPiFace (int pin, int mS) { return 0 ; }
273 * wiringPiSetupPiFace
274 * Setup the SPI interface and initialise the MCP23S17 chip
275 *********************************************************************************
278 static int _wiringPiSetupPiFace (void)
280 if ((spiFd = open (spiDevice, O_RDWR)) < 0)
283 // Set SPI parameters
284 // Why are we doing a read after write?
285 // I don't know - just blindliy copying an example elsewhere... -GH-
287 if (ioctl (spiFd, SPI_IOC_WR_MODE, &spiMode) < 0)
290 if (ioctl (spiFd, SPI_IOC_RD_MODE, &spiMode) < 0)
293 if (ioctl (spiFd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0)
296 if (ioctl (spiFd, SPI_IOC_RD_BITS_PER_WORD, &spiBPW) < 0)
299 if (ioctl (spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &spiSpeed) < 0)
302 if (ioctl (spiFd, SPI_IOC_RD_MAX_SPEED_HZ, &spiSpeed) < 0)
305 // Setup the MCP23S17
307 writeByte (IOCON, IOCON_INIT) ;
309 writeByte (IODIRA, 0x00) ; // Port A -> Outputs
310 writeByte (IODIRB, 0xFF) ; // Port B -> Inputs
316 int wiringPiSetupPiFace (void)
318 int x = _wiringPiSetupPiFace () ;
323 writeByte (GPIOA, 0x00) ; // Set all outptus off
324 writeByte (GPPUB, 0x00) ; // Disable any pull-ups on port B
326 pinMode = pinModePiFace ;
327 pullUpDnControl = pullUpDnControlPiFace ;
328 digitalWrite = digitalWritePiFace ;
329 digitalWriteByte = digitalWriteBytePiFace ;
330 pwmWrite = pwmWritePiFace ;
331 digitalRead = digitalReadPiFace ;
332 waitForInterrupt = waitForInterruptPiFace ;
339 * wiringPiSetupPiFaceForGpioProg:
340 * Setup the SPI interface and initialise the MCP23S17 chip
341 * Special version for the gpio program
342 *********************************************************************************
346 int wiringPiSetupPiFaceForGpioProg (void)
348 int x = _wiringPiSetupPiFace () ;
353 pinMode = pinModePiFace ;
354 pullUpDnControl = pullUpDnControlPiFaceSpecial ;
355 digitalWrite = digitalWritePiFaceSpecial ;
356 digitalWriteByte = digitalWriteBytePiFace ;
357 pwmWrite = pwmWritePiFace ;
358 digitalRead = digitalReadPiFace ;
359 waitForInterrupt = waitForInterruptPiFace ;