sbbif0.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /*
  2. * Copyright (C) 2007 by egnite Software GmbH. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  25. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  27. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. *
  32. */
  33. /*
  34. * $Log$
  35. * Revision 1.4 2009/01/18 16:46:47 haraldkipp
  36. * GPIO header file changed.
  37. *
  38. * Revision 1.3 2008/10/23 08:54:07 haraldkipp
  39. * Include the correct header file.
  40. *
  41. * Revision 1.2 2008/08/11 06:59:42 haraldkipp
  42. * BSD types replaced by stdint types (feature request #1282721).
  43. *
  44. * Revision 1.1 2007/04/12 09:07:54 haraldkipp
  45. * Configurable SPI added.
  46. *
  47. */
  48. #include <sys/timer.h>
  49. #include <dev/gpio.h>
  50. #include <dev/sbbif0.h>
  51. /* SPI modes of all devices. */
  52. static ureg_t sbbi0_mode[SBBI0_MAX_DEVICES];
  53. /* SPI mode of the currently selected device. */
  54. static ureg_t sel_mode;
  55. /* SPI bit delay of all devices. */
  56. static ureg_t sbbi0_delay[SBBI0_MAX_DEVICES];
  57. /* SPI bit delay of the currently selected device. */
  58. static ureg_t sel_delay;
  59. /*!
  60. * \brief Set mode for a given device at SPI0.
  61. *
  62. * This is typically the first call in order to use the device. It will
  63. * not directly enable the SPI hardware. This is done when selecting
  64. * the device.
  65. *
  66. * \param ix The device index, starting at 0.
  67. * \param mode The mode to set.
  68. * - 0: Leading edge is rising, data sampled on rising edge.
  69. * - 1: Leading edge is rising, data sampled on falling edge.
  70. * - 2: Leading edge is falling, data sampled on falling edge.
  71. * - 3: Leading edge is falling, data sampled on rising edge.
  72. *
  73. * \return 0, if the device index and the mode are both valid. Otherwise
  74. * the return value will be -1.
  75. */
  76. int Sbbi0SetMode(ureg_t ix, ureg_t mode)
  77. {
  78. if (ix < SBBI0_MAX_DEVICES && mode <= 3) {
  79. sbbi0_mode[ix] = mode;
  80. return 0;
  81. }
  82. return -1;
  83. }
  84. /*!
  85. * \brief Set transfer rate for a given device at SPI0.
  86. *
  87. * This is currently a dummy and does nothing.
  88. *
  89. * \param ix The device index, starting at 0.
  90. * \param rate Transfer rate in bits per second.
  91. *
  92. */
  93. void Sbbi0SetSpeed(ureg_t ix, uint32_t rate)
  94. {
  95. uint32_t fosc = NutGetCpuClock() / 16;
  96. if (rate) {
  97. fosc /= rate;
  98. }
  99. if (fosc < 5) {
  100. sbbi0_delay[ix] = 0;
  101. }
  102. else if (fosc < 255) {
  103. sbbi0_delay[ix] = (ureg_t)fosc;
  104. } else {
  105. sbbi0_delay[ix] = 255;
  106. }
  107. }
  108. static INLINE void Sbbi0Delay(void)
  109. {
  110. if (sel_delay) {
  111. ureg_t d;
  112. for (d = sel_delay; d; d--) {
  113. _NOP();
  114. }
  115. }
  116. }
  117. /*!
  118. * \brief Enable the serial peripheral interface 0.
  119. *
  120. * Enables SPI with the parameters previously set by Sbbi0SetMode().
  121. *
  122. * \param ix The device index, starting at 0. The routine will not check
  123. * if this is valid.
  124. */
  125. void Sbbi0Enable(ureg_t ix)
  126. {
  127. sel_mode = sbbi0_mode[ix];
  128. sel_delay = sbbi0_delay[ix];
  129. SBBI0_MOSI_ENA();
  130. SBBI0_MOSI_CLR();
  131. SBBI0_MOSI_OUTPUT();
  132. SBBI0_MISO_ENA();
  133. SBBI0_SCK_ENA();
  134. if (sel_mode == 0 || sel_mode == 1) {
  135. SBBI0_SCK_CLR();
  136. }
  137. else {
  138. SBBI0_SCK_SET();
  139. }
  140. SBBI0_SCK_OUTPUT();
  141. }
  142. /*!
  143. * \brief Set or clear a configured reset line for a given device.
  144. *
  145. * Reset lines must be configured when building the system libraries.
  146. * This routine silently ignores them, if not configured.
  147. *
  148. * \param ix The device index, starting at 0.
  149. * \param hi If 0, the reset line is driven low. Otherwise the
  150. * line is driven high.
  151. */
  152. void Sbbi0ChipReset(ureg_t ix, ureg_t hi)
  153. {
  154. #if defined(SBBI0_RST0_BIT)
  155. if (ix == 0) {
  156. SBBI0_RST0_ENA();
  157. if (hi) {
  158. SBBI0_RST0_SET();
  159. } else {
  160. SBBI0_RST0_CLR();
  161. }
  162. SBBI0_RST0_OUTPUT();
  163. }
  164. #endif
  165. #if defined(SBBI0_RST1_BIT)
  166. if (ix == 1) {
  167. SBBI0_RST1_ENA();
  168. if (hi) {
  169. SBBI0_RST1_SET();
  170. } else {
  171. SBBI0_RST1_CLR();
  172. }
  173. SBBI0_RST1_OUTPUT();
  174. }
  175. #endif
  176. #if defined(SBBI0_RST2_BIT)
  177. if (ix == 2) {
  178. SBBI0_RST2_ENA();
  179. if (hi) {
  180. SBBI0_RST2_SET();
  181. } else {
  182. SBBI0_RST2_CLR();
  183. }
  184. SBBI0_RST2_OUTPUT();
  185. }
  186. #endif
  187. #if defined(SBBI0_RST3_BIT)
  188. if (ix == 3) {
  189. SBBI0_RST3_ENA();
  190. if (hi) {
  191. SBBI0_RST3_SET();
  192. } else {
  193. SBBI0_RST3_CLR();
  194. }
  195. SBBI0_RST3_OUTPUT();
  196. }
  197. #endif
  198. }
  199. /*!
  200. * \brief Set or clear a configured chip select for a given device.
  201. *
  202. * Chip selects must be configured when building the system libraries.
  203. * This routine silently ignores selects, if they are not configured.
  204. *
  205. * \param ix The device index, starting at 0. Same as the chip select
  206. * number.
  207. * \param hi If 0, the chip select is driven low. Otherwise the
  208. * line is driven high.
  209. */
  210. void Sbbi0ChipSelect(ureg_t ix, ureg_t hi)
  211. {
  212. #if defined(SBBI0_CS0_BIT)
  213. if (ix == 0) {
  214. SBBI0_CS0_ENA();
  215. if (hi) {
  216. SBBI0_CS0_SET();
  217. } else {
  218. SBBI0_CS0_CLR();
  219. }
  220. SBBI0_CS0_OUTPUT();
  221. }
  222. #endif
  223. #if defined(SBBI0_CS1_BIT)
  224. if (ix == 1) {
  225. SBBI0_CS1_ENA();
  226. if (hi) {
  227. SBBI0_CS1_SET();
  228. } else {
  229. SBBI0_CS1_CLR();
  230. }
  231. SBBI0_CS1_OUTPUT();
  232. }
  233. #endif
  234. #if defined(SBBI0_CS2_BIT)
  235. if (ix == 2) {
  236. SBBI0_CS2_ENA();
  237. if (hi) {
  238. SBBI0_CS2_SET();
  239. } else {
  240. SBBI0_CS2_CLR();
  241. }
  242. SBBI0_CS2_OUTPUT();
  243. }
  244. #endif
  245. #if defined(SBBI0_CS3_BIT)
  246. if (ix == 3) {
  247. SBBI0_CS3_ENA();
  248. if (hi) {
  249. SBBI0_CS3_SET();
  250. } else {
  251. SBBI0_CS3_CLR();
  252. }
  253. SBBI0_CS3_OUTPUT();
  254. }
  255. #endif
  256. }
  257. /*!
  258. * \brief Select the device at a given chip select.
  259. *
  260. * Enables the serial peripheral interface with the parameters
  261. * previously set for the given device by Sbbi0SetMode() and
  262. * Sbbi0SetSpeed(). Then the configured chip select line is
  263. * driven high.
  264. *
  265. * \param ix The device index, starting at 0. The routine will not
  266. * check if this is a valid number.
  267. */
  268. void Sbbi0SelectDevice(ureg_t ix)
  269. {
  270. Sbbi0Enable(ix);
  271. Sbbi0ChipSelect(ix, 1);
  272. }
  273. /*!
  274. * \brief Deselect the device at a given chip select.
  275. *
  276. * The configured chip select line will be driven low.
  277. *
  278. * \param ix The device index, starting at 0. The routine will not
  279. * check if this is a valid number.
  280. */
  281. void Sbbi0DeselectDevice(ureg_t ix)
  282. {
  283. Sbbi0ChipSelect(ix, 0);
  284. }
  285. /*!
  286. * \brief Select the device at a given negated chip select.
  287. *
  288. * Enables the serial peripheral interface with the parameters
  289. * previously set for the given device by Sbbi0SetMode() and
  290. * Sbbi0SetSpeed(). Then the configured chip select line is
  291. * driven low.
  292. *
  293. * \param ix The device index, starting at 0. The routine will not
  294. * check if this is a valid number.
  295. */
  296. void Sbbi0NegSelectDevice(ureg_t ix)
  297. {
  298. Sbbi0Enable(ix);
  299. Sbbi0ChipSelect(ix, 0);
  300. }
  301. /*!
  302. * \brief Deselect the device at a given negated chip select.
  303. *
  304. * The configured chip select line will be driven high.
  305. *
  306. * \param ix The device index, starting at 0. The routine will not
  307. * check if this is a valid number.
  308. */
  309. void Sbbi0NegDeselectDevice(ureg_t ix)
  310. {
  311. Sbbi0ChipSelect(ix, 1);
  312. }
  313. /*!
  314. * \brief Exchange a byte with the currently selected SPI device.
  315. *
  316. * \param data Byte to transmit.
  317. *
  318. * \return Received byte.
  319. */
  320. uint8_t Sbbi0Byte(uint8_t data)
  321. {
  322. ureg_t mask;
  323. if (sel_mode == 3) {
  324. /* Mode 3: Leading edge is falling, data sampled on rising edge. */
  325. for (mask = 0x80; mask; mask >>= 1) {
  326. SBBI0_SCK_CLR();
  327. if (data & mask) {
  328. SBBI0_MOSI_SET();
  329. } else {
  330. SBBI0_MOSI_CLR();
  331. }
  332. Sbbi0Delay();
  333. SBBI0_SCK_SET();
  334. if (SBBI0_MISO_TST()) {
  335. data |= mask;
  336. }
  337. else {
  338. data &= ~mask;
  339. }
  340. Sbbi0Delay();
  341. }
  342. }
  343. else if (sel_mode == 2) {
  344. /* Mode 2: Leading edge is falling, data sampled on falling edge. */
  345. for (mask = 0x80; mask; mask >>= 1) {
  346. SBBI0_SCK_SET();
  347. if (data & mask) {
  348. SBBI0_MOSI_SET();
  349. } else {
  350. SBBI0_MOSI_CLR();
  351. }
  352. Sbbi0Delay();
  353. SBBI0_SCK_CLR();
  354. if (SBBI0_MISO_TST()) {
  355. data |= mask;
  356. }
  357. else {
  358. data &= ~mask;
  359. }
  360. Sbbi0Delay();
  361. }
  362. SBBI0_SCK_SET();
  363. }
  364. else if (sel_mode == 1) {
  365. /* Mode 1: Leading edge is rising, data sampled on falling edge. */
  366. for (mask = 0x80; mask; mask >>= 1) {
  367. SBBI0_SCK_SET();
  368. if (data & mask) {
  369. SBBI0_MOSI_SET();
  370. } else {
  371. SBBI0_MOSI_CLR();
  372. }
  373. Sbbi0Delay();
  374. SBBI0_SCK_CLR();
  375. if (SBBI0_MISO_TST()) {
  376. data |= mask;
  377. }
  378. else {
  379. data &= ~mask;
  380. }
  381. Sbbi0Delay();
  382. }
  383. }
  384. else {
  385. /* Mode 0: Leading edge is rising, data sampled on rising edge. */
  386. for (mask = 0x80; mask; mask >>= 1) {
  387. SBBI0_SCK_CLR();
  388. if (data & mask) {
  389. SBBI0_MOSI_SET();
  390. } else {
  391. SBBI0_MOSI_CLR();
  392. }
  393. Sbbi0Delay();
  394. SBBI0_SCK_SET();
  395. if (SBBI0_MISO_TST()) {
  396. data |= mask;
  397. }
  398. else {
  399. data &= ~mask;
  400. }
  401. Sbbi0Delay();
  402. }
  403. SBBI0_SCK_CLR();
  404. }
  405. return data;
  406. }
  407. /*!
  408. * \brief Exchange a specified number of bytes with the currently selected SPI device.
  409. *
  410. * It is assumed, that the serial peripheral interface has been properly
  411. * initialized by calling Sbbi0SetMode() and optionally Sbbi0SetSpeed().
  412. *
  413. * Further it is assumed, that the chip select (if there is one) had
  414. * been enabled by a previous call to Sbbi0SelectDevice() or
  415. * Sbbi0NegSelectDevice().
  416. *
  417. * \param wdata Pointer to the data to transmit.
  418. * \param rdata Pointer to a buffer that receives the data from the device.
  419. * Can be set to NULL for transmit only. May also point to the
  420. * tranmit buffer, in which case the transmitted bytes are
  421. * replaced by the bytes received.
  422. */
  423. void Sbbi0Transact(const void *wdata, void *rdata, size_t len)
  424. {
  425. const uint8_t *wp = (const uint8_t *)wdata;
  426. if (rdata) {
  427. uint8_t *rp = (uint8_t *)rdata;
  428. while(len--) {
  429. *rp++ = Sbbi0Byte(*wp);
  430. wp++;
  431. }
  432. } else {
  433. while(len--) {
  434. Sbbi0Byte(*wp);
  435. wp++;
  436. }
  437. }
  438. }