Microprocessor and peripheral 2 assignments for AUTH
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

528 lines
16 KiB

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