sdio_RP2MCU.pio 7.8 KB

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