sdio.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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. #include <stdint.h>
  13. #include "nrf.h"
  14. #include "nrf_delay.h"
  15. #include "sdio.h"
  16. #include "nrf_gpio.h"
  17. #include "sdio_config.h"
  18. /*lint ++flb "Enter library region" */
  19. /*lint -e717 -save "Suppress do {} while (0) for these macros" */
  20. #define SDIO_CLOCK_HIGH() do { NRF_GPIO->OUTSET = (1UL << SDIO_CONFIG_CLOCK_PIN_NUMBER); } while (0) /*!< Pulls SCL line high */
  21. #define SDIO_CLOCK_LOW() do { NRF_GPIO->OUTCLR = (1UL << SDIO_CONFIG_CLOCK_PIN_NUMBER); } while (0) /*!< Pulls SCL line low */
  22. #define SDIO_DATA_HIGH() do { NRF_GPIO->OUTSET = (1UL << SDIO_CONFIG_DATA_PIN_NUMBER); } while (0) /*!< Pulls SDA line high */
  23. #define SDIO_DATA_LOW() do { NRF_GPIO->OUTCLR = (1UL << SDIO_CONFIG_DATA_PIN_NUMBER); } while (0) /*!< Pulls SDA line low */
  24. #define SDIO_DATA_OUTPUT() do { NRF_GPIO->DIRSET = (1UL << SDIO_CONFIG_DATA_PIN_NUMBER); } while (0) /*!< Configures SDA pin as output */
  25. #define SDIO_CLOCK_OUTPUT() do { NRF_GPIO->DIRSET = (1UL << SDIO_CONFIG_CLOCK_PIN_NUMBER); } while (0) /*!< Configures SCL pin as output */
  26. /*lint -restore */
  27. /*lint -emacro(845,SDIO_DATA_INPUT) // A zero has been given as right argument to operator '|'" */
  28. #define SDIO_DATA_INPUT() do { \
  29. nrf_gpio_cfg_input(25, NRF_GPIO_PIN_NOPULL); \
  30. } while (0)
  31. #define SDIO_DATA_READ() ((NRF_GPIO->IN >> SDIO_CONFIG_DATA_PIN_NUMBER) & 0x1UL) /*!< Reads current state of SDA */
  32. #define SDIO_CLOCK_READ() ((NRF_GPIO->IN >> SDIO_CONFIG_CLOCK_PIN_NUMBER) & 0x1UL) /*!< Reads current state of SCL */
  33. #define SDIO_DELAY() nrf_delay_us(10) /*!< Time to wait when pin states are changed. For fast-mode the delay can be zero and for standard-mode 4 us delay is sufficient. */
  34. void sdio_init(void)
  35. {
  36. SDIO_CLOCK_HIGH();
  37. SDIO_DATA_HIGH();
  38. SDIO_CLOCK_OUTPUT();
  39. SDIO_DATA_INPUT();
  40. // If slave is stuck in the middle of transfer, clock out bits until the slave ACKs the transfer
  41. for (uint_fast8_t i = 16; i--;)
  42. {
  43. SDIO_DELAY();
  44. SDIO_CLOCK_LOW();
  45. SDIO_DELAY();
  46. SDIO_CLOCK_HIGH();
  47. SDIO_DELAY();
  48. if (SDIO_DATA_READ())
  49. {
  50. break;
  51. }
  52. }
  53. for (uint_fast8_t i = 5; i--;)
  54. {
  55. SDIO_DELAY();
  56. SDIO_CLOCK_LOW();
  57. SDIO_DELAY();
  58. SDIO_CLOCK_HIGH();
  59. }
  60. SDIO_DATA_OUTPUT();
  61. SDIO_DATA_HIGH();
  62. SDIO_DELAY();
  63. }
  64. uint8_t sdio_read_byte(uint8_t address)
  65. {
  66. uint8_t data_byte = 0;
  67. SDIO_DATA_OUTPUT();
  68. for (uint_fast8_t i = 8; i--;)
  69. {
  70. SDIO_DELAY();
  71. SDIO_CLOCK_LOW();
  72. if (address & (1U << i))
  73. {
  74. SDIO_DATA_HIGH();
  75. }
  76. else
  77. {
  78. SDIO_DATA_LOW();
  79. }
  80. SDIO_DELAY();
  81. SDIO_CLOCK_HIGH();
  82. }
  83. nrf_delay_us(20);
  84. SDIO_DATA_INPUT();
  85. for (uint_fast8_t i = 8; i--;)
  86. {
  87. SDIO_CLOCK_LOW();
  88. SDIO_DELAY();
  89. SDIO_CLOCK_HIGH();
  90. SDIO_DELAY();
  91. data_byte |= (uint8_t)(SDIO_DATA_READ() << i);
  92. }
  93. SDIO_DATA_HIGH();
  94. SDIO_DATA_OUTPUT();
  95. SDIO_DELAY();
  96. return data_byte;
  97. }
  98. void sdio_read_burst(uint8_t * target_buffer, uint8_t target_buffer_size)
  99. {
  100. uint_fast8_t address = 0x63;
  101. SDIO_DATA_OUTPUT();
  102. for (uint_fast8_t bit_index=8; bit_index--;)
  103. {
  104. SDIO_CLOCK_LOW();
  105. if (address & (1U << bit_index))
  106. {
  107. SDIO_DATA_HIGH();
  108. }
  109. else
  110. {
  111. SDIO_DATA_LOW();
  112. }
  113. SDIO_CLOCK_HIGH();
  114. }
  115. SDIO_DATA_INPUT();
  116. for (uint_fast8_t target_buffer_index = 0; target_buffer_index < target_buffer_size; target_buffer_index++)
  117. {
  118. target_buffer[target_buffer_index] = 0;
  119. for (uint_fast8_t bit_index = 8; bit_index--;)
  120. {
  121. SDIO_CLOCK_LOW();
  122. SDIO_CLOCK_HIGH();
  123. target_buffer[target_buffer_index] |= (uint8_t)(SDIO_DATA_READ() << bit_index);
  124. }
  125. }
  126. }
  127. void sdio_write_byte(uint8_t address, uint8_t data_byte)
  128. {
  129. // Add write indication bit
  130. address |= 0x80;
  131. SDIO_DATA_OUTPUT();
  132. for (uint_fast8_t i = 8; i--;)
  133. {
  134. SDIO_DELAY();
  135. SDIO_CLOCK_LOW();
  136. if (address & (1U << i))
  137. {
  138. SDIO_DATA_HIGH();
  139. }
  140. else
  141. {
  142. SDIO_DATA_LOW();
  143. }
  144. SDIO_DELAY();
  145. SDIO_CLOCK_HIGH();
  146. }
  147. SDIO_DELAY();
  148. for (uint_fast8_t i = 8; i--;)
  149. {
  150. SDIO_CLOCK_LOW();
  151. if (data_byte & (1U << i))
  152. {
  153. SDIO_DATA_HIGH();
  154. }
  155. else
  156. {
  157. SDIO_DATA_LOW();
  158. }
  159. SDIO_DELAY();
  160. SDIO_CLOCK_HIGH();
  161. SDIO_DELAY();
  162. }
  163. SDIO_DATA_HIGH();
  164. SDIO_DELAY();
  165. }
  166. /*lint --flb "Leave library region" */