[SC64][SW] (#30) Remove usage of CMD23 in SD card sector read/write

This commit is contained in:
Mateusz Faderewski 2023-02-21 01:02:40 +01:00
parent c2dc401393
commit 98fa69e4d7
3 changed files with 609 additions and 604 deletions

View File

@ -1,121 +1,122 @@
#include <stddef.h> #include <stddef.h>
#include "display.h" #include "display.h"
#include "io.h" #include "io.h"
#include "sc64.h" #include "sc64.h"
#include "test.h" #include "test.h"
static void test_rtc (void) { static void test_rtc (void) {
sc64_rtc_time_t t; sc64_rtc_time_t t;
const char *weekdays[8] = { const char *weekdays[8] = {
"", "",
"Monday", "Monday",
"Tuesday", "Tuesday",
"Wednesday", "Wednesday",
"Thursday", "Thursday",
"Friday", "Friday",
"Saturday", "Saturday",
"Sunday", "Sunday",
}; };
sc64_get_time(&t); sc64_get_time(&t);
display_printf("RTC current time:\n "); display_printf("RTC current time:\n ");
display_printf("%04d-%02d-%02d", 2000 + FROM_BCD(t.year), FROM_BCD(t.month), FROM_BCD(t.day)); display_printf("%04d-%02d-%02d", 2000 + FROM_BCD(t.year), FROM_BCD(t.month), FROM_BCD(t.day));
display_printf("T"); display_printf("T");
display_printf("%02d:%02d:%02d", FROM_BCD(t.hour), FROM_BCD(t.minute), FROM_BCD(t.second)); display_printf("%02d:%02d:%02d", FROM_BCD(t.hour), FROM_BCD(t.minute), FROM_BCD(t.second));
display_printf(" (%s)", weekdays[FROM_BCD(t.weekday)]); display_printf(" (%s)", weekdays[FROM_BCD(t.weekday)]);
display_printf("\n"); display_printf("\n");
} }
static void test_sd_card (void) { static void test_sd_card (void) {
sc64_sd_card_status_t card_status; sc64_sd_card_status_t card_status;
uint8_t card_info[32] __attribute__((aligned(8))); uint8_t card_info[32] __attribute__((aligned(8)));
uint8_t sector[512] __attribute__((aligned(8))); uint8_t sector[512] __attribute__((aligned(8)));
card_status = sc64_sd_card_get_status(); card_status = sc64_sd_card_get_status();
if (card_status & SD_CARD_STATUS_INSERTED) { if (card_status & SD_CARD_STATUS_INSERTED) {
display_printf("SD card is inserted\n"); display_printf("SD card is inserted\n");
} else { } else {
display_printf("SD card is not inserted\n"); display_printf("SD card is not inserted\n");
} }
if (sc64_sd_card_init()) { if (sc64_sd_card_init()) {
display_printf("SD card init error!\n"); display_printf("SD card init error!\n");
return; return;
} }
card_status = sc64_sd_card_get_status(); card_status = sc64_sd_card_get_status();
if (card_status & SD_CARD_STATUS_INITIALIZED) { if (card_status & SD_CARD_STATUS_INITIALIZED) {
display_printf("SD card is initialized\n"); display_printf("SD card is initialized\n");
} }
if (card_status & SD_CARD_STATUS_TYPE_BLOCK) { if (card_status & SD_CARD_STATUS_TYPE_BLOCK) {
display_printf("SD card type is block\n"); display_printf("SD card type is block\n");
} }
if (card_status & SD_CARD_STATUS_50MHZ_MODE) { if (card_status & SD_CARD_STATUS_50MHZ_MODE) {
display_printf("SD card runs at 50 MHz clock speed\n"); display_printf("SD card runs at 50 MHz clock speed\n");
} }
if (sc64_sd_card_get_info((uint32_t *) (SC64_BUFFERS->BUFFER))) { if (sc64_sd_card_get_info((uint32_t *) (SC64_BUFFERS->BUFFER))) {
display_printf("SD card get info error!\n"); display_printf("SD card get info error!\n");
return; return;
} }
pi_dma_read((io32_t *) (SC64_BUFFERS->BUFFER), card_info, sizeof(card_info)); pi_dma_read((io32_t *) (SC64_BUFFERS->BUFFER), card_info, sizeof(card_info));
display_printf("SD Card registers:\n CSD: 0x"); display_printf("SD Card registers:\n CSD: 0x");
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
display_printf("%02X ", card_info[i]); display_printf("%02X ", card_info[i]);
} }
display_printf("\n CID: 0x"); display_printf("\n CID: 0x");
for (int i = 16; i < 32; i++) { for (int i = 16; i < 32; i++) {
display_printf("%02X ", card_info[i]); display_printf("%02X ", card_info[i]);
} }
display_printf("\n "); display_printf("\n ");
for (int i = 16; i < 32; i++) { for (int i = 16; i < 32; i++) {
display_printf(" %c ", card_info[i] >= ' ' ? card_info[i] : 0xFF); display_printf(" %c ", card_info[i] >= ' ' ? card_info[i] : 0xFF);
} }
display_printf("\n"); display_printf("\n");
if (sc64_sd_read_sectors((void *) (SC64_BUFFERS->BUFFER), 0, 1)) { if (sc64_sd_read_sectors((void *) (SC64_BUFFERS->BUFFER), 0, 1)) {
display_printf("SD card read sector 0 error!\n"); display_printf("SD card read sector 0 error!\n");
} return;
}
pi_dma_read((io32_t *) (SC64_BUFFERS->BUFFER), sector, sizeof(sector));
pi_dma_read((io32_t *) (SC64_BUFFERS->BUFFER), sector, sizeof(sector));
display_printf("Sector 0 (0x1BE-0x1DD), partition entry 1/2:\n 0x");
for (int i = 0; i < 16; i++) { display_printf("Sector 0 (0x1BE-0x1DD), partition entry 1/2:\n 0x");
display_printf("%02X ", sector[0x1BE + i]); for (int i = 0; i < 16; i++) {
} display_printf("%02X ", sector[0x1BE + i]);
display_printf("\n 0x"); }
for (int i = 0; i < 16; i++) { display_printf("\n 0x");
display_printf("%02X ", sector[0x1CE + i]); for (int i = 0; i < 16; i++) {
} display_printf("%02X ", sector[0x1CE + i]);
display_printf("\n"); }
display_printf(" Boot signature: 0x%02X%02X", sector[510], sector[511]); display_printf("\n");
} display_printf(" Boot signature: 0x%02X%02X\n", sector[510], sector[511]);
}
bool test_check (void) {
if (OS_INFO->reset_type != OS_INFO_RESET_TYPE_COLD) { bool test_check (void) {
return false; if (OS_INFO->reset_type != OS_INFO_RESET_TYPE_COLD) {
} return false;
return sc64_get_config(CFG_ID_BUTTON_STATE); }
} return sc64_get_config(CFG_ID_BUTTON_STATE);
}
void test_execute (void) {
display_init(NULL); void test_execute (void) {
display_printf("SC64 Test suite\n\n"); display_init(NULL);
display_printf("SC64 Test suite\n\n");
display_printf("[ RTC tests ]\n");
test_rtc(); display_printf("[ RTC tests ]\n");
display_printf("\n"); test_rtc();
display_printf("\n");
display_printf("[ SD card tests ]\n");
test_sd_card(); display_printf("[ SD card tests ]\n");
display_printf("\n"); test_sd_card();
display_printf("\n");
while (1);
} while (1);
}

