You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

363 lines
8.3 KiB

  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 digitalWriteBytePiFace (int value)
  148. {
  149. writeByte (GPIOA, value) ;
  150. }
  151. void digitalWritePiFaceSpecial (int pin, int value)
  152. {
  153. uint8_t mask = 1 << pin ;
  154. uint8_t old ;
  155. old = readByte (GPIOA) ;
  156. if (value == 0)
  157. old &= (~mask) ;
  158. else
  159. old |= mask ;
  160. writeByte (GPIOA, old) ;
  161. }
  162. /*
  163. * digitalReadPiFace:
  164. * Perform the digitalRead function on the PiFace board
  165. *********************************************************************************
  166. */
  167. int digitalReadPiFace (int pin)
  168. {
  169. uint8_t mask = 1 << pin ;
  170. if ((readByte (GPIOB) & mask) != 0)
  171. return HIGH ;
  172. else
  173. return LOW ;
  174. }
  175. /*
  176. * pullUpDnControlPiFace:
  177. * Perform the pullUpDnControl function on the PiFace board
  178. *********************************************************************************
  179. */
  180. void pullUpDnControlPiFace (int pin, int pud)
  181. {
  182. uint8_t mask = 1 << pin ;
  183. if (pud == PUD_UP)
  184. pudRegister |= mask ;
  185. else
  186. pudRegister &= (~mask) ;
  187. writeByte (GPPUB, pudRegister) ;
  188. }
  189. void pullUpDnControlPiFaceSpecial (int pin, int pud)
  190. {
  191. uint8_t mask = 1 << pin ;
  192. uint8_t old ;
  193. old = readByte (GPPUB) ;
  194. if (pud == PUD_UP)
  195. old |= mask ;
  196. else
  197. old &= (~mask) ;
  198. writeByte (GPPUB, old) ;
  199. }
  200. /*
  201. * Dummy functions that are not used in this mode
  202. *********************************************************************************
  203. */
  204. void pinModePiFace (int pin, int mode) {}
  205. void pwmWritePiFace (int pin, int value) {}
  206. int waitForInterruptPiFace (int pin, int mS) { return 0 ; }
  207. /*
  208. * wiringPiSetupPiFace
  209. * Setup the SPI interface and initialise the MCP23S17 chip
  210. *********************************************************************************
  211. */
  212. static int _wiringPiSetupPiFace (void)
  213. {
  214. if ((spiFd = open (spiDevice, O_RDWR)) < 0)
  215. return -1 ;
  216. // Set SPI parameters
  217. // Why are we doing a read after write?
  218. // I don't know - just blindliy copying an example elsewhere... -GH-
  219. if (ioctl (spiFd, SPI_IOC_WR_MODE, &spiMode) < 0)
  220. return -1 ;
  221. if (ioctl (spiFd, SPI_IOC_RD_MODE, &spiMode) < 0)
  222. return -1 ;
  223. if (ioctl (spiFd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0)
  224. return -1 ;
  225. if (ioctl (spiFd, SPI_IOC_RD_BITS_PER_WORD, &spiBPW) < 0)
  226. return -1 ;
  227. if (ioctl (spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &spiSpeed) < 0)
  228. return -1 ;
  229. if (ioctl (spiFd, SPI_IOC_RD_MAX_SPEED_HZ, &spiSpeed) < 0)
  230. return -1 ;
  231. // Setup the MCP23S17
  232. writeByte (IOCON, IOCON_INIT) ;
  233. writeByte (IODIRA, 0x00) ; // Port A -> Outputs
  234. writeByte (IODIRB, 0xFF) ; // Port B -> Inputs
  235. return 0 ;
  236. }
  237. int wiringPiSetupPiFace (void)
  238. {
  239. int x = _wiringPiSetupPiFace () ;
  240. if (x != 0)
  241. return x ;
  242. writeByte (GPIOA, 0x00) ; // Set all outptus off
  243. writeByte (GPPUB, 0x00) ; // Disable any pull-ups on port B
  244. pinMode = pinModePiFace ;
  245. pullUpDnControl = pullUpDnControlPiFace ;
  246. digitalWrite = digitalWritePiFace ;
  247. digitalWriteByte = digitalWriteBytePiFace ;
  248. pwmWrite = pwmWritePiFace ;
  249. digitalRead = digitalReadPiFace ;
  250. waitForInterrupt = waitForInterruptPiFace ;
  251. return 0 ;
  252. }
  253. /*
  254. * wiringPiSetupPiFaceForGpioProg:
  255. * Setup the SPI interface and initialise the MCP23S17 chip
  256. * Special version for the gpio program
  257. *********************************************************************************
  258. */
  259. int wiringPiSetupPiFaceForGpioProg (void)
  260. {
  261. int x = _wiringPiSetupPiFace () ;
  262. if (x != 0)
  263. return x ;
  264. pinMode = pinModePiFace ;
  265. pullUpDnControl = pullUpDnControlPiFaceSpecial ;
  266. digitalWrite = digitalWritePiFaceSpecial ;
  267. digitalWriteByte = digitalWriteBytePiFace ;
  268. pwmWrite = pwmWritePiFace ;
  269. digitalRead = digitalReadPiFace ;
  270. waitForInterrupt = waitForInterruptPiFace ;
  271. return 0 ;
  272. }