rp2040_sdio.pio 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. ; RP2040 PIO program for implementing SD card access in SDIO mode
  2. ; Run "pioasm rp2040_sdio.pio rp2040_sdio.pio.h" to regenerate the C header from this.
  3. ;
  4. ; Copyright (c) 2022 Rabbit Hole Computing™
  5. ; Copyright (c) 2011-2024 Bill Greiman
  6. ; Copyright (c) 2024 Tech by Androda, LLC
  7. ; This file is part of the SdFat library for SD memory cards.
  8. ; Portions from Bill Greiman use the MIT License:
  9. ; MIT License
  10. ;
  11. ; Permission is hereby granted, free of charge, to any person obtaining a
  12. ; copy of this software and associated documentation files (the "Software"),
  13. ; to deal in the Software without restriction, including without limitation
  14. ; the rights to use, copy, modify, merge, publish, distribute, sublicense,
  15. ; and/or sell copies of the Software, and to permit persons to whom the
  16. ; Software is furnished to do so, subject to the following conditions:
  17. ;
  18. ; The above copyright notice and this permission notice shall be included
  19. ; in all copies or substantial portions of the Software.
  20. ;
  21. ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  22. ; OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  26. ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  27. ; DEALINGS IN THE SOFTWARE.
  28. ; The RP2040 official work-in-progress code at
  29. ; https://github.com/raspberrypi/pico-extras/tree/master/src/rp2_common/pico_sd_card
  30. ; may be useful reference, but this is independent implementation.
  31. ;
  32. ; For official SDIO specifications, refer to:
  33. ; https://www.sdcard.org/downloads/pls/
  34. ; "SDIO Physical Layer Simplified Specification Version 8.00"
  35. ; Clock settings
  36. ; For 3.3V communication the available speeds are:
  37. ; - Default speed: max. 25 MHz clock
  38. ; - High speed: max. 50 MHz clock
  39. ;
  40. ; From the default RP2040 clock speed of 125 MHz, the closest dividers
  41. ; are 3 for 41.7 MHz and 5 for 25 MHz. The CPU can apply further divider
  42. ; through state machine registers for the initial handshake.
  43. ;
  44. ; Because data is written on the falling edge and read on the rising
  45. ; edge, it is preferrable to have a long 0 state and short 1 state.
  46. ;.define CLKDIV 3
  47. .define CLKDIV 5
  48. .define D0 (((CLKDIV + 1) /2) - 1)
  49. .define D1 ((CLKDIV/2) - 1)
  50. .define SDIO_CLK_GPIO 10
  51. .define public SDIO_IRQ 7
  52. ; State Machine 0 is for the Command / Response
  53. ; This State Machine will stall with clock low after sending a command and receiving the response
  54. ; Note that the FIFOs are set to 8 bit mode here, because 8 bits evenly divides all command and response sizes
  55. .program cmd_rsp
  56. .side_set 1 opt
  57. .wrap_target
  58. cmd_begin:
  59. send_cmd:
  60. out pins, 1 side 0 [1] ; When TX FIFO is empty, this command will stall with clock low
  61. jmp X-- send_cmd side 1 [1]
  62. jmp !Y cmd_begin side 0 [1] ; If no response, go back to the beginning and stall
  63. set pindirs, 0 side 1 [3]
  64. wait_resp:
  65. nop side 0 [3]
  66. nop side 1 [2]
  67. jmp PIN wait_resp ; Run the SD clock until CMD pin goes low (First bit of response)
  68. read_resp:
  69. in pins, 1
  70. push iffull block side 0 [2] ; Read command response
  71. jmp Y-- read_resp side 1 [1]
  72. .wrap
  73. % c-sdk {
  74. static inline pio_sm_config pio_cmd_rsp_program_config(uint offset, uint cmd_pin, uint clk_pin, uint16_t div_int, uint8_t div_frac) {
  75. pio_sm_config c = cmd_rsp_program_get_default_config(offset);
  76. sm_config_set_sideset_pins(&c, clk_pin);
  77. sm_config_set_out_pins(&c, cmd_pin, 1);
  78. sm_config_set_in_pins(&c, cmd_pin);
  79. sm_config_set_set_pins(&c, cmd_pin, 1);
  80. sm_config_set_jmp_pin(&c, cmd_pin);
  81. sm_config_set_in_shift(&c, false, false, 8);
  82. sm_config_set_out_shift(&c, false, true, 8);
  83. sm_config_set_clkdiv_int_frac(&c, div_int, div_frac);
  84. return c;
  85. }
  86. %}
  87. ; Program which reads data and provides its own clock signal
  88. ; Use direct-execute PIO instructions to place the number of 4-bit nibbles to receive
  89. ; into the X register before enabling the state machine
  90. .program rd_data_w_clock
  91. .side_set 1
  92. mov X, Y side 0 ; Reinitialize number of nibbles to receive
  93. wait_d0:
  94. nop side 0 [3] ; Run the clock...
  95. jmp PIN wait_d0 side 1 [3] ; Until the first response nibble (all zeroes)
  96. nop side 0 [2] ; Clock transition low to make the SD card write out the first actual data nibble
  97. nop side 1 [1] ; Transition clock high to stick data value
  98. read_loop:
  99. in pins, 4 side 0 [2] ; Read in the nibble and transition the clock low
  100. push iffull block side 1 ; Transition the clock high and block execution if rx fifo is full
  101. jmp X--, read_loop side 1 ; No delays here or previous instruction, because instr [1] = two instr execution time
  102. % c-sdk {
  103. static inline pio_sm_config pio_rd_data_w_clock_program_config(uint offset, uint d0_pin, uint clk_pin, float clk_div) {
  104. pio_sm_config c = rd_data_w_clock_program_get_default_config(offset);
  105. sm_config_set_sideset_pins(&c, clk_pin);
  106. sm_config_set_in_pins(&c, d0_pin);
  107. sm_config_set_jmp_pin(&c, d0_pin);
  108. sm_config_set_in_shift(&c, false, false, 32);
  109. sm_config_set_out_shift(&c, false, true, 32);
  110. sm_config_set_clkdiv(&c, clk_div);
  111. return c;
  112. }
  113. %}
  114. ; Data transmission program
  115. ;
  116. ; Before running this program, pindirs should be set as output
  117. ; and register X should be initialized with the number of nibbles
  118. ; to send minus 1 (typically 8 + 1024 + 16 + 1 - 1 = 1048)
  119. ;
  120. ; Register Y must be set to the number of CRC bits to receive (8/32)
  121. ;
  122. ; Words written to TX FIFO must be:
  123. ; - Word 0: start token 0xFFFFFFF0
  124. ; - Word 1-128: transmitted data (512 bytes)
  125. ; - Word 129-130: CRC checksum
  126. ; - Word 131: end token 0xFFFFFFFF
  127. .program sdio_tx_w_clock
  128. .side_set 1 opt
  129. tx_loop:
  130. out PINS, 4 side 0 [2] ; Write nibble value and transition clock low
  131. jmp X-- tx_loop side 1 [1] ; Transition clock high, and check if more data needs to be sent
  132. set pindirs, 0 side 1 [2] ; Set input mode to receive CRC token, without changing clock phase
  133. crc_get:
  134. in pins, 1 side 1 [4] ; Input the first bit of CRC response
  135. jmp Y-- crc_get side 0 [4] ; Read the CRC bits
  136. bsy_wait:
  137. jmp PIN done side 1 [4]
  138. jmp bsy_wait side 0 [4] ; Clock until no longer BSY
  139. done:
  140. .wrap_target
  141. push iffull noblock side 0 ; Unconditional, just push the response token
  142. .wrap
  143. % c-sdk {
  144. static inline pio_sm_config pio_sdio_tx_w_clock_program_config(uint offset, uint data_pin, uint clk_pin, int clk_div) {
  145. pio_sm_config c = sdio_tx_w_clock_program_get_default_config(offset);
  146. sm_config_set_sideset_pins(&c, clk_pin);
  147. sm_config_set_out_pins(&c, data_pin, 4);
  148. sm_config_set_in_pins(&c, data_pin);
  149. sm_config_set_set_pins(&c, data_pin, 4);
  150. sm_config_set_in_shift(&c, false, false, 8);
  151. sm_config_set_out_shift(&c, false, true, 32);
  152. sm_config_set_jmp_pin(&c, data_pin);
  153. sm_config_set_clkdiv_int_frac(&c, clk_div, 0);
  154. return c;
  155. }
  156. %}