spibus0gpio.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. /*
  2. * Copyright (C) 2009 by egnite GmbH
  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. * \file arch/avr/dev/spibus0gpio.c
  36. * \brief GPIO bit banging SPI bus 0 driver.
  37. *
  38. * \verbatim
  39. * $Id: spibus0gpio.c 5718 2014-05-23 14:55:57Z u_bonnes $
  40. * \endverbatim
  41. */
  42. #include <cfg/spi.h>
  43. #include <cfg/arch/gpio.h>
  44. #include <dev/gpio.h>
  45. #include <dev/spibus_gpio.h>
  46. #include <sys/event.h>
  47. #include <sys/timer.h>
  48. #include <sys/nutdebug.h>
  49. #include <dev/board.h>
  50. #include <errno.h>
  51. #include <stdlib.h>
  52. /* Targets with single ports may not have set the port number. */
  53. #if defined(SBBI0_MISO_BIT) && !defined(SBBI0_MISO_PORT)
  54. #define SBBI0_MISO_PORT NUTGPIO_PORT
  55. #endif
  56. #if defined(SBBI0_MOSI_BIT) && !defined(SBBI0_MOSI_PORT)
  57. #define SBBI0_MOSI_PORT NUTGPIO_PORT
  58. #endif
  59. #if defined(SBBI0_SCK_BIT) && !defined(SBBI0_SCK_PORT)
  60. #define SBBI0_SCK_PORT NUTGPIO_PORT
  61. #endif
  62. #if defined(SBBI0_CS0_BIT) && !defined(SBBI0_CS0_PORT)
  63. #define SBBI0_CS0_PORT NUTGPIO_PORT
  64. #endif
  65. #if defined(SBBI0_CS1_BIT) && !defined(SBBI0_CS1_PORT)
  66. #define SBBI0_CS1_PORT NUTGPIO_PORT
  67. #endif
  68. #if defined(SBBI0_CS2_BIT) && !defined(SBBI0_CS2_PORT)
  69. #define SBBI0_CS2_PORT NUTGPIO_PORT
  70. #endif
  71. #if defined(SBBI0_CS3_BIT) && !defined(SBBI0_CS3_PORT)
  72. #define SBBI0_CS3_PORT NUTGPIO_PORT
  73. #endif
  74. static GSPIREG gspi_reg0;
  75. #if defined(SBBI0_CS1_BIT)
  76. static GSPIREG gspi_reg1;
  77. #endif
  78. #if defined(SBBI0_CS2_BIT)
  79. static GSPIREG gspi_reg2;
  80. #endif
  81. #if defined(SBBI0_CS3_BIT)
  82. static GSPIREG gspi_reg3;
  83. #endif
  84. /*!
  85. * \brief Set the specified chip select to a given level.
  86. */
  87. static GSPIREG *GpioSpi0ChipSelect(uint_fast8_t cs, uint_fast8_t hi)
  88. {
  89. GSPIREG *rc;
  90. switch (cs) {
  91. case 0:
  92. /* If CS0 is undefined, we assume permanent selection. */
  93. #if defined(SBBI0_CS0_BIT)
  94. GpioPinSet(SBBI0_CS0_PORT, SBBI0_CS0_BIT, hi);
  95. #endif
  96. rc = &gspi_reg0;
  97. break;
  98. #if defined(SBBI0_CS1_BIT)
  99. case 1:
  100. GpioPinSet(SBBI0_CS1_PORT, SBBI0_CS1_BIT, hi);
  101. rc = &gspi_reg1;
  102. break;
  103. #endif
  104. #if defined(SBBI0_CS2_BIT)
  105. case 2:
  106. GpioPinSet(SBBI0_CS2_PORT, SBBI0_CS2_BIT, hi);
  107. rc = &gspi_reg2;
  108. break;
  109. #endif
  110. #if defined(SBBI0_CS3_BIT)
  111. case 3:
  112. GpioPinSet(SBBI0_CS3_PORT, SBBI0_CS3_BIT, hi);
  113. rc = &gspi_reg3;
  114. break;
  115. #endif
  116. default:
  117. errno = EIO;
  118. rc = NULL;
  119. break;
  120. }
  121. return rc;
  122. }
  123. /* Idle clock is low and data is captured on the rising edge. */
  124. static void SpiMode0Transfer(GSPIREG *gspi, const uint8_t *txbuf, uint8_t *rxbuf, int xlen, int half_duplex)
  125. {
  126. #if defined(SBBI0_SCK_BIT)
  127. uint_fast8_t mask;
  128. while (xlen--) {
  129. for (mask = 0x80; mask; mask >>= 1) {
  130. #if defined(SBBI0_MOSI_BIT)
  131. if (txbuf) {
  132. GpioPinSet(SBBI0_MOSI_PORT, SBBI0_MOSI_BIT, (*txbuf & mask) != 0);
  133. }
  134. #endif /* SBBI0_MOSI_BIT */
  135. NutMicroDelay(gspi->gspi_dly_rate);
  136. GpioPinSetHigh(SBBI0_SCK_PORT, SBBI0_SCK_BIT);
  137. #if defined(SBBI0_MISO_BIT)
  138. if (rxbuf && !half_duplex) {
  139. if (GpioPinGet(SBBI0_MISO_PORT, SBBI0_MISO_BIT)) {
  140. *rxbuf |= mask;
  141. }
  142. else {
  143. *rxbuf &= ~mask;
  144. }
  145. }
  146. #endif /* SBBI0_MISO_BIT */
  147. #if defined(SBBI0_MOSI_BIT)
  148. if (rxbuf && half_duplex) {
  149. if (GpioPinGet(SBBI0_MOSI_PORT, SBBI0_MOSI_BIT)) {
  150. *rxbuf |= mask;
  151. }
  152. else {
  153. *rxbuf &= ~mask;
  154. }
  155. }
  156. #endif /* SBBI0_MOSI_BIT */
  157. NutMicroDelay(gspi->gspi_dly_rate);
  158. GpioPinSetLow(SBBI0_SCK_PORT, SBBI0_SCK_BIT);
  159. }
  160. if (txbuf) {
  161. txbuf++;
  162. }
  163. if (rxbuf) {
  164. rxbuf++;
  165. }
  166. }
  167. #endif /* SBBI0_SCK_BIT */
  168. }
  169. /* Idle clock is low and data is captured on the falling edge. */
  170. static void SpiMode1Transfer(GSPIREG *gspi, const uint8_t *txbuf, uint8_t *rxbuf, int xlen, int half_duplex)
  171. {
  172. #if defined(SBBI0_SCK_BIT)
  173. uint_fast8_t mask;
  174. while (xlen--) {
  175. for (mask = 0x80; mask; mask >>= 1) {
  176. NutMicroDelay(gspi->gspi_dly_rate);
  177. GpioPinSetHigh(SBBI0_SCK_PORT, SBBI0_SCK_BIT);
  178. #if defined(SBBI0_MOSI_BIT)
  179. if (txbuf) {
  180. GpioPinSet(SBBI0_MOSI_PORT, SBBI0_MOSI_BIT, (*txbuf & mask) != 0);
  181. }
  182. #endif /* SBBI0_MOSI_BIT */
  183. NutMicroDelay(gspi->gspi_dly_rate);
  184. GpioPinSetLow(SBBI0_SCK_PORT, SBBI0_SCK_BIT);
  185. #if defined(SBBI0_MISO_BIT)
  186. if (rxbuf && !half_duplex) {
  187. if (GpioPinGet(SBBI0_MISO_PORT, SBBI0_MISO_BIT)) {
  188. *rxbuf |= mask;
  189. }
  190. else {
  191. *rxbuf &= ~mask;
  192. }
  193. }
  194. #endif /* SBBI0_MISO_BIT */
  195. #if defined(SBBI0_MOSI_BIT)
  196. if (rxbuf && half_duplex) {
  197. if (GpioPinGet(SBBI0_MOSI_PORT, SBBI0_MOSI_BIT)) {
  198. *rxbuf |= mask;
  199. }
  200. else {
  201. *rxbuf &= ~mask;
  202. }
  203. }
  204. #endif /* SBBI0_MOSI_BIT */
  205. }
  206. if (txbuf) {
  207. txbuf++;
  208. }
  209. if (rxbuf) {
  210. rxbuf++;
  211. }
  212. }
  213. #endif /* SBBI0_SCK_BIT */
  214. }
  215. /* Idle clock is high and data is captured on the falling edge. */
  216. static void SpiMode2Transfer(GSPIREG *gspi, const uint8_t *txbuf, uint8_t *rxbuf, int xlen, int half_duplex)
  217. {
  218. #if defined(SBBI0_SCK_BIT)
  219. uint_fast8_t mask;
  220. while (xlen--) {
  221. for (mask = 0x80; mask; mask >>= 1) {
  222. #if defined(SBBI0_MOSI_BIT)
  223. if (txbuf) {
  224. GpioPinSet(SBBI0_MOSI_PORT, SBBI0_MOSI_BIT, (*txbuf & mask) != 0);
  225. }
  226. #endif /* SBBI0_MOSI_BIT */
  227. NutMicroDelay(gspi->gspi_dly_rate);
  228. GpioPinSetLow(SBBI0_SCK_PORT, SBBI0_SCK_BIT);
  229. #if defined(SBBI0_MISO_BIT)
  230. if (rxbuf && half_duplex) {
  231. if (GpioPinGet(SBBI0_MISO_PORT, SBBI0_MISO_BIT)) {
  232. *rxbuf |= mask;
  233. }
  234. else {
  235. *rxbuf &= ~mask;
  236. }
  237. }
  238. #endif /* SBBI0_MISO_BIT */
  239. #if defined(SBBI0_MOSI_BIT)
  240. if (rxbuf && half_duplex) {
  241. if (GpioPinGet(SBBI0_MOSI_PORT, SBBI0_MOSI_BIT)) {
  242. *rxbuf |= mask;
  243. }
  244. else {
  245. *rxbuf &= ~mask;
  246. }
  247. }
  248. #endif /* SBBI0_MOSI_BIT */
  249. NutMicroDelay(gspi->gspi_dly_rate);
  250. GpioPinSetHigh(SBBI0_SCK_PORT, SBBI0_SCK_BIT);
  251. }
  252. if (txbuf) {
  253. txbuf++;
  254. }
  255. if (rxbuf) {
  256. rxbuf++;
  257. }
  258. }
  259. #endif /* SBBI0_SCK_BIT */
  260. }
  261. /* Idle clock is high and data is captured on the rising edge. */
  262. static void SpiMode3Transfer(GSPIREG *gspi, const uint8_t *txbuf, uint8_t *rxbuf, int xlen, int half_duplex)
  263. {
  264. #if defined(SBBI0_SCK_BIT)
  265. uint_fast8_t mask;
  266. while (xlen--) {
  267. for (mask = 0x80; mask; mask >>= 1) {
  268. NutMicroDelay(gspi->gspi_dly_rate);
  269. GpioPinSetLow(SBBI0_SCK_PORT, SBBI0_SCK_BIT);
  270. #if defined(SBBI0_MOSI_BIT)
  271. if (txbuf) {
  272. GpioPinSet(SBBI0_MOSI_PORT, SBBI0_MOSI_BIT, (*txbuf & mask) != 0);
  273. }
  274. #endif /* SBBI0_MOSI_BIT */
  275. NutMicroDelay(gspi->gspi_dly_rate);
  276. GpioPinSetHigh(SBBI0_SCK_PORT, SBBI0_SCK_BIT);
  277. #if defined(SBBI0_MISO_BIT)
  278. if (rxbuf && half_duplex) {
  279. if (GpioPinGet(SBBI0_MISO_PORT, SBBI0_MISO_BIT)) {
  280. *rxbuf |= mask;
  281. }
  282. else {
  283. *rxbuf &= ~mask;
  284. }
  285. }
  286. #endif /* SBBI0_MISO_BIT */
  287. #if defined(SBBI0_MOSI_BIT)
  288. if (rxbuf && half_duplex) {
  289. if (GpioPinGet(SBBI0_MOSI_PORT, SBBI0_MOSI_BIT)) {
  290. *rxbuf |= mask;
  291. }
  292. else {
  293. *rxbuf &= ~mask;
  294. }
  295. }
  296. #endif /* SBBI0_MOSI_BIT */
  297. }
  298. if (txbuf) {
  299. txbuf++;
  300. }
  301. if (rxbuf) {
  302. rxbuf++;
  303. }
  304. }
  305. #endif /* SBBI0_SCK_BIT */
  306. }
  307. /*!
  308. * \brief Transfer data on the SPI bus.
  309. *
  310. * A device must have been selected by calling GpioSpi0Select().
  311. *
  312. * \param node Specifies the SPI bus node.
  313. * \param txbuf Pointer to the transmit buffer. If NULL, undetermined
  314. * byte values are transmitted.
  315. * \param rxbuf Pointer to the receive buffer. If NULL, then incoming
  316. * data is discarded.
  317. * \param xlen Number of bytes to transfer.
  318. *
  319. * \return Always 0.
  320. */
  321. int GpioSpiBus0Transfer(NUTSPINODE * node, const void *txbuf, void *rxbuf, int xlen)
  322. {
  323. GSPIREG *gspi;
  324. int half_duplex;
  325. /* Sanity check. */
  326. NUTASSERT(node != NULL);
  327. NUTASSERT(node->node_stat != NULL);
  328. gspi = (GSPIREG *)node->node_stat;
  329. half_duplex = (node->node_mode & SPI_MODE_HALFDUPLEX);
  330. #if defined(SBBI0_MOSI_BIT)
  331. if (half_duplex) {
  332. GpioPinSetHigh(SBBI0_MOSI_PORT,SBBI0_MOSI_BIT);
  333. GpioPinRelease(SBBI0_MOSI_PORT,SBBI0_MOSI_BIT);
  334. }
  335. else {
  336. GpioPinSetLow(SBBI0_MOSI_PORT,SBBI0_MOSI_BIT);
  337. GpioPinDrive(SBBI0_MOSI_PORT,SBBI0_MOSI_BIT);
  338. }
  339. #endif
  340. /* We use dedicated static routines for each mode in the hope that
  341. ** this improves the compiler's optimization for the inner loop. */
  342. switch (node->node_mode & SPI_MODE_3) {
  343. case SPI_MODE_0:
  344. SpiMode0Transfer(gspi, txbuf, rxbuf, xlen, half_duplex);
  345. break;
  346. case SPI_MODE_1:
  347. SpiMode1Transfer(gspi, txbuf, rxbuf, xlen, half_duplex);
  348. break;
  349. case SPI_MODE_2:
  350. SpiMode2Transfer(gspi, txbuf, rxbuf, xlen, half_duplex);
  351. break;
  352. case SPI_MODE_3:
  353. SpiMode3Transfer(gspi, txbuf, rxbuf, xlen, half_duplex);
  354. break;
  355. }
  356. return 0;
  357. }
  358. /*!
  359. * \brief Initialize an SPI bus node.
  360. *
  361. * This routine is called for each SPI node, which is registered via
  362. * NutRegisterSpiDevice().
  363. *
  364. * \param node Specifies the SPI bus node.
  365. *
  366. * \return 0 on success or -1 if there is no valid chip select.
  367. */
  368. int GpioSpiBus0NodeInit(NUTSPINODE * node)
  369. {
  370. /* Sanity check. */
  371. NUTASSERT(node != NULL);
  372. /* Try to deactivate the node's chip select. */
  373. #if defined(SBBI0_CS0_BIT)
  374. GpioPinConfigSet(SBBI0_CS0_PORT, SBBI0_CS0_BIT, GPIO_CFG_OUTPUT|GPIO_CFG_INIT_HIGH);
  375. #endif
  376. #if defined(SBBI0_CS1_BIT)
  377. GpioPinConfigSet(SBBI0_CS1_PORT, SBBI0_CS1_BIT, GPIO_CFG_OUTPUT|GPIO_CFG_INIT_HIGH);
  378. #endif
  379. #if defined(SBBI0_CS2_BIT)
  380. GpioPinConfigSet(SBBI0_CS2_PORT, SBBI0_CS2_BIT, GPIO_CFG_OUTPUT|GPIO_CFG_INIT_HIGH);
  381. #endif
  382. #if defined(SBBI0_CS3_BIT)
  383. GpioPinConfigSet(SBBI0_CS3_PORT, SBBI0_CS3_BIT, GPIO_CFG_OUTPUT|GPIO_CFG_INIT_HIGH);
  384. #endif
  385. node->node_stat = GpioSpi0ChipSelect(node->node_cs, (node->node_mode & SPI_MODE_CSHIGH) == 0);
  386. if (node->node_stat == NULL) {
  387. /* Chip select not configured. */
  388. return -1;
  389. }
  390. return GpioSpiSetup(node);
  391. }
  392. /*! \brief Select a device on the SPI bus.
  393. *
  394. * Locks and activates the bus for the specified node.
  395. *
  396. * \param node Specifies the SPI bus node.
  397. * \param tmo Timeout in milliseconds. To disable timeout, set this
  398. * parameter to NUT_WAIT_INFINITE.
  399. *
  400. * \return 0 on success. In case of an error, -1 is returned and the bus
  401. * is not locked.
  402. */
  403. int GpioSpiBus0Select(NUTSPINODE * node, uint32_t tmo)
  404. {
  405. int rc;
  406. /* Sanity check. */
  407. NUTASSERT(node != NULL);
  408. NUTASSERT(node->node_stat != NULL);
  409. /* Allocate the bus. */
  410. rc = NutEventWait(&node->node_bus->bus_mutex, tmo);
  411. if (rc) {
  412. errno = EIO;
  413. } else {
  414. /* Do the update, if the mode update bit is set. */
  415. if (node->node_mode & SPI_MODE_UPDATE) {
  416. GpioSpiSetup(node);
  417. }
  418. /* Set clock output using the correct idle mode level. */
  419. #if defined(SBBI0_SCK_BIT)
  420. GpioPinConfigSet(SBBI0_SCK_PORT, SBBI0_SCK_BIT, GPIO_CFG_OUTPUT);
  421. GpioPinSetLow(SBBI0_SCK_PORT, (node->node_mode & SPI_MODE_CPOL) != 0);
  422. #endif
  423. /* Enable MOSI output and MISO input. */
  424. #if defined(SBBI0_MOSI_BIT)
  425. GpioPinConfigSet(SBBI0_MOSI_PORT, SBBI0_MOSI_BIT, GPIO_CFG_OUTPUT);
  426. #endif
  427. #if defined(SBBI0_MISO_BIT)
  428. GpioPinConfigSet(SBBI0_MISO_PORT, SBBI0_MISO_BIT, 0);
  429. #endif
  430. /* Activate the node's chip select. */
  431. if (GpioSpi0ChipSelect(node->node_cs, (node->node_mode & SPI_MODE_CSHIGH) != 0) == NULL) {
  432. /* Release the bus in case of an error. */
  433. NutEventPost(&node->node_bus->bus_mutex);
  434. rc = -1;
  435. }
  436. }
  437. return rc;
  438. }
  439. /*! \brief Deselect a device on the SPI bus.
  440. *
  441. * Deactivates the chip select and unlocks the bus.
  442. *
  443. * \param node Specifies the SPI bus node.
  444. *
  445. * \return Always 0.
  446. */
  447. int GpioSpiBus0Deselect(NUTSPINODE * node)
  448. {
  449. /* Sanity check. */
  450. NUTASSERT(node != NULL);
  451. NUTASSERT(node->node_bus != NULL);
  452. /* Deactivate the node's chip select. */
  453. GpioSpi0ChipSelect(node->node_cs, (node->node_mode & SPI_MODE_CSHIGH) == 0);
  454. /* Release the bus. */
  455. NutEventPost(&node->node_bus->bus_mutex);
  456. return 0;
  457. }
  458. /*!
  459. * \brief AVR SPI bus driver implementation structure.
  460. */
  461. NUTSPIBUS spiBus0Gpio = {
  462. NULL, /*!< Bus mutex semaphore (bus_mutex). */
  463. NULL, /*!< Bus ready signal (bus_ready). */
  464. 0, /*!< Unused bus base address (bus_base). */
  465. NULL, /*!< Bus interrupt handler (bus_sig). */
  466. GpioSpiBus0NodeInit, /*!< Initialize the bus (bus_initnode). */
  467. GpioSpiBus0Select, /*!< Select the specified device (bus_alloc). */
  468. GpioSpiBus0Deselect, /*!< Deselect the specified device (bus_release). */
  469. GpioSpiBus0Transfer, /*!< Transfer data to and from a specified device (bus_transfer). */
  470. NutSpiBusWait, /*!< Wait for bus transfer ready (bus_wait). */
  471. NutSpiBusSetMode, /*!< Set SPI mode of a specified device (bus_set_mode). */
  472. GpioSpiBusSetRate, /*!< Set clock rate of a specified device (bus_set_rate). */
  473. NutSpiBusSetBits /*!< Set number of data bits of a specified device (bus_set_bits). */
  474. };