lpc177x_8x_gpio.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. /*
  2. * Copyright (C) 2012 by Ole Reinhardt (ole.reinhardt@embedded-it.de)
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of the copyright holders nor the names of
  16. * contributors may be used to endorse or promote products derived
  17. * from this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  22. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  23. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  24. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  25. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  26. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  27. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  28. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  29. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. * SUCH DAMAGE.
  31. *
  32. * For additional information see http://www.ethernut.de/
  33. */
  34. /*
  35. * \verbatim
  36. * $Id: lpc177x_8x_gpio.c $
  37. * \endverbatim
  38. */
  39. #include <cfg/os.h>
  40. #include <cfg/arch.h>
  41. #include <cfg/arch/gpio.h>
  42. #include <sys/nutdebug.h>
  43. #include <arch/cm3.h>
  44. #include <arch/cm3/nxp/lpc177x_8x_gpio.h>
  45. #include <dev/gpio.h>
  46. #include <string.h>
  47. #include <stdlib.h>
  48. /*!
  49. * \addtogroup xgNutArchCm3Lpc177x_8xGpio
  50. */
  51. /*@{*/
  52. #define NUTGPIOPORT_MAX NUTGPIO_PORT5+1
  53. /*!
  54. * \brief Get pin configuration.
  55. *
  56. * Trying to set undefined ports must be avoided.
  57. * If NUTDEBUG is enabled an assertion will be rised.
  58. *
  59. * \param bank GPIO bank/port number.
  60. * \param bit Bit number of the specified bank/port.
  61. *
  62. * \return Attribute flags of the pin.
  63. */
  64. uint32_t GpioPinConfigGet(int bank, int bit)
  65. {
  66. uint32_t rc = 0;
  67. uint32_t mode;
  68. __IO uint32_t *IOCON;
  69. NUTASSERT(bank < NUTGPIOPORT_MAX);
  70. NUTASSERT((bit < 32) && ((bank != NUTGPIOPORT_MAX - 1) || (bit < 5)));
  71. /* Calculate the address of the desired IOCON register */
  72. IOCON = (uint32_t *)(LPC_IOCON_BASE + ((bank * 32 + bit) * sizeof(uint32_t)));
  73. /*
  74. * See register description of the IOCON registers of each I/O pin.
  75. */
  76. mode = *IOCON;
  77. /* Query pin direction */
  78. if (CM3BBGET(GPIO_BANKID2BASE(bank), LPC_GPIO_TypeDef, FIODIR, bit)) {
  79. rc |= GPIO_CFG_OUTPUT;
  80. }
  81. /* Query currently set alternate function */
  82. rc |= ((mode >> IOCON_FUNC_POS) & IOCON_FUNC_BITMASK) << GPIO_CFG_PERIPHERAL_POS;
  83. if (rc & GPIO_CFG_PERIPHERAL_MASK) {
  84. rc |= GPIO_CFG_DISABLED;
  85. }
  86. switch (mode & IOCON_MODE_BITMASK) {
  87. case IOCON_MODE_PLAIN:
  88. /* Nothing special */
  89. break;
  90. case IOCON_MODE_PULLDOWN:
  91. rc |= GPIO_CFG_PULLDOWN;
  92. break;
  93. case IOCON_MODE_PULLUP:
  94. rc |= GPIO_CFG_PULLUP;
  95. break;
  96. case IOCON_MODE_REPEATER:
  97. rc |= GPIO_CFG_REPEATER;
  98. break;
  99. }
  100. if ((mode & IOCON_HYSTERESIS_BITMASK) == IOCON_HYSTERESIS) {
  101. rc |= GPIO_CFG_HYSTERESIS;
  102. }
  103. if ((mode & IOCON_INVERT_BITMASK) == IOCON_INVERTED) {
  104. rc |= GPIO_CFG_INVERT;
  105. }
  106. if ((mode & IOCON_ADMODE_BITMASK) == IOCON_ADMODE) {
  107. rc |= GPIO_CFG_ADMODE;
  108. }
  109. if ((mode & IOCON_GLITCH_FILTER_BITMASK) == IOCON_GLITCH_FILTER) {
  110. rc |= GPIO_CFG_DEBOUNCE;
  111. }
  112. if ((mode & IOCON_SLEW_BITMASK) == IOCON_SLEW) {
  113. rc |= GPIO_CFG_SLEWCTRL;
  114. }
  115. if ((mode & IOCON_ODMODE_BITMASK) == IOCON_ODMODE) {
  116. rc |= GPIO_CFG_MULTIDRIVE;
  117. }
  118. if ((mode & IOCON_DACEN_BITMASK) == IOCON_DACEN) {
  119. rc |= GPIO_CFG_DAC_ENABLE;
  120. }
  121. return rc;
  122. }
  123. /*!
  124. * \brief Set port wide pin configuration.
  125. *
  126. * \note This function does not check for undefined ports and pins or
  127. * invalid attributes. If this is required, use GpioPinConfigSet().
  128. * If NUTDEBUG is enabled accessing an undefined port will rise
  129. * an assertion.
  130. *
  131. * \note Port P0-7 .. P0-9 pins (W-Mode pins) are a little bit special and need
  132. bit 7 always be set for normal operation
  133. *
  134. * \param bank GPIO bank/port number.
  135. * \param mask The given attributes are set for a specific pin, if the
  136. * corresponding bit in this mask is 1.
  137. * \param flags Attribute flags to set.
  138. *
  139. * \return Always 0.
  140. */
  141. int GpioPortConfigSet(int bank, uint32_t mask, uint32_t flags)
  142. {
  143. uint32_t mode = 0;
  144. int i;
  145. __IO uint32_t *IOCON;
  146. NUTASSERT(bank < NUTGPIOPORT_MAX);
  147. /*
  148. * See register description of the IOCON registers of each I/O pin.
  149. */
  150. mode |= ((flags & GPIO_CFG_PERIPHERAL_MASK) >> GPIO_CFG_PERIPHERAL_POS) & IOCON_FUNC_BITMASK;
  151. if (flags & GPIO_CFG_PULLDOWN) {
  152. mode |= IOCON_MODE_PULLDOWN;
  153. } else
  154. if (flags & GPIO_CFG_PULLUP) {
  155. mode |= IOCON_MODE_PULLUP;
  156. } else
  157. if (flags & GPIO_CFG_REPEATER) {
  158. mode |= IOCON_MODE_REPEATER;
  159. }
  160. if (flags & GPIO_CFG_HYSTERESIS) {
  161. mode |= IOCON_HYSTERESIS;
  162. }
  163. if (flags & GPIO_CFG_INVERT) {
  164. mode |= IOCON_INVERTED;
  165. }
  166. if (flags & GPIO_CFG_ADMODE) {
  167. mode |= IOCON_ADMODE;
  168. }
  169. if (flags & GPIO_CFG_DEBOUNCE) {
  170. mode |= IOCON_GLITCH_FILTER;
  171. }
  172. if (flags & GPIO_CFG_SLEWCTRL) {
  173. mode |= IOCON_SLEW;
  174. }
  175. if (flags & GPIO_CFG_MULTIDRIVE) {
  176. mode |= IOCON_ODMODE;
  177. }
  178. if (flags & GPIO_CFG_DAC_ENABLE) {
  179. mode |= IOCON_DACEN;
  180. }
  181. IOCON = (uint32_t *)(LPC_IOCON_BASE + ((bank * 32) * sizeof(uint32_t)));
  182. for (i = 0; i < (bank != NUTGPIO_PORT5 ? 32 : 5); i ++) {
  183. if (mask & _BV(i)) {
  184. if ((bank == NUTGPIO_PORT0) && (i >= 7) && (i <= 9)) {
  185. /* Port P0-7 .. P0-9 pins (W-Mode pins) are a little bit special and need
  186. bit 7 always be set for normal operation
  187. */
  188. mode |= _BV(7);
  189. }
  190. *(IOCON ++) = mode;
  191. }
  192. }
  193. if (GPIO_CFG_OUTPUT) {
  194. CM3REG(GPIO_BANKID2BASE(bank), LPC_GPIO_TypeDef, FIODIR) |= mask;
  195. } else {
  196. CM3REG(GPIO_BANKID2BASE(bank), LPC_GPIO_TypeDef, FIODIR) &= ~mask;
  197. }
  198. return 0;
  199. }
  200. /*!
  201. * \brief Set pin configuration.
  202. *
  203. * Applications may also use this function to make sure, that a specific
  204. * attribute is available for a specific pin.
  205. *
  206. * \note GPIO pins are typically initialized to a safe state after power
  207. * up. This routine is not able to determine the consequences of
  208. * changing pin configurations. In the worst case you may permanently
  209. * damage your hardware by bad pin settings.
  210. *
  211. * \param bank GPIO bank/port number.
  212. * \param bit Bit number of the specified bank/port.
  213. * \param flags Attribute flags.
  214. *
  215. * \return 0 if all attributes had been set, -1 otherwise.
  216. */
  217. int GpioPinConfigSet(int bank, int bit, uint32_t flags)
  218. {
  219. uint32_t rc = 0;
  220. uint32_t mode;
  221. __IO uint32_t *IOCON;
  222. NUTASSERT(bank < NUTGPIOPORT_MAX);
  223. NUTASSERT((bit < 32) && ((bank != NUTGPIOPORT_MAX - 1) || (bit < 5)));
  224. /* Calculate the address of the desired IOCON register */
  225. IOCON = (uint32_t *)(LPC_IOCON_BASE + ((bank * 32 + bit) * sizeof(uint32_t)));
  226. /*
  227. * See register description of the IOCON registers of each I/O pin.
  228. */
  229. mode = 0;
  230. mode |= ((flags & GPIO_CFG_PERIPHERAL_MASK) >> GPIO_CFG_PERIPHERAL_POS) & IOCON_FUNC_BITMASK;
  231. if (flags & GPIO_CFG_PULLDOWN) {
  232. mode |= IOCON_MODE_PULLDOWN;
  233. } else
  234. if (flags & GPIO_CFG_PULLUP) {
  235. mode |= IOCON_MODE_PULLUP;
  236. } else
  237. if (flags & GPIO_CFG_REPEATER) {
  238. mode |= IOCON_MODE_REPEATER;
  239. }
  240. if (flags & GPIO_CFG_HYSTERESIS) {
  241. mode |= IOCON_HYSTERESIS;
  242. }
  243. if (flags & GPIO_CFG_INVERT) {
  244. mode |= IOCON_INVERTED;
  245. }
  246. if (flags & GPIO_CFG_ADMODE) {
  247. mode |= IOCON_ADMODE;
  248. }
  249. if (flags & GPIO_CFG_DEBOUNCE) {
  250. mode |= IOCON_GLITCH_FILTER;
  251. }
  252. if (flags & GPIO_CFG_SLEWCTRL) {
  253. mode |= IOCON_SLEW;
  254. }
  255. if (flags & GPIO_CFG_MULTIDRIVE) {
  256. mode |= IOCON_ODMODE;
  257. }
  258. if (flags & GPIO_CFG_DAC_ENABLE) {
  259. mode |= IOCON_DACEN;
  260. }
  261. if ((bank == NUTGPIO_PORT0) && (bit >= 7) && (bit <= 9)) {
  262. /* Port P0-7 .. P0-9 pins (W-Mode pins) are a little bit special and need
  263. bit 7 always be set for normal operation
  264. */
  265. mode |= _BV(7);
  266. }
  267. #if defined(MCU_LPC407x_8x)
  268. if ((bank == NUTGPIO_PORT1) && (((bit >= 5) && (bit <= 7)) || (bit == 14) || (bit == 16) || (bit == 17))) {
  269. /* Port P1-5 .. P1-7, P1-14, P1-16, P1-17 pins (W-Mode pins) are a little bit special and need
  270. bit 7 always be set for normal operation
  271. */
  272. mode |= _BV(7);
  273. }
  274. #endif
  275. *IOCON = mode;
  276. if (flags & GPIO_CFG_OUTPUT) {
  277. CM3BBSET(GPIO_BANKID2BASE(bank), LPC_GPIO_TypeDef, FIODIR, bit);
  278. } else {
  279. CM3BBCLR(GPIO_BANKID2BASE(bank), LPC_GPIO_TypeDef, FIODIR, bit);
  280. }
  281. if (mode != (*IOCON & (IOCON_FUNC_BITMASK | IOCON_MODE_BITMASK |
  282. IOCON_HYSTERESIS_BITMASK | IOCON_INVERT_BITMASK |
  283. IOCON_ADMODE_BITMASK | IOCON_GLITCH_FILTER_BITMASK |
  284. IOCON_I2C_MODE_BITMASK | IOCON_SLEW_BITMASK |
  285. IOCON_ODMODE_BITMASK | IOCON_DACEN_BITMASK))) {
  286. rc = -1;
  287. }
  288. if (CM3BBGET(GPIO_BANKID2BASE(bank), LPC_GPIO_TypeDef, FIODIR, bit) != (flags & GPIO_CFG_OUTPUT) ? 1 : 0) {
  289. rc = -1;
  290. }
  291. return rc;
  292. }
  293. /*!
  294. * \brief Register a GPIO pin interrupt handler.
  295. *
  296. * Generating interrupts on GPIO pin changes is not supported on all
  297. * platforms. In this case dedicated external interrupt pins may
  298. * be used with NutRegisterIrqHandler().
  299. *
  300. * On the LPC17xx interrupts are triggered on rising, falling or both
  301. * edges. Level triggering is not supported.
  302. *
  303. * After registering, interrupts are disabled. Calling GpioIrqEnable()
  304. * is required to activate the interrupt.
  305. *
  306. * The following code fragment registers an interrupt handler which is
  307. * called on a rising edge of bit 4 of the first GPIO port:
  308. * \code
  309. * #include <dev/gpio.h>
  310. *
  311. * static void PinChange(void *arg)
  312. * {
  313. * ...
  314. * }
  315. *
  316. * {
  317. * ...
  318. * GpioPinConfigSet(0, 4, GPIO_CFG_PULLUP);
  319. * GpioRegisterIrqHandler(&sig_GPIO0, 4, PinChange, NULL);
  320. * GpioIrqSetMode(&sig_GPIO0, 4, NUT_IRQMODE_RISINGEDGE);
  321. * GpioIrqEnable(&sig_GPIO0, 4);
  322. * ...
  323. * }
  324. * \endcode
  325. *
  326. * \param sig Bank/port interrupt to be associated with this handler.
  327. * \param bit Bit number of the specified bank/port.
  328. * \param handler This routine will be called by Nut/OS, when the specified
  329. * pin changes its state.
  330. * \param arg Argument to be passed to the interrupt handler routine.
  331. *
  332. * \return 0 on success, -1 otherwise.
  333. */
  334. int GpioRegisterIrqHandler(GPIO_SIGNAL * sig, int bit, void (*handler) (void *), void *arg)
  335. {
  336. int rc = 0;
  337. if (sig->ios_vector == 0) {
  338. /* This is the first call. Allocate the vector table. */
  339. sig->ios_vector = malloc(sizeof(GPIO_VECTOR) * 32);
  340. if (sig->ios_vector) {
  341. memset(sig->ios_vector, 0, sizeof(GPIO_VECTOR) * 32);
  342. /* Register our internal PIO interrupt service. */
  343. if (sig_PIO.ir_handler == NULL) {
  344. rc = NutRegisterIrqHandler(&sig_PIO, sig->ios_handler, NULL);
  345. if (rc == 0) {
  346. /* Clear any pending interrupts */
  347. LPC_GPIOINT->IO0IntClr = 0xFFFFFFFF;
  348. LPC_GPIOINT->IO2IntClr = 0xFFFFFFFF;
  349. rc = NutIrqEnable(&sig_PIO);
  350. }
  351. }
  352. }
  353. else {
  354. return -1;
  355. }
  356. }
  357. sig->ios_vector[bit].iov_handler = handler;
  358. sig->ios_vector[bit].iov_arg = arg;
  359. return rc;
  360. }
  361. /*!
  362. * \brief Enable a specified GPIO interrupt.
  363. *
  364. * A related interrupt handler must have been registered before calling
  365. * this function. See GpioRegisterIrqHandler().
  366. *
  367. * \param sig Interrupt to enable.
  368. * \param bit Bit number of the specified bank/port.
  369. *
  370. * \return 0 on success, -1 otherwise.
  371. */
  372. int GpioIrqEnable(GPIO_SIGNAL * sig, int bit)
  373. {
  374. return (sig->ios_ctl) (sig, NUT_IRQCTL_ENABLE, NULL, bit);
  375. }
  376. /*!
  377. * \brief Disable a specified GPIO interrupt.
  378. *
  379. * \param sig Interrupt to disable.
  380. * \param bit Bit number of the specified bank/port.
  381. *
  382. * \return 0 on success, -1 otherwise.
  383. */
  384. int GpioIrqDisable(GPIO_SIGNAL * sig, int bit)
  385. {
  386. return (sig->ios_ctl) (sig, NUT_IRQCTL_DISABLE, NULL, bit);
  387. }
  388. /*!
  389. * \brief Query the status of a specified GPIO interrupt.
  390. *
  391. * A related interrupt handler must have been registered before calling
  392. * this function. See GpioRegisterIrqHandler().
  393. *
  394. * \param sig Interrupt to query
  395. * \param bit Bit number of the specified bank/port.
  396. *
  397. * \return 0 if interrupt is disabled, 1 of enabled
  398. */
  399. int GpioIrqStatus(GPIO_SIGNAL * sig, int bit)
  400. {
  401. uint32_t status;
  402. (sig->ios_ctl) (sig, NUT_IRQCTL_STATUS, &status, bit);
  403. return status;
  404. }
  405. /*!
  406. * \brief Set the GPIO interrupt mode for a pin
  407. *
  408. * \param sig Interrupt to configure.
  409. * \param bit Bit number of the specified bank/port.
  410. * \param mode one of the following modes:
  411. * NUT_IRQMODE_RISINGEDGE,
  412. * NUT_IRQMODE_FALLINGEDGE,
  413. * NUT_IRQMODE_BOTHEDGE,
  414. * NUT_IRQMODE_NONE,
  415. *
  416. * \return 0 on success, -1 otherwise.
  417. */
  418. int GpioIrqSetMode(GPIO_SIGNAL * sig, int bit, int mode)
  419. {
  420. return (sig->ios_ctl) (sig, NUT_IRQCTL_SETMODE, &mode, bit);
  421. }
  422. /*@}*/