From e6751c262da40cacf08d9d5a2ad7d733132790b5 Mon Sep 17 00:00:00 2001 From: Mateusz Faderewski Date: Tue, 14 May 2024 01:36:34 +0200 Subject: [PATCH] [SC64][SW] bootloader/controller: added more meaningful errors in the SD card module Also added manual CRC16 check in the software for data blocks smaller than 512 bytes --- sw/bootloader/src/fatfs/diskio.c | 17 ++- sw/bootloader/src/init.c | 2 +- sw/bootloader/src/main.c | 4 +- sw/bootloader/src/menu.c | 20 ++- sw/bootloader/src/sc64.c | 58 ++++++- sw/bootloader/src/sc64.h | 56 ++++++- sw/bootloader/src/test.c | 87 ++++++----- sw/controller/src/cfg.c | 110 +++++++------- sw/controller/src/dd.c | 8 +- sw/controller/src/fpga.h | 1 - sw/controller/src/hw.c | 12 +- sw/controller/src/hw.h | 10 +- sw/controller/src/lcmxo2.c | 4 +- sw/controller/src/sd.c | 249 ++++++++++++++++++++++--------- sw/controller/src/sd.h | 47 +++++- sw/controller/src/writeback.c | 4 +- 16 files changed, 468 insertions(+), 221 deletions(-) diff --git a/sw/bootloader/src/fatfs/diskio.c b/sw/bootloader/src/fatfs/diskio.c index 0afa1e9..ee10d0d 100644 --- a/sw/bootloader/src/fatfs/diskio.c +++ b/sw/bootloader/src/fatfs/diskio.c @@ -10,6 +10,9 @@ #define BUFFER_BLOCKS_MAX (sizeof(SC64_BUFFERS->BUFFER) / SD_SECTOR_SIZE) +sc64_error_t sc64_error_fatfs; + + DSTATUS disk_status (BYTE pdrv) { if (pdrv > 0) { return STA_NODISK; @@ -20,7 +23,7 @@ DSTATUS disk_status (BYTE pdrv) { sc64_sd_card_status_t sd_card_status; if ((error = sc64_sd_card_get_status(&sd_card_status)) != SC64_OK) { - error_display("Could not get SD card status: %d", error); + error_display("Could not get SD card status\n (%08X) - %s", error, sc64_error_description(error)); } if (!(sd_card_status & SD_CARD_STATUS_INSERTED)) { @@ -38,7 +41,7 @@ DSTATUS disk_initialize (BYTE pdrv) { return STA_NODISK; } - sc64_sd_card_init(); + sc64_error_fatfs = sc64_sd_card_init(); return disk_status(pdrv); } @@ -53,7 +56,7 @@ DRESULT disk_read (BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) { while (count > 0) { uint32_t blocks = ((count > BUFFER_BLOCKS_MAX) ? BUFFER_BLOCKS_MAX : count); size_t length = (blocks * SD_SECTOR_SIZE); - if (sc64_sd_read_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks) != SC64_OK) { + if ((sc64_error_fatfs = sc64_sd_read_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks)) != SC64_OK) { return RES_ERROR; } if (((uint32_t) (buff) % 8) == 0) { @@ -67,7 +70,7 @@ DRESULT disk_read (BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) { count -= blocks; } } else { - if (sc64_sd_read_sectors(physical_address, sector, count) != SC64_OK) { + if ((sc64_error_fatfs = sc64_sd_read_sectors(physical_address, sector, count)) != SC64_OK) { return RES_ERROR; } } @@ -91,7 +94,7 @@ DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) { memcpy(aligned_buffer, buff, length); pi_dma_write((io32_t *) (SC64_BUFFERS->BUFFER), aligned_buffer, length); } - if (sc64_sd_write_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks) != SC64_OK) { + if ((sc64_error_fatfs = sc64_sd_write_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks)) != SC64_OK) { return RES_ERROR; } buff += length; @@ -99,7 +102,7 @@ DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) { count -= blocks; } } else { - if (sc64_sd_write_sectors(physical_address, sector, count) != SC64_OK) { + if ((sc64_error_fatfs = sc64_sd_write_sectors(physical_address, sector, count)) != SC64_OK) { return RES_ERROR; } } @@ -122,7 +125,7 @@ DWORD get_fattime(void) { sc64_rtc_time_t t; if ((error = sc64_get_time(&t)) != SC64_OK) { - error_display("Command TIME_GET failed: %d", error); + error_display("Command TIME_GET failed\n (%08X) - %s", error, sc64_error_description(error)); } return ( diff --git a/sw/bootloader/src/init.c b/sw/bootloader/src/init.c index 0829b68..c41ab01 100644 --- a/sw/bootloader/src/init.c +++ b/sw/bootloader/src/init.c @@ -28,7 +28,7 @@ void init (init_tv_type_t tv_type, init_reset_type_t reset_type, uint32_t entrop exception_enable_interrupts(); if ((error = sc64_set_config(CFG_ID_BOOTLOADER_SWITCH, false)) != SC64_OK) { - error_display("Command CONFIG_SET [BOOTLOADER_SWITCH] failed: %d", error); + error_display("Command CONFIG_SET [BOOTLOADER_SWITCH] failed\n (%08X) - %s", error, sc64_error_description(error)); } if (test_check()) { diff --git a/sw/bootloader/src/main.c b/sw/bootloader/src/main.c index f162fb0..b185701 100644 --- a/sw/bootloader/src/main.c +++ b/sw/bootloader/src/main.c @@ -12,7 +12,7 @@ void main (void) { sc64_boot_params_t sc64_boot_params; if ((error = sc64_get_boot_params(&sc64_boot_params)) != SC64_OK) { - error_display("Could not obtain boot info: %d", error); + error_display("Could not obtain boot info\n (%08X) - %s", error, sc64_error_description(error)); } boot_params_t boot_params; @@ -40,7 +40,7 @@ void main (void) { break; default: - error_display("Unknown boot mode selected [%d]\n", sc64_boot_params.boot_mode); + error_display("Unknown boot mode selected (%d)\n", sc64_boot_params.boot_mode); break; } diff --git a/sw/bootloader/src/menu.c b/sw/bootloader/src/menu.c index 89daf32..a5c72de 100644 --- a/sw/bootloader/src/menu.c +++ b/sw/bootloader/src/menu.c @@ -8,8 +8,11 @@ #define ROM_ADDRESS (0x10000000) +extern sc64_error_t sc64_error_fatfs; + + static const char *fatfs_error_codes[] = { - "Succeeded", + "No error", "A hard error occurred in the low level disk I/O layer", "Assertion failed", "The physical drive cannot work", @@ -35,7 +38,14 @@ static const char *fatfs_error_codes[] = { #define FF_CHECK(x, message, ...) { \ fresult = x; \ if (fresult != FR_OK) { \ - error_display(message ".\nReason: %s", __VA_ARGS__ __VA_OPT__(,) fatfs_error_codes[fresult]); \ + error_display( \ + message "\n" \ + " > FatFs error: %s\n" \ + " > SD card error: %s (%08X)", \ + __VA_ARGS__ __VA_OPT__(,) \ + fatfs_error_codes[fresult], \ + sc64_error_description(sc64_error_fatfs), sc64_error_fatfs \ + ); \ } \ } @@ -55,15 +65,15 @@ void menu_load (void) { do { if ((error = sc64_writeback_pending(&writeback_pending)) != SC64_OK) { - error_display("Command WRITEBACK_PENDING failed: %d", error); + error_display("Command WRITEBACK_PENDING failed\n (%08X) - %s", error, sc64_error_description(error)); } } while (writeback_pending); if ((error = sc64_writeback_disable()) != SC64_OK) { - error_display("Could not disable writeback: %d", error); + error_display("Could not disable save writeback\n (%08X) - %s", error, sc64_error_description(error)); } - FF_CHECK(f_mount(&fs, "", 1), "SD card initialize error. No SD card or invalid partition table"); + FF_CHECK(f_mount(&fs, "", 1), "SD card initialize error"); FF_CHECK(f_open(&fil, "sc64menu.n64", FA_READ), "Could not open menu executable (sc64menu.n64)"); fix_menu_file_size(&fil); FF_CHECK(f_read(&fil, (void *) (ROM_ADDRESS), f_size(&fil), &bytes_read), "Could not read menu file"); diff --git a/sw/bootloader/src/sc64.c b/sw/bootloader/src/sc64.c index f6ada8f..ddc6cb2 100644 --- a/sw/bootloader/src/sc64.c +++ b/sw/bootloader/src/sc64.c @@ -89,6 +89,61 @@ static sc64_error_t sc64_execute_cmd (sc64_cmd_t *cmd) { } +const char *sc64_error_description (sc64_error_t error) { + sc64_error_type_t type = (sc64_error_type_t) ((error >> 24) & 0xFF); + error &= 0xFFFFFF; + + if (type == ERROR_TYPE_CFG) { + switch ((sc64_cfg_error_t) (error)) { + case SC64_OK: return "No error"; + case CFG_ERROR_UNKNOWN_COMMAND: return "Unknown command"; + case CFG_ERROR_INVALID_ARGUMENT: return "Invalid argument"; + case CFG_ERROR_INVALID_ADDRESS: return "Invalid address"; + case CFG_ERROR_INVALID_ID: return "Invalid ID"; + default: return "Unknown error (CFG)"; + } + } + + if (type == ERROR_TYPE_SD_CARD) { + switch ((sc64_sd_error_t) (error)) { + case SD_OK: return "No error (SD)"; + case SD_ERROR_NO_CARD_IN_SLOT: return "No SD card in the slot"; + case SD_ERROR_NOT_INITIALIZED: return "SD card is not initialized"; + case SD_ERROR_INVALID_ARGUMENT: return "Invalid argument (SD)"; + case SD_ERROR_INVALID_ADDRESS: return "Invalid address (SD)"; + case SD_ERROR_INVALID_OPERATION: return "Invalid operation (SD)"; + case SD_ERROR_CMD2_IO: return "CMD2 I/O"; + case SD_ERROR_CMD3_IO: return "CMD3 I/O"; + case SD_ERROR_CMD6_CHECK_IO: return "CMD6 I/O (check)"; + case SD_ERROR_CMD6_CHECK_CRC: return "CMD6 CRC (check)"; + case SD_ERROR_CMD6_CHECK_TIMEOUT: return "CMD6 timeout (check)"; + case SD_ERROR_CMD6_CHECK_RESPONSE: return "CMD6 invalid response (check)"; + case SD_ERROR_CMD6_SWITCH_IO: return "CMD6 I/O (switch)"; + case SD_ERROR_CMD6_SWITCH_CRC: return "CMD6 CRC (switch)"; + case SD_ERROR_CMD6_SWITCH_TIMEOUT: return "CMD6 timeout (switch)"; + case SD_ERROR_CMD6_SWITCH_RESPONSE: return "CMD6 invalid response (switch)"; + case SD_ERROR_CMD7_IO: return "CMD7 I/O"; + case SD_ERROR_CMD8_IO: return "CMD8 I/O"; + case SD_ERROR_CMD9_IO: return "CMD9 I/O"; + case SD_ERROR_CMD10_IO: return "CMD10 I/O"; + case SD_ERROR_CMD18_IO: return "CMD18 I/O"; + case SD_ERROR_CMD18_CRC: return "CMD18 CRC"; + case SD_ERROR_CMD18_TIMEOUT: return "CMD18 timeout"; + case SD_ERROR_CMD25_IO: return "CMD25 I/O"; + case SD_ERROR_CMD25_CRC: return "CMD25 CRC"; + case SD_ERROR_CMD25_TIMEOUT: return "CMD25 timeout"; + case SD_ERROR_ACMD6_IO: return "ACMD6 I/O"; + case SD_ERROR_ACMD41_IO: return "ACMD41 I/O"; + case SD_ERROR_ACMD41_OCR: return "ACMD41 OCR"; + case SD_ERROR_ACMD41_TIMEOUT: return "ACMD41 timeout"; + default: return "Unknown error (SD)"; + } + } + + return "Unknown error (type)"; +} + + void sc64_unlock (void) { pi_io_write(&SC64_REGS->KEY, SC64_KEY_RESET); pi_io_write(&SC64_REGS->KEY, SC64_KEY_UNLOCK_1); @@ -396,8 +451,7 @@ sc64_error_t sc64_writeback_enable (void *address) { sc64_error_t sc64_writeback_disable (void) { sc64_error_t error; uint32_t save_type; - error = sc64_get_config(CFG_ID_SAVE_TYPE, &save_type); - if (error != SC64_OK) { + if ((error = sc64_get_config(CFG_ID_SAVE_TYPE, &save_type)) != SC64_OK) { return error; } return sc64_set_config(CFG_ID_SAVE_TYPE, save_type); diff --git a/sw/bootloader/src/sc64.h b/sw/bootloader/src/sc64.h index 4d6457b..9f7b0e0 100644 --- a/sw/bootloader/src/sc64.h +++ b/sw/bootloader/src/sc64.h @@ -8,14 +8,52 @@ typedef enum { - SC64_OK, - SC64_ERROR_BAD_ARGUMENT, - SC64_ERROR_BAD_ADDRESS, - SC64_ERROR_BAD_CONFIG_ID, - SC64_ERROR_TIMEOUT, - SC64_ERROR_SD_CARD, - SC64_ERROR_UNKNOWN_CMD = -1 -} sc64_error_t; + ERROR_TYPE_CFG = 0, + ERROR_TYPE_SD_CARD = 1, +} sc64_error_type_t; + +typedef enum { + SC64_OK = 0, + CFG_ERROR_UNKNOWN_COMMAND = 1, + CFG_ERROR_INVALID_ARGUMENT = 2, + CFG_ERROR_INVALID_ADDRESS = 3, + CFG_ERROR_INVALID_ID = 4, +} sc64_cfg_error_t; + +typedef enum { + SD_OK = 0, + SD_ERROR_NO_CARD_IN_SLOT = 1, + SD_ERROR_NOT_INITIALIZED = 2, + SD_ERROR_INVALID_ARGUMENT = 3, + SD_ERROR_INVALID_ADDRESS = 4, + SD_ERROR_INVALID_OPERATION = 5, + SD_ERROR_CMD2_IO = 6, + SD_ERROR_CMD3_IO = 7, + SD_ERROR_CMD6_CHECK_IO = 8, + SD_ERROR_CMD6_CHECK_CRC = 9, + SD_ERROR_CMD6_CHECK_TIMEOUT = 10, + SD_ERROR_CMD6_CHECK_RESPONSE = 11, + SD_ERROR_CMD6_SWITCH_IO = 12, + SD_ERROR_CMD6_SWITCH_CRC = 13, + SD_ERROR_CMD6_SWITCH_TIMEOUT = 14, + SD_ERROR_CMD6_SWITCH_RESPONSE = 15, + SD_ERROR_CMD7_IO = 16, + SD_ERROR_CMD8_IO = 17, + SD_ERROR_CMD9_IO = 18, + SD_ERROR_CMD10_IO = 19, + SD_ERROR_CMD18_IO = 20, + SD_ERROR_CMD18_CRC = 21, + SD_ERROR_CMD18_TIMEOUT = 22, + SD_ERROR_CMD25_IO = 23, + SD_ERROR_CMD25_CRC = 24, + SD_ERROR_CMD25_TIMEOUT = 25, + SD_ERROR_ACMD6_IO = 26, + SD_ERROR_ACMD41_IO = 27, + SD_ERROR_ACMD41_OCR = 28, + SD_ERROR_ACMD41_TIMEOUT = 29, +} sc64_sd_error_t; + +typedef uint32_t sc64_error_t; typedef enum { CFG_ID_BOOTLOADER_SWITCH, @@ -133,6 +171,8 @@ typedef struct { #define SC64_BUFFERS ((sc64_buffers_t *) SC64_BUFFERS_BASE) +const char *sc64_error_description (sc64_error_t error); + void sc64_unlock (void); void sc64_lock (void); bool sc64_check_presence (void); diff --git a/sw/bootloader/src/test.c b/sw/bootloader/src/test.c index 24ed141..0a661fd 100644 --- a/sw/bootloader/src/test.c +++ b/sw/bootloader/src/test.c @@ -63,22 +63,22 @@ static void test_sc64_cfg (void) { do { if ((error = sc64_get_config(CFG_ID_BUTTON_STATE, &button_state)) != SC64_OK) { - error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error); + error_display("Command CONFIG_GET [BUTTON_STATE] failed\n (%08X) - %s", error, sc64_error_description(error)); } } while (button_state != 0); display_printf("done\n\n"); if ((error = sc64_get_identifier(&identifier)) != SC64_OK) { - error_display("Command IDENTIFIER_GET failed: %d", error); + error_display("Command IDENTIFIER_GET failed\n (%08X) - %s", error, sc64_error_description(error)); } if ((error = sc64_get_version(&major, &minor, &revision)) != SC64_OK) { - error_display("Command VERSION_GET failed: %d", error); + error_display("Command VERSION_GET failed\n (%08X) - %s", error, sc64_error_description(error)); } if ((error = sc64_get_diagnostic(DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE, &tmp)) != SC64_OK) { - error_display("Command DIAGNOSTIC_GET failed: %d", error); + error_display("Command DIAGNOSTIC_GET failed\n (%08X) - %s", error, sc64_error_description(error)); } uint16_t voltage = (uint16_t) (tmp >> 16); @@ -104,7 +104,7 @@ static void test_sc64_cfg (void) { sc64_rtc_time_t t; if ((error = sc64_get_time(&t)) != SC64_OK) { - error_display("Command TIME_GET failed: %d", error); + error_display("Command TIME_GET failed\n (%08X) - %s", error, sc64_error_description(error)); } display_printf("RTC current time:\n "); @@ -136,16 +136,14 @@ static void test_pi (void) { for (int i = 0; i < size / sizeof(uint32_t); i++) { if (w_buffer[i] != r_buffer[i]) { - display_printf( - "\n" + error_display( + "PI test failed:\n" " > Mismatch error at address 0x%08lX\n" " > 0x%08lX (W) != 0x%08lX (R)", (uint32_t) (SC64_BUFFERS->BUFFER) + (i * sizeof(uint32_t)), w_buffer[i], r_buffer[i] ); - - while (true); } } } @@ -162,7 +160,7 @@ static void test_sd_card_io (void) { uint8_t sector[512] __attribute__((aligned(8))); if ((error = sc64_sd_card_get_status(&card_status)) != SC64_OK) { - error_display("Could not get SD card info: %d", error); + error_display("Could not get SD card info\n (%08X) - %s", error, sc64_error_description(error)); } if (card_status & SD_CARD_STATUS_INSERTED) { @@ -172,15 +170,15 @@ static void test_sd_card_io (void) { } if ((error = sc64_sd_card_deinit()) != SC64_OK) { - return display_printf("SD card deinit error: %d", error); + error_display("SD card deinit error\n (%08X) - %s", error, sc64_error_description(error)); } if ((error = sc64_sd_card_init()) != SC64_OK) { - return display_printf("SD card init error: %d\n", error); + return display_printf("SD card init error\n (%08X) - %s\n", error, sc64_error_description(error)); } if ((error = sc64_sd_card_get_status(&card_status)) != SC64_OK) { - error_display("Could not get SD card info: %d", error); + error_display("Could not get SD card info\n (%08X) - %s", error, sc64_error_description(error)); } if (card_status & SD_CARD_STATUS_INITIALIZED) { @@ -197,7 +195,7 @@ static void test_sd_card_io (void) { } if ((error = sc64_sd_card_get_info((uint32_t *) (SC64_BUFFERS->BUFFER))) != SC64_OK) { - return display_printf("SD card get info error: %d\n", error); + error_display("SD card get info error\n (%08X) - %s", error, sc64_error_description(error)); } pi_dma_read((io32_t *) (SC64_BUFFERS->BUFFER), card_info, sizeof(card_info)); @@ -217,7 +215,7 @@ static void test_sd_card_io (void) { display_printf("\n"); if ((error = sc64_sd_read_sectors((void *) (SC64_BUFFERS->BUFFER), 0, 1)) != SC64_OK) { - return display_printf("SD card read sector 0 error: %d\n", error); + return display_printf("SD card read sector 0 error\n (%08X) - %s\n", error, sc64_error_description(error)); } pi_dma_read((io32_t *) (SC64_BUFFERS->BUFFER), sector, sizeof(sector)); @@ -245,21 +243,21 @@ static void test_sd_card_fatfs (void) { UINT bytes; if ((error = sc64_sd_card_deinit()) != SC64_OK) { - return display_printf("SD card deinit error: %d", error); + error_display("SD card deinit error\n (%08X) - %s", error, sc64_error_description(error)); } if ((fresult = f_mount(&fs, "", 1)) != FR_OK) { - return display_printf("f_mount error: %d\n", fresult); + display_printf("f_mount error: %d\n", fresult); } if ((fresult = f_getlabel("", label, &vsn)) != FR_OK) { - return display_printf("f_getlabel error: %d\n", fresult); + display_printf("f_getlabel error: %d\n", fresult); + } else { + display_printf("Volume [%s] / [%08lX]\n\n", label, vsn); } - display_printf("Volume [%s] / [%08lX]\n\n", label, vsn); - if ((fresult = f_open(&fil, "sc64test.bin", FA_CREATE_ALWAYS | FA_WRITE)) != FR_OK) { - return display_printf("f_open (write) error: %d\n", fresult); + display_printf("f_open (write) error: %d\n", fresult); } srand(random_seed); @@ -276,11 +274,13 @@ static void test_sd_card_fatfs (void) { fill_random(w_buffer, block_size, 0, 0); if ((fresult = f_write(&fil, w_buffer, block_size, &bytes)) != FR_OK) { - return display_printf("\nf_write error: %d\n", fresult); + display_printf("\nf_write error: %d", fresult); + break; } if (bytes != block_size) { - return display_printf("\nf_write (%ld!=%ld) error: %d\n", bytes, block_size, fresult); + display_printf("\nf_write (%ld!=%ld) error: %d", bytes, block_size, fresult); + break; } left -= block_size; @@ -289,15 +289,15 @@ static void test_sd_card_fatfs (void) { display_printf("\n"); if ((fresult = f_close(&fil)) != FR_OK) { - return display_printf("f_close (write) error: %d\n", fresult); + display_printf("f_close (write) error: %d\n", fresult); } if ((fresult = f_open(&fil, "sc64test.bin", FA_OPEN_EXISTING | FA_READ)) != FR_OK) { - return display_printf("f_open (read) error: %d\n", fresult); + display_printf("f_open (read) error: %d\n", fresult); } if (f_size(&fil) != SD_TEST_FILE_SIZE) { - return display_printf("f_size (%d!=%d) error\n", f_size(&fil), SD_TEST_FILE_SIZE); + display_printf("f_size (%d!=%d) error\n", f_size(&fil), SD_TEST_FILE_SIZE); } srand(random_seed); @@ -314,25 +314,25 @@ static void test_sd_card_fatfs (void) { fill_random(w_buffer, block_size, 0, 0); if ((fresult = f_read(&fil, r_buffer, block_size, &bytes)) != FR_OK) { - return display_printf("\nf_read error: %d\n", fresult); + display_printf("\nf_read error: %d", fresult); + break; } if (bytes != block_size) { - return display_printf("\nf_read (%ld!=%ld) error: %d\n", bytes, block_size, fresult); + display_printf("\nf_read (%ld!=%ld) error: %d", bytes, block_size, fresult); + break; } for (UINT i = 0; i < (block_size / sizeof(uint32_t)); i++) { if (w_buffer[i] != r_buffer[i]) { - display_printf( - "\n" + error_display( + "SD card (FatFs) test failed:\n" " > Mismatch error at file offset 0x%08lX\n" " > 0x%08lX (W) != 0x%08lX (R)", f_tell(&fil) + (i * sizeof(uint32_t)), w_buffer[i], r_buffer[i] ); - - while (true); } } @@ -342,15 +342,15 @@ static void test_sd_card_fatfs (void) { display_printf("\n"); if ((fresult = f_close(&fil)) != FR_OK) { - return display_printf("f_close (read) error: %d\n", fresult); + display_printf("f_close (read) error: %d\n", fresult); } if ((fresult = f_unlink("sc64test.bin")) != FR_OK) { - return display_printf("f_unlink error: %d\n", fresult); + display_printf("f_unlink error: %d\n", fresult); } if ((fresult = f_unmount("")) != FR_OK) { - return display_printf("f_unmount error: %d\n", fresult); + display_printf("f_unmount error: %d\n", fresult); } random_seed += c0_count(); @@ -473,16 +473,15 @@ static void test_sdram (void) { for (int i = 0; i < TEST_BUFFER_SIZE / sizeof(uint64_t); i++) { if (test_data[i] != check_data[i]) { - display_printf( - "\n" + error_display( + "SDRAM test failed, %s\n" " > Mismatch error at address 0x%08lX\n" " > 0x%016llX (W) != 0x%016llX (R)", + test->name, SDRAM_ADDRESS + offset + (i * sizeof(uint64_t)), test_data[i], check_data[i] ); - - while (true); } } } @@ -511,7 +510,7 @@ bool test_check (void) { } if ((error = sc64_get_config(CFG_ID_BUTTON_STATE, &button_state)) != SC64_OK) { - error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error); + error_display("Command CONFIG_GET [BUTTON_STATE] failed\n (%08X) - %s", error, sc64_error_description(error)); } return (button_state != 0); @@ -538,12 +537,12 @@ void test_execute (void) { pi_io_config(0x0F, 0x05, 0x0C, 0x02); - if ((error = sc64_set_config(CFG_ID_ROM_WRITE_ENABLE, true))) { - error_display("Command CONFIG_SET [ROM_WRITE_ENABLE] failed: %d", error); + if ((error = sc64_set_config(CFG_ID_ROM_WRITE_ENABLE, true)) != SC64_OK) { + error_display("Command CONFIG_SET [ROM_WRITE_ENABLE] failed\n (%08X) - %s", error, sc64_error_description(error)); } - if ((error = sc64_set_config(CFG_ID_ROM_SHADOW_ENABLE, false))) { - error_display("Command CONFIG_SET [ROM_SHADOW_ENABLE] failed: %d", error); + if ((error = sc64_set_config(CFG_ID_ROM_SHADOW_ENABLE, false)) != SC64_OK) { + error_display("Command CONFIG_SET [ROM_SHADOW_ENABLE] failed\n (%08X) - %s", error, sc64_error_description(error)); } random_seed = __entropy + c0_count(); diff --git a/sw/controller/src/cfg.c b/sw/controller/src/cfg.c index 7dad6a5..59a5c9e 100644 --- a/sw/controller/src/cfg.c +++ b/sw/controller/src/cfg.c @@ -66,16 +66,6 @@ typedef enum { TV_TYPE_PASSTHROUGH = 3 } tv_type_t; -typedef enum { - CFG_ERROR_OK = 0, - CFG_ERROR_BAD_ARGUMENT = 1, - CFG_ERROR_BAD_ADDRESS = 2, - CFG_ERROR_BAD_CONFIG_ID = 3, - CFG_ERROR_TIMEOUT = 4, - CFG_ERROR_SD_CARD = 5, - CFG_ERROR_UNKNOWN_CMD = -1, -} cfg_error_t; - typedef enum { SD_CARD_OP_DEINIT = 0, SD_CARD_OP_INIT = 1, @@ -95,6 +85,18 @@ typedef enum { BRAM = (1 << 2), } translate_type_t; +typedef enum { + ERROR_TYPE_CFG = 0, + ERROR_TYPE_SD_CARD = 1, +} error_type_t; + +typedef enum { + CFG_OK = 0, + CFG_ERROR_UNKNOWN_COMMAND = 1, + CFG_ERROR_INVALID_ARGUMENT = 2, + CFG_ERROR_INVALID_ADDRESS = 3, + CFG_ERROR_INVALID_ID = 4, +} cfg_error_t; struct process { boot_mode_t boot_mode; @@ -169,8 +171,8 @@ static bool cfg_translate_address (uint32_t *address, uint32_t length, translate return true; } -static void cfg_set_error (cfg_error_t error) { - fpga_reg_set(REG_CFG_DATA_0, error); +static void cfg_set_error (error_type_t type, uint32_t error) { + fpga_reg_set(REG_CFG_DATA_0, ((type & 0xFF) << 24) | (error & 0xFFFFFF)); fpga_reg_set(REG_CFG_DATA_1, 0); fpga_reg_set(REG_CFG_CMD, CFG_CMD_ERROR | CFG_CMD_DONE); } @@ -504,7 +506,7 @@ void cfg_process (void) { case 'c': if (cfg_query(args)) { - cfg_set_error(CFG_ERROR_BAD_CONFIG_ID); + cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ID); return; } break; @@ -513,7 +515,7 @@ void cfg_process (void) { prev_cfg[0] = args[0]; cfg_query(prev_cfg); if (cfg_update(args)) { - cfg_set_error(CFG_ERROR_BAD_CONFIG_ID); + cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ID); return; } args[1] = prev_cfg[1]; @@ -521,14 +523,14 @@ void cfg_process (void) { case 'a': if (cfg_query_setting(args)) { - cfg_set_error(CFG_ERROR_BAD_CONFIG_ID); + cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ID); return; } break; case 'A': if (cfg_update_setting(args)) { - cfg_set_error(CFG_ERROR_BAD_CONFIG_ID); + cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ID); return; } break; @@ -543,7 +545,7 @@ void cfg_process (void) { case 'm': if (cfg_translate_address(&args[0], args[1], (SDRAM | BRAM))) { - cfg_set_error(CFG_ERROR_BAD_ADDRESS); + cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS); return; } if (!usb_prepare_read(args)) { @@ -553,7 +555,7 @@ void cfg_process (void) { case 'M': if (cfg_translate_address(&args[0], args[1] & 0xFFFFFF, (SDRAM | BRAM))) { - cfg_set_error(CFG_ERROR_BAD_ADDRESS); + cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS); return; } usb_create_packet(&packet_info, PACKET_CMD_DEBUG_OUTPUT); @@ -584,10 +586,10 @@ void cfg_process (void) { break; case SD_CARD_OP_INIT: { led_activity_on(); - bool error = sd_card_init(); + sd_error_t error = sd_card_init(); led_activity_off(); - if (error) { - cfg_set_error(CFG_ERROR_SD_CARD); + if (error != SD_OK) { + cfg_set_error(ERROR_TYPE_SD_CARD, error); return; } break; @@ -595,30 +597,36 @@ void cfg_process (void) { case SD_CARD_OP_GET_STATUS: args[1] = sd_card_get_status(); break; - case SD_CARD_OP_GET_INFO: + case SD_CARD_OP_GET_INFO: { if (cfg_translate_address(&args[0], SD_CARD_INFO_SIZE, (SDRAM | BRAM))) { - cfg_set_error(CFG_ERROR_BAD_ADDRESS); + cfg_set_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ADDRESS); return; } - if (sd_card_get_info(args[0])) { - cfg_set_error(CFG_ERROR_SD_CARD); + sd_error_t error = sd_card_get_info(args[0]); + if (error != SD_OK) { + cfg_set_error(ERROR_TYPE_SD_CARD, error); return; } break; - case SD_CARD_OP_BYTE_SWAP_ON: - if (sd_set_byte_swap(true)) { - cfg_set_error(CFG_ERROR_SD_CARD); + } + case SD_CARD_OP_BYTE_SWAP_ON: { + sd_error_t error = sd_set_byte_swap(true); + if (error != SD_OK) { + cfg_set_error(ERROR_TYPE_SD_CARD, error); return; } break; - case SD_CARD_OP_BYTE_SWAP_OFF: - if (sd_set_byte_swap(false)) { - cfg_set_error(CFG_ERROR_SD_CARD); + } + case SD_CARD_OP_BYTE_SWAP_OFF: { + sd_error_t error = sd_set_byte_swap(false); + if (error != SD_OK) { + cfg_set_error(ERROR_TYPE_SD_CARD, error); return; } break; + } default: - cfg_set_error(CFG_ERROR_BAD_ARGUMENT); + cfg_set_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_OPERATION); return; } break; @@ -629,18 +637,18 @@ void cfg_process (void) { case 's': { if (args[1] >= 0x800000) { - cfg_set_error(CFG_ERROR_BAD_ARGUMENT); + cfg_set_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ARGUMENT); return; } if (cfg_translate_address(&args[0], args[1] * SD_SECTOR_SIZE, (SDRAM | FLASH | BRAM))) { - cfg_set_error(CFG_ERROR_BAD_ADDRESS); + cfg_set_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ADDRESS); return; } led_activity_on(); - bool error = sd_read_sectors(args[0], p.sd_card_sector, args[1]); + sd_error_t error = sd_read_sectors(args[0], p.sd_card_sector, args[1]); led_activity_off(); - if (error) { - cfg_set_error(CFG_ERROR_SD_CARD); + if (error != SD_OK) { + cfg_set_error(ERROR_TYPE_SD_CARD, error); return; } p.sd_card_sector += args[1]; @@ -649,18 +657,18 @@ void cfg_process (void) { case 'S': { if (args[1] >= 0x800000) { - cfg_set_error(CFG_ERROR_BAD_ARGUMENT); + cfg_set_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ARGUMENT); return; } if (cfg_translate_address(&args[0], args[1] * SD_SECTOR_SIZE, (SDRAM | FLASH | BRAM))) { - cfg_set_error(CFG_ERROR_BAD_ADDRESS); + cfg_set_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ADDRESS); return; } led_activity_on(); - bool error = sd_write_sectors(args[0], p.sd_card_sector, args[1]); + sd_error_t error = sd_write_sectors(args[0], p.sd_card_sector, args[1]); led_activity_off(); - if (error) { - cfg_set_error(CFG_ERROR_SD_CARD); + if (error != SD_OK) { + cfg_set_error(ERROR_TYPE_SD_CARD, error); return; } p.sd_card_sector += args[1]; @@ -669,7 +677,7 @@ void cfg_process (void) { case 'D': if (cfg_translate_address(&args[0], args[1], (SDRAM | BRAM))) { - cfg_set_error(CFG_ERROR_BAD_ADDRESS); + cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS); return; } dd_set_disk_mapping(args[0], args[1]); @@ -681,7 +689,7 @@ void cfg_process (void) { case 'W': if (cfg_translate_address(&args[0], WRITEBACK_SECTOR_TABLE_SIZE, (SDRAM | BRAM))) { - cfg_set_error(CFG_ERROR_BAD_ADDRESS); + cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS); return; } writeback_load_sector_table(args[0]); @@ -690,15 +698,15 @@ void cfg_process (void) { case 'K': if (args[1] >= DATA_BUFFER_SIZE) { - cfg_set_error(CFG_ERROR_BAD_ARGUMENT); + cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ARGUMENT); return; } if (cfg_translate_address(&args[0], args[1], FLASH)) { - cfg_set_error(CFG_ERROR_BAD_ADDRESS); + cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS); return; } if (flash_program(DATA_BUFFER_ADDRESS, args[0], args[1])) { - cfg_set_error(CFG_ERROR_BAD_ARGUMENT); + cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ARGUMENT); return; } break; @@ -712,24 +720,24 @@ void cfg_process (void) { case 'P': if (cfg_translate_address(&args[0], FLASH_ERASE_BLOCK_SIZE, FLASH)) { - cfg_set_error(CFG_ERROR_BAD_ADDRESS); + cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS); return; } if (flash_erase_block(args[0])) { - cfg_set_error(CFG_ERROR_BAD_ARGUMENT); + cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ARGUMENT); return; } break; case '%': if (cfg_read_diagnostic_data(args)) { - cfg_set_error(CFG_ERROR_BAD_CONFIG_ID); + cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ID); return; } break; default: - cfg_set_error(CFG_ERROR_UNKNOWN_CMD); + cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_UNKNOWN_COMMAND); return; } diff --git a/sw/controller/src/dd.c b/sw/controller/src/dd.c index 4b1331a..0f6be8e 100644 --- a/sw/controller/src/dd.c +++ b/sw/controller/src/dd.c @@ -137,9 +137,9 @@ static bool dd_block_read_request (void) { uint32_t sector_table[DD_SD_SECTOR_TABLE_SIZE]; uint32_t sectors = dd_fill_sd_sector_table(index, sector_table, false); led_activity_on(); - bool error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_read_sectors); + sd_error_t error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_read_sectors); led_activity_off(); - dd_set_block_ready(!error); + dd_set_block_ready(error == SD_OK); } else { usb_tx_info_t packet_info; usb_create_packet(&packet_info, PACKET_CMD_DD_REQUEST); @@ -161,9 +161,9 @@ static bool dd_block_write_request (void) { uint32_t sector_table[DD_SD_SECTOR_TABLE_SIZE]; uint32_t sectors = dd_fill_sd_sector_table(index, sector_table, true); led_activity_on(); - bool error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_write_sectors); + sd_error_t error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_write_sectors); led_activity_off(); - dd_set_block_ready(!error); + dd_set_block_ready(error == SD_OK); } else { usb_tx_info_t packet_info; usb_create_packet(&packet_info, PACKET_CMD_DD_REQUEST); diff --git a/sw/controller/src/fpga.h b/sw/controller/src/fpga.h index 5fafded..7c3f0d5 100644 --- a/sw/controller/src/fpga.h +++ b/sw/controller/src/fpga.h @@ -61,7 +61,6 @@ typedef enum { #define ALIGN(value, align) (((value) + ((typeof(value))(align) - 1)) & ~((typeof(value))(align) - 1)) -#define SWAP16(x) ((((x) & 0xFF) << 8) | (((x) & 0xFF00) >> 8)) #define SWAP32(x) (((x) & 0xFF) << 24 | ((x) & 0xFF00) << 8 | ((x) & 0xFF0000) >> 8 | ((x) & 0xFF000000) >> 24) #define FPGA_ID (0x64) diff --git a/sw/controller/src/hw.c b/sw/controller/src/hw.c index bd09a7f..4b87e28 100644 --- a/sw/controller/src/hw.c +++ b/sw/controller/src/hw.c @@ -339,12 +339,12 @@ static void hw_i2c_init (void) { I2C1->CR1 |= I2C_CR1_PE; } -i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length) { +i2c_error_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length) { hw_timeout_start(); while (I2C1->ISR & I2C_ISR_BUSY) { if (hw_timeout_elapsed(I2C_TIMEOUT_US_BUSY)) { - return I2C_ERR_BUSY; + return I2C_ERROR_BUSY; } } @@ -372,11 +372,11 @@ i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint } if (isr & I2C_ISR_NACKF) { - return I2C_ERR_NACK; + return I2C_ERROR_NACK; } if (hw_timeout_elapsed(tx_timeout)) { - return I2C_ERR_TIMEOUT; + return I2C_ERROR_TIMEOUT; } } @@ -386,7 +386,7 @@ i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint while (!(I2C1->ISR & I2C_ISR_TC)) { if (hw_timeout_elapsed(tx_timeout)) { - return I2C_ERR_TIMEOUT; + return I2C_ERROR_TIMEOUT; } } } @@ -415,7 +415,7 @@ i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint } if (hw_timeout_elapsed(rx_timeout)) { - return I2C_ERR_TIMEOUT; + return I2C_ERROR_TIMEOUT; } } } diff --git a/sw/controller/src/hw.h b/sw/controller/src/hw.h index d9f2d05..99cf1e1 100644 --- a/sw/controller/src/hw.h +++ b/sw/controller/src/hw.h @@ -27,10 +27,10 @@ typedef enum { typedef enum { I2C_OK, - I2C_ERR_BUSY, - I2C_ERR_TIMEOUT, - I2C_ERR_NACK, -} i2c_err_t; + I2C_ERROR_BUSY, + I2C_ERROR_TIMEOUT, + I2C_ERROR_NACK, +} i2c_error_t; typedef uint64_t hw_flash_t; @@ -72,7 +72,7 @@ void hw_spi_stop (void); void hw_spi_rx (uint8_t *data, int length); void hw_spi_tx (uint8_t *data, int length); -i2c_err_t hw_i2c_trx (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length); +i2c_error_t hw_i2c_trx (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length); void hw_crc32_reset (void); uint32_t hw_crc32_calculate (uint8_t *data, uint32_t length); diff --git a/sw/controller/src/lcmxo2.c b/sw/controller/src/lcmxo2.c index d7a5a56..fe35b03 100644 --- a/sw/controller/src/lcmxo2.c +++ b/sw/controller/src/lcmxo2.c @@ -133,9 +133,9 @@ static bool lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint packet_length += length; } - i2c_err_t err = hw_i2c_trx(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length)); + i2c_error_t error = hw_i2c_trx(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length)); - return (err != I2C_OK); + return (error != I2C_OK); #else lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_WBCE); diff --git a/sw/controller/src/sd.c b/sw/controller/src/sd.c index 20498c4..635829f 100644 --- a/sw/controller/src/sd.c +++ b/sw/controller/src/sd.c @@ -9,6 +9,10 @@ #define CMD6_ARG_CHECK_HS (0x00FFFFF1UL) #define CMD6_ARG_SWITCH_HS (0x80FFFFF1UL) +#define CMD6_DATA_LENGTH (64) +#define CMD6_INVALID_CURRENT_LIMIT(b) ((((b)[0] << 8) | (b)[1]) == 0) +#define CMD6_HS_SUPPORTED(b) ((b)[13] & (1 << 1)) +#define CMD6_HS_ENABLED(b) (((b)[16] & 0x0F) == 0x01) #define CMD8_ARG_SUPPLY_VOLTAGE_27_36_V (1 << 8) #define CMD8_ARG_CHECK_PATTERN (0xAA << 0) @@ -18,6 +22,9 @@ #define ACMD41_ARG_OCR (0x300000 << 0) #define ACMD41_ARG_HCS (1 << 30) +#define R1_APP_CMD (1 << 5) +#define R1_ILLEGAL_COMMAND (1 << 22) + #define R3_OCR (0x300000 << 0) #define R3_CCS (1 << 30) #define R3_BUSY (1 << 31) @@ -27,12 +34,9 @@ #define R7_SUPPLY_VOLTAGE_27_36_V (1 << 8) #define R7_CHECK_PATTERN (0xAA << 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_HS (1 << 1) - #define TIMEOUT_INIT_MS (1000) +#define DAT_CRC16_LENGTH (8) #define DAT_BLOCK_MAX_COUNT (256) #define DAT_TIMEOUT_INIT_MS (2000) #define DAT_TIMEOUT_DATA_MS (5000) @@ -62,9 +66,17 @@ typedef enum { typedef enum { DAT_OK, - DAT_ERR_IO, - DAT_ERR_TIMEOUT, -} dat_err_t; + DAT_ERROR_IO, + DAT_ERROR_TIMEOUT, +} dat_error_t; + +typedef enum { + CMD6_OK, + CMD6_ERROR_ILLEGAL_CMD, + CMD6_ERROR_IO, + CMD6_ERROR_CRC, + CMD6_ERROR_TIMEOUT, +} cmd6_error_t; struct process { @@ -150,7 +162,11 @@ static bool sd_cmd (uint8_t cmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) { } 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)) { + uint32_t acmd_rsp; + if (sd_cmd(55, p.rca, RSP_R1, &acmd_rsp)) { + return true; + } + if (!(acmd_rsp & R1_APP_CMD)) { return true; } if (sd_cmd(acmd, arg, rsp_type, rsp)) { @@ -185,7 +201,7 @@ static void sd_dat_abort (void) { fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH); } -static dat_err_t sd_dat_wait (uint16_t timeout_ms) { +static dat_error_t sd_dat_wait (uint16_t timeout_ms) { timer_countdown_start(TIMER_ID_SD, timeout_ms); do { @@ -194,7 +210,7 @@ static dat_err_t sd_dat_wait (uint16_t timeout_ms) { if ((!(sd_dat & SD_DAT_BUSY)) && (!(sd_dma_scr & DMA_SCR_BUSY))) { if (sd_dat & SD_DAT_ERROR) { sd_dat_abort(); - return DAT_ERR_IO; + return DAT_ERROR_IO; } return DAT_OK; } @@ -202,19 +218,87 @@ static dat_err_t sd_dat_wait (uint16_t timeout_ms) { sd_dat_abort(); - return DAT_ERR_TIMEOUT; + return DAT_ERROR_TIMEOUT; +} + +static bool sd_dat_check_crc16 (uint8_t *data, uint32_t length) { + uint16_t device_crc[4]; + uint16_t controller_crc[4]; + + for (int crc = 0; crc < 4; crc++) { + device_crc[crc] = 0; + controller_crc[crc] = 0; + } + + for (uint32_t index = length; index < (length + DAT_CRC16_LENGTH); index++) { + uint8_t byte = data[index]; + for (int nibble = 0; nibble < 2; nibble++) { + for (int crc = 0; crc < 4; crc++) { + device_crc[crc] <<= 1; + device_crc[crc] |= (byte >> (7 - crc)) & (1 << 0); + } + byte <<= 4; + } + } + + for (uint32_t index = 0; index < length; index++) { + uint8_t byte = data[index]; + for (int nibble = 0; nibble < 2; nibble++) { + for (int crc = 0; crc < 4; crc++) { + uint8_t inv = ((controller_crc[crc] >> 15) ^ (byte >> (7 - crc))) & (1 << 0); + controller_crc[crc] ^= (inv << 11) | (inv << 4); + controller_crc[crc] <<= 1; + controller_crc[crc] |= inv; + } + byte <<= 4; + } + } + + for (int crc = 0; crc < 4; crc++) { + if (controller_crc[crc] != device_crc[crc]) { + return true; + } + } + + return false; +} + +static cmd6_error_t sd_cmd6 (uint32_t arg, uint8_t *buffer) { + uint32_t rsp; + sd_dat_prepare(SD_INIT_BUFFER_ADDRESS, 1, DAT_READ); + if (sd_cmd(6, arg, RSP_R1, &rsp)) { + sd_dat_abort(); + return CMD6_ERROR_IO; + } + if (rsp & R1_ILLEGAL_COMMAND) { + sd_dat_abort(); + return CMD6_ERROR_ILLEGAL_CMD; + } + if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERROR_TIMEOUT) { + return CMD6_ERROR_TIMEOUT; + } + fpga_mem_read(SD_INIT_BUFFER_ADDRESS, CMD6_DATA_LENGTH + DAT_CRC16_LENGTH, buffer); + if (sd_dat_check_crc16(buffer, CMD6_DATA_LENGTH)) { + return CMD6_ERROR_CRC; + } + return SD_OK; } -bool sd_card_init (void) { +sd_error_t sd_card_init (void) { uint32_t arg; uint32_t rsp; - uint16_t tmp; + cmd6_error_t cmd6_error; + uint8_t cmd6_buffer[CMD6_DATA_LENGTH + DAT_CRC16_LENGTH]; p.byte_swap = false; if (p.card_initialized) { - return false; + return SD_OK; + } + + if (!sd_card_is_inserted()) { + return SD_ERROR_NO_CARD_IN_SLOT; } p.card_initialized = true; @@ -230,7 +314,7 @@ bool sd_card_init (void) { } else { if (rsp != (R7_SUPPLY_VOLTAGE_27_36_V | R7_CHECK_PATTERN)) { sd_card_deinit(); - return true; + return SD_ERROR_CMD8_IO; } arg = (ACMD41_ARG_HCS | ACMD41_ARG_OCR); } @@ -239,16 +323,16 @@ bool sd_card_init (void) { do { if (timer_countdown_elapsed(TIMER_ID_SD)) { sd_card_deinit(); - return true; + return SD_ERROR_ACMD41_TIMEOUT; } if (sd_acmd(41, arg, RSP_R3, &rsp)) { sd_card_deinit(); - return true; + return SD_ERROR_ACMD41_IO; } if (rsp & R3_BUSY) { if ((rsp & R3_OCR) == 0) { sd_card_deinit(); - return true; + return SD_ERROR_ACMD41_OCR; } p.card_type_block = (rsp & R3_CCS); break; @@ -257,71 +341,78 @@ bool sd_card_init (void) { if (sd_cmd(2, 0, RSP_R2, NULL)) { sd_card_deinit(); - return true; + return SD_ERROR_CMD2_IO; } if (sd_cmd(3, 0, RSP_R6, &rsp)) { sd_card_deinit(); - return true; + return SD_ERROR_CMD3_IO; } p.rca = (rsp & R6_RCA_MASK); if (sd_cmd(9, p.rca, RSP_R2, p.csd)) { sd_card_deinit(); - return true; + return SD_ERROR_CMD9_IO; } if (sd_cmd(10, p.rca, RSP_R2, p.cid)) { sd_card_deinit(); - return true; + return SD_ERROR_CMD10_IO; } if (sd_cmd(7, p.rca, RSP_R1b, NULL)) { sd_card_deinit(); - return true; + return SD_ERROR_CMD7_IO; } sd_set_clock(CLOCK_25MHZ); if (sd_acmd(6, ACMD6_ARG_BUS_WIDTH_4BIT, RSP_R1, NULL)) { sd_card_deinit(); - return true; + return SD_ERROR_ACMD6_IO; } - sd_dat_prepare(SD_INIT_BUFFER_ADDRESS, 1, DAT_READ); - if (sd_cmd(6, CMD6_ARG_CHECK_HS, RSP_R1, NULL)) { - sd_dat_abort(); - sd_card_deinit(); - return true; + if ((cmd6_error = sd_cmd6(CMD6_ARG_CHECK_HS, cmd6_buffer)) == CMD6_ERROR_ILLEGAL_CMD) { + return SD_OK; } - if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERR_TIMEOUT) { + + if (cmd6_error != CMD6_OK) { sd_card_deinit(); - return true; - } - fpga_mem_read(SWITCH_FUNCTION_CURRENT_LIMIT, 2, (uint8_t *) (&tmp)); - if (SWAP16(tmp) == 0) { - sd_card_deinit(); - return true; - } - fpga_mem_read(SWITCH_FUNCTION_GROUP_1, 2, (uint8_t *) (&tmp)); - if (SWAP16(tmp) & SWITCH_FUNCTION_GROUP_1_HS) { - sd_dat_prepare(SD_INIT_BUFFER_ADDRESS, 1, DAT_READ); - if (sd_cmd(6, CMD6_ARG_SWITCH_HS, RSP_R1, NULL)) { - sd_dat_abort(); - sd_card_deinit(); - return true; + switch (cmd6_error) { + case CMD6_ERROR_IO: return SD_ERROR_CMD6_CHECK_IO; + case CMD6_ERROR_CRC: return SD_ERROR_CMD6_CHECK_CRC; + case CMD6_ERROR_TIMEOUT: return SD_ERROR_CMD6_CHECK_TIMEOUT; + default: return SD_ERROR_CMD6_CHECK_IO; } - if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERR_TIMEOUT) { + } + + if (CMD6_INVALID_CURRENT_LIMIT(cmd6_buffer)) { + sd_card_deinit(); + return SD_ERROR_CMD6_CHECK_RESPONSE; + } + + if (CMD6_HS_SUPPORTED(cmd6_buffer)) { + if ((cmd6_error = sd_cmd6(CMD6_ARG_SWITCH_HS, cmd6_buffer)) != CMD6_OK) { sd_card_deinit(); - return true; + switch (cmd6_error) { + case CMD6_ERROR_IO: return SD_ERROR_CMD6_SWITCH_IO; + case CMD6_ERROR_CRC: return SD_ERROR_CMD6_SWITCH_CRC; + case CMD6_ERROR_TIMEOUT: return SD_ERROR_CMD6_SWITCH_TIMEOUT; + default: return SD_ERROR_CMD6_SWITCH_IO; + } } - fpga_mem_read(SWITCH_FUNCTION_GROUP_1, 2, (uint8_t *) (&tmp)); - if (SWAP16(tmp) & SWITCH_FUNCTION_GROUP_1_HS) { + + if (CMD6_INVALID_CURRENT_LIMIT(cmd6_buffer)) { + sd_card_deinit(); + return SD_ERROR_CMD6_SWITCH_RESPONSE; + } + + if (CMD6_HS_ENABLED(cmd6_buffer)) { sd_set_clock(CLOCK_50MHZ); } } - return false; + return SD_OK; } void sd_card_deinit (void) { @@ -354,29 +445,33 @@ uint32_t sd_card_get_status (void) { ); } -bool sd_card_get_info (uint32_t address) { +sd_error_t sd_card_get_info (uint32_t address) { if (!p.card_initialized) { - return true; + return SD_ERROR_NOT_INITIALIZED; } fpga_mem_write(address, sizeof(p.csd), p.csd); address += sizeof(p.csd); fpga_mem_write(address, sizeof(p.cid), p.cid); address += sizeof(p.cid); - return false; + return SD_OK; } -bool sd_set_byte_swap (bool enabled) { +sd_error_t sd_set_byte_swap (bool enabled) { if (!p.card_initialized) { - return true; + return SD_ERROR_NOT_INITIALIZED; } p.byte_swap = enabled; - return false; + return SD_OK; } -bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) { - if (!p.card_initialized || (count == 0)) { - return true; +sd_error_t sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) { + if (!p.card_initialized) { + return SD_ERROR_NOT_INITIALIZED; + } + + if (count == 0) { + return SD_ERROR_INVALID_ARGUMENT; } if (!p.card_type_block) { @@ -386,12 +481,13 @@ bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) { while (count > 0) { uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count); if (sd_cmd(25, sector, RSP_R1, NULL)) { - return true; + return SD_ERROR_CMD25_IO; } sd_dat_prepare(address, blocks, DAT_WRITE); - if (sd_dat_wait(DAT_TIMEOUT_DATA_MS) != DAT_OK) { + dat_error_t error = sd_dat_wait(DAT_TIMEOUT_DATA_MS); + if (error != DAT_OK) { sd_cmd(12, 0, RSP_R1b, NULL); - return true; + return (error == DAT_ERROR_IO) ? SD_ERROR_CMD25_CRC : SD_ERROR_CMD25_TIMEOUT; } sd_cmd(12, 0, RSP_R1b, NULL); address += (blocks * SD_SECTOR_SIZE); @@ -402,13 +498,17 @@ bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) { return false; } -bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) { - if (!p.card_initialized || (count == 0)) { - return true; +sd_error_t sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) { + if (!p.card_initialized) { + return SD_ERROR_NOT_INITIALIZED; + } + + if (count == 0) { + return SD_ERROR_INVALID_ARGUMENT; } if (p.byte_swap && ((address % 2) != 0)) { - return true; + return SD_ERROR_INVALID_ARGUMENT; } if (!p.card_type_block) { @@ -420,11 +520,12 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) { sd_dat_prepare(address, blocks, DAT_READ); if (sd_cmd(18, sector, RSP_R1, NULL)) { sd_dat_abort(); - return true; + return SD_ERROR_CMD18_IO; } - if (sd_dat_wait(DAT_TIMEOUT_DATA_MS) != DAT_OK) { + dat_error_t error = sd_dat_wait(DAT_TIMEOUT_DATA_MS); + if (error != DAT_OK) { sd_cmd(12, 0, RSP_R1b, NULL); - return true; + return (error == DAT_ERROR_IO) ? SD_ERROR_CMD18_CRC : SD_ERROR_CMD18_TIMEOUT; } sd_cmd(12, 0, RSP_R1b, NULL); address += (blocks * SD_SECTOR_SIZE); @@ -432,21 +533,21 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) { count -= blocks; } - return false; + return SD_OK; } -bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors) { +sd_error_t 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; uint32_t sectors_to_process = 0; if (count == 0) { - return true; + return SD_ERROR_INVALID_ARGUMENT; } for (uint32_t i = 0; i < count; i++) { if (sector_table[i] == 0) { - return true; + return SD_ERROR_INVALID_ARGUMENT; } sectors_to_process += 1; if ((i < (count - 1)) && ((sector_table[i] + 1) == sector_table[i + 1])) { @@ -454,14 +555,14 @@ bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t cou } bool error = sd_process_sectors(address, sector_table[starting_sector], sectors_to_process); if (error) { - return true; + return error; } address += (sectors_to_process * SD_SECTOR_SIZE); starting_sector += sectors_to_process; sectors_to_process = 0; } - return false; + return SD_OK; } diff --git a/sw/controller/src/sd.h b/sw/controller/src/sd.h index e530af5..d3e326d 100644 --- a/sw/controller/src/sd.h +++ b/sw/controller/src/sd.h @@ -10,20 +10,53 @@ #define SD_CARD_INFO_SIZE (32) -typedef bool sd_process_sectors_t (uint32_t address, uint32_t sector, uint32_t count); +typedef enum { + SD_OK = 0, + SD_ERROR_NO_CARD_IN_SLOT = 1, + SD_ERROR_NOT_INITIALIZED = 2, + SD_ERROR_INVALID_ARGUMENT = 3, + SD_ERROR_INVALID_ADDRESS = 4, + SD_ERROR_INVALID_OPERATION = 5, + SD_ERROR_CMD2_IO = 6, + SD_ERROR_CMD3_IO = 7, + SD_ERROR_CMD6_CHECK_IO = 8, + SD_ERROR_CMD6_CHECK_CRC = 9, + SD_ERROR_CMD6_CHECK_TIMEOUT = 10, + SD_ERROR_CMD6_CHECK_RESPONSE = 11, + SD_ERROR_CMD6_SWITCH_IO = 12, + SD_ERROR_CMD6_SWITCH_CRC = 13, + SD_ERROR_CMD6_SWITCH_TIMEOUT = 14, + SD_ERROR_CMD6_SWITCH_RESPONSE = 15, + SD_ERROR_CMD7_IO = 16, + SD_ERROR_CMD8_IO = 17, + SD_ERROR_CMD9_IO = 18, + SD_ERROR_CMD10_IO = 19, + SD_ERROR_CMD18_IO = 20, + SD_ERROR_CMD18_CRC = 21, + SD_ERROR_CMD18_TIMEOUT = 22, + SD_ERROR_CMD25_IO = 23, + SD_ERROR_CMD25_CRC = 24, + SD_ERROR_CMD25_TIMEOUT = 25, + SD_ERROR_ACMD6_IO = 26, + SD_ERROR_ACMD41_IO = 27, + SD_ERROR_ACMD41_OCR = 28, + SD_ERROR_ACMD41_TIMEOUT = 29, +} sd_error_t; + +typedef sd_error_t sd_process_sectors_t (uint32_t address, uint32_t sector, uint32_t count); -bool sd_card_init (void); +sd_error_t sd_card_init (void); void sd_card_deinit (void); bool sd_card_is_inserted (void); uint32_t sd_card_get_status (void); -bool sd_card_get_info (uint32_t address); -bool sd_set_byte_swap (bool enabled); +sd_error_t sd_card_get_info (uint32_t address); +sd_error_t sd_set_byte_swap (bool enabled); -bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count); -bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count); +sd_error_t sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count); +sd_error_t sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count); -bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors); +sd_error_t sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors); void sd_init (void); diff --git a/sw/controller/src/writeback.c b/sw/controller/src/writeback.c index d2e4c91..f089d96 100644 --- a/sw/controller/src/writeback.c +++ b/sw/controller/src/writeback.c @@ -82,9 +82,9 @@ static void writeback_save_to_sd (void) { return; } - bool error = sd_optimize_sectors(address, p.sectors, (length / SD_SECTOR_SIZE), sd_write_sectors); + sd_error_t error = sd_optimize_sectors(address, p.sectors, (length / SD_SECTOR_SIZE), sd_write_sectors); - if (error) { + if (error != SD_OK) { writeback_disable(); return; }