| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- ; RP2040 PIO program for implementing SD card access in SDIO mode
- ; Run "pioasm rp2040_sdio.pio rp2040_sdio.pio.h" to regenerate the C header from this.
- ;
- ; Copyright (c) 2022 Rabbit Hole Computing™
- ; Copyright (c) 2011-2024 Bill Greiman
- ; Copyright (c) 2024 Tech by Androda, LLC
- ; This file is part of the SdFat library for SD memory cards.
- ; Portions from Bill Greiman use the MIT License:
- ; MIT License
- ;
- ; Permission is hereby granted, free of charge, to any person obtaining a
- ; copy of this software and associated documentation files (the "Software"),
- ; to deal in the Software without restriction, including without limitation
- ; the rights to use, copy, modify, merge, publish, distribute, sublicense,
- ; and/or sell copies of the Software, and to permit persons to whom the
- ; Software is furnished to do so, subject to the following conditions:
- ;
- ; The above copyright notice and this permission notice shall be included
- ; in all copies or substantial portions of the Software.
- ;
- ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- ; OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- ; DEALINGS IN THE SOFTWARE.
- ; The RP2040 official work-in-progress code at
- ; https://github.com/raspberrypi/pico-extras/tree/master/src/rp2_common/pico_sd_card
- ; may be useful reference, but this is independent implementation.
- ;
- ; For official SDIO specifications, refer to:
- ; https://www.sdcard.org/downloads/pls/
- ; "SDIO Physical Layer Simplified Specification Version 8.00"
- ; Clock settings
- ; For 3.3V communication the available speeds are:
- ; - Default speed: max. 25 MHz clock
- ; - High speed: max. 50 MHz clock
- ;
- ; From the default RP2040 clock speed of 125 MHz, the closest dividers
- ; are 3 for 41.7 MHz and 5 for 25 MHz. The CPU can apply further divider
- ; through state machine registers for the initial handshake.
- ;
- ; Because data is written on the falling edge and read on the rising
- ; edge, it is preferrable to have a long 0 state and short 1 state.
- ;.define CLKDIV 3
- .define CLKDIV 5
- .define D0 (((CLKDIV + 1) /2) - 1)
- .define D1 ((CLKDIV/2) - 1)
- .define SDIO_CLK_GPIO 10
- .define public SDIO_IRQ 7
- ; State Machine 0 is for the Command / Response
- ; This State Machine will stall with clock low after sending a command and receiving the response
- ; Note that the FIFOs are set to 8 bit mode here, because 8 bits evenly divides all command and response sizes
- .program cmd_rsp
- .side_set 1 opt
- .wrap_target
- cmd_begin:
- send_cmd:
- out pins, 1 side 0 [1] ; When TX FIFO is empty, this command will stall with clock low
- jmp X-- send_cmd side 1 [1]
- jmp !Y cmd_begin side 0 [1] ; If no response, go back to the beginning and stall
- set pindirs, 0 side 1 [3]
- wait_resp:
- nop side 0 [3]
- nop side 1 [2]
- jmp PIN wait_resp ; Run the SD clock until CMD pin goes low (First bit of response)
-
- read_resp:
- in pins, 1
- push iffull block side 0 [2] ; Read command response
- jmp Y-- read_resp side 1 [1]
- .wrap
- % c-sdk {
- 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) {
- pio_sm_config c = cmd_rsp_program_get_default_config(offset);
- sm_config_set_sideset_pins(&c, clk_pin);
- sm_config_set_out_pins(&c, cmd_pin, 1);
- sm_config_set_in_pins(&c, cmd_pin);
- sm_config_set_set_pins(&c, cmd_pin, 1);
- sm_config_set_jmp_pin(&c, cmd_pin);
- sm_config_set_in_shift(&c, false, false, 8);
- sm_config_set_out_shift(&c, false, true, 8);
- sm_config_set_clkdiv_int_frac(&c, div_int, div_frac);
- return c;
- }
- %}
- ; Program which reads data and provides its own clock signal
- ; Use direct-execute PIO instructions to place the number of 4-bit nibbles to receive
- ; into the X register before enabling the state machine
- .program rd_data_w_clock
- .side_set 1
- mov X, Y side 0 ; Reinitialize number of nibbles to receive
- wait_d0:
- nop side 0 [3] ; Run the clock...
- jmp PIN wait_d0 side 1 [3] ; Until the first response nibble (all zeroes)
- nop side 0 [2] ; Clock transition low to make the SD card write out the first actual data nibble
- nop side 1 [1] ; Transition clock high to stick data value
- read_loop:
- in pins, 4 side 0 [2] ; Read in the nibble and transition the clock low
- push iffull block side 1 ; Transition the clock high and block execution if rx fifo is full
- jmp X--, read_loop side 1 ; No delays here or previous instruction, because instr [1] = two instr execution time
- % c-sdk {
- static inline pio_sm_config pio_rd_data_w_clock_program_config(uint offset, uint d0_pin, uint clk_pin, float clk_div) {
- pio_sm_config c = rd_data_w_clock_program_get_default_config(offset);
- sm_config_set_sideset_pins(&c, clk_pin);
- sm_config_set_in_pins(&c, d0_pin);
- sm_config_set_jmp_pin(&c, d0_pin);
- sm_config_set_in_shift(&c, false, false, 32);
- sm_config_set_out_shift(&c, false, true, 32);
- sm_config_set_clkdiv(&c, clk_div);
- return c;
- }
- %}
- ; Data transmission program
- ;
- ; Before running this program, pindirs should be set as output
- ; and register X should be initialized with the number of nibbles
- ; to send minus 1 (typically 8 + 1024 + 16 + 1 - 1 = 1048)
- ;
- ; Register Y must be set to the number of CRC bits to receive (8/32)
- ;
- ; Words written to TX FIFO must be:
- ; - Word 0: start token 0xFFFFFFF0
- ; - Word 1-128: transmitted data (512 bytes)
- ; - Word 129-130: CRC checksum
- ; - Word 131: end token 0xFFFFFFFF
- .program sdio_tx_w_clock
- .side_set 1 opt
- tx_loop:
- out PINS, 4 side 0 [2] ; Write nibble value and transition clock low
- jmp X-- tx_loop side 1 [1] ; Transition clock high, and check if more data needs to be sent
- set pindirs, 0 side 1 [2] ; Set input mode to receive CRC token, without changing clock phase
- crc_get:
- in pins, 1 side 1 [4] ; Input the first bit of CRC response
- jmp Y-- crc_get side 0 [4] ; Read the CRC bits
- bsy_wait:
- jmp PIN done side 1 [4]
- jmp bsy_wait side 0 [4] ; Clock until no longer BSY
- done:
- .wrap_target
- push iffull noblock side 0 ; Unconditional, just push the response token
- .wrap
- % c-sdk {
- static inline pio_sm_config pio_sdio_tx_w_clock_program_config(uint offset, uint data_pin, uint clk_pin, int clk_div) {
- pio_sm_config c = sdio_tx_w_clock_program_get_default_config(offset);
- sm_config_set_sideset_pins(&c, clk_pin);
- sm_config_set_out_pins(&c, data_pin, 4);
- sm_config_set_in_pins(&c, data_pin);
- sm_config_set_set_pins(&c, data_pin, 4);
- sm_config_set_in_shift(&c, false, false, 8);
- sm_config_set_out_shift(&c, false, true, 32);
- sm_config_set_jmp_pin(&c, data_pin);
- sm_config_set_clkdiv_int_frac(&c, clk_div, 0);
- return c;
- }
- %}
|