View File

@ -1,478 +1,473 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "fpga.h" #include "fpga.h"
#include "hw.h" #include "hw.h"
#include "led.h" #include "led.h"
#include "sd.h" #include "sd.h"
#define SD_INIT_BUFFER_ADDRESS (0x05002800UL) #define SD_INIT_BUFFER_ADDRESS (0x05002800UL)
#define CMD6_ARG_CHECK_HS (0x00FFFFF1UL) #define CMD6_ARG_CHECK_HS (0x00FFFFF1UL)
#define CMD6_ARG_SWITCH_HS (0x80FFFFF1UL) #define CMD6_ARG_SWITCH_HS (0x80FFFFF1UL)
#define CMD8_ARG_SUPPLY_VOLTAGE_27_36_V (1 << 8) #define CMD8_ARG_SUPPLY_VOLTAGE_27_36_V (1 << 8)
#define CMD8_ARG_CHECK_PATTERN (0xAA << 0) #define CMD8_ARG_CHECK_PATTERN (0xAA << 0)
#define ACMD6_ARG_BUS_WIDTH_4BIT (2 << 0) #define ACMD6_ARG_BUS_WIDTH_4BIT (2 << 0)
#define ACMD41_ARG_OCR (0x300000 << 0) #define ACMD41_ARG_OCR (0x300000 << 0)
#define ACMD41_ARG_HCS (1 << 30) #define ACMD41_ARG_HCS (1 << 30)
#define R3_OCR (0x300000 << 0) #define R3_OCR (0x300000 << 0)
#define R3_CCS (1 << 30) #define R3_CCS (1 << 30)
#define R3_BUSY (1 << 31) #define R3_BUSY (1 << 31)
#define R6_RCA_MASK (0xFFFF0000UL) #define R6_RCA_MASK (0xFFFF0000UL)
#define R7_SUPPLY_VOLTAGE_27_36_V (1 << 8) #define R7_SUPPLY_VOLTAGE_27_36_V (1 << 8)
#define R7_CHECK_PATTERN (0xAA << 0) #define R7_CHECK_PATTERN (0xAA << 0)
#define SWITCH_FUNCTION_CURRENT_LIMIT (SD_INIT_BUFFER_ADDRESS + 0) #define SWITCH_FUNCTION_CURRENT_LIMIT (SD_INIT_BUFFER_ADDRESS + 0)
#define SWITCH_FUNCTION_GROUP_1 (SD_INIT_BUFFER_ADDRESS + 12) #define SWITCH_FUNCTION_GROUP_1 (SD_INIT_BUFFER_ADDRESS + 12)
#define SWITCH_FUNCTION_GROUP_1_HS (1 << 1) #define SWITCH_FUNCTION_GROUP_1_HS (1 << 1)
#define DAT_BLOCK_MAX_COUNT (256) #define DAT_BLOCK_MAX_COUNT (256)
#define DAT_TIMEOUT_MS (1000) #define DAT_TIMEOUT_INIT_MS (2000)
#define DAT_TIMEOUT_DATA_MS (5000)
typedef enum {
CLOCK_STOP, typedef enum {
CLOCK_400KHZ, CLOCK_STOP,
CLOCK_25MHZ, CLOCK_400KHZ,
CLOCK_50MHZ, CLOCK_25MHZ,
} sd_clock_t; CLOCK_50MHZ,
} sd_clock_t;
typedef enum {
RSP_NONE, typedef enum {
RSP_R1, RSP_NONE,
RSP_R1b, RSP_R1,
RSP_R2, RSP_R1b,
RSP_R3, RSP_R2,
RSP_R6, RSP_R3,
RSP_R7, RSP_R6,
} rsp_type_t; RSP_R7,
} rsp_type_t;
typedef enum {
DAT_READ, typedef enum {
DAT_WRITE, DAT_READ,
} dat_mode_t; DAT_WRITE,
} dat_mode_t;
struct process {
bool card_initialized; struct process {
bool card_type_block; bool card_initialized;
uint32_t rca; bool card_type_block;
uint8_t csd[16]; uint32_t rca;
uint8_t cid[16]; uint8_t csd[16];
volatile bool timeout; uint8_t cid[16];
}; volatile bool timeout;
};
static struct process p;
static struct process p;
static void sd_trigger_timeout (void) {
p.timeout = true; static void sd_trigger_timeout (void) {
} p.timeout = true;
}
static void sd_prepare_timeout (uint16_t value) {
p.timeout = false; static void sd_prepare_timeout (uint16_t value) {
hw_tim_setup(TIM_ID_SD, value, sd_trigger_timeout); p.timeout = false;
} hw_tim_setup(TIM_ID_SD, value, sd_trigger_timeout);
}
static bool sd_did_timeout (void) {
return p.timeout; static bool sd_did_timeout (void) {
} return p.timeout;
}
static void sd_clear_timeout (void) {
hw_tim_stop(TIM_ID_SD); static void sd_clear_timeout (void) {
p.timeout = false; hw_tim_stop(TIM_ID_SD);
} p.timeout = false;
}
static void sd_set_clock (sd_clock_t mode) {
fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_OFF); static void sd_set_clock (sd_clock_t mode) {
fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_OFF);
switch (mode) {
case CLOCK_400KHZ: switch (mode) {
fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_400KHZ); case CLOCK_400KHZ:
break; fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_400KHZ);
case CLOCK_25MHZ: break;
fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_25MHZ); case CLOCK_25MHZ:
break; fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_25MHZ);
case CLOCK_50MHZ: break;
fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_50MHZ); case CLOCK_50MHZ:
break; fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_50MHZ);
default: break;
break; default:
} break;
} }
}
static bool sd_cmd (uint8_t cmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) {
uint32_t scr; static bool sd_cmd (uint8_t cmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) {
uint32_t cmd_data; uint32_t scr;
uint32_t cmd_data;
cmd_data = ((cmd << SD_CMD_INDEX_BIT) & SD_CMD_INDEX_MASK);
switch (rsp_type) { cmd_data = ((cmd << SD_CMD_INDEX_BIT) & SD_CMD_INDEX_MASK);
case RSP_NONE: switch (rsp_type) {
cmd_data |= SD_CMD_SKIP_RESPONSE; case RSP_NONE:
break; cmd_data |= SD_CMD_SKIP_RESPONSE;
case RSP_R2: break;
cmd_data |= (SD_CMD_LONG_RESPONSE | SD_CMD_RESERVED_RESPONSE); case RSP_R2:
break; cmd_data |= (SD_CMD_LONG_RESPONSE | SD_CMD_RESERVED_RESPONSE);
case RSP_R3: break;
cmd_data |= (SD_CMD_IGNORE_CRC | SD_CMD_RESERVED_RESPONSE); case RSP_R3:
break; cmd_data |= (SD_CMD_IGNORE_CRC | SD_CMD_RESERVED_RESPONSE);
default: break;
break; default:
} break;
}
fpga_reg_set(REG_SD_ARG, arg);
fpga_reg_set(REG_SD_CMD, cmd_data); fpga_reg_set(REG_SD_ARG, arg);
fpga_reg_set(REG_SD_CMD, cmd_data);
do {
scr = fpga_reg_get(REG_SD_SCR); do {
} while (scr & SD_SCR_CMD_BUSY); scr = fpga_reg_get(REG_SD_SCR);
} while (scr & SD_SCR_CMD_BUSY);
if (rsp != NULL) {
if (cmd_data & SD_CMD_LONG_RESPONSE) { if (rsp != NULL) {
uint8_t *rsp_8 = (uint8_t *) (rsp); if (cmd_data & SD_CMD_LONG_RESPONSE) {
for (int i = 0; i < 4; i++) { uint8_t *rsp_8 = (uint8_t *) (rsp);
uint32_t rsp_data = fpga_reg_get(REG_SD_RSP_3 - i); for (int i = 0; i < 4; i++) {
uint8_t *rsp_data_8 = (uint8_t *) (&rsp_data); uint32_t rsp_data = fpga_reg_get(REG_SD_RSP_3 - i);
rsp_data = SWAP32(rsp_data); uint8_t *rsp_data_8 = (uint8_t *) (&rsp_data);
for (int i = 0; i < 4; i++) { rsp_data = SWAP32(rsp_data);
*rsp_8++ = *rsp_data_8++; for (int i = 0; i < 4; i++) {
} *rsp_8++ = *rsp_data_8++;
} }
} else { }
(*(uint32_t *) (rsp)) = fpga_reg_get(REG_SD_RSP_0); } else {
} (*(uint32_t *) (rsp)) = fpga_reg_get(REG_SD_RSP_0);
} }
}
if (rsp_type == RSP_R1b) {
do { if (rsp_type == RSP_R1b) {
scr = fpga_reg_get(REG_SD_SCR); do {
} while (scr & SD_SCR_CARD_BUSY); scr = fpga_reg_get(REG_SD_SCR);
} } while (scr & SD_SCR_CARD_BUSY);
}
return (scr & SD_SCR_CMD_ERROR);
} return (scr & SD_SCR_CMD_ERROR);
}
static bool sd_acmd (uint8_t acmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) {
if (sd_cmd(55, p.rca, RSP_R1, NULL)) { static bool sd_acmd (uint8_t acmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) {
return true; if (sd_cmd(55, p.rca, RSP_R1, NULL)) {
} return true;
if (sd_cmd(acmd, arg, rsp_type, rsp)) { }
return true; if (sd_cmd(acmd, arg, rsp_type, rsp)) {
} return true;
return false; }
} return false;
}
static void sd_dat_prepare (uint32_t address, uint32_t count, dat_mode_t mode) {
uint32_t length = (count * SD_SECTOR_SIZE); static void sd_dat_prepare (uint32_t address, uint32_t count, dat_mode_t mode) {
uint32_t sd_dat = (((count - 1) << SD_DAT_BLOCKS_BIT) | SD_DAT_FIFO_FLUSH); uint32_t length = (count * SD_SECTOR_SIZE);
uint32_t sd_dma_scr = DMA_SCR_START; uint32_t sd_dat = (((count - 1) << SD_DAT_BLOCKS_BIT) | SD_DAT_FIFO_FLUSH);
uint32_t sd_dma_scr = DMA_SCR_START;
if (mode == DAT_READ) {
sd_dat |= SD_DAT_START_READ; if (mode == DAT_READ) {
sd_dma_scr |= DMA_SCR_DIRECTION; sd_dat |= SD_DAT_START_READ;
} else { sd_dma_scr |= DMA_SCR_DIRECTION;
sd_dat |= SD_DAT_START_WRITE; } else {
} sd_dat |= SD_DAT_START_WRITE;
}
fpga_reg_set(REG_SD_DAT, sd_dat);
fpga_reg_set(REG_SD_DMA_ADDRESS, address); fpga_reg_set(REG_SD_DAT, sd_dat);
fpga_reg_set(REG_SD_DMA_LENGTH, length); fpga_reg_set(REG_SD_DMA_ADDRESS, address);
fpga_reg_set(REG_SD_DMA_SCR, sd_dma_scr); fpga_reg_set(REG_SD_DMA_LENGTH, length);
} fpga_reg_set(REG_SD_DMA_SCR, sd_dma_scr);
}
static void sd_dat_abort (void) {
fpga_reg_set(REG_SD_DMA_SCR, DMA_SCR_STOP); static void sd_dat_abort (void) {
fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH); fpga_reg_set(REG_SD_DMA_SCR, DMA_SCR_STOP);
} fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH);
}
static bool sd_dat_wait (uint16_t timeout) {
sd_prepare_timeout(timeout); static bool sd_dat_wait (uint16_t timeout) {
sd_prepare_timeout(timeout);
do {
uint32_t sd_dat = fpga_reg_get(REG_SD_DAT); do {
uint32_t sd_dma_scr = fpga_reg_get(REG_SD_DMA_SCR); uint32_t sd_dat = fpga_reg_get(REG_SD_DAT);
led_blink_act(); uint32_t sd_dma_scr = fpga_reg_get(REG_SD_DMA_SCR);
if ((!(sd_dat & SD_DAT_BUSY)) && (!(sd_dma_scr & DMA_SCR_BUSY))) { led_blink_act();
sd_clear_timeout(); if ((!(sd_dat & SD_DAT_BUSY)) && (!(sd_dma_scr & DMA_SCR_BUSY))) {
return (sd_dat & SD_DAT_ERROR); sd_clear_timeout();
} return (sd_dat & SD_DAT_ERROR);
} while (!sd_did_timeout()); }
} while (!sd_did_timeout());
sd_dat_abort();
sd_dat_abort();
return true;
} return true;
}
bool sd_card_init (void) {
uint32_t arg; bool sd_card_init (void) {
uint32_t rsp; uint32_t arg;
uint16_t tmp; uint32_t rsp;
uint16_t tmp;
if (p.card_initialized) {
return false; if (p.card_initialized) {
} return false;
}
p.card_initialized = true;
p.rca = 0; p.card_initialized = true;
p.rca = 0;
led_blink_act();
led_blink_act();
sd_set_clock(CLOCK_400KHZ);
sd_set_clock(CLOCK_400KHZ);
sd_cmd(0, 0, RSP_NONE, NULL);
sd_cmd(0, 0, RSP_NONE, NULL);
arg = (CMD8_ARG_SUPPLY_VOLTAGE_27_36_V | CMD8_ARG_CHECK_PATTERN);
if (sd_cmd(8, arg, RSP_R7, &rsp)) { arg = (CMD8_ARG_SUPPLY_VOLTAGE_27_36_V | CMD8_ARG_CHECK_PATTERN);
arg = ACMD41_ARG_OCR; if (sd_cmd(8, arg, RSP_R7, &rsp)) {
} else { arg = ACMD41_ARG_OCR;
if (rsp != (R7_SUPPLY_VOLTAGE_27_36_V | R7_CHECK_PATTERN)) { } else {
sd_card_deinit(); if (rsp != (R7_SUPPLY_VOLTAGE_27_36_V | R7_CHECK_PATTERN)) {
return true; sd_card_deinit();
} return true;
arg = (ACMD41_ARG_HCS | ACMD41_ARG_OCR); }
} arg = (ACMD41_ARG_HCS | ACMD41_ARG_OCR);
}
sd_prepare_timeout(1000);
do { sd_prepare_timeout(1000);
if (sd_did_timeout()) { do {
sd_card_deinit(); if (sd_did_timeout()) {
return true; sd_card_deinit();
} return true;
if (sd_acmd(41, arg, RSP_R3, &rsp)) { }
sd_card_deinit(); if (sd_acmd(41, arg, RSP_R3, &rsp)) {
return true; sd_card_deinit();
} return true;
if (rsp & R3_BUSY) { }
if ((rsp & R3_OCR) == 0) { if (rsp & R3_BUSY) {
sd_card_deinit(); if ((rsp & R3_OCR) == 0) {
return true; sd_card_deinit();
} return true;
p.card_type_block = (rsp & R3_CCS); }
break; p.card_type_block = (rsp & R3_CCS);
} break;
} while (1); }
sd_clear_timeout(); } while (1);
sd_clear_timeout();
if (sd_cmd(2, 0, RSP_R2, NULL)) {
sd_card_deinit(); if (sd_cmd(2, 0, RSP_R2, NULL)) {
return true; sd_card_deinit();
} return true;
}
if (sd_cmd(3, 0, RSP_R6, &rsp)) {
sd_card_deinit(); if (sd_cmd(3, 0, RSP_R6, &rsp)) {
return true; sd_card_deinit();
} return true;
p.rca = (rsp & R6_RCA_MASK); }
p.rca = (rsp & R6_RCA_MASK);
if (sd_cmd(9, p.rca, RSP_R2, p.csd)) {
sd_card_deinit(); if (sd_cmd(9, p.rca, RSP_R2, p.csd)) {
return true; sd_card_deinit();
} return true;
}
if (sd_cmd(10, p.rca, RSP_R2, p.cid)) {
sd_card_deinit(); if (sd_cmd(10, p.rca, RSP_R2, p.cid)) {
return true; sd_card_deinit();
} return true;
}
if (sd_cmd(7, p.rca, RSP_R1b, NULL)) {
sd_card_deinit(); if (sd_cmd(7, p.rca, RSP_R1b, NULL)) {
return true; sd_card_deinit();
} return true;
}
sd_set_clock(CLOCK_25MHZ);
sd_set_clock(CLOCK_25MHZ);
if (sd_acmd(6, ACMD6_ARG_BUS_WIDTH_4BIT, RSP_R1, NULL)) {
sd_card_deinit(); if (sd_acmd(6, ACMD6_ARG_BUS_WIDTH_4BIT, RSP_R1, NULL)) {
return true; sd_card_deinit();
} return true;
}
sd_dat_prepare(SD_INIT_BUFFER_ADDRESS, 1, DAT_READ);
if (sd_cmd(6, CMD6_ARG_CHECK_HS, RSP_R1, NULL)) { sd_dat_prepare(SD_INIT_BUFFER_ADDRESS, 1, DAT_READ);
sd_dat_abort(); if (sd_cmd(6, CMD6_ARG_CHECK_HS, RSP_R1, NULL)) {
sd_card_deinit(); sd_dat_abort();
return true; sd_card_deinit();
} return true;
sd_dat_wait(DAT_TIMEOUT_MS); }
if (sd_did_timeout()) { sd_dat_wait(DAT_TIMEOUT_INIT_MS);
sd_card_deinit(); if (sd_did_timeout()) {
return true; sd_card_deinit();
} return true;
fpga_mem_read(SWITCH_FUNCTION_CURRENT_LIMIT, 2, (uint8_t *) (&tmp)); }
if (SWAP16(tmp) == 0) { fpga_mem_read(SWITCH_FUNCTION_CURRENT_LIMIT, 2, (uint8_t *) (&tmp));
sd_card_deinit(); if (SWAP16(tmp) == 0) {
return true; sd_card_deinit();
} return true;
fpga_mem_read(SWITCH_FUNCTION_GROUP_1, 2, (uint8_t *) (&tmp)); }
if (SWAP16(tmp) & SWITCH_FUNCTION_GROUP_1_HS) { fpga_mem_read(SWITCH_FUNCTION_GROUP_1, 2, (uint8_t *) (&tmp));
sd_dat_prepare(SD_INIT_BUFFER_ADDRESS, 1, DAT_READ); if (SWAP16(tmp) & SWITCH_FUNCTION_GROUP_1_HS) {
if (sd_cmd(6, CMD6_ARG_SWITCH_HS, RSP_R1, NULL)) { sd_dat_prepare(SD_INIT_BUFFER_ADDRESS, 1, DAT_READ);
sd_dat_abort(); if (sd_cmd(6, CMD6_ARG_SWITCH_HS, RSP_R1, NULL)) {
sd_card_deinit(); sd_dat_abort();
return true; sd_card_deinit();
} return true;
sd_dat_wait(DAT_TIMEOUT_MS); }
if (sd_did_timeout()) { sd_dat_wait(DAT_TIMEOUT_INIT_MS);
sd_card_deinit(); if (sd_did_timeout()) {
return true; sd_card_deinit();
} return true;
fpga_mem_read(SWITCH_FUNCTION_GROUP_1, 2, (uint8_t *) (&tmp)); }
if (SWAP16(tmp) & SWITCH_FUNCTION_GROUP_1_HS) { fpga_mem_read(SWITCH_FUNCTION_GROUP_1, 2, (uint8_t *) (&tmp));
sd_set_clock(CLOCK_50MHZ); if (SWAP16(tmp) & SWITCH_FUNCTION_GROUP_1_HS) {
} sd_set_clock(CLOCK_50MHZ);
} }
}
return false;
} return false;
}
void sd_card_deinit (void) {
if (p.card_initialized) { void sd_card_deinit (void) {
p.card_initialized = false; if (p.card_initialized) {
sd_set_clock(CLOCK_400KHZ); p.card_initialized = false;
sd_cmd(0, 0, RSP_NONE, NULL); sd_set_clock(CLOCK_400KHZ);
sd_set_clock(CLOCK_STOP); sd_cmd(0, 0, RSP_NONE, NULL);
} sd_set_clock(CLOCK_STOP);
} }
}
bool sd_card_is_inserted (void) {
return (fpga_reg_get(REG_SD_SCR) & SD_SCR_CARD_INSERTED); bool sd_card_is_inserted (void) {
} return (fpga_reg_get(REG_SD_SCR) & SD_SCR_CARD_INSERTED);
}
uint32_t sd_card_get_status (void) {
uint32_t scr = fpga_reg_get(REG_SD_SCR); uint32_t sd_card_get_status (void) {
uint32_t clock_mode_50mhz = ((scr & SD_SCR_CLOCK_MODE_MASK) == SD_SCR_CLOCK_MODE_50MHZ) ? 1 : 0; uint32_t scr = fpga_reg_get(REG_SD_SCR);
uint32_t card_type_block = p.card_type_block ? 1 : 0; uint32_t clock_mode_50mhz = ((scr & SD_SCR_CLOCK_MODE_MASK) == SD_SCR_CLOCK_MODE_50MHZ) ? 1 : 0;
uint32_t card_initialized = p.card_initialized ? 1 : 0; uint32_t card_type_block = p.card_type_block ? 1 : 0;
uint32_t card_inserted = (scr & SD_SCR_CARD_INSERTED) ? 1 : 0; uint32_t card_initialized = p.card_initialized ? 1 : 0;
return ( uint32_t card_inserted = (scr & SD_SCR_CARD_INSERTED) ? 1 : 0;
(clock_mode_50mhz << 3) | return (
(card_type_block << 2) | (clock_mode_50mhz << 3) |
(card_initialized << 1) | (card_type_block << 2) |
(card_inserted << 0) (card_initialized << 1) |
); (card_inserted << 0)
} );
}
bool sd_card_get_info (uint32_t address) {
if (!p.card_initialized) { bool sd_card_get_info (uint32_t address) {
return true; if (!p.card_initialized) {
} return true;
fpga_mem_write(address, sizeof(p.csd), p.csd); }
address += sizeof(p.csd); fpga_mem_write(address, sizeof(p.csd), p.csd);
fpga_mem_write(address, sizeof(p.cid), p.cid); address += sizeof(p.csd);
address += sizeof(p.cid); fpga_mem_write(address, sizeof(p.cid), p.cid);
return false; address += sizeof(p.cid);
} return false;
}
bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
if (!p.card_initialized || (count == 0)) { bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
return true; if (!p.card_initialized || (count == 0)) {
} return true;
}
if (!p.card_type_block) {
sector *= SD_SECTOR_SIZE; if (!p.card_type_block) {
} sector *= SD_SECTOR_SIZE;
}
while (count > 0) {
uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count); while (count > 0) {
led_blink_act(); uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count);
if (sd_cmd(23, blocks, RSP_R1, NULL)) { led_blink_act();
return true; if (sd_cmd(25, sector, RSP_R1, NULL)) {
} return true;
if (sd_cmd(25, sector, RSP_R1, NULL)) { }
return true; sd_dat_prepare(address, blocks, DAT_WRITE);
} if (sd_dat_wait(DAT_TIMEOUT_DATA_MS)) {
sd_dat_prepare(address, blocks, DAT_WRITE); sd_dat_abort();
if (sd_dat_wait(DAT_TIMEOUT_MS)) { sd_cmd(12, 0, RSP_R1b, NULL);
sd_dat_abort(); return true;
sd_cmd(12, 0, RSP_R1b, NULL); }
return true; sd_cmd(12, 0, RSP_R1b, NULL);
} address += (blocks * SD_SECTOR_SIZE);
sd_cmd(12, 0, RSP_R1b, NULL); sector += (blocks * (p.card_type_block ? 1 : SD_SECTOR_SIZE));
address += (blocks * SD_SECTOR_SIZE); count -= blocks;
sector += (blocks * (p.card_type_block ? 1 : SD_SECTOR_SIZE)); }
count -= blocks;
} return false;
}
return false;
} bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
if (!p.card_initialized || (count == 0)) {
bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) { return true;
if (!p.card_initialized || (count == 0)) { }
return true;
} if (!p.card_type_block) {
sector *= SD_SECTOR_SIZE;
if (!p.card_type_block) { }
sector *= SD_SECTOR_SIZE;
} while (count > 0) {
uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count);
while (count > 0) { led_blink_act();
uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count); sd_dat_prepare(address, blocks, DAT_READ);
led_blink_act(); if (sd_cmd(18, sector, RSP_R1, NULL)) {
sd_dat_prepare(address, blocks, DAT_READ); sd_dat_abort();
if (sd_cmd(23, blocks, RSP_R1, NULL)) { return true;
sd_dat_abort(); }
return true; if (sd_dat_wait(DAT_TIMEOUT_DATA_MS)) {
} if (sd_did_timeout()) {
if (sd_cmd(18, sector, RSP_R1, NULL)) { sd_cmd(12, 0, RSP_R1b, NULL);
sd_dat_abort(); }
return true; return true;
} }
if (sd_dat_wait(DAT_TIMEOUT_MS)) { sd_cmd(12, 0, RSP_R1b, NULL);
if (sd_did_timeout()) { address += (blocks * SD_SECTOR_SIZE);
sd_cmd(12, 0, RSP_R1b, NULL); sector += (blocks * (p.card_type_block ? 1 : SD_SECTOR_SIZE));
} count -= blocks;
return true; }
}
address += (blocks * SD_SECTOR_SIZE); return false;
sector += (blocks * (p.card_type_block ? 1 : SD_SECTOR_SIZE)); }
count -= blocks;
} bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors) {
uint32_t starting_sector = 0;
return false; uint32_t sectors_to_process = 0;
}
if (count == 0) {
bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors) { return true;
uint32_t starting_sector = 0; }
uint32_t sectors_to_process = 0;
for (uint32_t i = 0; i < count; i++) {
if (count == 0) { if (sector_table[i] == 0) {
return true; return true;
} }
sectors_to_process += 1;
for (uint32_t i = 0; i < count; i++) { if ((i < (count - 1)) && ((sector_table[i] + 1) == sector_table[i + 1])) {
if (sector_table[i] == 0) { continue;
return true; }
} bool error = sd_process_sectors(address, sector_table[starting_sector], sectors_to_process);
sectors_to_process += 1; if (error) {
if ((i < (count - 1)) && ((sector_table[i] + 1) == sector_table[i + 1])) { return true;
continue; }
} address += (sectors_to_process * SD_SECTOR_SIZE);
bool error = sd_process_sectors(address, sector_table[starting_sector], sectors_to_process); starting_sector += sectors_to_process;
if (error) { sectors_to_process = 0;
return true; }
}
address += (sectors_to_process * SD_SECTOR_SIZE); return false;
starting_sector += sectors_to_process; }
sectors_to_process = 0;
} void sd_init (void) {
p.card_initialized = false;
return false; sd_set_clock(CLOCK_STOP);
} }
void sd_init (void) { void sd_process (void) {
p.card_initialized = false; if (!sd_card_is_inserted()) {
sd_set_clock(CLOCK_STOP); sd_card_deinit();
} }
}
void sd_process (void) {
if (!sd_card_is_inserted()) {
sd_card_deinit();
}
}

