wiringPiFace.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  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. #include <stdio.h>
  29. #include <stdint.h>
  30. #include <fcntl.h>
  31. #include <sys/ioctl.h>
  32. #include <sys/types.h>
  33. #include <linux/spi/spidev.h>
  34. #include "wiringPi.h"
  35. // The SPI bus parameters
  36. // Variables as they need to be passed as pointers later on
  37. static char *spiDevice = "/dev/spidev0.0" ;
  38. static uint8_t spiMode = 0 ;
  39. static uint8_t spiBPW = 8 ;
  40. static uint32_t spiSpeed = 5000000 ;
  41. static uint16_t spiDelay = 0;
  42. // Locals here to keep track of everything
  43. static int spiFd ;
  44. // The MCP23S17 doesn't have bit-set operations, so it's
  45. // cheaper to keep a copy here than to read/modify/write it
  46. uint8_t dataOutRegister = 0 ;
  47. uint8_t pudRegister = 0 ;
  48. // MCP23S17 Registers
  49. #define IOCON 0x0A
  50. #define IODIRA 0x00
  51. #define IPOLA 0x02
  52. #define GPINTENA 0x04
  53. #define DEFVALA 0x06
  54. #define INTCONA 0x08
  55. #define GPPUA 0x0C
  56. #define INTFA 0x0E
  57. #define INTCAPA 0x10
  58. #define GPIOA 0x12
  59. #define OLATA 0x14
  60. #define IODIRB 0x01
  61. #define IPOLB 0x03
  62. #define GPINTENB 0x05
  63. #define DEFVALB 0x07
  64. #define INTCONB 0x09
  65. #define GPPUB 0x0D
  66. #define INTFB 0x0F
  67. #define INTCAPB 0x11
  68. #define GPIOB 0x13
  69. #define OLATB 0x15
  70. // Bits in the IOCON register
  71. #define IOCON_BANK_MODE 0x80
  72. #define IOCON_MIRROR 0x40
  73. #define IOCON_SEQOP 0x20
  74. #define IOCON_DISSLW 0x10
  75. #define IOCON_HAEN 0x08
  76. #define IOCON_ODR 0x04
  77. #define IOCON_INTPOL 0x02
  78. #define IOCON_UNUSED 0x01
  79. // Default initialisation mode
  80. #define IOCON_INIT (IOCON_SEQOP)
  81. // Command codes
  82. #define CMD_WRITE 0x40
  83. #define CMD_READ 0x41
  84. /*
  85. * writeByte:
  86. * Write a byte to a register on the MCP23S17 on the SPI bus.
  87. * This is using the synchronous access mechanism.
  88. *********************************************************************************
  89. */
  90. static void writeByte (uint8_t reg, uint8_t data)
  91. {
  92. uint8_t spiBufTx [3] ;
  93. uint8_t spiBufRx [3] ;
  94. struct spi_ioc_transfer spi ;
  95. spiBufTx [0] = CMD_WRITE ;
  96. spiBufTx [1] = reg ;
  97. spiBufTx [2] = data ;
  98. spi.tx_buf = (unsigned long)spiBufTx ;
  99. spi.rx_buf = (unsigned long)spiBufRx ;
  100. spi.len = 3 ;
  101. spi.delay_usecs = spiDelay ;
  102. spi.speed_hz = spiSpeed ;
  103. spi.bits_per_word = spiBPW ;
  104. ioctl (spiFd, SPI_IOC_MESSAGE(1), &spi) ;
  105. }
  106. /*
  107. * readByte:
  108. * Read a byte from a register on the MCP23S17 on the SPI bus.
  109. * This is the synchronous access mechanism.
  110. * What appears to happen is that the data returned is at
  111. * the same offset as the number of bytes written to the device. So if we
  112. * write 2 bytes (e.g. command then register number), then the data returned
  113. * will by at the 3rd byte...
  114. *********************************************************************************
  115. */
  116. static uint8_t readByte (uint8_t reg)
  117. {
  118. uint8_t tx [4] ;
  119. uint8_t rx [4] ;
  120. struct spi_ioc_transfer spi ;
  121. tx [0] = CMD_READ ;
  122. tx [1] = reg ;
  123. tx [2] = 0 ;
  124. spi.tx_buf = (unsigned long)tx ;
  125. spi.rx_buf = (unsigned long)rx ;
  126. spi.len = 3 ;
  127. spi.delay_usecs = spiDelay ;
  128. spi.speed_hz = spiSpeed ;
  129. spi.bits_per_word = spiBPW ;
  130. ioctl (spiFd, SPI_IOC_MESSAGE(1), &spi) ;
  131. return rx [2] ;
  132. }
  133. /*
  134. * digitalWritePiFace:
  135. * Perform the digitalWrite function on the PiFace board
  136. *********************************************************************************
  137. */
  138. void digitalWritePiFace (int pin, int value)
  139. {
  140. uint8_t mask = 1 << pin ;
  141. if (value == 0)
  142. dataOutRegister &= (~mask) ;
  143. else
  144. dataOutRegister |= mask ;
  145. writeByte (GPIOA, dataOutRegister) ;
  146. }
  147. void digitalWritePiFaceSpecial (int pin, int value)
  148. {
  149. uint8_t mask = 1 << pin ;
  150. uint8_t old ;
  151. old = readByte (GPIOA) ;
  152. if (value == 0)
  153. old &= (~mask) ;
  154. else
  155. old |= mask ;
  156. writeByte (GPIOA, old) ;
  157. }
  158. /*
  159. * digitalReadPiFace:
  160. * Perform the digitalRead function on the PiFace board
  161. *********************************************************************************
  162. */
  163. int digitalReadPiFace (int pin)
  164. {
  165. uint8_t mask = 1 << pin ;
  166. if ((readByte (GPIOB) & mask) != 0)
  167. return HIGH ;
  168. else
  169. return LOW ;
  170. }
  171. /*
  172. * pullUpDnControlPiFace:
  173. * Perform the pullUpDnControl function on the PiFace board
  174. *********************************************************************************
  175. */
  176. void pullUpDnControlPiFace (int pin, int pud)
  177. {
  178. uint8_t mask = 1 << pin ;
  179. if (pud == PUD_UP)
  180. pudRegister |= mask ;
  181. else
  182. pudRegister &= (~mask) ;
  183. writeByte (GPPUB, pudRegister) ;
  184. }
  185. void pullUpDnControlPiFaceSpecial (int pin, int pud)
  186. {
  187. uint8_t mask = 1 << pin ;
  188. uint8_t old ;
  189. old = readByte (GPPUB) ;
  190. if (pud == PUD_UP)
  191. old |= mask ;
  192. else
  193. old &= (~mask) ;
  194. writeByte (GPPUB, old) ;
  195. }
  196. /*
  197. * Dummy functions that are not used in this mode
  198. *********************************************************************************
  199. */
  200. void pinModePiFace (int pin, int mode) {}
  201. void pwmWritePiFace (int pin, int value) {}
  202. int waitForInterruptPiFace (int pin, int mS) { return 0 ; }
  203. /*
  204. * wiringPiSetupPiFace
  205. * Setup the SPI interface and initialise the MCP23S17 chip
  206. *********************************************************************************
  207. */
  208. static int _wiringPiSetupPiFace (void)
  209. {
  210. if ((spiFd = open (spiDevice, O_RDWR)) < 0)
  211. return -1 ;
  212. // Set SPI parameters
  213. // Why are we doing a read after write?
  214. // I don't know - just blindliy copying an example elsewhere... -GH-
  215. if (ioctl (spiFd, SPI_IOC_WR_MODE, &spiMode) < 0)
  216. return -1 ;
  217. if (ioctl (spiFd, SPI_IOC_RD_MODE, &spiMode) < 0)
  218. return -1 ;
  219. if (ioctl (spiFd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0)
  220. return -1 ;
  221. if (ioctl (spiFd, SPI_IOC_RD_BITS_PER_WORD, &spiBPW) < 0)
  222. return -1 ;
  223. if (ioctl (spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &spiSpeed) < 0)
  224. return -1 ;
  225. if (ioctl (spiFd, SPI_IOC_RD_MAX_SPEED_HZ, &spiSpeed) < 0)
  226. return -1 ;
  227. // Setup the MCP23S17
  228. writeByte (IOCON, IOCON_INIT) ;
  229. writeByte (IODIRA, 0x00) ; // Port A -> Outputs
  230. writeByte (IODIRB, 0xFF) ; // Port B -> Inputs
  231. return 0 ;
  232. }
  233. int wiringPiSetupPiFace (void)
  234. {
  235. int x = _wiringPiSetupPiFace () ;
  236. if (x != 0)
  237. return x ;
  238. writeByte (GPIOA, 0x00) ; // Set all outptus off
  239. writeByte (GPPUB, 0x00) ; // Disable any pull-ups on port B
  240. pinMode = pinModePiFace ;
  241. pullUpDnControl = pullUpDnControlPiFace ;
  242. digitalWrite = digitalWritePiFace ;
  243. pwmWrite = pwmWritePiFace ;
  244. digitalRead = digitalReadPiFace ;
  245. waitForInterrupt = waitForInterruptPiFace ;
  246. return 0 ;
  247. }
  248. /*
  249. * wiringPiSetupPiFaceForGpioProg:
  250. * Setup the SPI interface and initialise the MCP23S17 chip
  251. * Special version for the gpio program
  252. *********************************************************************************
  253. */
  254. int wiringPiSetupPiFaceForGpioProg (void)
  255. {
  256. int x = _wiringPiSetupPiFace () ;
  257. if (x != 0)
  258. return x ;
  259. pinMode = pinModePiFace ;
  260. pullUpDnControl = pullUpDnControlPiFaceSpecial ;
  261. digitalWrite = digitalWritePiFaceSpecial ;
  262. pwmWrite = pwmWritePiFace ;
  263. digitalRead = digitalReadPiFace ;
  264. waitForInterrupt = waitForInterruptPiFace ;
  265. return 0 ;
  266. }