Guest User

my_twi_master_v2.c

a guest
May 7th, 2015
564
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.07 KB | None | 0 0
  1.  
  2. /* Copyright (c) 2009 Nordic Semiconductor. All Rights Reserved.
  3. *
  4. * The information contained herein is property of Nordic Semiconductor ASA.
  5. * Terms and conditions of usage are described in detail in NORDIC
  6. * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
  7. *
  8. * Licensees are granted free, non-transferable use of the information. NO
  9. * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
  10. * the file.
  11. *
  12. */
  13.  
  14. #include "my_twi_master.h"
  15. #include "my_twi_master_config.h"
  16. #include <stdbool.h>
  17. #include <stdint.h>
  18. #include "nrf.h"
  19. #include "nrf_delay.h"
  20. #include "nrf_gpio.h"
  21. #include "nrf_sdm.h"
  22.  
  23. /* Max cycles approximately to wait on RXDREADY and TXDREADY event,
  24. * This is optimized way instead of using timers, this is not power aware. */
  25. #define MAX_TIMEOUT_LOOPS (20000UL) /**< MAX while loops to wait for RXD/TXD event */
  26.  
  27. static uint8_t sd_enabled;
  28.  
  29. static bool twi_master_write(uint8_t *data, uint8_t data_length, bool issue_stop_condition)
  30. {
  31. uint32_t timeout = MAX_TIMEOUT_LOOPS; /* max loops to wait for EVENTS_TXDSENT event*/
  32.  
  33. if (data_length == 0)
  34. {
  35. /* Return false for requesting data of size 0 */
  36. return false;
  37. }
  38.  
  39. NRF_TWI1->TXD = *data++;
  40. NRF_TWI1->TASKS_STARTTX = 1;
  41.  
  42. /** @snippet [TWI HW master write] */
  43. while (true)
  44. {
  45. while(NRF_TWI1->EVENTS_TXDSENT == 0 && NRF_TWI1->EVENTS_ERROR == 0 && (--timeout))
  46. {
  47. // Do nothing.
  48. }
  49.  
  50. if (timeout == 0 || NRF_TWI1->EVENTS_ERROR != 0)
  51. {
  52. // Recover the peripheral as indicated by PAN 56: "TWI: TWI module lock-up." found at
  53. // Product Anomaly Notification document found at
  54. // https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads
  55. NRF_TWI1->EVENTS_ERROR = 0;
  56. NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
  57. NRF_TWI1->POWER = 0;
  58. nrf_delay_us(5);
  59. NRF_TWI1->POWER = 1;
  60. NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos;
  61.  
  62. (void)twi_master_init();
  63.  
  64. return false;
  65. }
  66. NRF_TWI1->EVENTS_TXDSENT = 0;
  67. if (--data_length == 0)
  68. {
  69. break;
  70. }
  71.  
  72. NRF_TWI1->TXD = *data++;
  73. }
  74. /** @snippet [TWI HW master write] */
  75.  
  76. if (issue_stop_condition)
  77. {
  78. NRF_TWI1->EVENTS_STOPPED = 0;
  79. NRF_TWI1->TASKS_STOP = 1;
  80. /* Wait until stop sequence is sent */
  81. while(NRF_TWI1->EVENTS_STOPPED == 0)
  82. {
  83. // Do nothing.
  84. }
  85. }
  86. return true;
  87. }
  88.  
  89.  
  90. /** @brief Function for read by twi_master.
  91. */
  92. static bool twi_master_read(uint8_t *data, uint8_t data_length, bool issue_stop_condition)
  93. {
  94. uint32_t timeout = MAX_TIMEOUT_LOOPS; /* max loops to wait for RXDREADY event*/
  95.  
  96. sd_softdevice_is_enabled(&sd_enabled);
  97.  
  98. if (data_length == 0)
  99. {
  100. /* Return false for requesting data of size 0 */
  101. return false;
  102. }
  103. else if (data_length == 1)
  104. {
  105. if(sd_enabled)
  106. {
  107. sd_ppi_channel_assign(0, &NRF_TWI1->EVENTS_BB, &NRF_TWI1->TASKS_STOP);
  108. }
  109. else
  110. {
  111. NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TWI1->TASKS_STOP;
  112. }
  113. }
  114. else
  115. {
  116. if(sd_enabled)
  117. {
  118. sd_ppi_channel_assign(0, &NRF_TWI1->EVENTS_BB, &NRF_TWI1->TASKS_SUSPEND);
  119. }
  120. else
  121. {
  122. NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TWI1->TASKS_SUSPEND;
  123. }
  124. }
  125.  
  126. if(sd_enabled)
  127. {
  128. sd_ppi_channel_enable_set(1 << 0);
  129. }
  130. else
  131. {
  132. NRF_PPI->CHENSET = PPI_CHENSET_CH0_Msk;
  133. }
  134. NRF_TWI1->EVENTS_RXDREADY = 0;
  135. NRF_TWI1->TASKS_STARTRX = 1;
  136.  
  137. /** @snippet [TWI HW master read] */
  138. while (true)
  139. {
  140. while(NRF_TWI1->EVENTS_RXDREADY == 0 && NRF_TWI1->EVENTS_ERROR == 0 && (--timeout))
  141. {
  142. // Do nothing.
  143. }
  144. NRF_TWI1->EVENTS_RXDREADY = 0;
  145.  
  146. if (timeout == 0 || NRF_TWI1->EVENTS_ERROR != 0)
  147. {
  148. // Recover the peripheral as indicated by PAN 56: "TWI: TWI module lock-up." found at
  149. // Product Anomaly Notification document found at
  150. // https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads
  151. NRF_TWI1->EVENTS_ERROR = 0;
  152. NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
  153. NRF_TWI1->POWER = 0;
  154. nrf_delay_us(5);
  155. NRF_TWI1->POWER = 1;
  156. NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos;
  157.  
  158. (void)twi_master_init();
  159.  
  160. return false;
  161. }
  162.  
  163. *data++ = NRF_TWI1->RXD;
  164.  
  165. /* Configure PPI to stop TWI master before we get last BB event */
  166. if (--data_length == 1)
  167. {
  168. sd_softdevice_is_enabled(&sd_enabled);
  169. if(sd_enabled)
  170. {
  171. sd_ppi_channel_assign(0, &NRF_TWI1->EVENTS_BB, &NRF_TWI1->TASKS_STOP);
  172. }
  173. else
  174. {
  175. NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TWI1->TASKS_STOP;
  176. }
  177. }
  178.  
  179. if (data_length == 0)
  180. {
  181. break;
  182. }
  183.  
  184. // Recover the peripheral as indicated by PAN 56: "TWI: TWI module lock-up." found at
  185. // Product Anomaly Notification document found at
  186. // https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads
  187. nrf_delay_us(20);
  188. NRF_TWI1->TASKS_RESUME = 1;
  189. }
  190. /** @snippet [TWI HW master read] */
  191.  
  192. /* Wait until stop sequence is sent */
  193. while(NRF_TWI1->EVENTS_STOPPED == 0)
  194. {
  195. // Do nothing.
  196. }
  197. NRF_TWI1->EVENTS_STOPPED = 0;
  198.  
  199. sd_softdevice_is_enabled(&sd_enabled);
  200. if(sd_enabled)
  201. {
  202. sd_ppi_channel_enable_clr(1 << 0);
  203. }
  204. else
  205. {
  206. NRF_PPI->CHENCLR = PPI_CHENCLR_CH0_Msk;
  207. }
  208. return true;
  209. }
  210.  
  211.  
  212. /**
  213. * @brief Function for detecting stuck slaves (SDA = 0 and SCL = 1) and tries to clear the bus.
  214. *
  215. * @return
  216. * @retval false Bus is stuck.
  217. * @retval true Bus is clear.
  218. */
  219. static bool twi_master_clear_bus(void)
  220. {
  221. uint32_t twi_state;
  222. bool bus_clear;
  223. uint32_t clk_pin_config;
  224. uint32_t data_pin_config;
  225.  
  226. // Save and disable TWI hardware so software can take control over the pins.
  227. twi_state = NRF_TWI1->ENABLE;
  228. NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
  229.  
  230. clk_pin_config = \
  231. NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER];
  232. NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER] = \
  233. (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \
  234. | (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \
  235. | (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) \
  236. | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \
  237. | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
  238.  
  239. data_pin_config = \
  240. NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER];
  241. NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER] = \
  242. (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \
  243. | (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \
  244. | (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) \
  245. | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \
  246. | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
  247.  
  248. TWI_SDA_HIGH();
  249. TWI_SCL_HIGH();
  250. TWI_DELAY();
  251.  
  252. if ((TWI_SDA_READ() == 1) && (TWI_SCL_READ() == 1))
  253. {
  254. bus_clear = true;
  255. }
  256. else
  257. {
  258. uint_fast8_t i;
  259. bus_clear = false;
  260.  
  261. // Clock max 18 pulses worst case scenario(9 for master to send the rest of command and 9
  262. // for slave to respond) to SCL line and wait for SDA come high.
  263. for (i=18; i--;)
  264. {
  265. TWI_SCL_LOW();
  266. TWI_DELAY();
  267. TWI_SCL_HIGH();
  268. TWI_DELAY();
  269.  
  270. if (TWI_SDA_READ() == 1)
  271. {
  272. bus_clear = true;
  273. break;
  274. }
  275. }
  276. }
  277.  
  278. NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER] = clk_pin_config;
  279. NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER] = data_pin_config;
  280.  
  281. NRF_TWI1->ENABLE = twi_state;
  282.  
  283. return bus_clear;
  284. }
  285.  
  286.  
  287. /** @brief Function for initializing the twi_master.
  288. */
  289. bool twi_master_init(void)
  290. {
  291. /* To secure correct signal levels on the pins used by the TWI
  292. master when the system is in OFF mode, and when the TWI master is
  293. disabled, these pins must be configured in the GPIO peripheral.
  294. */
  295. NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER] = \
  296. (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \
  297. | (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \
  298. | (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) \
  299. | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \
  300. | (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos);
  301.  
  302. NRF_GPIO->PIN_CNF[TWI_MASTER_CONFIG_DATA_PIN_NUMBER] = \
  303. (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) \
  304. | (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos) \
  305. | (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) \
  306. | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) \
  307. | (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos);
  308.  
  309. NRF_TWI1->EVENTS_RXDREADY = 0;
  310. NRF_TWI1->EVENTS_TXDSENT = 0;
  311. NRF_TWI1->PSELSCL = TWI_MASTER_CONFIG_CLOCK_PIN_NUMBER;
  312. NRF_TWI1->PSELSDA = TWI_MASTER_CONFIG_DATA_PIN_NUMBER;
  313. NRF_TWI1->FREQUENCY = TWI_FREQUENCY_FREQUENCY_K100 << TWI_FREQUENCY_FREQUENCY_Pos;
  314.  
  315. sd_softdevice_is_enabled(&sd_enabled);
  316. if(sd_enabled)
  317. {
  318. sd_ppi_channel_assign(0, &NRF_TWI1->EVENTS_BB, &NRF_TWI1->TASKS_SUSPEND);
  319. sd_ppi_channel_enable_clr(1 << 0);
  320. }
  321. else
  322. {
  323. NRF_PPI->CH[0].EEP = (uint32_t)&NRF_TWI1->EVENTS_BB;
  324. NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TWI1->TASKS_SUSPEND;
  325. NRF_PPI->CHENCLR = PPI_CHENCLR_CH0_Msk;
  326. }
  327.  
  328. NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos;
  329.  
  330. return twi_master_clear_bus();
  331. }
  332.  
  333.  
  334. /** @brief Function for transfer by twi_master.
  335. */
  336. bool twi_master_transfer(uint8_t address,
  337. uint8_t * data,
  338. uint8_t data_length,
  339. bool issue_stop_condition)
  340. {
  341. bool transfer_succeeded = false;
  342. if (data_length > 0 && twi_master_clear_bus())
  343. {
  344. NRF_TWI1->ADDRESS = (address >> 1);
  345.  
  346. if ((address & TWI_READ_BIT))
  347. {
  348. transfer_succeeded = twi_master_read(data, data_length, issue_stop_condition);
  349. }
  350. else
  351. {
  352. transfer_succeeded = twi_master_write(data, data_length, issue_stop_condition);
  353. }
  354. }
  355. return transfer_succeeded;
  356. }
  357.  
  358.  
  359.  
  360. // Following is added by me
  361.  
  362. // Read from 8-bit register, I2C protocol
  363. // Input:
  364. // slave_base_addr: The base address of slave device without the R/W bit
  365. // reg_addr: 8-bit register address
  366. // data: address of the data buffer that the read data go to
  367. // data_length: how many bytes to read
  368. // Output: whether the read operation is successful
  369. bool slave_reg8_read(uint8_t slave_base_addr, uint8_t reg_addr, uint8_t * data, uint8_t data_length)
  370. {
  371. bool transfer_succeeded = false;
  372. if (twi_master_transfer(slave_base_addr, (uint8_t*)&reg_addr, 1, TWI_DONT_ISSUE_STOP))
  373. {
  374. uint8_t data_buffer[data_length];
  375. if (twi_master_transfer(slave_base_addr | TWI_READ_BIT, data_buffer, data_length, TWI_ISSUE_STOP))
  376. {
  377. *data = data_buffer[0];
  378. transfer_succeeded = true;
  379. }
  380. }
  381. return transfer_succeeded;
  382. }
  383.  
  384. // Write to 8-bit register, I2C protocol
  385. // Input:
  386. // slave_base_addr: The base address of slave device without the R/W bit
  387. // reg_addr: 8-bit register address
  388. // data: address of the data buffer to write to the register
  389. // data_length: how many bytes to write
  390. // Output: whether the write operation is successful
  391. bool slave_reg8_write(uint8_t slave_base_addr, uint8_t reg_addr, uint8_t * data)
  392. {
  393. bool transfer_succeeded = false;
  394. uint8_t data_len = sizeof(data)/sizeof(data[0]);
  395. uint8_t i;
  396. uint8_t data_buffer[1+data_len];
  397. data_buffer[0] = reg_addr;
  398. for (i=0;i<data_len;i++) data_buffer[i+1] = data[i];
  399. transfer_succeeded = twi_master_transfer(slave_base_addr, data_buffer, 1+data_len, TWI_ISSUE_STOP);
  400. return transfer_succeeded;
  401. }
  402.  
  403.  
  404. /*lint --flb "Leave library region" */
Advertisement
Add Comment
Please, Sign In to add comment