View File

@ -338,7 +338,7 @@ class SC64:
def __get_int(self, data: bytes) -> int: def __get_int(self, data: bytes) -> int:
return int.from_bytes(data[:4], byteorder='big') return int.from_bytes(data[:4], byteorder='big')
def check_firmware_version(self) -> None: def check_firmware_version(self) -> tuple[str, bool]:
try: try:
version = self.__link.execute_cmd(cmd=b'V') version = self.__link.execute_cmd(cmd=b'V')
major = self.__get_int(version[0:2]) major = self.__get_int(version[0:2])
@ -347,8 +347,9 @@ class SC64:
raise ConnectionException() raise ConnectionException()
if (minor < self.__SUPPORTED_MINOR_VERSION): if (minor < self.__SUPPORTED_MINOR_VERSION):
raise ConnectionException() raise ConnectionException()
return (f'{major}.{minor}', minor > self.__SUPPORTED_MINOR_VERSION)
except ConnectionException: except ConnectionException:
raise ConnectionException(f'Unsupported SC64 version ({major}.{minor}), please update firmware') raise ConnectionException(f'Unsupported SC64 version [{major}.{minor}], please update firmware')
def __set_config(self, config: __CfgId, value: int) -> None: def __set_config(self, config: __CfgId, value: int) -> None:
try: try:
@ -1054,7 +1055,15 @@ if __name__ == '__main__':
sc64.update_firmware(f.read(), status_callback) sc64.update_firmware(f.read(), status_callback)
print('done') print('done')
sc64.check_firmware_version() (version, script_outdated) = sc64.check_firmware_version()
print(f'SC64 firmware version: [{version}]')
if (script_outdated):
print('\x1b[33m')
print('[ SC64 firmware is newer than last known version. ]')
print('[ Consider downloading latest script from ]')
print('[ https://github.com/Polprzewodnikowy/SummerCart64/releases ]')
print('\x1b[0m')
if (args.reset_state): if (args.reset_state):
sc64.reset_state() sc64.reset_state()
@ -1142,6 +1151,6 @@ if __name__ == '__main__':
f.write(sc64.download_memory(address, length)) f.write(sc64.download_memory(address, length))
print('done') print('done')
except ValueError as e: except ValueError as e:
print(f'\nValue error: {e}') print(f'\n\x1b[31mValue error: {e}\x1b[0m\n')
except ConnectionException as e: except ConnectionException as e:
print(f'\nSC64 error: {e}') print(f'\n\x1b[31mSC64 error: {e}\x1b[0m\n')