Gordons Projects

--> Projects Top-Level GIT

Slight change to the gpio program to fix SPI buffer size when loading
[wiringPi] / 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 void digitalWriteBytePiFace (int value)
186 {
187   writeByte (GPIOA, value) ;
188 }
189
190
191 void digitalWritePiFaceSpecial (int pin, int value)
192 {
193   uint8_t mask = 1 << pin ;
194   uint8_t old ;
195
196   old = readByte (GPIOA) ;
197
198   if (value == 0)
199     old &= (~mask) ;
200   else
201     old |=   mask ;
202
203   writeByte (GPIOA, old) ;
204 }
205
206
207 /*
208  * digitalReadPiFace:
209  *      Perform the digitalRead function on the PiFace board
210  *********************************************************************************
211  */
212
213 int digitalReadPiFace (int pin)
214 {
215   uint8_t mask = 1 << pin ;
216
217   if ((readByte (GPIOB) & mask) != 0)
218     return HIGH ;
219   else
220     return LOW ;
221 }
222
223
224 /*
225  * pullUpDnControlPiFace:
226  *      Perform the pullUpDnControl function on the PiFace board
227  *********************************************************************************
228  */
229
230 void pullUpDnControlPiFace (int pin, int pud)
231 {
232   uint8_t mask = 1 << pin ;
233
234   if (pud == PUD_UP)
235     pudRegister |=   mask ;
236   else
237     pudRegister &= (~mask) ;
238
239   writeByte (GPPUB, pudRegister) ;
240
241 }
242
243
244 void pullUpDnControlPiFaceSpecial (int pin, int pud)
245 {
246   uint8_t mask = 1 << pin ;
247   uint8_t old ;
248
249   old = readByte (GPPUB) ;
250
251   if (pud == PUD_UP)
252     old |=   mask ;
253   else
254     old &= (~mask) ;
255
256   writeByte (GPPUB, old) ;
257
258 }
259
260
261
262 /*
263  * Dummy functions that are not used in this mode
264  *********************************************************************************
265  */
266
267 void pinModePiFace          (int pin, int mode)  {}
268 void pwmWritePiFace         (int pin, int value) {}
269 int  waitForInterruptPiFace (int pin, int mS)    { return 0 ; }
270
271
272 /*
273  * wiringPiSetupPiFace
274  *      Setup the SPI interface and initialise the MCP23S17 chip
275  *********************************************************************************
276  */
277
278 static int _wiringPiSetupPiFace (void)
279 {
280   if ((spiFd = open (spiDevice, O_RDWR)) < 0)
281     return -1 ;
282
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-
286
287   if (ioctl (spiFd, SPI_IOC_WR_MODE, &spiMode) < 0)
288     return -1 ;
289
290   if (ioctl (spiFd, SPI_IOC_RD_MODE, &spiMode) < 0)
291     return -1 ;
292
293   if (ioctl (spiFd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0)
294     return -1 ;
295
296   if (ioctl (spiFd, SPI_IOC_RD_BITS_PER_WORD, &spiBPW) < 0)
297     return -1 ;
298
299   if (ioctl (spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &spiSpeed) < 0)
300     return -1 ;
301
302   if (ioctl (spiFd, SPI_IOC_RD_MAX_SPEED_HZ, &spiSpeed) < 0)
303     return -1 ;
304
305 // Setup the MCP23S17
306
307   writeByte (IOCON, IOCON_INIT) ;
308
309   writeByte (IODIRA, 0x00) ;    // Port A -> Outputs
310   writeByte (IODIRB, 0xFF) ;    // Port B -> Inputs
311
312   return 0 ;
313 }
314
315
316 int wiringPiSetupPiFace (void)
317 {
318   int x = _wiringPiSetupPiFace () ;
319
320   if (x != 0)
321     return x ;
322
323   writeByte (GPIOA, 0x00) ;     // Set all outptus off
324   writeByte (GPPUB, 0x00) ;     // Disable any pull-ups on port B
325
326            pinMode =              pinModePiFace ;
327    pullUpDnControl =      pullUpDnControlPiFace ;
328       digitalWrite =         digitalWritePiFace ;
329   digitalWriteByte =     digitalWriteBytePiFace ;
330           pwmWrite =             pwmWritePiFace ;
331        digitalRead =          digitalReadPiFace ;
332   waitForInterrupt =     waitForInterruptPiFace ;
333
334   return 0 ;
335 }
336
337
338 /*
339  * wiringPiSetupPiFaceForGpioProg:
340  *      Setup the SPI interface and initialise the MCP23S17 chip
341  *      Special version for the gpio program
342  *********************************************************************************
343  */
344
345
346 int wiringPiSetupPiFaceForGpioProg (void)
347 {
348   int x = _wiringPiSetupPiFace () ;
349
350   if (x != 0)
351     return x ;
352
353            pinMode =                 pinModePiFace ;
354    pullUpDnControl =  pullUpDnControlPiFaceSpecial ;
355       digitalWrite =     digitalWritePiFaceSpecial ;
356   digitalWriteByte =        digitalWriteBytePiFace ;
357           pwmWrite =                pwmWritePiFace ;
358        digitalRead =             digitalReadPiFace ;
359   waitForInterrupt =        waitForInterruptPiFace ;
360
361   return 0 ;
362 }