121 lines
4.2 KiB
C
Executable File
121 lines
4.2 KiB
C
Executable File
|
|
// SD card access using SDIO for RP2040 platform.
|
|
// This module contains the low-level SDIO bus implementation using
|
|
// the PIO peripheral. The high-level commands are in sd_card_sdio.cpp.
|
|
|
|
#pragma once
|
|
#include <stdint.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include "sd_card.h"
|
|
|
|
//FIXME: why?
|
|
typedef struct sd_card_t sd_card_t;
|
|
|
|
typedef
|
|
enum sdio_status_t {
|
|
SDIO_OK = 0,
|
|
SDIO_BUSY = 1,
|
|
SDIO_ERR_RESPONSE_TIMEOUT = 2, // Timed out waiting for response from card
|
|
SDIO_ERR_RESPONSE_CRC = 3, // Response CRC is wrong
|
|
SDIO_ERR_RESPONSE_CODE = 4, // Response command code does not match what was sent
|
|
SDIO_ERR_DATA_TIMEOUT = 5, // Timed out waiting for data block
|
|
SDIO_ERR_DATA_CRC = 6, // CRC for data packet is wrong
|
|
SDIO_ERR_WRITE_CRC = 7, // Card reports bad CRC for write
|
|
SDIO_ERR_WRITE_FAIL = 8, // Card reports write failure
|
|
} sdio_status_t;
|
|
|
|
#define SDIO_BLOCK_SIZE 512
|
|
#define SDIO_WORDS_PER_BLOCK (SDIO_BLOCK_SIZE / 4) // 128
|
|
|
|
// Maximum number of 512 byte blocks to transfer in one request
|
|
#define SDIO_MAX_BLOCKS 256
|
|
|
|
typedef enum sdio_transfer_state_t { SDIO_IDLE, SDIO_RX, SDIO_TX, SDIO_TX_WAIT_IDLE} sdio_transfer_state_t;
|
|
|
|
typedef struct sd_sdio_if_state_t {
|
|
bool resources_claimed;
|
|
|
|
uint32_t ocr; // Operating condition register from card
|
|
uint32_t rca; // Relative card address
|
|
int error_line;
|
|
sdio_status_t error;
|
|
uint32_t dma_buf[128];
|
|
|
|
int SDIO_DMA_CH;
|
|
int SDIO_DMA_CHB;
|
|
int SDIO_CMD_SM;
|
|
int SDIO_DATA_SM;
|
|
|
|
uint32_t pio_cmd_clk_offset;
|
|
uint32_t pio_data_rx_offset;
|
|
pio_sm_config pio_cfg_data_rx;
|
|
uint32_t pio_data_tx_offset;
|
|
pio_sm_config pio_cfg_data_tx;
|
|
|
|
sdio_transfer_state_t transfer_state;
|
|
uint32_t transfer_start_time;
|
|
uint32_t *data_buf;
|
|
uint32_t blocks_done; // Number of blocks transferred so far
|
|
uint32_t total_blocks; // Total number of blocks to transfer
|
|
uint32_t blocks_checksumed; // Number of blocks that have had CRC calculated
|
|
uint32_t checksum_errors; // Number of checksum errors detected
|
|
|
|
// Variables for block writes
|
|
uint64_t next_wr_block_checksum;
|
|
uint32_t end_token_buf[3]; // CRC and end token for write block
|
|
sdio_status_t wr_status;
|
|
uint32_t card_response;
|
|
|
|
// Variables for extended block writes
|
|
bool ongoing_wr_mlt_blk;
|
|
uint32_t wr_mlt_blk_cnt_sector;
|
|
|
|
// Variables for block reads
|
|
// This is used to perform DMA into data buffers and checksum buffers separately.
|
|
struct {
|
|
void * write_addr;
|
|
uint32_t transfer_count;
|
|
} dma_blocks[SDIO_MAX_BLOCKS * 2];
|
|
struct {
|
|
uint32_t top;
|
|
uint32_t bottom;
|
|
} received_checksums[SDIO_MAX_BLOCKS];
|
|
} sd_sdio_if_state_t;
|
|
|
|
// Execute a command that has 48-bit reply (response types R1, R6, R7)
|
|
// If response is NULL, does not wait for reply.
|
|
sdio_status_t rp2040_sdio_command_R1(sd_card_t *sd_card_p, uint8_t command, uint32_t arg, uint32_t *response);
|
|
|
|
// Execute a command that has 136-bit reply (response type R2)
|
|
// Response buffer should have space for 16 bytes (the 128 bit payload)
|
|
sdio_status_t rp2040_sdio_command_R2(const sd_card_t *sd_card_p, uint8_t command, uint32_t arg, uint8_t *response);
|
|
|
|
// Execute a command that has 48-bit reply but without CRC (response R3)
|
|
sdio_status_t rp2040_sdio_command_R3(sd_card_t *sd_card_p, uint8_t command, uint32_t arg, uint32_t *response);
|
|
|
|
// Start transferring data from SD card to memory buffer
|
|
sdio_status_t rp2040_sdio_rx_start(sd_card_t *sd_card_p, uint8_t *buffer, uint32_t num_blocks, size_t block_size);
|
|
|
|
// Check if reception is complete
|
|
// Returns SDIO_BUSY while transferring, SDIO_OK when done and error on failure.
|
|
sdio_status_t rp2040_sdio_rx_poll(sd_card_t *sd_card_p, size_t block_size_words);
|
|
|
|
// Start transferring data from memory to SD card
|
|
sdio_status_t rp2040_sdio_tx_start(sd_card_t *sd_card_p, const uint8_t *buffer, uint32_t num_blocks);
|
|
|
|
// Check if transmission is complete
|
|
sdio_status_t rp2040_sdio_tx_poll(sd_card_t *sd_card_p, uint32_t *bytes_complete /* = nullptr */);
|
|
|
|
// (Re)initialize the SDIO interface
|
|
bool rp2040_sdio_init(sd_card_t *sd_card_p, float clk_div);
|
|
|
|
void __not_in_flash_func(sdio_irq_handler)(sd_card_t *sd_card_p);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|