spidigio.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. /*
  2. * Copyright (C) 2001-2003 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. * \file arch/avr/dev/spidigio.c
  35. * \brief AVR external shift register I/O support.
  36. *
  37. * \verbatim
  38. * $Id: spidigio.c 4706 2012-10-06 17:42:01Z haraldkipp $
  39. * \endverbatim
  40. */
  41. /*
  42. * This header file specifies the hardware port bits. You
  43. * need to change or replace it, if your hardware differs.
  44. */
  45. #include <cfg/arch/avr.h>
  46. /*
  47. * The following header file contains the prototypes of
  48. * all global functions, which this module provides.
  49. */
  50. #include <dev/spidigio.h>
  51. /*
  52. * Determine ports, which had not been explicitly configured.
  53. */
  54. #ifndef SPIDIGIO_SOUT_BIT
  55. #define SPIDIGIO_SOUT_BIT 5
  56. #define SPIDIGIO_SOUT_AVRPORT AVRPORTD
  57. #define SPIDIGIO_SIN_BIT 6
  58. #define SPIDIGIO_SIN_AVRPORT AVRPORTD
  59. #define SPIDIGIO_SCLK_BIT 7
  60. #define SPIDIGIO_SCLK_AVRPORT AVRPORTD
  61. #define SPIDIGIO_LDI_BIT 7
  62. #define SPIDIGIO_LDI_AVRPORT AVRPORTB
  63. #define SPIDIGIO_LDO_BIT 5
  64. #define SPIDIGIO_LDO_AVRPORT AVRPORTB
  65. #endif
  66. #if (SPIDIGIO_SOUT_AVRPORT == AVRPORTB)
  67. #define SPIDIGIO_SOUT_PORT PORTB
  68. #define SPIDIGIO_SOUT_DDR DDRB
  69. #elif (SPIDIGIO_SOUT_AVRPORT == AVRPORTD)
  70. #define SPIDIGIO_SOUT_PORT PORTD
  71. #define SPIDIGIO_SOUT_DDR DDRD
  72. #elif (SPIDIGIO_SOUT_AVRPORT == AVRPORTE)
  73. #define SPIDIGIO_SOUT_PORT PORTE
  74. #define SPIDIGIO_SOUT_DDR DDRE
  75. #elif (SPIDIGIO_SOUT_AVRPORT == AVRPORTF)
  76. #define SPIDIGIO_SOUT_PORT PORTF
  77. #define SPIDIGIO_SOUT_DDR DDRF
  78. #endif
  79. #if (SPIDIGIO_SIN_AVRPORT == AVRPORTB)
  80. #define SPIDIGIO_SIN_PORT PORTB
  81. #define SPIDIGIO_SIN_PIN PINB
  82. #define SPIDIGIO_SIN_DDR DDRB
  83. #elif (SPIDIGIO_SIN_AVRPORT == AVRPORTD)
  84. #define SPIDIGIO_SIN_PORT PORTD
  85. #define SPIDIGIO_SIN_PIN PIND
  86. #define SPIDIGIO_SIN_DDR DDRD
  87. #elif (SPIDIGIO_SIN_AVRPORT == AVRPORTE)
  88. #define SPIDIGIO_SIN_PORT PORTE
  89. #define SPIDIGIO_SIN_PIN PINE
  90. #define SPIDIGIO_SIN_DDR DDRE
  91. #elif (SPIDIGIO_SIN_AVRPORT == AVRPORTF)
  92. #define SPIDIGIO_SIN_PORT PORTF
  93. #define SPIDIGIO_SIN_PIN PINF
  94. #define SPIDIGIO_SIN_DDR DDRF
  95. #endif
  96. #if (SPIDIGIO_SCLK_AVRPORT == AVRPORTB)
  97. #define SPIDIGIO_SCLK_PORT PORTB
  98. #define SPIDIGIO_SCLK_DDR DDRB
  99. #elif (SPIDIGIO_SCLK_AVRPORT == AVRPORTD)
  100. #define SPIDIGIO_SCLK_PORT PORTD
  101. #define SPIDIGIO_SCLK_DDR DDRD
  102. #elif (SPIDIGIO_SCLK_AVRPORT == AVRPORTE)
  103. #define SPIDIGIO_SCLK_PORT PORTE
  104. #define SPIDIGIO_SCLK_DDR DDRE
  105. #elif (SPIDIGIO_SCLK_AVRPORT == AVRPORTF)
  106. #define SPIDIGIO_SCLK_PORT PORTF
  107. #define SPIDIGIO_SCLK_DDR DDRF
  108. #endif /* SPIDIGIO_SCLK_AVRPORT */
  109. #if (SPIDIGIO_LDO_AVRPORT == AVRPORTB)
  110. #define SPIDIGIO_LDO_PORT PORTB
  111. #define SPIDIGIO_LDO_DDR DDRB
  112. #elif (SPIDIGIO_LDO_AVRPORT == AVRPORTD)
  113. #define SPIDIGIO_LDO_PORT PORTD
  114. #define SPIDIGIO_LDO_DDR DDRD
  115. #elif (SPIDIGIO_LDO_AVRPORT == AVRPORTE)
  116. #define SPIDIGIO_LDO_PORT PORTE
  117. #define SPIDIGIO_LDO_DDR DDRE
  118. #elif (SPIDIGIO_LDO_AVRPORT == AVRPORTF)
  119. #define SPIDIGIO_LDO_PORT PORTF
  120. #define SPIDIGIO_LDO_DDR DDRF
  121. #endif /* SPIDIGIO_LDO_AVRPORT */
  122. #if (SPIDIGIO_LDI_AVRPORT == AVRPORTB)
  123. #define SPIDIGIO_LDI_PORT PORTB
  124. #define SPIDIGIO_LDI_DDR DDRB
  125. #elif (SPIDIGIO_LDI_AVRPORT == AVRPORTD)
  126. #define SPIDIGIO_LDI_PORT PORTD
  127. #define SPIDIGIO_LDI_DDR DDRD
  128. #elif (SPIDIGIO_LDI_AVRPORT == AVRPORTE)
  129. #define SPIDIGIO_LDI_PORT PORTE
  130. #define SPIDIGIO_LDI_DDR DDRE
  131. #elif (SPIDIGIO_LDI_AVRPORT == AVRPORTF)
  132. #define SPIDIGIO_LDI_PORT PORTF
  133. #define SPIDIGIO_LDI_DDR DDRF
  134. #endif /* SPIDIGIO_LDI_AVRPORT */
  135. /*!
  136. * \addtogroup xgSpiDigIo
  137. */
  138. /*@{*/
  139. static ureg_t us_loops = 1;
  140. /*!
  141. * \brief Loop for a small number of microseconds.
  142. *
  143. * This call will not release the CPU and will not switch to another
  144. * thread. It simply executes a number of NOP (no operation) assembly
  145. * statements.
  146. *
  147. * The routine is quite limited. Depending on the value of the
  148. * global variable us_loop, which is calculated in SpiDigitalInit(),
  149. * and based on the CPU clock. On a 14 MHz standard Ethernut its
  150. * value is 3, allowing a maximum delay of 85 microseconds.
  151. *
  152. * \param us Approximate delay in microseconds.
  153. *
  154. */
  155. static INLINE void delay_us(ureg_t us)
  156. {
  157. ureg_t _cnt = us * us_loops;
  158. while (_cnt--) {
  159. /*
  160. * A no-operation assembly statement is used here.
  161. * Without this statement, the compiler may completely
  162. * wipe out the loop during optimization.
  163. */
  164. _NOP();
  165. }
  166. }
  167. /*!
  168. * \brief Toggle shift register clock to perform a shift.
  169. *
  170. * Shifting is done on the falling edge of the clock line.
  171. *
  172. * The required puls width is 150 ns for the UCN5841 output and only
  173. * 25 ns for the SN74HC165 input shift register hardware. However,
  174. * longer cables and additional noise filters may increase the required
  175. * minimum pulse length. On the reference hardware the rising edge of
  176. * the RC filters used is about 3 microseconds.
  177. */
  178. static INLINE void ShiftDigital(void)
  179. {
  180. /* Switch clock line low. */
  181. cbi(SPIDIGIO_SCLK_PORT, SPIDIGIO_SCLK_BIT);
  182. /* Four microseconds delay. */
  183. delay_us(4);
  184. /* Switch clock line back high. */
  185. sbi(SPIDIGIO_SCLK_PORT, SPIDIGIO_SCLK_BIT);
  186. /* Four microseconds delay. */
  187. delay_us(4);
  188. }
  189. /*!
  190. * \brief Query digital inputs.
  191. *
  192. * SpiDigitalInit() must have been called by the application before
  193. * calling this function.
  194. *
  195. * This routine does not check the validity of the parameter.
  196. *
  197. * \param num Number of bits to query, typically 8, 16, 24 or the maximum
  198. * value of 32. This number should exactly match the number of
  199. * input pins. If it is lower, only the most significant bits
  200. * are returned. However, this may be used by an application
  201. * to scan these bits more often with reduced overhead.
  202. *
  203. * \return Binary value of the requested inputs. Only the specified number
  204. * of bits are used. Bit 0 is the one, which has been shifted out
  205. * last.
  206. */
  207. uint32_t SpiDigitalGet(ureg_t num)
  208. {
  209. uint32_t bits = 0;
  210. cbi(SPIDIGIO_SOUT_PORT, SPIDIGIO_SOUT_BIT);
  211. /*
  212. * Toggle the input strobe. The shift register will latch
  213. * the current value at the parallel inputs into the shift
  214. * register.
  215. */
  216. sbi(SPIDIGIO_LDI_PORT, SPIDIGIO_LDI_BIT);
  217. delay_us(4);
  218. cbi(SPIDIGIO_LDI_PORT, SPIDIGIO_LDI_BIT);
  219. delay_us(4);
  220. /* Loop for the specified number of bits. */
  221. while (num--) {
  222. /* Shift the resulting value first. */
  223. bits <<= 1;
  224. /*
  225. * The shift register's serial output pin is connected to
  226. * the port input pin. If this input is high, set the least
  227. * significant bit of the resulting value. Otherwise leave
  228. * it zero.
  229. */
  230. if (bit_is_set(SPIDIGIO_SIN_PIN, SPIDIGIO_SIN_BIT)) {
  231. bits |= 1;
  232. }
  233. /*
  234. * This will toggle the clock line, presenting the next bit
  235. * at the shift register's serial output pin.
  236. */
  237. ShiftDigital();
  238. }
  239. return bits;
  240. }
  241. /*!
  242. * \brief Set digital outputs.
  243. *
  244. * SpiDigitalInit() must have been called by the application before
  245. * calling this function.
  246. *
  247. * This routine does not check the validity of any parameter.
  248. *
  249. * \param num Number of bits to set, typically 8, 16, 24 or 32, which is
  250. * the maximum. The number must not be lower than the number
  251. * of shift register output bits.
  252. * \param bits The bit value to set. Only the number of bits specified are
  253. * used, of which the most significant bit is shifted in first.
  254. */
  255. void SpiDigitalSet(ureg_t num, uint32_t bits)
  256. {
  257. uint32_t mask;
  258. /* Nothing to do, if the number of bits is zero. */
  259. if (num) {
  260. /*
  261. * Create the bit mask of the most significant bit. Note the UL
  262. * specifier. Most compilers will use integers by default, when
  263. * calculating of the right side. They do not consider the left
  264. * side. In our case this would create unexpected results, if
  265. * integers are 16 bit only.
  266. */
  267. mask = 1UL << (num - 1);
  268. /* Loop for the specified number of bits. */
  269. while (num--) {
  270. /*
  271. * The shift register input is connected to the CPU output.
  272. * If the currently masked bit is set, then set the CPU
  273. * output pin to high level. Otherwise set the output
  274. * pin to low.
  275. */
  276. if (bits & mask) {
  277. /* Set bit instruction. */
  278. sbi(SPIDIGIO_SOUT_PORT, SPIDIGIO_SOUT_BIT);
  279. }
  280. else {
  281. /* Clear bit instruction. */
  282. cbi(SPIDIGIO_SOUT_PORT, SPIDIGIO_SOUT_BIT);
  283. }
  284. /* Let the value get settled. */
  285. delay_us(4);
  286. /* Toggle the shift register clock line. */
  287. ShiftDigital();
  288. /* Left shift the mask by one. */
  289. mask >>= 1;
  290. }
  291. /*
  292. * Toggle the output strobe line. The shift register will latch
  293. * the shifted value and present it at its parallel output pins.
  294. */
  295. cbi(SPIDIGIO_LDO_PORT, SPIDIGIO_LDO_BIT);
  296. delay_us(4);
  297. sbi(SPIDIGIO_LDO_PORT, SPIDIGIO_LDO_BIT);
  298. }
  299. }
  300. /*!
  301. * \brief Return the number of shifts required to get an expected bit
  302. * value at the input.
  303. *
  304. * When calling this function, it is assumed, that the shift register is
  305. * already filled with the complement of the input bit.
  306. *
  307. * If the search mode is zero, then the function will return the number
  308. * of shifts until the bit value at the input appears at the output.
  309. * This can be used to detect the total size of the shift register.
  310. *
  311. * If the search mode is set to one, then the input strobe will be
  312. * toggled before shifting and the function returns the number of shifts
  313. * until the first unmodified bit appears. This can be used to detect
  314. * the number of inputs. This method requires, that the parallel shift
  315. * register inputs do not change during shifting. If they do change, then
  316. * the resulting number will be lower than expected. The routine may be
  317. * called several times to compensate this problem.
  318. *
  319. * \param num Total number of shifts, should be 8, 16, 24 or 32.
  320. * \param bit Input bit, either 0 or 1.
  321. * \param smode Search mode.
  322. *
  323. * \return The number of shifts.
  324. */
  325. static ureg_t CountDigitalShifts(ureg_t num, ureg_t bit, ureg_t smode)
  326. {
  327. ureg_t i;
  328. ureg_t rc = 0;
  329. /*
  330. * Toggle input strobe if we are searching the last modified bit.
  331. * Input lines are latched on the falling edge.
  332. */
  333. if (smode) {
  334. sbi(SPIDIGIO_LDI_PORT, SPIDIGIO_LDI_BIT);
  335. delay_us(4);
  336. cbi(SPIDIGIO_LDI_PORT, SPIDIGIO_LDI_BIT);
  337. }
  338. /*
  339. * Set the shift register input.
  340. */
  341. if (bit) {
  342. sbi(SPIDIGIO_SOUT_PORT, SPIDIGIO_SOUT_BIT);
  343. } else {
  344. cbi(SPIDIGIO_SOUT_PORT, SPIDIGIO_SOUT_BIT);
  345. }
  346. delay_us(4);
  347. /*
  348. * Do the requested number of shifts and watch the requested bit
  349. * position.
  350. */
  351. for (i = 0; i < num; i++) {
  352. if (bit_is_set(SPIDIGIO_SIN_PIN, SPIDIGIO_SIN_BIT)) {
  353. if (bit) {
  354. if (smode) {
  355. rc = i + 1;
  356. } else if (rc == 0) {
  357. rc = i + 1;
  358. }
  359. }
  360. } else {
  361. if (bit == 0) {
  362. if (smode) {
  363. rc = i + 1;
  364. } else if (rc == 0) {
  365. rc = i + 1;
  366. }
  367. }
  368. }
  369. ShiftDigital();
  370. }
  371. return rc;
  372. }
  373. /*!
  374. * \brief Initialize the digital I/O shift register interface.
  375. *
  376. * This routine must be called before using the interface.
  377. *
  378. * Automatically detects the number of digital inputs and outputs. However,
  379. * the method used is limited and may fail on fast changing inputs. The
  380. * application should check the result for plausibility. It is save to
  381. * call the routine more than once.
  382. *
  383. * \param inputs Pointer to an 8-bit value, where the number of
  384. * detected inputs will be stored.
  385. * \param outputs Pointer to an 8-bit value, where the number of
  386. * detected outputs will be stored.
  387. */
  388. void SpiDigitalInit(ureg_t * inputs, ureg_t * outputs)
  389. {
  390. ureg_t total = 0;
  391. ureg_t i;
  392. ureg_t cnt;
  393. /*
  394. * Determine the delay loop count based on the CPU clock.
  395. */
  396. if ((us_loops = (NutGetCpuClock() + 500000UL) / 4000000UL) < 1) {
  397. us_loops = 1;
  398. }
  399. /*
  400. * Set serial data output line direction.
  401. */
  402. sbi(SPIDIGIO_SOUT_DDR, SPIDIGIO_SOUT_BIT);
  403. /*
  404. * Set serial data input line direction and enable pullup.
  405. */
  406. sbi(SPIDIGIO_SIN_PORT, SPIDIGIO_SIN_BIT);
  407. cbi(SPIDIGIO_SIN_DDR, SPIDIGIO_SIN_BIT);
  408. /*
  409. * Clock. Input data is shifted on the falling, output data on the
  410. * rising edge.
  411. */
  412. sbi(SPIDIGIO_SCLK_PORT, SPIDIGIO_SCLK_BIT);
  413. sbi(SPIDIGIO_SCLK_DDR, SPIDIGIO_SCLK_BIT);
  414. /*
  415. * UCN5841 output strobe. Shift register data appears on the output
  416. * pins as long as this line is held high.
  417. */
  418. sbi(SPIDIGIO_LDO_PORT, SPIDIGIO_LDO_BIT);
  419. sbi(SPIDIGIO_LDO_DDR, SPIDIGIO_LDO_BIT);
  420. /*
  421. * SN74HC165 input strobe. Data at input pins is latched in the shift
  422. * register on the falling edge.
  423. */
  424. cbi(SPIDIGIO_LDI_PORT, SPIDIGIO_LDI_BIT);
  425. sbi(SPIDIGIO_LDI_DDR, SPIDIGIO_LDI_BIT);
  426. /*
  427. * Fill the shift register with zeros. Then shift in ones until the
  428. * first appears on the output. This gives us the total size plus one
  429. * of the shift register.
  430. */
  431. CountDigitalShifts(32, 0, 0);
  432. total = CountDigitalShifts(32, 1, 0) - 1;
  433. /*
  434. * Determine the number of inputs. We do this five times for zeros
  435. * and ones and take the maximum count. This way we compensate
  436. * changing inputs while counting.
  437. */
  438. *inputs = 0;
  439. for (i = 0; i < 5; i++) {
  440. if ((cnt = CountDigitalShifts(total, 0, 1)) > *inputs) {
  441. *inputs = cnt;
  442. }
  443. if ((cnt = CountDigitalShifts(total, 1, 1)) > *inputs) {
  444. *inputs = cnt;
  445. }
  446. }
  447. *outputs = total - *inputs;
  448. }
  449. /*@}*/