Microprocessor and peripheral 2 assignments for AUTH
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

onewire_uart.c 17 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. /*!
  2. * \file onewire_uart.c
  3. * \brief
  4. * A target independent 1-wire implementation using a microprocessor's uart
  5. * for bit timing
  6. *
  7. * Copyright (C) 2015 Choutouridis Christos (http://www.houtouridis.net)
  8. *
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU Lesser General Public License as
  11. * published by the Free Software Foundation, either version 3
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. */
  23. #include "onewire_uart.h"
  24. /*
  25. * ========= Private helper macros ===========
  26. */
  27. /*!
  28. * Clear a virtual 64bit unsigned register.
  29. * \note
  30. * We use a uint8_t array[8] to represent that kind
  31. * of data for this module
  32. * \param _reg Pointer to register location. Usual the name of
  33. * The array
  34. */
  35. #define _clear_u64(_reg_) \
  36. memset ((void*)(_reg_), 0, 8*sizeof(uint8_t))
  37. /*!
  38. * Read a bit value of a virtual 64bit unsigned register.
  39. * \note
  40. * We use a uint8_t array[8] to represent that kind
  41. * of data for this module
  42. * \param _reg Pointer to register location. Usual the name of
  43. * The array
  44. * \param _bit The bit location we want to read
  45. */
  46. #define _read_bit_u64(_reg_, _bit_) \
  47. (_reg_[(_bit_)/8] & (1<<((_bit_)%8))) ? 1:0
  48. /*!
  49. * Write/modify a bit value from a virtual 64bit unsigned register.
  50. * \note
  51. * We use a uint8_t array[8] to represent that kind
  52. * of data for this module
  53. * \param _reg Pointer to register location. Usual the name of
  54. * The array
  55. * \param _bit The bit location we want to set
  56. * \param _v The value we want to set
  57. * \arg 0 Set to zero
  58. * \arg !0 Set to One
  59. */
  60. #define _write_bit_u64(_reg_, _bit_, _v_) \
  61. do { \
  62. if (_v_) _reg_[(_bit_)/8] |= 1 << ((_bit_)%8); \
  63. else _reg_[(_bit_)/8] &= ~(1 << ((_bit_)%8)); \
  64. } while (0)
  65. /*
  66. * ============= Private functions ===========
  67. */
  68. /* Data manipulation functions */
  69. static int _cmp_u64 (uint8_t *reg1, uint8_t *reg2);
  70. /* Set functions */
  71. static drv_status_en _set_baudrate (ow_uart_t *ow, ow_uart_state_en st);
  72. /* Bus functions */
  73. static uint8_t _write_bit (ow_uart_t *ow, uint8_t b);
  74. static uint8_t _read_bit (ow_uart_t *ow);
  75. /*!
  76. * \brief
  77. * Compare two 64bit virtual unsigned registers
  78. * \note
  79. * We use a uint8_t array[8] to represent that kind
  80. * of data for this module
  81. * \param reg1 Pointer to first register location. Usual the name of
  82. * the array
  83. * \param reg1 Pointer to 2nd register location. Usual the name of
  84. * the array
  85. * \return The comparison result
  86. * \arg 0 Registers are equal
  87. * \arg 1 Register 1 is larger than register 2
  88. * \arg -1 Register 2 is larger than register 1
  89. */
  90. static int _cmp_u64 (uint8_t *reg1, uint8_t *reg2) {
  91. int i;
  92. for (i=7 ; i>=0 ; --i) {
  93. if (reg1[i] > reg2[i]) return 1; /* reg1 > reg2 */
  94. else if (reg1[i] < reg2[i]) return -1; /* reg1 < reg2 */
  95. }
  96. return 0; /* reg1 equal reg2 */
  97. }
  98. /*!
  99. * \brief
  100. * Set UART Baudrate and handle all function calls and data
  101. * manipulation
  102. * \param ow Pointer to select 1-Wire structure for the operation.
  103. * \param st The 1-Wire operational state \sa ow_uart_state_en
  104. * \return The status of the operation
  105. * \arg DRV_ERROR Could not set baudrate (callback pointer function error)
  106. * \arg DRV_READY Success
  107. */
  108. static drv_status_en _set_baudrate (ow_uart_t *ow, ow_uart_state_en st)
  109. {
  110. uint32_t st_br;
  111. /* Get the desired baudrate */
  112. switch (st) {
  113. case OWS_RESET: st_br = ow->baudrate.reset; break;
  114. default:
  115. case OWS_OPER: st_br = ow->baudrate.oper; break;
  116. }
  117. if (ow->baudrate.current != st_br) {
  118. if (ow->io.br (st_br) != DRV_READY) return DRV_ERROR;
  119. ow->baudrate.current = st_br;
  120. }
  121. return DRV_READY;
  122. }
  123. /*!
  124. * \brief
  125. * Send a 1-Wire write bit
  126. *
  127. * --- --------------------------------------
  128. * Write 1 \ /
  129. * ----
  130. * RS: | | | | | | | | | | |
  131. * bit: st 0 1 2 3 4 5 6 7 st
  132. * < ------------- 87/11 usec ------------->
  133. * 8 bits, no parity, 1 stop
  134. * standard: BR: 115200 Overdrive: BR: 921600
  135. * TX: 0xFF
  136. * RX: 0xFF
  137. *
  138. * --- ------
  139. * Write 0 \ /
  140. * -------------------------------------
  141. * RS: | | | | | | | | | | |
  142. * bit: st 0 1 2 3 4 5 6 7 st
  143. * < ------------- 87/11 usec ------------->
  144. * 8 bits, no parity, 1 stop
  145. * standard: BR: 115200 Overdrive: BR: 921600
  146. * TX: 0x00
  147. * RX: 0x00
  148. *
  149. * \param ow Pointer to select 1-Wire structure for the operation.
  150. * \param b The bit to send
  151. * \return Status of the operation
  152. * \arg 0 Success
  153. * \arg 1 Fail
  154. */
  155. static uint8_t _write_bit (ow_uart_t *ow, uint8_t b)
  156. {
  157. uint8_t w;
  158. uint16_t r;
  159. /*
  160. * Make sure we are at the right baudrate
  161. */
  162. if (_set_baudrate (ow, OWS_OPER) != DRV_READY)
  163. return 1;
  164. /* Select frame to send and check the bus by evaluating the return value */
  165. w = (b) ? 0xFF : 0x00;
  166. r = ow->io.rw (w);
  167. if (r != w) return 1;
  168. else return 0;
  169. }
  170. /*!
  171. * \brief
  172. * Read a bit from the 1-Wire bus, return it and provide
  173. * the recovery time.
  174. *
  175. * --- - - - - - - - - - - - ------
  176. * Read \ / X X X X X X X X X X X X X X X /
  177. * ---- - - - - - - - - - - -
  178. * RS: | | | | | | | | | | |
  179. * bit: st 0 1 2 3 4 5 6 7 st
  180. * < ------------- 87/11 usec ------------->
  181. * ^
  182. * |
  183. * Master sample
  184. *
  185. * 8 bits, no parity, 1 stop
  186. * standard: BR: 115200 Overdrive: BR: 921600
  187. * TX: 0xFF
  188. * RX: {1 - 0xFF, 0 - [0x00 - 0xFE] }
  189. *
  190. * \return The answer
  191. * \arg 0 Read 0
  192. * \arg 1 Read 1 (This is also returned on transition error).
  193. */
  194. static uint8_t _read_bit (ow_uart_t *ow)
  195. {
  196. uint16_t r;
  197. /*
  198. * Make sure we are at the right baudrate
  199. */
  200. if (_set_baudrate (ow, OWS_OPER) != DRV_READY)
  201. return 1;
  202. /* Send frame for read */
  203. r = ow->io.rw (0xFF);
  204. /* Dispatch answer */
  205. if (r < 0xFF) return 0;
  206. else return 1;
  207. }
  208. /*
  209. * ============= PUBLIC 1-Wire API =============
  210. */
  211. /*
  212. * Link and Glue functions
  213. */
  214. /*!
  215. * \brief link driver's UART read-write function
  216. * \param ow pointer to select 1-Wire structure for the operation.
  217. * \param tx ow_uart_rx_ft pointer to drivers UART rx function
  218. */
  219. void ow_uart_link_rw (ow_uart_t *ow, ow_uart_rw_ft rw) {
  220. ow->io.rw = (ow_uart_rw_ft)((rw != 0) ? rw : 0);
  221. }
  222. /*!
  223. * \brief link driver's UART baudrate function
  224. * \param ow pointer to select 1-Wire structure for the operation.
  225. * \param tx ow_uart_tx_ft pointer to drivers UART baudrate function
  226. */
  227. void ow_uart_link_br (ow_uart_t *ow, ow_uart_br_ft br) {
  228. ow->io.br = (ow_uart_br_ft)((br != 0) ? br : 0);
  229. }
  230. /*
  231. * Set functions
  232. */
  233. /*!
  234. * \brief set 1-wire timing mode and update baudrate table.
  235. * If the owt parameter is not a valid ow_uart_timing_en
  236. * then set timings to OW_STANDTARD.
  237. * \param ow pointer to select 1-Wire structure for the operation.
  238. * \param owt Timing type
  239. * \arg OWT_STANDARD Use standard timing
  240. * \arg OWT_OVERDRIVE Use overdrive timing
  241. */
  242. void ow_uart_set_timing (ow_uart_t *ow, uint32_t owt) {
  243. ow->timing = (_ow_uart_is_timings(owt)) ? owt : OW_UART_T_STANDARD;
  244. switch (owt) {
  245. case OW_UART_T_STANDARD: _ow_baudrate_standard (ow->baudrate); break;
  246. case OW_UART_T_OVERDRIVE: _ow_baudrate_overdrive (ow->baudrate); break;
  247. }
  248. }
  249. /*
  250. * User Functions
  251. */
  252. /*!
  253. * \brief
  254. * De-Initialize the 1-Wire interface and leave bus pin in input state
  255. * \param ow pointer to select 1-Wire structure for the operation.
  256. * \return none
  257. */
  258. void ow_uart_deinit (ow_uart_t *ow)
  259. {
  260. // Clear data
  261. memset ((void*)ow, 0, sizeof (ow_uart_t));
  262. /*!<
  263. * This leaves the status = DRV_NOINIT
  264. */
  265. }
  266. /*!
  267. * \brief
  268. * Initialize the 1-Wire interface and leave bus high
  269. * \param ow pointer to select 1-Wire structure for the operation.
  270. * \return The driver status after init.
  271. * \arg DRV_READY
  272. * \arg DRV_ERROR
  273. */
  274. drv_status_en ow_uart_init (ow_uart_t *ow)
  275. {
  276. // Check requirements
  277. if (!ow->io.rw) return ow->status = DRV_ERROR;
  278. if (!ow->io.br) return ow->status = DRV_ERROR;
  279. // Init the bus
  280. ow->status = DRV_BUSY;
  281. if ( _ow_uart_is_timings(ow->timing) != 1) {
  282. ow->timing = OW_UART_T_STANDARD;
  283. _ow_baudrate_standard (ow->baudrate);
  284. }
  285. switch (ow->timing) {
  286. case OW_UART_T_STANDARD: _ow_baudrate_standard (ow->baudrate); break;
  287. case OW_UART_T_OVERDRIVE: _ow_baudrate_overdrive (ow->baudrate); break;
  288. }
  289. if (_set_baudrate (ow, OWS_RESET) != DRV_READY)
  290. return ow->status = DRV_ERROR;
  291. return ow->status = DRV_READY;
  292. }
  293. /*!
  294. * \brief
  295. * Generate a 1-wire reset
  296. *
  297. * --- ---- - - - -------
  298. * Reset \ / \ X X X /
  299. * -------------------- - - - -
  300. * RS: | | | | | | | | | | |
  301. * bit: st 0 1 2 3 4 5 6 7 st
  302. * < ---------- 1024/174 usec ------------->
  303. *
  304. * 8 bits, no parity, 1 stop
  305. * Standard: Overdrive :
  306. * BR: 9600, BR: 57600
  307. * TX: 0xF0, TX: 0xF8
  308. * RX: 0xF0 not present RX: 0xF8 not present
  309. * less if present less if present
  310. *
  311. * \note Does not handle alarm presence from DS2404/DS1994
  312. * \param None
  313. * \return The status of the operation
  314. * \arg DRV_ERROR Error, callback baudrate error or bus error
  315. * \arg DRV_NODEV If no presence detect was found
  316. * \arg DRV_READY Otherwise
  317. */
  318. drv_status_en ow_uart_reset (ow_uart_t *ow)
  319. {
  320. uint8_t w;
  321. uint16_t r;
  322. /*
  323. * Make sure we are at the write baudrate
  324. */
  325. if (_set_baudrate (ow, OWS_RESET) != DRV_READY)
  326. return DRV_ERROR;
  327. /* Select frame to send */
  328. w = (ow->timing == OW_UART_T_OVERDRIVE) ? 0xF8 : 0xF0;
  329. r = ow->io.rw (w);
  330. r = ow->io.rw (w); // Send it twice to make sure
  331. if (w>r) return DRV_READY;
  332. else if (w==r) return DRV_NODEV;
  333. else return DRV_ERROR;
  334. }
  335. /*!
  336. * \brief
  337. * Read a byte from 1-Wire bus
  338. * \param ow pointer to select 1-Wire structure for the operation.
  339. * \return The byte received.
  340. */
  341. uint8_t ow_uart_rx (ow_uart_t *ow)
  342. {
  343. uint8_t i;
  344. byte_t byte;
  345. for (i=8, byte=0 ; i>0 ; --i) {
  346. byte >>= 1; /* shift bits to right as LSB comes first */
  347. if (_read_bit (ow) != 0) byte |= 0x80; /* Mask bit to MSB */
  348. }
  349. return byte;
  350. }
  351. /*!
  352. * \brief
  353. * Write a byte to 1-Wire bus
  354. * \param ow pointer to select 1-Wire structure for the operation.
  355. * \param b: The byte to write
  356. * \return none
  357. */
  358. void ow_uart_tx (ow_uart_t *ow, byte_t byte)
  359. {
  360. uint8_t i;
  361. for (i=8 ; i>0 ; --i) {
  362. _write_bit (ow, byte & 0x01); /* Send LSB */
  363. byte >>= 1; /* shift bits to right */
  364. }
  365. }
  366. /*!
  367. * \brief
  368. * Write a byte to 1-Wire bus and read the response
  369. * \param ow Pointer to select 1-Wire structure for the operation.
  370. * \param byte The byte to write
  371. * \return The byte received.
  372. */
  373. uint8_t ow_uart_rw (ow_uart_t *ow, byte_t byte)
  374. {
  375. uint8_t i;
  376. byte_t ret;
  377. for (i=8, ret=0 ; i>0 ; --i) {
  378. ret >>= 1; /* shift read bits to right as LSB comes first */
  379. if ((byte & 0x01) != 0) ret |= (_read_bit (ow) != 0) ? 0x80 : 0x0;
  380. else _write_bit (ow, 0);
  381. byte >>= 1; /* shift bits to right */
  382. /*!<
  383. * If the bit is 1 we use the read sequence, as it has the same
  384. * waveform with write-1 and we get the slave response
  385. * If the bit is 0, we can not read the slave response so we just write-0
  386. */
  387. }
  388. return byte;
  389. }
  390. /*!
  391. * \brief
  392. * 1-Wire search algorithm based on maxim-ic application note 187
  393. *
  394. * \param ow Pointer to select 1-Wire structure for the operation.
  395. * \param romid Pointer to romid to return. If the search is success
  396. * this points to and 64bit long array with ROM ID
  397. * \return The status of the search
  398. * \arg DRV_NODEV (-1) Search was failed, No device found
  399. * \arg DRV_READY (1) Search is complete, all ROM IDs was found. This was the last
  400. * \arg DRV_BUSY (2) Search is succeed, plus there are more ROM IDs to found
  401. * \arg DRV_ERROR (3) Search failed, Reading error
  402. */
  403. drv_status_en ow_uart_search (ow_uart_t *ow, uint8_t *romid)
  404. {
  405. static uint8_t dec[8]; /*!<
  406. * Hold the algorithm's select bit when a discrepancy
  407. * is detected. We use this variable to navigate to the
  408. * ROM tree as we store the path we take each time (0-1).
  409. * Each bit represent a bit position in the ROM ID.
  410. */
  411. static uint8_t pos[8]; /*!<
  412. * Hold the discrepancy position. We use this variable to
  413. * navigate to the ROM tree as we store the crossroads(1) we encounter.
  414. * Each bit represent a bit position in the ROM ID.
  415. */
  416. uint8_t i, cur[8]; /* Current pass bit position, in a pos[8] like representation of it */
  417. uint8_t b, b1, b2; /* bit helper vars */
  418. if (ow_uart_reset (ow) != DRV_READY)
  419. return DRV_NODEV;
  420. ow_uart_tx (ow, 0xF0); /* Issue search command */
  421. for (i=0 ; i<64 ; ++i) {
  422. /* Get response pair bits */
  423. b1 = _read_bit (ow);
  424. b2 = _read_bit (ow);
  425. switch (b1 | (b2<<1)) {
  426. case 0x00: /* 00 - We have discrepancy */
  427. _write_bit_u64 (cur, i, 1);
  428. switch (_cmp_u64 (pos, cur)) {
  429. default:
  430. case -1: b = 0;
  431. _write_bit_u64 (pos, i, 1); break;
  432. case 0: b = 1;
  433. _write_bit_u64 (dec, i, 1); break;
  434. case 1: b = _read_bit_u64 (dec, i); break;
  435. /*<
  436. * -1) pos < cur: This discrepancy is the most far for now.
  437. * Mark position and select 0.
  438. * 0) pos == cur: This was the last discrepancy in the last pass.
  439. * Select the other branch this time (1).
  440. * 1) pos > cur: We had a discrepancy in a MSB than that, in a previous pass.
  441. * Continue with the last pass decision.
  442. */
  443. }
  444. /* Send selection and update romid */
  445. _write_bit (ow, b);
  446. _write_bit_u64 (romid, i, b);
  447. break;
  448. case 0x01: /* 01 - All bits of all ROMs are 1s */
  449. _write_bit (ow, 1);
  450. _write_bit_u64 (romid, i, 1); break;
  451. case 0x02: /* 10 - All bits of all ROMs are 0s */
  452. _write_bit (ow, 0);
  453. _write_bit_u64 (romid, i, 0); break;
  454. default:
  455. case 0x03: /* 11 - No device on the bus */
  456. _clear_u64 (romid);
  457. return DRV_NODEV;
  458. } /* switch (b1 | (b2<<1)) */
  459. } /* for */
  460. switch (_cmp_u64 (dec, pos)) {
  461. case -1: return DRV_BUSY;
  462. case 0: _clear_u64 (dec);
  463. _clear_u64 (pos);
  464. return DRV_READY;
  465. default:
  466. case 1: _clear_u64 (dec);
  467. _clear_u64 (pos);
  468. return DRV_ERROR;
  469. /*<
  470. * -1) des < pos: We have more leafs(ROMs) to found
  471. * 0) des == pos: We have found all the leafs(ROMs)
  472. * 1) des > pos: We have more decision that discrepancies ?!?!?, Error.
  473. */
  474. }
  475. }
  476. #undef _clear_u64
  477. #undef _read_bit_u64
  478. #undef _write_bit_u64
  479. #undef _ow_is_timings