smbus.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /*
  2. * File : smbus.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. *
  20. * Change Logs:
  21. * Date Author Notes
  22. * 2017-12-04 Haley the first version
  23. */
  24. #include <rtthread.h>
  25. #include <rtdevice.h>
  26. #include "am_mcu_apollo.h"
  27. #ifdef RT_USING_SMBUS
  28. #define SMBUS_GPIO_SDA 5
  29. #define SMBUS_GPIO_SCL 6
  30. #define mSDA_LOW() am_hal_gpio_out_bit_clear(SMBUS_GPIO_SDA) /* Clear SDA line */
  31. #define mSDA_HIGH() am_hal_gpio_out_bit_set(SMBUS_GPIO_SDA) /* Set SDA line */
  32. #define mSCL_LOW() am_hal_gpio_out_bit_clear(SMBUS_GPIO_SCL) /* Clear SCL line */
  33. #define mSCL_HIGH() am_hal_gpio_out_bit_set(SMBUS_GPIO_SCL) /* Set SCL line */
  34. #define mSDA_READ() am_hal_gpio_input_bit_read(SMBUS_GPIO_SDA) /* Read SDA line */
  35. #define mSDA_IN() am_hal_gpio_pin_config(SMBUS_GPIO_SDA, AM_HAL_GPIO_INPUT | AM_HAL_GPIO_PULL6K) /* Set SDA as Input */
  36. #define mSDA_OUT() am_hal_gpio_pin_config(SMBUS_GPIO_SDA, AM_HAL_GPIO_OUTPUT) /* Set SDA as Output */
  37. #define mSCL_OUT() am_hal_gpio_pin_config(SMBUS_GPIO_SCL, AM_HAL_GPIO_OUTPUT) /* Set SCL as Output */
  38. #define ACK 0
  39. #define NACK 1
  40. /* SCL keep time */
  41. static void keep_delay(void)
  42. {
  43. int i;
  44. for(i = 0; i < 30; i++)
  45. __nop();
  46. }
  47. static void few_delay(void)
  48. {
  49. __nop();
  50. __nop();
  51. }
  52. static rt_uint8_t am_smbus_send_bit(rt_uint8_t send_bit)
  53. {
  54. mSDA_OUT();
  55. few_delay();
  56. if(send_bit) /* Send a bit */
  57. mSDA_HIGH();
  58. else
  59. mSDA_LOW();
  60. mSCL_HIGH(); /* High Level of Clock Pulse */
  61. keep_delay();
  62. mSCL_LOW();
  63. keep_delay();
  64. return 0;
  65. }
  66. static rt_uint8_t am_smbus_read_bit(void)
  67. {
  68. rt_uint8_t read_bit;
  69. mSDA_IN();
  70. few_delay();
  71. mSCL_HIGH(); /* High Level of Clock Pulse */
  72. keep_delay();
  73. read_bit = mSDA_READ(); /* Read a bit, save it in Read_bit */
  74. mSCL_LOW();
  75. keep_delay();
  76. return read_bit;
  77. }
  78. static void am_smbus_start_bit(void)
  79. {
  80. mSDA_OUT();
  81. mSDA_HIGH(); /* Generate bus free time between Stop */
  82. keep_delay();
  83. mSCL_HIGH();
  84. keep_delay();
  85. mSDA_LOW(); /* Hold time after (Repeated) Start */
  86. keep_delay();
  87. mSCL_LOW();
  88. keep_delay();
  89. }
  90. static void am_smbus_stop_bit(void)
  91. {
  92. mSDA_OUT();
  93. mSDA_HIGH(); /* Generate bus free time between Stop */
  94. keep_delay();
  95. mSCL_LOW();
  96. keep_delay();
  97. mSDA_LOW(); /* Hold time after Stop */
  98. keep_delay();
  99. mSCL_HIGH(); /* For sleep mode(SCL needs to be high during Sleep.) */
  100. keep_delay();
  101. }
  102. static rt_uint8_t am_smbus_tx_byte(rt_uint8_t tx_byte)
  103. {
  104. int i;
  105. rt_uint8_t ack_bit;
  106. rt_uint8_t bit_out;
  107. for(i = 0; i < 8; i++)
  108. {
  109. if(tx_byte&0x80)
  110. bit_out = 1; /* If the current bit of Tx_buffer is 1 set bit_out */
  111. else
  112. bit_out = 0; /* else clear bit_out */
  113. am_smbus_send_bit(bit_out); /* Send the current bit on SDA */
  114. tx_byte <<= 1; /* Get next bit for checking */
  115. }
  116. ack_bit = am_smbus_read_bit(); /* Get acknowledgment bit */
  117. return ack_bit;
  118. }
  119. static rt_uint8_t am_smbus_rx_byte(rt_uint8_t ack_nack)
  120. {
  121. int i;
  122. rt_uint8_t rx_byte;
  123. for(i = 0; i < 8; i++)
  124. {
  125. if(am_smbus_read_bit()) /* Get a bit from the SDA line */
  126. {
  127. rx_byte <<= 1; /* If the bit is HIGH save 1 in RX_buffer */
  128. rx_byte |=0x01;
  129. }
  130. else
  131. {
  132. rx_byte <<= 1; /* If the bit is LOW save 0 in RX_buffer */
  133. rx_byte &=0xfe;
  134. }
  135. }
  136. am_smbus_send_bit(ack_nack); /* Sends acknowledgment bit */
  137. return rx_byte;
  138. }
  139. rt_uint8_t am_smbus_tx_then_tx(rt_uint8_t SlaveAddress, rt_uint8_t command, rt_uint8_t* pBuffer, rt_uint16_t bytesNumber)
  140. {
  141. int i;
  142. am_smbus_start_bit(); /* Start condition */
  143. if(am_smbus_tx_byte(SlaveAddress)) /* Send SlaveAddress and write */
  144. return 1;
  145. if(am_smbus_tx_byte(command)) /* Send command */
  146. return 1;
  147. for(i = 0; i < bytesNumber; i++)
  148. {
  149. am_smbus_tx_byte(pBuffer[i]); /* Write data, slave must send ACK */
  150. }
  151. am_smbus_stop_bit(); /* Stop condition */
  152. return 0;
  153. }
  154. rt_uint8_t am_smbus_tx_then_rx(rt_uint8_t SlaveAddress, rt_uint8_t command, rt_uint8_t* pBuffer, rt_uint16_t bytesNumber)
  155. {
  156. int i;
  157. am_smbus_start_bit(); /* Start condition */
  158. if(am_smbus_tx_byte(SlaveAddress)) /* Send SlaveAddress and write */
  159. return 1;
  160. if(am_smbus_tx_byte(command)) /* Send command */
  161. return 1;
  162. am_smbus_start_bit(); /* Repeated Start condition */
  163. if(am_smbus_tx_byte(SlaveAddress | 0x01)) /* Send SlaveAddress and read */
  164. return 1;
  165. for(i = 0; i < bytesNumber; i++)
  166. {
  167. pBuffer[i] = am_smbus_rx_byte(ACK); /* Read data, master must send ACK */
  168. }
  169. am_smbus_stop_bit(); /* Stop condition */
  170. return 0;
  171. }
  172. void am_smbus_scl_high(void)
  173. {
  174. mSCL_HIGH(); /* For sleep mode(SCL needs to be high during Sleep.) */
  175. keep_delay();
  176. }
  177. void am_smbus_scl_low(void)
  178. {
  179. mSCL_LOW(); /* For sleep mode(SCL needs to be high during Sleep.) */
  180. keep_delay();
  181. }
  182. int rt_hw_smbus_init(void)
  183. {
  184. mSDA_OUT();
  185. mSCL_OUT();
  186. mSDA_HIGH(); /* bus free */
  187. mSCL_HIGH();
  188. return 0;
  189. }
  190. #ifdef RT_USING_COMPONENTS_INIT
  191. INIT_BOARD_EXPORT(rt_hw_smbus_init);
  192. #endif
  193. #endif
  194. /*@}*/