Guest User

my_twi_master.c

a guest
May 7th, 2015
593
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.80 KB | None | 0 0
  1. /* Copyright (c) 2009 Nordic Semiconductor. All Rights Reserved.
  2. *
  3. * The information contained herein is property of Nordic Semiconductor ASA.
  4. * Terms and conditions of usage are described in detail in NORDIC
  5. * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
  6. *
  7. * Licensees are granted free, non-transferable use of the information. NO
  8. * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
  9. * the file.
  10. *
  11. */
  12.  
  13. // A copy of twi_sw_master.c
  14.  
  15. #include <stdbool.h>
  16. #include <stdint.h>
  17. #include "my_twi_master.h"
  18. #include "nrf_delay.h"
  19. #include "my_twi_master_config.h"
  20.  
  21. /*lint -e415 -e845 -save "Out of bounds access" */
  22. #define TWI_SDA_STANDARD0_NODRIVE1() do { \
  23. NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \
  24. |(GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \
  25. |(GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) \
  26. |(GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \
  27. |(GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); \
  28. } while (0) /*!< Configures SDA pin to Standard-0, No-drive 1 */
  29.  
  30.  
  31. #define TWI_SCL_STANDARD0_NODRIVE1() do { \
  32. NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \
  33. |(GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \
  34. |(GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) \
  35. |(GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \
  36. |(GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); \
  37. } while (0) /*!< Configures SCL pin to Standard-0, No-drive 1 */
  38.  
  39.  
  40. /*lint -restore */
  41.  
  42. #ifndef TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE
  43. #define TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE (0UL) //!< Unit is number of empty loops. Timeout for SMBus devices is 35 ms. Set to zero to disable slave timeout altogether.
  44. #endif
  45.  
  46.  
  47. // Some static methods with scope only in this file
  48. static bool twi_master_clear_bus(void);
  49. static bool twi_master_wait_while_scl_low(void);
  50. static bool twi_master_issue_startcondition(void);
  51. static bool twi_master_issue_stopcondition(void);
  52. static bool twi_master_clock_byte(uint_fast8_t databyte);
  53. static bool twi_master_clock_byte_in(uint8_t * databyte, bool ack);
  54.  
  55. bool twi_master_init(void)
  56. {
  57. // Configure both pins to output Standard 0, No-drive (open-drain) 1
  58. TWI_SDA_STANDARD0_NODRIVE1(); /*lint !e416 "Creation of out of bounds pointer" */
  59. TWI_SCL_STANDARD0_NODRIVE1(); /*lint !e416 "Creation of out of bounds pointer" */
  60.  
  61. // Configure SCL as output
  62. TWI_SCL_HIGH();
  63. TWI_SCL_OUTPUT();
  64.  
  65. // Configure SDA as output
  66. TWI_SDA_HIGH();
  67. TWI_SDA_OUTPUT();
  68.  
  69. return twi_master_clear_bus();
  70. }
  71.  
  72. bool twi_master_transfer(uint8_t address, uint8_t * data, uint8_t data_length, bool issue_stop_condition)
  73. {
  74. bool transfer_succeeded = true;
  75.  
  76. transfer_succeeded &= twi_master_issue_startcondition();
  77. transfer_succeeded &= twi_master_clock_byte(address);
  78.  
  79. if (address & TWI_READ_BIT)
  80. {
  81. /* Transfer direction is from Slave to Master */
  82. while (data_length-- && transfer_succeeded)
  83. {
  84. // To indicate to slave that we've finished transferring last data byte
  85. // we need to NACK the last transfer.
  86. if (data_length == 0)
  87. {
  88. transfer_succeeded &= twi_master_clock_byte_in(data, (bool)false);
  89. }
  90. else
  91. {
  92. transfer_succeeded &= twi_master_clock_byte_in(data, (bool)true);
  93. }
  94. data++;
  95. }
  96. }
  97. else
  98. {
  99. /* Transfer direction is from Master to Slave */
  100. while (data_length-- && transfer_succeeded)
  101. {
  102. transfer_succeeded &= twi_master_clock_byte(*data);
  103. data++;
  104. }
  105. }
  106.  
  107. if (issue_stop_condition || !transfer_succeeded)
  108. {
  109. transfer_succeeded &= twi_master_issue_stopcondition();
  110. }
  111.  
  112. return transfer_succeeded;
  113. }
  114.  
  115. /**
  116. * @brief Function for detecting stuck slaves and tries to clear the bus.
  117. *
  118. * @return
  119. * @retval false Bus is stuck.
  120. * @retval true Bus is clear.
  121. */
  122. static bool twi_master_clear_bus(void)
  123. {
  124. bool bus_clear;
  125.  
  126. TWI_SDA_HIGH();
  127. TWI_SCL_HIGH();
  128. TWI_DELAY();
  129.  
  130.  
  131. if (TWI_SDA_READ() == 1 && TWI_SCL_READ() == 1)
  132. {
  133. bus_clear = true;
  134. }
  135. else if (TWI_SCL_READ() == 1)
  136. {
  137. bus_clear = false;
  138. // Clock max 18 pulses worst case scenario(9 for master to send the rest of command and 9 for slave to respond) to SCL line and wait for SDA come high
  139. for (uint_fast8_t i = 18; i--;)
  140. {
  141. TWI_SCL_LOW();
  142. TWI_DELAY();
  143. TWI_SCL_HIGH();
  144. TWI_DELAY();
  145.  
  146. if (TWI_SDA_READ() == 1)
  147. {
  148. bus_clear = true;
  149. break;
  150. }
  151. }
  152. }
  153. else
  154. {
  155. bus_clear = false;
  156. }
  157.  
  158. return bus_clear;
  159. }
  160.  
  161. /**
  162. * @brief Function for issuing TWI START condition to the bus.
  163. *
  164. * START condition is signaled by pulling SDA low while SCL is high. After this function SCL and SDA will be low.
  165. *
  166. * @return
  167. * @retval false Timeout detected
  168. * @retval true Clocking succeeded
  169. */
  170.  
  171. static bool twi_master_issue_startcondition(void)
  172. //bool twi_master_issue_startcondition(void)
  173. {
  174. #if 0
  175. if (TWI_SCL_READ() == 1 && TWI_SDA_READ() == 1)
  176. {
  177. // Pull SDA low
  178. TWI_SDA_LOW();
  179. }
  180. else if (TWI_SCL_READ() == 1 && TWI_SDA_READ() == 0)
  181. {
  182. // Issue Stop by pulling SDA high
  183. TWI_SDA_HIGH();
  184. TWI_DELAY();
  185.  
  186. // Then Start by pulling SDA low
  187. TWI_SDA_LOW();
  188. }
  189. else if (TWI_SCL_READ() == 0 && TWI_SDA_READ() == 0)
  190. {
  191. // First pull SDA high
  192. TWI_SDA_HIGH();
  193.  
  194. // Then SCL high
  195. if (!twi_master_wait_while_scl_low())
  196. {
  197. return false;
  198. }
  199.  
  200. // Then SDA low
  201. TWI_SDA_LOW();
  202. }
  203. else if (TWI_SCL_READ() == 0 && TWI_SDA_READ() == 1)
  204. {
  205. // SCL high
  206. if (!twi_master_wait_while_scl_low())
  207. {
  208. return false;
  209. }
  210.  
  211. // Then SDA low
  212. TWI_SDA_LOW();
  213. }
  214.  
  215. TWI_DELAY();
  216. TWI_SCL_LOW();
  217. #endif
  218.  
  219. // Make sure both SDA and SCL are high before pulling SDA low.
  220. TWI_SDA_HIGH();
  221. TWI_DELAY();
  222. if (!twi_master_wait_while_scl_low())
  223. {
  224. return false;
  225. }
  226.  
  227. TWI_SDA_LOW();
  228. TWI_DELAY();
  229.  
  230. // Other module function expect SCL to be low
  231. TWI_SCL_LOW();
  232. TWI_DELAY();
  233.  
  234. return true;
  235. }
  236.  
  237. /**
  238. * @brief Function for issuing TWI STOP condition to the bus.
  239. *
  240. * STOP condition is signaled by pulling SDA high while SCL is high. After this function SDA and SCL will be high.
  241. *
  242. * @return
  243. * @retval false Timeout detected
  244. * @retval true Clocking succeeded
  245. */
  246.  
  247. static bool twi_master_issue_stopcondition(void)
  248. //bool twi_master_issue_stopcondition(void)
  249. {
  250. #if 0
  251. if (TWI_SCL_READ() == 1 && TWI_SDA_READ() == 1)
  252. {
  253. // Issue start, then issue stop
  254.  
  255. // Pull SDA low to issue START
  256. TWI_SDA_LOW();
  257. TWI_DELAY();
  258.  
  259. // Pull SDA high while SCL is high to issue STOP
  260. TWI_SDA_HIGH();
  261. }
  262. else if (TWI_SCL_READ() == 1 && TWI_SDA_READ() == 0)
  263. {
  264. // Pull SDA high while SCL is high to issue STOP
  265. TWI_SDA_HIGH();
  266. }
  267. else if (TWI_SCL_READ() == 0 && TWI_SDA_READ() == 0)
  268. {
  269. if (!twi_master_wait_while_scl_low())
  270. {
  271. return false;
  272. }
  273.  
  274. // Pull SDA high while SCL is high to issue STOP
  275. TWI_SDA_HIGH();
  276. }
  277. else if (TWI_SCL_READ() == 0 && TWI_SDA_READ() == 1)
  278. {
  279. TWI_SDA_LOW();
  280. TWI_DELAY();
  281.  
  282. // SCL high
  283. if (!twi_master_wait_while_scl_low())
  284. {
  285. return false;
  286. }
  287.  
  288. // Pull SDA high while SCL is high to issue STOP
  289. TWI_SDA_HIGH();
  290. }
  291.  
  292. TWI_DELAY();
  293. #endif
  294.  
  295. TWI_SDA_LOW();
  296. TWI_DELAY();
  297. if (!twi_master_wait_while_scl_low())
  298. {
  299. return false;
  300. }
  301.  
  302. TWI_SDA_HIGH();
  303. TWI_DELAY();
  304.  
  305. return true;
  306. }
  307.  
  308. /**
  309. * @brief Function for clocking one data byte out and reads slave acknowledgment.
  310. *
  311. * Can handle clock stretching.
  312. * After calling this function SCL is low and SDA low/high depending on the
  313. * value of LSB of the data byte.
  314. * SCL is expected to be output and low when entering this function.
  315. *
  316. * @param databyte Data byte to clock out.
  317. * @return
  318. * @retval true Slave acknowledged byte.
  319. * @retval false Timeout or slave didn't acknowledge byte.
  320. */
  321.  
  322. static bool twi_master_clock_byte(uint_fast8_t databyte)
  323. //bool twi_master_clock_byte(uint_fast8_t databyte)
  324. {
  325. bool transfer_succeeded = true;
  326.  
  327. /** @snippet [TWI SW master write] */
  328. // Make sure SDA is an output
  329. TWI_SDA_OUTPUT();
  330.  
  331. // MSB first
  332. for (uint_fast8_t i = 0x80; i != 0; i >>= 1)
  333. {
  334. TWI_SCL_LOW();
  335. TWI_DELAY();
  336.  
  337. if (databyte & i)
  338. {
  339. TWI_SDA_HIGH();
  340. }
  341. else
  342. {
  343. TWI_SDA_LOW();
  344. }
  345.  
  346. if (!twi_master_wait_while_scl_low())
  347. {
  348. transfer_succeeded = false; // Timeout
  349. break;
  350. }
  351. }
  352.  
  353. // Finish last data bit by pulling SCL low
  354. TWI_SCL_LOW();
  355. TWI_DELAY();
  356.  
  357. /** @snippet [TWI SW master write] */
  358.  
  359. // Configure TWI_SDA pin as input for receiving the ACK bit
  360. TWI_SDA_INPUT();
  361.  
  362. // Give some time for the slave to load the ACK bit on the line
  363. TWI_DELAY();
  364.  
  365. // Pull SCL high and wait a moment for SDA line to settle
  366. // Make sure slave is not stretching the clock
  367. transfer_succeeded &= twi_master_wait_while_scl_low();
  368.  
  369. // Read ACK/NACK. NACK == 1, ACK == 0
  370. transfer_succeeded &= !(TWI_SDA_READ());
  371.  
  372. // Finish ACK/NACK bit clock cycle and give slave a moment to release control
  373. // of the SDA line
  374. TWI_SCL_LOW();
  375. TWI_DELAY();
  376.  
  377. // Configure TWI_SDA pin as output as other module functions expect that
  378. TWI_SDA_OUTPUT();
  379.  
  380. return transfer_succeeded;
  381. }
  382.  
  383.  
  384. /**
  385. * @brief Function for clocking one data byte in and sends ACK/NACK bit.
  386. *
  387. * Can handle clock stretching.
  388. * SCL is expected to be output and low when entering this function.
  389. * After calling this function, SCL is high and SDA low/high depending if ACK/NACK was sent.
  390. *
  391. * @param databyte Data byte to clock out.
  392. * @param ack If true, send ACK. Otherwise send NACK.
  393. * @return
  394. * @retval true Byte read succesfully
  395. * @retval false Timeout detected
  396. */
  397.  
  398. static bool twi_master_clock_byte_in(uint8_t *databyte, bool ack)
  399. // bool twi_master_clock_byte_in(uint8_t *databyte, bool ack)
  400. {
  401. uint_fast8_t byte_read = 0;
  402. bool transfer_succeeded = true;
  403.  
  404. /** @snippet [TWI SW master read] */
  405. // Make sure SDA is an input
  406. TWI_SDA_INPUT();
  407.  
  408. // SCL state is guaranteed to be high here
  409.  
  410. // MSB first
  411. for (uint_fast8_t i = 0x80; i != 0; i >>= 1)
  412. {
  413. if (!twi_master_wait_while_scl_low())
  414. {
  415. transfer_succeeded = false;
  416. break;
  417. }
  418.  
  419. if (TWI_SDA_READ())
  420. {
  421. byte_read |= i;
  422. }
  423. else
  424. {
  425. // No need to do anything
  426. }
  427.  
  428. TWI_SCL_LOW();
  429. TWI_DELAY();
  430. }
  431.  
  432. // Make sure SDA is an output before we exit the function
  433. TWI_SDA_OUTPUT();
  434. /** @snippet [TWI SW master read] */
  435.  
  436. *databyte = (uint8_t)byte_read;
  437.  
  438. // Send ACK bit
  439.  
  440. // SDA high == NACK, SDA low == ACK
  441. if (ack)
  442. {
  443. TWI_SDA_LOW();
  444. }
  445. else
  446. {
  447. TWI_SDA_HIGH();
  448. }
  449.  
  450. // Let SDA line settle for a moment
  451. TWI_DELAY();
  452.  
  453. // Drive SCL high to start ACK/NACK bit transfer
  454. // Wait until SCL is high, or timeout occurs
  455. if (!twi_master_wait_while_scl_low())
  456. {
  457. transfer_succeeded = false; // Timeout
  458. }
  459.  
  460. // Finish ACK/NACK bit clock cycle and give slave a moment to react
  461. TWI_SCL_LOW();
  462. TWI_DELAY();
  463.  
  464. return transfer_succeeded;
  465. }
  466.  
  467.  
  468. /**
  469. * @brief Function for pulling SCL high and waits until it is high or timeout occurs.
  470. *
  471. * SCL is expected to be output before entering this function.
  472. * @note If TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE is set to zero, timeout functionality is not compiled in.
  473. * @return
  474. * @retval true SCL is now high.
  475. * @retval false Timeout occurred and SCL is still low.
  476. */
  477. static bool twi_master_wait_while_scl_low(void)
  478. {
  479. #if TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE != 0
  480. uint32_t volatile timeout_counter = TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE;
  481. #endif
  482.  
  483. // Pull SCL high just in case if something left it low
  484. TWI_SCL_HIGH();
  485. TWI_DELAY();
  486.  
  487. while (TWI_SCL_READ() == 0)
  488. {
  489. // If SCL is low, one of the slaves is busy and we must wait
  490.  
  491. #if TWI_MASTER_TIMEOUT_COUNTER_LOAD_VALUE != 0
  492. if (timeout_counter-- == 0)
  493. {
  494. // If timeout_detected, return false
  495. return false;
  496. }
  497. #endif
  498. }
  499.  
  500. return true;
  501. }
  502.  
  503.  
  504.  
  505. // Following is added by me
  506.  
  507. // Read from 8-bit register, I2C protocol
  508. // Input:
  509. // slave_base_addr: The base address of slave device without the R/W bit
  510. // reg_addr: 8-bit register address
  511. // data: address of the data buffer that the read data go to
  512. // data_length: how many bytes to read
  513. // Output: whether the read operation is successful
  514. bool slave_reg8_read(uint8_t slave_base_addr, uint8_t reg_addr, uint8_t * data, uint8_t data_length)
  515. {
  516. bool transfer_succeeded = false;
  517. if (twi_master_transfer(slave_base_addr, (uint8_t*)&reg_addr, 1, TWI_DONT_ISSUE_STOP))
  518. {
  519. uint8_t data_buffer[data_length];
  520. if (twi_master_transfer(slave_base_addr | TWI_READ_BIT, data_buffer, data_length, TWI_ISSUE_STOP))
  521. {
  522. *data = data_buffer[0];
  523. transfer_succeeded = true;
  524. }
  525. }
  526. return transfer_succeeded;
  527. }
  528.  
  529. // Write to 8-bit register, I2C protocol
  530. // Input:
  531. // slave_base_addr: The base address of slave device without the R/W bit
  532. // reg_addr: 8-bit register address
  533. // data: address of the data buffer to write to the register
  534. // data_length: how many bytes to write
  535. // Output: whether the write operation is successful
  536. bool slave_reg8_write(uint8_t slave_base_addr, uint8_t reg_addr, uint8_t * data)
  537. {
  538. bool transfer_succeeded = false;
  539. uint8_t data_len = sizeof(data)/sizeof(data[0]);
  540. uint8_t i;
  541. uint8_t data_buffer[1+data_len];
  542. data_buffer[0] = reg_addr;
  543. for (i=0;i<data_len;i++) data_buffer[i+1] = data[i];
  544. transfer_succeeded = twi_master_transfer(slave_base_addr, data_buffer, 1+data_len, TWI_ISSUE_STOP);
  545. return transfer_succeeded;
  546. }
  547.  
  548.  
  549. /*lint --flb "Leave library region" */
Advertisement
Add Comment
Please, Sign In to add comment