chiark / gitweb /
Added some comments about removing the call to pullUpDnControl()
[wiringPi.git] / wiringPi / wiringPiFace.c
1 /*
2  * wiringPiFace:
3  *      Arduino compatable (ish) Wiring library for the Raspberry Pi
4  *      Copyright (c) 2012 Gordon Henderson
5  *
6  *      This file to interface with the PiFace peripheral device which
7  *      has an MCP23S17 GPIO device connected via the SPI bus.
8  *
9  ***********************************************************************
10  * This file is part of wiringPi:
11  *      https://projects.drogon.net/raspberry-pi/wiringpi/
12  *
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.
17  *
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.
22  *
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  ***********************************************************************
27  */
28
29
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <fcntl.h>
33 #include <sys/ioctl.h>
34 #include <sys/types.h>
35 #include <linux/spi/spidev.h>
36
37 #include "wiringPi.h"
38
39
40 // The SPI bus parameters
41 //      Variables as they need to be passed as pointers later on
42
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;
48
49 // Locals here to keep track of everything
50
51 static int spiFd ;
52
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
55
56 uint8_t dataOutRegister = 0 ;
57 uint8_t     pudRegister = 0 ;
58
59 // MCP23S17 Registers
60
61 #define IOCON           0x0A
62
63 #define IODIRA          0x00
64 #define IPOLA           0x02
65 #define GPINTENA        0x04
66 #define DEFVALA         0x06
67 #define INTCONA         0x08
68 #define GPPUA           0x0C
69 #define INTFA           0x0E
70 #define INTCAPA         0x10
71 #define GPIOA           0x12
72 #define OLATA           0x14
73
74 #define IODIRB          0x01
75 #define IPOLB           0x03
76 #define GPINTENB        0x05
77 #define DEFVALB         0x07
78 #define INTCONB         0x09
79 #define GPPUB           0x0D
80 #define INTFB           0x0F
81 #define INTCAPB         0x11
82 #define GPIOB           0x13
83 #define OLATB           0x15
84
85 // Bits in the IOCON register
86
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
95
96 // Default initialisation mode
97
98 #define IOCON_INIT      (IOCON_SEQOP)
99
100 // Command codes
101
102 #define CMD_WRITE       0x40
103 #define CMD_READ        0x41
104
105
106 /*
107  * writeByte:
108  *      Write a byte to a register on the MCP23S17 on the SPI bus.
109  *      This is using the synchronous access mechanism.
110  *********************************************************************************
111  */
112
113 static void writeByte (uint8_t reg, uint8_t data)
114 {
115   uint8_t spiBufTx [3] ;
116   uint8_t spiBufRx [3] ;
117   struct spi_ioc_transfer spi ;
118
119   spiBufTx [0] = CMD_WRITE ;
120   spiBufTx [1] = reg ;
121   spiBufTx [2] = data ;
122
123   spi.tx_buf        = (unsigned long)spiBufTx ;
124   spi.rx_buf        = (unsigned long)spiBufRx ;
125   spi.len           = 3 ;
126   spi.delay_usecs   = spiDelay ;
127   spi.speed_hz      = spiSpeed ;
128   spi.bits_per_word = spiBPW ;
129
130   ioctl (spiFd, SPI_IOC_MESSAGE(1), &spi) ;
131 }
132
133 /*
134  * readByte:
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  *********************************************************************************
142  */
143
144 static uint8_t readByte (uint8_t reg)
145 {
146   uint8_t tx [4] ;
147   uint8_t rx [4] ;
148   struct spi_ioc_transfer spi ;
149
150   tx [0] = CMD_READ ;
151   tx [1] = reg ;
152   tx [2] = 0 ;
153
154   spi.tx_buf        = (unsigned long)tx ;
155   spi.rx_buf        = (unsigned long)rx ;
156   spi.len           = 3 ;
157   spi.delay_usecs   = spiDelay ;
158   spi.speed_hz      = spiSpeed ;
159   spi.bits_per_word = spiBPW ;
160
161   ioctl (spiFd, SPI_IOC_MESSAGE(1), &spi) ;
162
163   return rx [2] ;
164 }
165
166
167 /*
168  * digitalWritePiFace:
169  *      Perform the digitalWrite function on the PiFace board
170  *********************************************************************************
171  */
172
173 void digitalWritePiFace (int pin, int value)
174 {
175   uint8_t mask = 1 << pin ;
176
177   if (value == 0)
178     dataOutRegister &= (~mask) ;
179   else
180     dataOutRegister |=   mask ;
181
182   writeByte (GPIOA, dataOutRegister) ;
183 }
184
185
186 void digitalWritePiFaceSpecial (int pin, int value)
187 {
188   uint8_t mask = 1 << pin ;
189   uint8_t old ;
190
191   old = readByte (GPIOA) ;
192
193   if (value == 0)
194     old &= (~mask) ;
195   else
196     old |=   mask ;
197
198   writeByte (GPIOA, old) ;
199 }
200
201
202 /*
203  * digitalReadPiFace:
204  *      Perform the digitalRead function on the PiFace board
205  *********************************************************************************
206  */
207
208 int digitalReadPiFace (int pin)
209 {
210   uint8_t mask = 1 << pin ;
211
212   if ((readByte (GPIOB) & mask) != 0)
213     return HIGH ;
214   else
215     return LOW ;
216 }
217
218
219 /*
220  * pullUpDnControlPiFace:
221  *      Perform the pullUpDnControl function on the PiFace board
222  *********************************************************************************
223  */
224
225 void pullUpDnControlPiFace (int pin, int pud)
226 {
227   uint8_t mask = 1 << pin ;
228
229   if (pud == PUD_UP)
230     pudRegister |=   mask ;
231   else
232     pudRegister &= (~mask) ;
233
234   writeByte (GPPUB, pudRegister) ;
235
236 }
237
238
239 void pullUpDnControlPiFaceSpecial (int pin, int pud)
240 {
241   uint8_t mask = 1 << pin ;
242   uint8_t old ;
243
244   old = readByte (GPPUB) ;
245
246   if (pud == PUD_UP)
247     old |=   mask ;
248   else
249     old &= (~mask) ;
250
251   writeByte (GPPUB, old) ;
252
253 }
254
255
256
257 /*
258  * Dummy functions that are not used in this mode
259  *********************************************************************************
260  */
261
262 void pinModePiFace          (int pin, int mode)  {}
263 void pwmWritePiFace         (int pin, int value) {}
264 int  waitForInterruptPiFace (int pin, int mS)    { return 0 ; }
265
266
267 /*
268  * wiringPiSetupPiFace
269  *      Setup the SPI interface and initialise the MCP23S17 chip
270  *********************************************************************************
271  */
272
273 static int _wiringPiSetupPiFace (void)
274 {
275   if ((spiFd = open (spiDevice, O_RDWR)) < 0)
276     return -1 ;
277
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-
281
282   if (ioctl (spiFd, SPI_IOC_WR_MODE, &spiMode) < 0)
283     return -1 ;
284
285   if (ioctl (spiFd, SPI_IOC_RD_MODE, &spiMode) < 0)
286     return -1 ;
287
288   if (ioctl (spiFd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0)
289     return -1 ;
290
291   if (ioctl (spiFd, SPI_IOC_RD_BITS_PER_WORD, &spiBPW) < 0)
292     return -1 ;
293
294   if (ioctl (spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &spiSpeed) < 0)
295     return -1 ;
296
297   if (ioctl (spiFd, SPI_IOC_RD_MAX_SPEED_HZ, &spiSpeed) < 0)
298     return -1 ;
299
300 // Setup the MCP23S17
301
302   writeByte (IOCON, IOCON_INIT) ;
303
304   writeByte (IODIRA, 0x00) ;    // Port A -> Outputs
305   writeByte (IODIRB, 0xFF) ;    // Port B -> Inputs
306
307   return 0 ;
308 }
309
310
311 int wiringPiSetupPiFace (void)
312 {
313   int x = _wiringPiSetupPiFace () ;
314
315   if (x != 0)
316     return x ;
317
318   writeByte (GPIOA, 0x00) ;     // Set all outptus off
319   writeByte (GPPUB, 0x00) ;     // Disable any pull-ups on port B
320
321            pinMode =          pinModePiFace ;
322    pullUpDnControl =  pullUpDnControlPiFace ;
323       digitalWrite =     digitalWritePiFace ;
324           pwmWrite =         pwmWritePiFace ;
325        digitalRead =      digitalReadPiFace ;
326   waitForInterrupt = waitForInterruptPiFace ;
327
328   return 0 ;
329 }
330
331
332 /*
333  * wiringPiSetupPiFaceForGpioProg:
334  *      Setup the SPI interface and initialise the MCP23S17 chip
335  *      Special version for the gpio program
336  *********************************************************************************
337  */
338
339
340 int wiringPiSetupPiFaceForGpioProg (void)
341 {
342   int x = _wiringPiSetupPiFace () ;
343
344   if (x != 0)
345     return x ;
346
347            pinMode =          pinModePiFace ;
348    pullUpDnControl =  pullUpDnControlPiFaceSpecial ;
349       digitalWrite =     digitalWritePiFaceSpecial ;
350           pwmWrite =         pwmWritePiFace ;
351        digitalRead =      digitalReadPiFace ;
352   waitForInterrupt = waitForInterruptPiFace ;
353
354   return 0 ;
355 }